🤖 feat: Claude Sonnet 4.6 support (#11829)
Some checks are pending
Docker Dev Images Build / build (Dockerfile, librechat-dev, node) (push) Waiting to run
Docker Dev Images Build / build (Dockerfile.multi, librechat-dev-api, api-build) (push) Waiting to run
Sync Locize Translations & Create Translation PR / Sync Translation Keys with Locize (push) Waiting to run
Sync Locize Translations & Create Translation PR / Create Translation PR on Version Published (push) Blocked by required conditions

* 🤖 feat: Claude Sonnet 4.6 support

- Updated .env.example to include claude-sonnet-4-6 in the list of available models.
- Enhanced token value assignments in api/models/tx.js and packages/api/src/utils/tokens.ts to accommodate claude-sonnet-4-6.
- Added tests in packages/data-provider/specs/bedrock.spec.ts to verify support for claude-sonnet-4-6 in adaptive thinking and context-1m functionalities.
- Modified bedrock.ts to correctly parse and identify the version of claude-sonnet-4-6 for adaptive thinking checks.
- Included claude-sonnet-4-6 in sharedAnthropicModels and bedrockModels for consistent model availability.

* chore: additional Claude Sonnet 4.6 tests

- Added unit tests for Claude Sonnet 4.6 in `tokens.spec.js` to verify context length and max output tokens.
- Updated `helpers.ts` documentation to reflect adaptive thinking support for Sonnet 4.6.
- Enhanced `llm.spec.ts` with tests for context headers and adaptive thinking configurations for Claude Sonnet 4.6.
- Improved `bedrock.spec.ts` to ensure correct parsing and handling of Claude Sonnet 4.6 model variations with adaptive thinking.
This commit is contained in:
Danny Avila 2026-02-17 15:24:03 -05:00 committed by GitHub
parent e710a12bfb
commit 0697e8cd60
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 218 additions and 16 deletions

View file

@ -65,7 +65,7 @@ function getClaudeHeaders(
/**
* Configures reasoning-related options for Claude models.
* Models supporting adaptive thinking (Opus 4.6+, Sonnet 5+) use effort control instead of manual budget_tokens.
* Models supporting adaptive thinking (Opus 4.6+, Sonnet 4.6+) use effort control instead of manual budget_tokens.
*/
function configureReasoning(
anthropicInput: AnthropicClientOptions & { max_tokens?: number },

View file

@ -121,6 +121,39 @@ describe('getLLMConfig', () => {
});
});
it('should add "context-1m" beta header for claude-sonnet-4-6 model', () => {
const modelOptions = {
model: 'claude-sonnet-4-6',
promptCache: true,
};
const result = getLLMConfig('test-key', { modelOptions });
const clientOptions = result.llmConfig.clientOptions;
expect(clientOptions?.defaultHeaders).toBeDefined();
expect(clientOptions?.defaultHeaders).toHaveProperty('anthropic-beta');
const defaultHeaders = clientOptions?.defaultHeaders as Record<string, string>;
expect(defaultHeaders['anthropic-beta']).toBe('context-1m-2025-08-07');
expect(result.llmConfig.promptCache).toBe(true);
});
it('should add "context-1m" beta header for claude-sonnet-4-6 model formats', () => {
const modelVariations = [
'claude-sonnet-4-6',
'claude-sonnet-4-6-20260101',
'anthropic/claude-sonnet-4-6',
];
modelVariations.forEach((model) => {
const modelOptions = { model, promptCache: true };
const result = getLLMConfig('test-key', { modelOptions });
const clientOptions = result.llmConfig.clientOptions;
expect(clientOptions?.defaultHeaders).toBeDefined();
expect(clientOptions?.defaultHeaders).toHaveProperty('anthropic-beta');
const defaultHeaders = clientOptions?.defaultHeaders as Record<string, string>;
expect(defaultHeaders['anthropic-beta']).toBe('context-1m-2025-08-07');
expect(result.llmConfig.promptCache).toBe(true);
});
});
it('should pass promptCache boolean for claude-opus-4-5 model (no beta header needed)', () => {
const modelOptions = {
model: 'claude-opus-4-5',
@ -963,6 +996,51 @@ describe('getLLMConfig', () => {
});
});
it('should use adaptive thinking for Sonnet 4.6 instead of enabled + budget_tokens', () => {
const result = getLLMConfig('test-key', {
modelOptions: {
model: 'claude-sonnet-4-6',
thinking: true,
thinkingBudget: 10000,
},
});
expect((result.llmConfig.thinking as unknown as { type: string }).type).toBe('adaptive');
expect(result.llmConfig.thinking).not.toHaveProperty('budget_tokens');
expect(result.llmConfig.maxTokens).toBe(64000);
});
it('should set effort via output_config for Sonnet 4.6', () => {
const result = getLLMConfig('test-key', {
modelOptions: {
model: 'claude-sonnet-4-6',
thinking: true,
effort: AnthropicEffort.high,
},
});
expect((result.llmConfig.thinking as unknown as { type: string }).type).toBe('adaptive');
expect(result.llmConfig.invocationKwargs).toHaveProperty('output_config');
expect(result.llmConfig.invocationKwargs?.output_config).toEqual({
effort: AnthropicEffort.high,
});
});
it('should exclude topP/topK for Sonnet 4.6 with adaptive thinking', () => {
const result = getLLMConfig('test-key', {
modelOptions: {
model: 'claude-sonnet-4-6',
thinking: true,
topP: 0.9,
topK: 40,
},
});
expect((result.llmConfig.thinking as unknown as { type: string }).type).toBe('adaptive');
expect(result.llmConfig).not.toHaveProperty('topP');
expect(result.llmConfig).not.toHaveProperty('topK');
});
it('should NOT set adaptive thinking or effort for non-adaptive models', () => {
const nonAdaptiveModels = [
'claude-opus-4-5',

View file

@ -148,6 +148,7 @@ const anthropicModels = {
'claude-3.5-sonnet-latest': 200000,
'claude-haiku-4-5': 200000,
'claude-sonnet-4': 1000000,
'claude-sonnet-4-6': 1000000,
'claude-4': 200000,
'claude-opus-4': 200000,
'claude-opus-4-5': 200000,
@ -401,6 +402,7 @@ const anthropicMaxOutputs = {
'claude-3-opus': 4096,
'claude-haiku-4-5': 64000,
'claude-sonnet-4': 64000,
'claude-sonnet-4-6': 64000,
'claude-opus-4': 32000,
'claude-opus-4-5': 64000,
'claude-opus-4-6': 128000,