Skip to content

Commit 90e2451

Browse files
Add Anthropic Claude Sonnet 4.6 support across providers (#11509)
* Add Anthropic Claude Sonnet 4.6 support across providers Add model definitions and capability flags for Anthropic, Bedrock, Vertex, OpenRouter, and Vercel AI Gateway. Update Anthropic handler and UI model selection logic to support Claude Sonnet 4.6 1M context behavior and tier pricing. Add focused tests for provider handlers, fetchers, and selected-model hooks. Keep Bedrock UI tier pricing parity as-is because this is a pre-existing issue for Opus 4.6 and will be handled separately. Reference: - https://www.anthropic.com/news/claude-sonnet-4-6 - https://platform.claude.com/docs/en/about-claude/models/overview#latest-models-comparison * Delete .changeset/soft-carpets-hunt.md --------- Co-authored-by: Hannes Rudolph <hrudolph@gmail.com>
1 parent dc243e4 commit 90e2451

File tree

14 files changed

+225
-4
lines changed

14 files changed

+225
-4
lines changed

packages/types/src/providers/anthropic.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,27 @@ export type AnthropicModelId = keyof typeof anthropicModels
77
export const anthropicDefaultModelId: AnthropicModelId = "claude-sonnet-4-5"
88

99
export const anthropicModels = {
10+
"claude-sonnet-4-6": {
11+
maxTokens: 64_000, // Overridden to 8k if `enableReasoningEffort` is false.
12+
contextWindow: 200_000, // Default 200K, extendable to 1M with beta flag 'context-1m-2025-08-07'
13+
supportsImages: true,
14+
supportsPromptCache: true,
15+
inputPrice: 3.0, // $3 per million input tokens (≤200K context)
16+
outputPrice: 15.0, // $15 per million output tokens (≤200K context)
17+
cacheWritesPrice: 3.75, // $3.75 per million tokens
18+
cacheReadsPrice: 0.3, // $0.30 per million tokens
19+
supportsReasoningBudget: true,
20+
// Tiered pricing for extended context (requires beta flag 'context-1m-2025-08-07')
21+
tiers: [
22+
{
23+
contextWindow: 1_000_000, // 1M tokens with beta flag
24+
inputPrice: 6.0, // $6 per million input tokens (>200K context)
25+
outputPrice: 22.5, // $22.50 per million output tokens (>200K context)
26+
cacheWritesPrice: 7.5, // $7.50 per million tokens (>200K context)
27+
cacheReadsPrice: 0.6, // $0.60 per million tokens (>200K context)
28+
},
29+
],
30+
},
1031
"claude-sonnet-4-5": {
1132
maxTokens: 64_000, // Overridden to 8k if `enableReasoningEffort` is false.
1233
contextWindow: 200_000, // Default 200K, extendable to 1M with beta flag 'context-1m-2025-08-07'

packages/types/src/providers/bedrock.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,30 @@ export const bedrockModels = {
2727
maxCachePoints: 4,
2828
cachableFields: ["system", "messages", "tools"],
2929
},
30+
"anthropic.claude-sonnet-4-6-20260114-v1:0": {
31+
maxTokens: 8192,
32+
contextWindow: 200_000, // Default 200K, extendable to 1M with beta flag 'context-1m-2025-08-07'
33+
supportsImages: true,
34+
supportsPromptCache: true,
35+
supportsReasoningBudget: true,
36+
inputPrice: 3.0, // $3 per million input tokens (≤200K context)
37+
outputPrice: 15.0, // $15 per million output tokens (≤200K context)
38+
cacheWritesPrice: 3.75, // $3.75 per million tokens
39+
cacheReadsPrice: 0.3, // $0.30 per million tokens
40+
minTokensPerCachePoint: 1024,
41+
maxCachePoints: 4,
42+
cachableFields: ["system", "messages", "tools"],
43+
// Tiered pricing for extended context (requires beta flag 'context-1m-2025-08-07')
44+
tiers: [
45+
{
46+
contextWindow: 1_000_000, // 1M tokens with beta flag
47+
inputPrice: 6.0, // $6 per million input tokens (>200K context)
48+
outputPrice: 22.5, // $22.50 per million output tokens (>200K context)
49+
cacheWritesPrice: 7.5, // $7.50 per million tokens (>200K context)
50+
cacheReadsPrice: 0.6, // $0.60 per million tokens (>200K context)
51+
},
52+
],
53+
},
3054
"amazon.nova-pro-v1:0": {
3155
maxTokens: 5000,
3256
contextWindow: 300_000,
@@ -499,19 +523,22 @@ export const BEDROCK_REGIONS = [
499523
export const BEDROCK_1M_CONTEXT_MODEL_IDS = [
500524
"anthropic.claude-sonnet-4-20250514-v1:0",
501525
"anthropic.claude-sonnet-4-5-20250929-v1:0",
526+
"anthropic.claude-sonnet-4-6-20260114-v1:0",
502527
"anthropic.claude-opus-4-6-v1",
503528
] as const
504529

505530
// Amazon Bedrock models that support Global Inference profiles
506531
// As of Nov 2025, AWS supports Global Inference for:
507532
// - Claude Sonnet 4
508533
// - Claude Sonnet 4.5
534+
// - Claude Sonnet 4.6
509535
// - Claude Haiku 4.5
510536
// - Claude Opus 4.5
511537
// - Claude Opus 4.6
512538
export const BEDROCK_GLOBAL_INFERENCE_MODEL_IDS = [
513539
"anthropic.claude-sonnet-4-20250514-v1:0",
514540
"anthropic.claude-sonnet-4-5-20250929-v1:0",
541+
"anthropic.claude-sonnet-4-6-20260114-v1:0",
515542
"anthropic.claude-haiku-4-5-20251001-v1:0",
516543
"anthropic.claude-opus-4-5-20251101-v1:0",
517544
"anthropic.claude-opus-4-6-v1",

packages/types/src/providers/openrouter.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ export const OPEN_ROUTER_PROMPT_CACHING_MODELS = new Set([
3838
"anthropic/claude-3.7-sonnet:thinking",
3939
"anthropic/claude-sonnet-4",
4040
"anthropic/claude-sonnet-4.5",
41+
"anthropic/claude-sonnet-4.6",
4142
"anthropic/claude-opus-4",
4243
"anthropic/claude-opus-4.1",
4344
"anthropic/claude-opus-4.5",
@@ -75,6 +76,7 @@ export const OPEN_ROUTER_REASONING_BUDGET_MODELS = new Set([
7576
"anthropic/claude-opus-4.6",
7677
"anthropic/claude-sonnet-4",
7778
"anthropic/claude-sonnet-4.5",
79+
"anthropic/claude-sonnet-4.6",
7880
"anthropic/claude-haiku-4.5",
7981
"google/gemini-2.5-pro-preview",
8082
"google/gemini-2.5-pro",

packages/types/src/providers/vercel-ai-gateway.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ export const VERCEL_AI_GATEWAY_PROMPT_CACHING_MODELS = new Set([
1414
"anthropic/claude-opus-4.5",
1515
"anthropic/claude-opus-4.6",
1616
"anthropic/claude-sonnet-4",
17+
"anthropic/claude-sonnet-4.6",
1718
"openai/gpt-4.1",
1819
"openai/gpt-4.1-mini",
1920
"openai/gpt-4.1-nano",
@@ -55,6 +56,7 @@ export const VERCEL_AI_GATEWAY_VISION_AND_TOOLS_MODELS = new Set([
5556
"anthropic/claude-opus-4.5",
5657
"anthropic/claude-opus-4.6",
5758
"anthropic/claude-sonnet-4",
59+
"anthropic/claude-sonnet-4.6",
5860
"google/gemini-1.5-flash",
5961
"google/gemini-1.5-pro",
6062
"google/gemini-2.0-flash",

packages/types/src/providers/vertex.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,27 @@ export const vertexModels = {
263263
},
264264
],
265265
},
266+
"claude-sonnet-4-6@20260114": {
267+
maxTokens: 8192,
268+
contextWindow: 200_000, // Default 200K, extendable to 1M with beta flag 'context-1m-2025-08-07'
269+
supportsImages: true,
270+
supportsPromptCache: true,
271+
inputPrice: 3.0, // $3 per million input tokens (≤200K context)
272+
outputPrice: 15.0, // $15 per million output tokens (≤200K context)
273+
cacheWritesPrice: 3.75, // $3.75 per million tokens
274+
cacheReadsPrice: 0.3, // $0.30 per million tokens
275+
supportsReasoningBudget: true,
276+
// Tiered pricing for extended context (requires beta flag 'context-1m-2025-08-07')
277+
tiers: [
278+
{
279+
contextWindow: 1_000_000, // 1M tokens with beta flag
280+
inputPrice: 6.0, // $6 per million input tokens (>200K context)
281+
outputPrice: 22.5, // $22.50 per million output tokens (>200K context)
282+
cacheWritesPrice: 7.5, // $7.50 per million tokens (>200K context)
283+
cacheReadsPrice: 0.6, // $0.60 per million tokens (>200K context)
284+
},
285+
],
286+
},
266287
"claude-haiku-4-5@20251001": {
267288
maxTokens: 8192,
268289
contextWindow: 200_000,
@@ -491,6 +512,7 @@ export const vertexModels = {
491512
export const VERTEX_1M_CONTEXT_MODEL_IDS = [
492513
"claude-sonnet-4@20250514",
493514
"claude-sonnet-4-5@20250929",
515+
"claude-sonnet-4-6@20260114",
494516
"claude-opus-4-6",
495517
] as const
496518

src/api/providers/__tests__/anthropic-vertex.spec.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -899,6 +899,21 @@ describe("VertexHandler", () => {
899899
expect(model.betas).toContain("context-1m-2025-08-07")
900900
})
901901

902+
it("should enable 1M context for Claude Sonnet 4.6 when beta flag is set", () => {
903+
const handler = new AnthropicVertexHandler({
904+
apiModelId: "claude-sonnet-4-6@20260114",
905+
vertexProjectId: "test-project",
906+
vertexRegion: "us-central1",
907+
vertex1MContext: true,
908+
})
909+
910+
const model = handler.getModel()
911+
expect(model.info.contextWindow).toBe(1_000_000)
912+
expect(model.info.inputPrice).toBe(6.0)
913+
expect(model.info.outputPrice).toBe(22.5)
914+
expect(model.betas).toContain("context-1m-2025-08-07")
915+
})
916+
902917
it("should not enable 1M context when flag is disabled", () => {
903918
const handler = new AnthropicVertexHandler({
904919
apiModelId: VERTEX_1M_CONTEXT_MODEL_IDS[0],

src/api/providers/__tests__/anthropic.spec.ts

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,28 @@ describe("AnthropicHandler", () => {
187187
// Verify API
188188
expect(mockCreate).toHaveBeenCalled()
189189
})
190+
191+
it("should include 1M context beta header for Claude Sonnet 4.6 when enabled", async () => {
192+
const sonnet46Handler = new AnthropicHandler({
193+
apiKey: "test-api-key",
194+
apiModelId: "claude-sonnet-4-6",
195+
anthropicBeta1MContext: true,
196+
})
197+
198+
const stream = sonnet46Handler.createMessage(systemPrompt, [
199+
{
200+
role: "user",
201+
content: [{ type: "text" as const, text: "Hello" }],
202+
},
203+
])
204+
205+
for await (const _chunk of stream) {
206+
// Consume stream
207+
}
208+
209+
const requestOptions = mockCreate.mock.calls[mockCreate.mock.calls.length - 1]?.[1]
210+
expect(requestOptions?.headers?.["anthropic-beta"]).toContain("context-1m-2025-08-07")
211+
})
190212
})
191213

192214
describe("completePrompt", () => {
@@ -286,6 +308,18 @@ describe("AnthropicHandler", () => {
286308
expect(model.info.supportsReasoningBudget).toBe(true)
287309
})
288310

311+
it("should handle Claude 4.6 Sonnet model correctly", () => {
312+
const handler = new AnthropicHandler({
313+
apiKey: "test-api-key",
314+
apiModelId: "claude-sonnet-4-6",
315+
})
316+
const model = handler.getModel()
317+
expect(model.id).toBe("claude-sonnet-4-6")
318+
expect(model.info.maxTokens).toBe(64000)
319+
expect(model.info.contextWindow).toBe(200000)
320+
expect(model.info.supportsReasoningBudget).toBe(true)
321+
})
322+
289323
it("should enable 1M context for Claude 4.5 Sonnet when beta flag is set", () => {
290324
const handler = new AnthropicHandler({
291325
apiKey: "test-api-key",
@@ -297,6 +331,18 @@ describe("AnthropicHandler", () => {
297331
expect(model.info.inputPrice).toBe(6.0)
298332
expect(model.info.outputPrice).toBe(22.5)
299333
})
334+
335+
it("should enable 1M context for Claude 4.6 Sonnet when beta flag is set", () => {
336+
const handler = new AnthropicHandler({
337+
apiKey: "test-api-key",
338+
apiModelId: "claude-sonnet-4-6",
339+
anthropicBeta1MContext: true,
340+
})
341+
const model = handler.getModel()
342+
expect(model.info.contextWindow).toBe(1000000)
343+
expect(model.info.inputPrice).toBe(6.0)
344+
expect(model.info.outputPrice).toBe(22.5)
345+
})
300346
})
301347

302348
describe("reasoning block filtering", () => {

src/api/providers/__tests__/bedrock.spec.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -701,6 +701,21 @@ describe("AwsBedrockHandler", () => {
701701
expect(model.info.contextWindow).toBe(1_000_000)
702702
})
703703

704+
it("should apply 1M tier pricing when awsBedrock1MContext is true for Claude Sonnet 4.6", () => {
705+
const handler = new AwsBedrockHandler({
706+
apiModelId: "anthropic.claude-sonnet-4-6-20260114-v1:0",
707+
awsAccessKey: "test",
708+
awsSecretKey: "test",
709+
awsRegion: "us-east-1",
710+
awsBedrock1MContext: true,
711+
})
712+
713+
const model = handler.getModel()
714+
expect(model.info.contextWindow).toBe(1_000_000)
715+
expect(model.info.inputPrice).toBe(6.0)
716+
expect(model.info.outputPrice).toBe(22.5)
717+
})
718+
704719
it("should use default context window when awsBedrock1MContext is false for Claude Sonnet 4", () => {
705720
const handler = new AwsBedrockHandler({
706721
apiModelId: BEDROCK_1M_CONTEXT_MODEL_IDS[0],

src/api/providers/anthropic.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,10 +64,11 @@ export class AnthropicHandler extends BaseProvider implements SingleCompletionHa
6464
// Filter out non-Anthropic blocks (reasoning, thoughtSignature, etc.) before sending to the API
6565
const sanitizedMessages = filterNonAnthropicBlocks(messages)
6666

67-
// Add 1M context beta flag if enabled for supported models (Claude Sonnet 4/4.5, Opus 4.6)
67+
// Add 1M context beta flag if enabled for supported models (Claude Sonnet 4/4.5/4.6, Opus 4.6)
6868
if (
6969
(modelId === "claude-sonnet-4-20250514" ||
7070
modelId === "claude-sonnet-4-5" ||
71+
modelId === "claude-sonnet-4-6" ||
7172
modelId === "claude-opus-4-6") &&
7273
this.options.anthropicBeta1MContext
7374
) {
@@ -80,6 +81,7 @@ export class AnthropicHandler extends BaseProvider implements SingleCompletionHa
8081
}
8182

8283
switch (modelId) {
84+
case "claude-sonnet-4-6":
8385
case "claude-sonnet-4-5":
8486
case "claude-sonnet-4-20250514":
8587
case "claude-opus-4-6":
@@ -145,6 +147,7 @@ export class AnthropicHandler extends BaseProvider implements SingleCompletionHa
145147

146148
// Then check for models that support prompt caching
147149
switch (modelId) {
150+
case "claude-sonnet-4-6":
148151
case "claude-sonnet-4-5":
149152
case "claude-sonnet-4-20250514":
150153
case "claude-opus-4-6":
@@ -336,7 +339,10 @@ export class AnthropicHandler extends BaseProvider implements SingleCompletionHa
336339

337340
// If 1M context beta is enabled for supported models, update the model info
338341
if (
339-
(id === "claude-sonnet-4-20250514" || id === "claude-sonnet-4-5" || id === "claude-opus-4-6") &&
342+
(id === "claude-sonnet-4-20250514" ||
343+
id === "claude-sonnet-4-5" ||
344+
id === "claude-sonnet-4-6" ||
345+
id === "claude-opus-4-6") &&
340346
this.options.anthropicBeta1MContext
341347
) {
342348
// Use the tier pricing for 1M context

src/api/providers/fetchers/__tests__/openrouter.spec.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,30 @@ describe("OpenRouter API", () => {
266266
})
267267

268268
describe("parseOpenRouterModel", () => {
269+
it("sets claude-sonnet-4.6 model to Anthropic max tokens", () => {
270+
const mockModel = {
271+
name: "Claude Sonnet 4.6",
272+
description: "Test model",
273+
context_length: 200000,
274+
max_completion_tokens: 8192,
275+
pricing: {
276+
prompt: "0.000003",
277+
completion: "0.000015",
278+
},
279+
}
280+
281+
const result = parseOpenRouterModel({
282+
id: "anthropic/claude-sonnet-4.6",
283+
model: mockModel,
284+
inputModality: ["text"],
285+
outputModality: ["text"],
286+
maxTokens: 8192,
287+
})
288+
289+
expect(result.maxTokens).toBe(64000)
290+
expect(result.contextWindow).toBe(200000)
291+
})
292+
269293
it("sets horizon-alpha model to 32k max tokens", () => {
270294
const mockModel = {
271295
name: "Horizon Alpha",

0 commit comments

Comments
 (0)