feat(catalog): add Claude Fable 5 to Anthropic model registry

This commit is contained in:
Sergey authored and GitHub committed 2026-06-10 13:03:38 -04:00
1 parent cf90f48240
commit 298c89f2c3
9 files changed
+85 -1

No files matched your search

@@ -168,6 +168,19 @@ describe('Model Catalog', () => {
assert.strictEqual(opus48.extendedContext, true);
});
it('includes Claude Fable 5 with adaptive levels and extended context', () => {
const { MODEL_CATALOG } = modelCatalog;
const fable5 = MODEL_CATALOG.claude.models.find((m) => m.id === 'claude-fable-5');
assert(fable5, 'Should include Claude Fable 5');
assert.strictEqual(fable5.name, 'Claude Fable 5');
// New top tier above Opus; same adaptive thinking surface as Opus 4.8:
// Anthropic only accepts effort levels, budget_tokens is rejected with 400.
assert.strictEqual(fable5.thinking.type, 'levels');
assert.deepStrictEqual(fable5.thinking.levels, ['low', 'medium', 'high', 'xhigh', 'max']);
assert.strictEqual(fable5.thinking.maxLevel, 'max');
assert.strictEqual(fable5.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);
@@ -60,6 +60,15 @@ describe('Thinking Validator', () => {
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.
const result = validateThinking('claude', 'claude-fable-5', 'max');
expect(result.valid).toBe(true);
expect(result.value).toBe('max');
expect(result.warning).toBeUndefined();
});
it('should still alias max -> xhigh for models without a max level (backcompat)', () => {
// Codex catalog uses ['low','medium','high','xhigh'] with maxLevel 'xhigh'.
// User input "max" should map down to xhigh rather than be rejected.
+1
View File
@@ -63,6 +63,7 @@ function shouldShowWarnings(thinkingConfig: ThinkingConfig): boolean {
*/
export function detectTierFromModel(modelName: string): ModelTier {
const lower = modelName.toLowerCase();
if (lower.includes('fable')) return 'opus'; // Fable is the top tier; thinking defaults match Opus
if (lower.includes('opus')) return 'opus';
if (lower.includes('haiku')) return 'haiku';
return 'sonnet'; // Default to sonnet (most common)
@@ -65,6 +65,13 @@ describe('detectTierFromModel', () => {
expect(result).toBe('sonnet');
});
it('should map Claude Fable 5 to the opus tier', () => {
// Fable is the top tier above Opus; auto-mode thinking defaults should
// match the opus tier (effort high), not the sonnet fallback.
const result = detectTierFromModel('claude-fable-5');
expect(result).toBe('opus');
});
it('should detect haiku from model name containing "haiku"', () => {
const result = detectTierFromModel('claude-haiku-4-5-20251001');
expect(result).toBe('haiku');
+15
View File
@@ -369,6 +369,21 @@ export const MODEL_CATALOG: Partial<Record<CLIProxyProvider, ProviderCatalog>> =
displayName: 'Claude (Anthropic)',
defaultModel: 'claude-sonnet-4-6',
models: [
{
id: 'claude-fable-5',
name: 'Claude Fable 5',
description: 'Most powerful model',
nativeImageInput: true,
// New tier above Opus. Same adaptive-thinking surface as Opus 4.8:
// Anthropic accepts only effort levels; manual budget_tokens is rejected with 400.
thinking: {
type: 'levels',
levels: ['low', 'medium', 'high', 'xhigh', 'max'],
maxLevel: 'max',
dynamicAllowed: true,
},
extendedContext: true,
},
{
id: 'claude-opus-4-8',
name: 'Claude Opus 4.8',
+7
View File
@@ -316,6 +316,13 @@ const PRICING_REGISTRY: Record<string, ModelPricing> = {
fast: OPUS_48_FAST_RATES,
},
},
// Claude Fable 5 ($10/$50) — most powerful tier, above Opus
'claude-fable-5': {
inputPerMillion: 10.0,
outputPerMillion: 50.0,
cacheCreationPerMillion: 12.5,
cacheReadPerMillion: 1.0,
},
// ---------------------------------------------------------------------------
// OpenAI Models - Source: better-ccusage