mirror of
https://github.com/tiennm99/ccs.git
synced 2026-10-03 20:13:02 +00:00
feat: support claude opus 5
This commit is contained in:
1 parent
2043c65de7
commit
ee90dd2640
5 files changed
+84
-1
No files matched your search
@@ -236,6 +236,22 @@ describe('Model Catalog', () => {
|
||||
assert.strictEqual(fable5.extendedContext, true);
|
||||
});
|
||||
|
||||
it('includes Claude Opus 5 with adaptive levels and extended context', () => {
|
||||
const { MODEL_CATALOG } = modelCatalog;
|
||||
const opus5 = MODEL_CATALOG.claude.models.find((m) => m.id === 'claude-opus-5');
|
||||
assert(opus5, 'Should include Claude Opus 5');
|
||||
assert.strictEqual(opus5.name, 'Claude Opus 5');
|
||||
// Opus 5 requires adaptive thinking (type: 'levels') like Sonnet 5 and Opus 4.8;
|
||||
// manual budget_tokens is rejected with 400. Proxy reports zero + dynamic allowed.
|
||||
assert.strictEqual(opus5.thinking.type, 'levels');
|
||||
assert.deepStrictEqual(opus5.thinking.levels, ['low', 'medium', 'high', 'xhigh', 'max']);
|
||||
assert.strictEqual(opus5.thinking.maxLevel, 'max');
|
||||
assert.strictEqual(opus5.thinking.zeroAllowed, true);
|
||||
assert.strictEqual(opus5.thinking.dynamicAllowed, true);
|
||||
assert.strictEqual(opus5.nativeImageInput, true);
|
||||
assert.strictEqual(opus5.extendedContext, true);
|
||||
});
|
||||
|
||||
it('retains previous 4.5 snapshot models for explicit selection', () => {
|
||||
const { MODEL_CATALOG } = modelCatalog;
|
||||
const ids = MODEL_CATALOG.claude.models.map((m) => m.id);
|
||||
|
||||
@@ -499,6 +499,23 @@ export const MODEL_CATALOG: Partial<Record<CLIProxyProvider, ProviderCatalog>> =
|
||||
},
|
||||
extendedContext: true,
|
||||
},
|
||||
{
|
||||
id: 'claude-opus-5',
|
||||
name: 'Claude Opus 5',
|
||||
description: 'Latest premium model',
|
||||
nativeImageInput: true,
|
||||
// Opus 5 (released 2026-07-14) uses adaptive thinking, matching Sonnet 5
|
||||
// and Opus 4.8: Anthropic accepts only effort levels; manual budget_tokens
|
||||
// is rejected with 400. Proxy metadata reports zero + dynamic allowed.
|
||||
thinking: {
|
||||
type: 'levels',
|
||||
levels: ['low', 'medium', 'high', 'xhigh', 'max'],
|
||||
maxLevel: 'max',
|
||||
zeroAllowed: true,
|
||||
dynamicAllowed: true,
|
||||
},
|
||||
extendedContext: true,
|
||||
},
|
||||
{
|
||||
id: 'claude-opus-4-8',
|
||||
name: 'Claude Opus 4.8',
|
||||
|
||||
@@ -331,6 +331,28 @@ const PRICING_REGISTRY: Record<string, ModelPricing> = {
|
||||
fast: OPUS_48_FAST_RATES,
|
||||
},
|
||||
},
|
||||
// Claude Opus 5 ($5/$25) — Claude 5 generation Opus (released 2026-07-14).
|
||||
// Rates mirror Opus 4.8 (same Opus tier); fast mode reuses the 2x premium
|
||||
// pending official Opus 5 numbers. Registered explicitly so it resolves to
|
||||
// Opus-tier pricing instead of the unknown-model fallback.
|
||||
'claude-opus-5': {
|
||||
inputPerMillion: 5.0,
|
||||
outputPerMillion: 25.0,
|
||||
cacheCreationPerMillion: 6.25,
|
||||
cacheReadPerMillion: 0.5,
|
||||
serviceTiers: {
|
||||
fast: OPUS_48_FAST_RATES,
|
||||
},
|
||||
},
|
||||
'claude-opus-5-thinking': {
|
||||
inputPerMillion: 5.0,
|
||||
outputPerMillion: 25.0,
|
||||
cacheCreationPerMillion: 6.25,
|
||||
cacheReadPerMillion: 0.5,
|
||||
serviceTiers: {
|
||||
fast: OPUS_48_FAST_RATES,
|
||||
},
|
||||
},
|
||||
// Claude Fable 5 ($10/$50) — most powerful tier, above Opus
|
||||
'claude-fable-5': {
|
||||
inputPerMillion: 10.0,
|
||||
|
||||
@@ -285,10 +285,26 @@ describe('model-pricing', () => {
|
||||
expect(sonnet5.cacheReadPerMillion).toBe(0.3);
|
||||
});
|
||||
|
||||
it('should return Opus-tier pricing for Claude Opus 5', () => {
|
||||
// Opus 5 mirrors Opus 4.8 rates; date-stamped ids resolve via stripDateSuffix.
|
||||
const opus5 = getModelPricing('claude-opus-5');
|
||||
expect(opus5.inputPerMillion).toBe(5.0);
|
||||
expect(opus5.outputPerMillion).toBe(25.0);
|
||||
expect(opus5.cacheCreationPerMillion).toBe(6.25);
|
||||
expect(opus5.cacheReadPerMillion).toBe(0.5);
|
||||
expect(getModelPricing('claude-opus-5-20270101').inputPerMillion).toBe(5.0);
|
||||
});
|
||||
|
||||
it('should apply fast-tier pricing for Claude Opus 5', () => {
|
||||
const opus5fast = getModelPricing('claude-opus-5', { serviceTier: 'fast' });
|
||||
expect(opus5fast.inputPerMillion).toBe(10.0);
|
||||
expect(opus5fast.outputPerMillion).toBe(50.0);
|
||||
});
|
||||
|
||||
it('should not map unknown future model families onto known family pricing', () => {
|
||||
const fallback = getModelPricing('unknown-model-xyz');
|
||||
|
||||
expect(getModelPricing('claude-opus-5-20270101')).toEqual(fallback);
|
||||
expect(getModelPricing('claude-opus-6-20270101')).toEqual(fallback);
|
||||
expect(getModelPricing('gemini-3.2-pro')).toEqual(fallback);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -982,6 +982,18 @@ export const MODEL_CATALOGS: Record<string, ProviderCatalog> = {
|
||||
haiku: 'claude-haiku-4-5-20251001',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'claude-opus-5',
|
||||
name: 'Claude Opus 5',
|
||||
description: 'Latest premium model',
|
||||
extendedContext: true,
|
||||
presetMapping: {
|
||||
default: 'claude-opus-5',
|
||||
opus: 'claude-opus-5',
|
||||
sonnet: 'claude-sonnet-5',
|
||||
haiku: 'claude-haiku-4-5-20251001',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'claude-opus-4-8',
|
||||
name: 'Claude Opus 4.8',
|
||||
|
||||
Reference in new issue
Block a user