📖 feat: Add Claude Fable 5.1 Support (#15512)
Some checks are pending
Docker Dev Images Build / publish (push) Waiting to run
Sync Helm Chart Tags / Ignore non-main push (push) Waiting to run
Sync Helm Chart Tags / Sync chart tags (push) Waiting to run

Claude Fable 5.1 (`claude-fable-5-1`, GA 2026-09-01) succeeds Claude Fable 5
at the same input/output prices, with a 1M context window and 128K max output.
The Mythos-class helpers added for Fable 5 already match it — `isMythosClassModel`
tests `claude-(?:fable|mythos)[-.]?\d`, so adaptive thinking, summarized-display
opt-in, sampling omission, 1M context, the 128K output clamp, prompt caching,
the Vertex multi-region gate, and the Bedrock PDF exemption all cover 5.1
without a code change. What was missing was registration and pricing.

Cache reads are the one rate that differs, and the substring matcher would have
silently gotten it wrong: `claude-fable-5-1` falls through to the `claude-fable-5`
key, which prices cache hits at the usual 0.1x base input ($1/MTok). Fable 5.1
and Mythos 5.1 price them at 0.025x ($0.25/MTok), so every cache read would have
billed 4x — on exactly the long agentic sessions this model is built for.

- Register `claude-fable-5-1` in the shared Anthropic list and
  `global.anthropic.claude-fable-5-1` in the Bedrock list
- Add 1M context / 128K output entries for `claude-fable-5-1` and
  `claude-mythos-5-1`
- Add $10/$50 rates and `{ write: 12.5, read: 0.25 }` cache rates for both
- Update the `.env.example` and Vertex `librechat.example.yaml` examples
- Test that 5.1 resolves to its own key rather than collapsing onto 5.0, across
  token maps, pricing, cache rates, and Mythos-class detection

The three documented breaking changes from Fable 5 need no handling here:
LibreChat never sends a forced `tool_choice` on the Anthropic path (the agents
SDK omits the param when unset, so the API default `auto` applies); thinking
blocks an earlier model can't read are dropped server-side, unbilled; and
history is rebuilt from stored content parts rather than replayed signed
thinking blocks, so the prefix-binding check has nothing to reject.

Refs #15506
This commit is contained in:
Danny Avila 2026-09-02 10:45:54 -04:00 • committed by GitHub
parent 1c7a172321
commit d5b2a8580e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 91 additions and 8 deletions

View file

@ -419,14 +419,14 @@ PROXY=
#============#
ANTHROPIC_API_KEY=user_provided
# ANTHROPIC_MODELS=claude-fable-5,claude-opus-5,claude-opus-4-8,claude-opus-4-7,claude-sonnet-5,claude-sonnet-4-6,claude-opus-4-6,claude-opus-4-20250514,claude-3-7-sonnet-20250219,claude-3-5-sonnet-20241022,claude-3-5-haiku-20241022,claude-3-opus-20240229,claude-3-sonnet-20240229,claude-3-haiku-20240307
# ANTHROPIC_MODELS=claude-fable-5-1,claude-fable-5,claude-opus-5,claude-opus-4-8,claude-opus-4-7,claude-sonnet-5,claude-sonnet-4-6,claude-opus-4-6,claude-opus-4-20250514,claude-3-7-sonnet-20250219,claude-3-5-sonnet-20241022,claude-3-5-haiku-20241022,claude-3-opus-20240229,claude-3-sonnet-20240229,claude-3-haiku-20240307
# ANTHROPIC_REVERSE_PROXY=
# Set to true to use Anthropic models through Google Vertex AI instead of direct API
# ANTHROPIC_USE_VERTEX=
# Supports regional locations like us-east5 and multi-region locations: us, eu, global
# IMPORTANT: specific regional endpoints (us-east5, europe-west1, ...) only serve Claude Sonnet 4.6
# and earlier. Newer models (Opus 4.7+, Opus 5, Sonnet 5, Fable 5) require `global` or a multi-region
# and earlier. Newer models (Opus 4.7+, Opus 5, Sonnet 5, Fable 5/5.1) require `global` or a multi-region
# location (`us`/`eu`) and will 404 on a specific region. `global` also avoids the 10% regional premium.
# ANTHROPIC_VERTEX_REGION=us-east5
@ -490,8 +490,8 @@ ANTHROPIC_API_KEY=user_provided
# Note: This example list is not meant to be exhaustive. If omitted, all known, supported model IDs will be included for you.
# Claude 4+ models cannot be invoked on-demand by their bare `anthropic.` foundation-model ID; Bedrock requires a
# cross-region inference profile (`global.` or `us.`) for those. The `global.` profile has no regional pricing premium.
# BEDROCK_AWS_MODELS=global.anthropic.claude-fable-5,global.anthropic.claude-opus-5,global.anthropic.claude-opus-4-8,global.anthropic.claude-opus-4-7,global.anthropic.claude-sonnet-5,global.anthropic.claude-sonnet-4-6,global.anthropic.claude-opus-4-6-v1,global.anthropic.claude-haiku-4-5-20251001-v1:0,meta.llama3-1-8b-instruct-v1:0
# US-only routing alternative: us.anthropic.claude-fable-5,us.anthropic.claude-opus-5,us.anthropic.claude-opus-4-8,us.anthropic.claude-opus-4-7,us.anthropic.claude-sonnet-5,us.anthropic.claude-sonnet-4-6,us.anthropic.claude-opus-4-6-v1
# BEDROCK_AWS_MODELS=global.anthropic.claude-fable-5-1,global.anthropic.claude-fable-5,global.anthropic.claude-opus-5,global.anthropic.claude-opus-4-8,global.anthropic.claude-opus-4-7,global.anthropic.claude-sonnet-5,global.anthropic.claude-sonnet-4-6,global.anthropic.claude-opus-4-6-v1,global.anthropic.claude-haiku-4-5-20251001-v1:0,meta.llama3-1-8b-instruct-v1:0
# US-only routing alternative: us.anthropic.claude-fable-5-1,us.anthropic.claude-fable-5,us.anthropic.claude-opus-5,us.anthropic.claude-opus-4-8,us.anthropic.claude-opus-4-7,us.anthropic.claude-sonnet-5,us.anthropic.claude-sonnet-4-6,us.anthropic.claude-opus-4-6-v1
# List the profiles available to your account with: aws bedrock list-inference-profiles --region <your-region>
# See all Bedrock model IDs here: https://docs.aws.amazon.com/bedrock/latest/userguide/model-ids.html#model-ids-arns
@ -503,9 +503,10 @@ ANTHROPIC_API_KEY=user_provided
# The following models are not support due to not supporting conversation history:
# ai21.j2-ultra-v1, cohere.command-text-v14, cohere.command-light-text-v14
# Claude Mythos-class models (anthropic.claude-fable-5, anthropic.claude-mythos-5) are inference-profile
# only on Bedrock — use a profile ID (e.g. us.anthropic.claude-fable-5) — and require opting into Anthropic
# data sharing via the Bedrock Data Retention API/console before they can be invoked.
# Claude Mythos-class models (anthropic.claude-fable-5-1, anthropic.claude-mythos-5-1, and their 5.0
# predecessors) are inference-profile only on Bedrock — use a profile ID (e.g. us.anthropic.claude-fable-5-1)
# — and require opting into Anthropic data sharing via the Bedrock Data Retention API/console before they
# can be invoked.
#============#
# Google #

View file

@ -1640,6 +1640,40 @@ describe('Claude Model Tests', () => {
});
});
it('should return correct context length for Claude Fable 5.1 (1M)', () => {
expect(maxTokensMap[EModelEndpoint.anthropic]['claude-fable-5-1']).toBe(1000000);
expect(maxTokensMap[EModelEndpoint.anthropic]['claude-mythos-5-1']).toBe(1000000);
expect(getModelMaxTokens('claude-fable-5-1', EModelEndpoint.anthropic)).toBe(1000000);
expect(getModelMaxTokens('claude-mythos-5-1', EModelEndpoint.anthropic)).toBe(1000000);
});
it('should return correct max output tokens for Claude Fable 5.1 (128K)', () => {
const { getModelMaxOutputTokens } = require('@librechat/api');
expect(maxOutputTokensMap[EModelEndpoint.anthropic]['claude-fable-5-1']).toBe(128000);
expect(maxOutputTokensMap[EModelEndpoint.anthropic]['claude-mythos-5-1']).toBe(128000);
expect(getModelMaxOutputTokens('claude-fable-5-1', EModelEndpoint.anthropic)).toBe(128000);
expect(getModelMaxOutputTokens('claude-mythos-5-1', EModelEndpoint.anthropic)).toBe(128000);
});
it('should match model names correctly for Claude Fable 5.1 without collapsing to Fable 5', () => {
const modelVariations = [
'claude-fable-5-1',
'claude-fable-5-1-20260901',
'claude-fable-5-1-latest',
'anthropic/claude-fable-5-1',
'claude-fable-5-1/anthropic',
'anthropic.claude-fable-5-1',
];
modelVariations.forEach((model) => {
expect(matchModelName(model, EModelEndpoint.anthropic)).toBe('claude-fable-5-1');
});
expect(matchModelName('claude-fable-5-20260609', EModelEndpoint.anthropic)).toBe(
'claude-fable-5',
);
});
it('should return correct context length for Claude Sonnet 4.6 (1M)', () => {
expect(getModelMaxTokens('claude-sonnet-4-6', EModelEndpoint.anthropic)).toBe(
maxTokensMap[EModelEndpoint.anthropic]['claude-sonnet-4-6'],

View file

@ -656,7 +656,7 @@ endpoints:
# # Available regions: us-east5, us-central1, europe-west1, europe-west4, asia-southeast1
# # Multi-region endpoints: us, eu, global
# # IMPORTANT: specific regional endpoints only serve Claude Sonnet 4.6 and earlier. Newer
# # models (Opus 4.7+, Opus 5, Sonnet 5, Fable 5) require "global" or a multi-region value
# # models (Opus 4.7+, Opus 5, Sonnet 5, Fable 5/5.1) require "global" or a multi-region value
# # ("us"/"eu") and will 404 on a specific region. "global" also avoids the 10% regional premium.
# region: "us-east5"
# # Path to Google service account key file (optional)
@ -675,6 +675,7 @@ endpoints:
# # Option 1: Simple array (legacy format - model name = deployment name)
# # Use this if you want the technical model IDs to show in the UI
# # models:
# # - "claude-fable-5-1"
# # - "claude-fable-5"
# # - "claude-opus-5"
# # - "claude-opus-4-8"
@ -688,6 +689,8 @@ endpoints:
# # The deploymentName is the actual Vertex AI model ID used for API calls
# # You can use friendly names (avoid spaces for cleaner YAML) or technical IDs as keys
# models:
# claude-fable-5.1:
# deploymentName: claude-fable-5-1
# claude-fable-5:
# deploymentName: claude-fable-5
# claude-opus-5:

View file

@ -183,6 +183,8 @@ const anthropicModels = {
'claude-opus-5': 1000000,
'claude-fable-5': 1000000,
'claude-mythos-5': 1000000,
'claude-fable-5-1': 1000000,
'claude-mythos-5-1': 1000000,
};
const ANTHROPIC_CONTEXT_1M = 1000000;
@ -539,6 +541,8 @@ const anthropicMaxOutputs = {
'claude-opus-5': 128000,
'claude-fable-5': 128000,
'claude-mythos-5': 128000,
'claude-fable-5-1': 128000,
'claude-mythos-5-1': 128000,
'claude-3.5-sonnet': 8192,
'claude-3-5-sonnet': 8192,
'claude-3.7-sonnet': 128000,

View file

@ -29,6 +29,8 @@ describe('isMythosClassModel (single source of truth for Fable/Mythos)', () => {
expect(isMythosClassModel(`anthropic.claude-${family}-5`)).toBe(true);
expect(isMythosClassModel(`us.anthropic.claude-${family}-5`)).toBe(true);
expect(isMythosClassModel(`claude-${family}-5-20260609`)).toBe(true);
expect(isMythosClassModel(`claude-${family}-5-1`)).toBe(true);
expect(isMythosClassModel(`global.anthropic.claude-${family}-5-1`)).toBe(true);
});
});

View file

@ -2663,6 +2663,7 @@ const sharedOpenAIModels = [
];
const sharedAnthropicModels = [
'claude-fable-5-1',
'claude-fable-5',
'claude-opus-5',
'claude-opus-4-8',
@ -2698,6 +2699,7 @@ const sharedAnthropicModels = [
* availability); Opus 4.1 has no global profile, so it uses `us.`.
*/
export const bedrockModels = [
'global.anthropic.claude-fable-5-1',
'global.anthropic.claude-fable-5',
'global.anthropic.claude-opus-5',
'global.anthropic.claude-opus-4-8',

View file

@ -2661,6 +2661,38 @@ describe('Claude Model Tests', () => {
);
});
it('should pin Claude Fable 5.1 pricing to $10 / $50 per MTok', () => {
expect(tokenValues['claude-fable-5-1']).toEqual({ prompt: 10, completion: 50 });
expect(tokenValues['claude-mythos-5-1']).toEqual({ prompt: 10, completion: 50 });
});
it('should charge Claude Fable 5.1 cache reads at a quarter of the Fable 5 rate', () => {
expect(cacheTokenValues['claude-fable-5-1']).toEqual({ write: 12.5, read: 0.25 });
expect(cacheTokenValues['claude-mythos-5-1']).toEqual({ write: 12.5, read: 0.25 });
expect(getCacheMultiplier({ model: 'claude-fable-5-1', cacheType: 'read' })).toBe(0.25);
expect(getCacheMultiplier({ model: 'claude-fable-5-1', cacheType: 'write' })).toBe(12.5);
expect(getCacheMultiplier({ model: 'claude-fable-5', cacheType: 'read' })).toBe(1);
});
it('should handle Claude Fable 5.1 model name variations without collapsing to Fable 5', () => {
const modelVariations = [
'claude-fable-5-1',
'claude-fable-5-1-20260901',
'claude-fable-5-1-latest',
'anthropic/claude-fable-5-1',
'claude-fable-5-1/anthropic',
'anthropic.claude-fable-5-1',
'global.anthropic.claude-fable-5-1',
];
modelVariations.forEach((model) => {
expect(getValueKey(model)).toBe('claude-fable-5-1');
expect(getCacheMultiplier({ model, cacheType: 'read' })).toBe(0.25);
});
expect(getValueKey('claude-fable-5-20260609')).toBe('claude-fable-5');
});
it('should return correct prompt and completion rates for Claude Sonnet 5', () => {
expect(getMultiplier({ model: 'claude-sonnet-5', tokenType: 'prompt' })).toBe(
tokenValues['claude-sonnet-5'].prompt,

View file

@ -186,6 +186,8 @@ export const tokenValues: Record<string, { prompt: number; completion: number }>
'claude-opus-5': { prompt: 5, completion: 25 },
'claude-fable-5': { prompt: 10, completion: 50 },
'claude-mythos-5': { prompt: 10, completion: 50 },
'claude-fable-5-1': { prompt: 10, completion: 50 },
'claude-mythos-5-1': { prompt: 10, completion: 50 },
'claude-sonnet-4': { prompt: 3, completion: 15 },
'claude-sonnet-4-5': { prompt: 3, completion: 15 },
'claude-sonnet-4-6': { prompt: 3, completion: 15 },
@ -367,6 +369,9 @@ export const cacheTokenValues: Record<string, { write: number; read: number }> =
'claude-opus-5': { write: 6.25, read: 0.5 },
'claude-fable-5': { write: 12.5, read: 1 },
'claude-mythos-5': { write: 12.5, read: 1 },
// Fable/Mythos 5.1 cache reads are 0.025x base input, not the usual 0.1x.
'claude-fable-5-1': { write: 12.5, read: 0.25 },
'claude-mythos-5-1': { write: 12.5, read: 0.25 },
'gpt-4o': { write: 2.5, read: 1.25 },
'gpt-4o-mini': { write: 0.15, read: 0.075 },
'gpt-4.1': { write: 2, read: 0.5 },