mirror of
https://github.com/danny-avila/LibreChat.git
synced 2026-10-22 01:53:33 +00:00
📖 feat: Add Claude Fable 5.1 Support (#15512)
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:
parent
1c7a172321
commit
d5b2a8580e
8 changed files with 91 additions and 8 deletions
15
.env.example
15
.env.example
|
|
@ -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 #
|
||||
|
|
|
|||
|
|
@ -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'],
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -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',
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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 },
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue