mirror of
https://github.com/tiennm99/ccs.git
synced 2026-10-03 07:12:18 +00:00
feat(models): add Claude Fable 5.1 and correct Sonnet 5 pricing
Register `claude-fable-5-1` in the CLIProxy model catalog, the dashboard
catalog, and the usage pricing registry.
Pricing is taken from Anthropic's official pricing page:
- Fable 5.1 base rates are $10/$50 per MTok with a $12.50 5m cache write,
matching Fable 5.
- Cache hits bill at 0.025x base input ($0.25/MTok) rather than the
standard 0.1x multiplier. Anthropic applies that reduced rate only to
Fable 5.1 and Mythos 5.1, so this entry cannot derive its cache rates
from CACHE_READ_MULTIPLIER.
This also corrects Claude Sonnet 5 from $3/$15 to $2/$10 (cache write
$2.50, cache read $0.20). The launch introductory rate became the
standard price and the increase scheduled for 2026-09-01 was cancelled,
so the previous entry over-reported Sonnet 5 usage cost by 50%.
Thinking on Fable 5.1 is always on and can only be steered through
effort levels, so the catalog entry exposes the same `low`..`max` level
surface as Fable 5 and Opus 5 instead of a manual token budget.
The GitHub Copilot catalog is deliberately left unchanged, since Copilot
availability for Fable 5.1 is not verified; surfacing it there would
offer a model the backend may reject.
Regenerates docs/reports/hardening-inventory.{json,md} so the ci-parity
gate matches the source tree.
This commit is contained in:
1 parent
485c436958
commit
3583b544d0
8 files changed
+83
-22
No files matched your search
@@ -739,7 +739,7 @@
|
||||
},
|
||||
{
|
||||
"file": "src/web-server/model-pricing.ts",
|
||||
"loc": 1127
|
||||
"loc": 1138
|
||||
},
|
||||
{
|
||||
"file": "src/cliproxy/config/generator.ts",
|
||||
@@ -778,8 +778,8 @@
|
||||
"loc": 939
|
||||
},
|
||||
{
|
||||
"file": "src/cliproxy/accounts/registry.ts",
|
||||
"loc": 871
|
||||
"file": "src/cliproxy/model-catalog.ts",
|
||||
"loc": 884
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -93,7 +93,7 @@ Scope: `src/**/*.{ts,tsx,js,jsx,mjs,cjs}`
|
||||
| `src/web-server/routes/cliproxy-auth-routes.ts` | 1531 |
|
||||
| `src/cliproxy/auth/oauth-handler.ts` | 1510 |
|
||||
| `src/cursor/cursor-executor.ts` | 1234 |
|
||||
| `src/web-server/model-pricing.ts` | 1127 |
|
||||
| `src/web-server/model-pricing.ts` | 1138 |
|
||||
| `src/cliproxy/config/generator.ts` | 1109 |
|
||||
| `src/cliproxy/auth/oauth-process.ts` | 1048 |
|
||||
| `src/cliproxy/config/env-builder.ts` | 1045 |
|
||||
@@ -103,5 +103,5 @@ Scope: `src/**/*.{ts,tsx,js,jsx,mjs,cjs}`
|
||||
| `src/cliproxy/quota/quota-manager.ts` | 954 |
|
||||
| `src/web-server/services/codex-dashboard-service.ts` | 940 |
|
||||
| `src/glmt/glmt-proxy.ts` | 939 |
|
||||
| `src/cliproxy/accounts/registry.ts` | 871 |
|
||||
| `src/cliproxy/model-catalog.ts` | 884 |
|
||||
|
||||
@@ -60,6 +60,14 @@ describe('Thinking Validator', () => {
|
||||
expect(result.warning).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should treat max as a distinct top tier on Claude Fable 5.1', () => {
|
||||
// Fable 5.1 has always-on adaptive thinking steered only by effort level.
|
||||
const result = validateThinking('claude', 'claude-fable-5-1', 'max');
|
||||
expect(result.valid).toBe(true);
|
||||
expect(result.value).toBe('max');
|
||||
expect(result.warning).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should treat max as a distinct top tier on Claude Fable 5', () => {
|
||||
// Fable 5 shares Opus 4.8's adaptive thinking surface; max must remain
|
||||
// distinct from xhigh.
|
||||
|
||||
@@ -531,10 +531,27 @@ export const MODEL_CATALOG: Partial<Record<CLIProxyProvider, ProviderCatalog>> =
|
||||
},
|
||||
extendedContext: true,
|
||||
},
|
||||
{
|
||||
id: 'claude-fable-5-1',
|
||||
name: 'Claude Fable 5.1',
|
||||
description: 'Most powerful model (1M context, 128K output)',
|
||||
contextWindow: 1000000,
|
||||
nativeImageInput: true,
|
||||
// Thinking is always on and cannot be disabled: Anthropic rejects both
|
||||
// `thinking.type: "disabled"` and manual budget_tokens with 400. Depth is
|
||||
// steered only through effort levels (default `high`).
|
||||
thinking: {
|
||||
type: 'levels',
|
||||
levels: ['low', 'medium', 'high', 'xhigh', 'max'],
|
||||
maxLevel: 'max',
|
||||
dynamicAllowed: true,
|
||||
},
|
||||
extendedContext: true,
|
||||
},
|
||||
{
|
||||
id: 'claude-fable-5',
|
||||
name: 'Claude Fable 5',
|
||||
description: 'Most powerful model',
|
||||
description: 'Previous most powerful model',
|
||||
contextWindow: 1000000,
|
||||
nativeImageInput: true,
|
||||
// New tier above Opus. Same adaptive-thinking surface as Opus 4.8:
|
||||
|
||||
@@ -216,20 +216,21 @@ const PRICING_REGISTRY: Record<string, ModelPricing> = {
|
||||
cacheCreationPerMillion: 3.75,
|
||||
cacheReadPerMillion: 0.3,
|
||||
},
|
||||
// Claude Sonnet 5 ($3/$15) — latest Sonnet; shares the standard Sonnet rates.
|
||||
// Claude Sonnet 5 ($2/$10) — the launch introductory rate is now the standard
|
||||
// price; Anthropic cancelled the scheduled 2026-09-01 increase to $3/$15.
|
||||
// Registered explicitly so it is a known model rather than relying on the
|
||||
// unknown-model fallback that coincidentally matches these rates.
|
||||
// unknown-model fallback.
|
||||
'claude-sonnet-5': {
|
||||
inputPerMillion: 3.0,
|
||||
outputPerMillion: 15.0,
|
||||
cacheCreationPerMillion: 3.75,
|
||||
cacheReadPerMillion: 0.3,
|
||||
inputPerMillion: 2.0,
|
||||
outputPerMillion: 10.0,
|
||||
cacheCreationPerMillion: 2.5,
|
||||
cacheReadPerMillion: 0.2,
|
||||
},
|
||||
'claude-sonnet-5-thinking': {
|
||||
inputPerMillion: 3.0,
|
||||
outputPerMillion: 15.0,
|
||||
cacheCreationPerMillion: 3.75,
|
||||
cacheReadPerMillion: 0.3,
|
||||
inputPerMillion: 2.0,
|
||||
outputPerMillion: 10.0,
|
||||
cacheCreationPerMillion: 2.5,
|
||||
cacheReadPerMillion: 0.2,
|
||||
},
|
||||
// Claude 4 Opus ($15/$75)
|
||||
'claude-4-opus-20250514': {
|
||||
@@ -360,6 +361,16 @@ const PRICING_REGISTRY: Record<string, ModelPricing> = {
|
||||
cacheCreationPerMillion: 12.5,
|
||||
cacheReadPerMillion: 1.0,
|
||||
},
|
||||
// Claude Fable 5.1 ($10/$50) — same tier and base rates as Fable 5, but cache
|
||||
// hits are billed at 0.025x base input ($0.25/MTok) instead of the usual 0.1x.
|
||||
// Anthropic applies that reduced multiplier only to Fable 5.1 and Mythos 5.1,
|
||||
// so this entry cannot use CACHE_READ_MULTIPLIER-derived rates.
|
||||
'claude-fable-5-1': {
|
||||
inputPerMillion: 10.0,
|
||||
outputPerMillion: 50.0,
|
||||
cacheCreationPerMillion: 12.5,
|
||||
cacheReadPerMillion: 0.25,
|
||||
},
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// OpenAI Models - Source: better-ccusage
|
||||
|
||||
@@ -277,12 +277,24 @@ describe('model-pricing', () => {
|
||||
expect(fable5.cacheReadPerMillion).toBe(1.0);
|
||||
});
|
||||
|
||||
it('should return correct pricing for Claude Fable 5.1', () => {
|
||||
// Same base rates as Fable 5, but cache hits bill at 0.025x base input
|
||||
// ($0.25/MTok) rather than the standard 0.1x multiplier.
|
||||
const fable51 = getModelPricing('claude-fable-5-1');
|
||||
expect(fable51.inputPerMillion).toBe(10.0);
|
||||
expect(fable51.outputPerMillion).toBe(50.0);
|
||||
expect(fable51.cacheCreationPerMillion).toBe(12.5);
|
||||
expect(fable51.cacheReadPerMillion).toBe(0.25);
|
||||
});
|
||||
|
||||
it('should return correct pricing for Claude Sonnet 5', () => {
|
||||
// The $2/$10 launch introductory rate became the standard price; the
|
||||
// scheduled 2026-09-01 increase to $3/$15 was cancelled.
|
||||
const sonnet5 = getModelPricing('claude-sonnet-5');
|
||||
expect(sonnet5.inputPerMillion).toBe(3.0);
|
||||
expect(sonnet5.outputPerMillion).toBe(15.0);
|
||||
expect(sonnet5.cacheCreationPerMillion).toBe(3.75);
|
||||
expect(sonnet5.cacheReadPerMillion).toBe(0.3);
|
||||
expect(sonnet5.inputPerMillion).toBe(2.0);
|
||||
expect(sonnet5.outputPerMillion).toBe(10.0);
|
||||
expect(sonnet5.cacheCreationPerMillion).toBe(2.5);
|
||||
expect(sonnet5.cacheReadPerMillion).toBe(0.2);
|
||||
});
|
||||
|
||||
it('should return Opus-tier pricing for Claude Opus 5', () => {
|
||||
@@ -430,7 +442,7 @@ describe('model-pricing', () => {
|
||||
cacheReadTokens: 1_000_000,
|
||||
};
|
||||
const cost = calculateCost(usage, 'claude-sonnet-5');
|
||||
expect(cost).toBe(22.05); // 3 + 15 + 3.75 + 0.3
|
||||
expect(cost).toBe(14.7); // 2 + 10 + 2.5 + 0.2
|
||||
});
|
||||
|
||||
it('should calculate fast-tier Claude Opus 4.8 cost (2x premium)', () => {
|
||||
|
||||
@@ -977,10 +977,22 @@ export const MODEL_CATALOGS: Record<string, ProviderCatalog> = {
|
||||
haiku: 'claude-haiku-4-5-20251001',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'claude-fable-5-1',
|
||||
name: 'Claude Fable 5.1',
|
||||
description: 'Most powerful model',
|
||||
extendedContext: true,
|
||||
presetMapping: {
|
||||
default: 'claude-fable-5-1',
|
||||
opus: 'claude-fable-5-1',
|
||||
sonnet: 'claude-sonnet-5',
|
||||
haiku: 'claude-haiku-4-5-20251001',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'claude-fable-5',
|
||||
name: 'Claude Fable 5',
|
||||
description: 'Most powerful model',
|
||||
description: 'Previous most powerful model',
|
||||
extendedContext: true,
|
||||
presetMapping: {
|
||||
default: 'claude-fable-5',
|
||||
|
||||
@@ -22,6 +22,7 @@ describe('claude preset utils', () => {
|
||||
|
||||
expect(claudeCatalog.defaultModel).toBe('claude-sonnet-5');
|
||||
expect(ids).toContain('claude-sonnet-5');
|
||||
expect(ids).toContain('claude-fable-5-1');
|
||||
expect(ids).toContain('claude-fable-5');
|
||||
expect(ids).toContain('claude-opus-5');
|
||||
expect(ids).toContain('claude-opus-4-8');
|
||||
|
||||
Reference in new issue
Block a user