From d650a5d4d00a20ddd764942f25f87ec96cf9c84f Mon Sep 17 00:00:00 2001 From: Peter Dave Hello Date: Wed, 18 Feb 2026 02:42:15 +0800 Subject: [PATCH 1/2] 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 --- .changeset/soft-carpets-hunt.md | 6 +++ packages/types/src/providers/anthropic.ts | 21 +++++++++ packages/types/src/providers/bedrock.ts | 27 +++++++++++ packages/types/src/providers/openrouter.ts | 2 + .../types/src/providers/vercel-ai-gateway.ts | 2 + packages/types/src/providers/vertex.ts | 22 +++++++++ .../__tests__/anthropic-vertex.spec.ts | 15 ++++++ src/api/providers/__tests__/anthropic.spec.ts | 46 +++++++++++++++++++ src/api/providers/__tests__/bedrock.spec.ts | 15 ++++++ src/api/providers/anthropic.ts | 10 +++- .../fetchers/__tests__/openrouter.spec.ts | 24 ++++++++++ src/api/providers/fetchers/openrouter.ts | 5 ++ .../settings/providers/Anthropic.tsx | 1 + .../hooks/__tests__/useSelectedModel.spec.ts | 32 +++++++++++++ .../components/ui/hooks/useSelectedModel.ts | 7 ++- 15 files changed, 231 insertions(+), 4 deletions(-) create mode 100644 .changeset/soft-carpets-hunt.md diff --git a/.changeset/soft-carpets-hunt.md b/.changeset/soft-carpets-hunt.md new file mode 100644 index 00000000000..a4a52e26ff4 --- /dev/null +++ b/.changeset/soft-carpets-hunt.md @@ -0,0 +1,6 @@ +--- +"roo-cline": patch +--- + +Add support for Claude Sonnet 4.6 across Anthropic, Bedrock, Vertex, +OpenRouter, and Vercel AI Gateway providers. diff --git a/packages/types/src/providers/anthropic.ts b/packages/types/src/providers/anthropic.ts index 62e377c7e54..40a3d885d84 100644 --- a/packages/types/src/providers/anthropic.ts +++ b/packages/types/src/providers/anthropic.ts @@ -7,6 +7,27 @@ export type AnthropicModelId = keyof typeof anthropicModels export const anthropicDefaultModelId: AnthropicModelId = "claude-sonnet-4-5" export const anthropicModels = { + "claude-sonnet-4-6": { + maxTokens: 64_000, // Overridden to 8k if `enableReasoningEffort` is false. + contextWindow: 200_000, // Default 200K, extendable to 1M with beta flag 'context-1m-2025-08-07' + supportsImages: true, + supportsPromptCache: true, + inputPrice: 3.0, // $3 per million input tokens (≤200K context) + outputPrice: 15.0, // $15 per million output tokens (≤200K context) + cacheWritesPrice: 3.75, // $3.75 per million tokens + cacheReadsPrice: 0.3, // $0.30 per million tokens + supportsReasoningBudget: true, + // Tiered pricing for extended context (requires beta flag 'context-1m-2025-08-07') + tiers: [ + { + contextWindow: 1_000_000, // 1M tokens with beta flag + inputPrice: 6.0, // $6 per million input tokens (>200K context) + outputPrice: 22.5, // $22.50 per million output tokens (>200K context) + cacheWritesPrice: 7.5, // $7.50 per million tokens (>200K context) + cacheReadsPrice: 0.6, // $0.60 per million tokens (>200K context) + }, + ], + }, "claude-sonnet-4-5": { maxTokens: 64_000, // Overridden to 8k if `enableReasoningEffort` is false. contextWindow: 200_000, // Default 200K, extendable to 1M with beta flag 'context-1m-2025-08-07' diff --git a/packages/types/src/providers/bedrock.ts b/packages/types/src/providers/bedrock.ts index 008961b3018..575db6984af 100644 --- a/packages/types/src/providers/bedrock.ts +++ b/packages/types/src/providers/bedrock.ts @@ -27,6 +27,30 @@ export const bedrockModels = { maxCachePoints: 4, cachableFields: ["system", "messages", "tools"], }, + "anthropic.claude-sonnet-4-6-20260114-v1:0": { + maxTokens: 8192, + contextWindow: 200_000, // Default 200K, extendable to 1M with beta flag 'context-1m-2025-08-07' + supportsImages: true, + supportsPromptCache: true, + supportsReasoningBudget: true, + inputPrice: 3.0, // $3 per million input tokens (≤200K context) + outputPrice: 15.0, // $15 per million output tokens (≤200K context) + cacheWritesPrice: 3.75, // $3.75 per million tokens + cacheReadsPrice: 0.3, // $0.30 per million tokens + minTokensPerCachePoint: 1024, + maxCachePoints: 4, + cachableFields: ["system", "messages", "tools"], + // Tiered pricing for extended context (requires beta flag 'context-1m-2025-08-07') + tiers: [ + { + contextWindow: 1_000_000, // 1M tokens with beta flag + inputPrice: 6.0, // $6 per million input tokens (>200K context) + outputPrice: 22.5, // $22.50 per million output tokens (>200K context) + cacheWritesPrice: 7.5, // $7.50 per million tokens (>200K context) + cacheReadsPrice: 0.6, // $0.60 per million tokens (>200K context) + }, + ], + }, "amazon.nova-pro-v1:0": { maxTokens: 5000, contextWindow: 300_000, @@ -499,6 +523,7 @@ export const BEDROCK_REGIONS = [ export const BEDROCK_1M_CONTEXT_MODEL_IDS = [ "anthropic.claude-sonnet-4-20250514-v1:0", "anthropic.claude-sonnet-4-5-20250929-v1:0", + "anthropic.claude-sonnet-4-6-20260114-v1:0", "anthropic.claude-opus-4-6-v1", ] as const @@ -506,12 +531,14 @@ export const BEDROCK_1M_CONTEXT_MODEL_IDS = [ // As of Nov 2025, AWS supports Global Inference for: // - Claude Sonnet 4 // - Claude Sonnet 4.5 +// - Claude Sonnet 4.6 // - Claude Haiku 4.5 // - Claude Opus 4.5 // - Claude Opus 4.6 export const BEDROCK_GLOBAL_INFERENCE_MODEL_IDS = [ "anthropic.claude-sonnet-4-20250514-v1:0", "anthropic.claude-sonnet-4-5-20250929-v1:0", + "anthropic.claude-sonnet-4-6-20260114-v1:0", "anthropic.claude-haiku-4-5-20251001-v1:0", "anthropic.claude-opus-4-5-20251101-v1:0", "anthropic.claude-opus-4-6-v1", diff --git a/packages/types/src/providers/openrouter.ts b/packages/types/src/providers/openrouter.ts index c8168e60244..834f40528e2 100644 --- a/packages/types/src/providers/openrouter.ts +++ b/packages/types/src/providers/openrouter.ts @@ -38,6 +38,7 @@ export const OPEN_ROUTER_PROMPT_CACHING_MODELS = new Set([ "anthropic/claude-3.7-sonnet:thinking", "anthropic/claude-sonnet-4", "anthropic/claude-sonnet-4.5", + "anthropic/claude-sonnet-4.6", "anthropic/claude-opus-4", "anthropic/claude-opus-4.1", "anthropic/claude-opus-4.5", @@ -75,6 +76,7 @@ export const OPEN_ROUTER_REASONING_BUDGET_MODELS = new Set([ "anthropic/claude-opus-4.6", "anthropic/claude-sonnet-4", "anthropic/claude-sonnet-4.5", + "anthropic/claude-sonnet-4.6", "anthropic/claude-haiku-4.5", "google/gemini-2.5-pro-preview", "google/gemini-2.5-pro", diff --git a/packages/types/src/providers/vercel-ai-gateway.ts b/packages/types/src/providers/vercel-ai-gateway.ts index 43a94a0697c..ac633747ba2 100644 --- a/packages/types/src/providers/vercel-ai-gateway.ts +++ b/packages/types/src/providers/vercel-ai-gateway.ts @@ -14,6 +14,7 @@ export const VERCEL_AI_GATEWAY_PROMPT_CACHING_MODELS = new Set([ "anthropic/claude-opus-4.5", "anthropic/claude-opus-4.6", "anthropic/claude-sonnet-4", + "anthropic/claude-sonnet-4.6", "openai/gpt-4.1", "openai/gpt-4.1-mini", "openai/gpt-4.1-nano", @@ -55,6 +56,7 @@ export const VERCEL_AI_GATEWAY_VISION_AND_TOOLS_MODELS = new Set([ "anthropic/claude-opus-4.5", "anthropic/claude-opus-4.6", "anthropic/claude-sonnet-4", + "anthropic/claude-sonnet-4.6", "google/gemini-1.5-flash", "google/gemini-1.5-pro", "google/gemini-2.0-flash", diff --git a/packages/types/src/providers/vertex.ts b/packages/types/src/providers/vertex.ts index 55e5648011b..2f8a05602a4 100644 --- a/packages/types/src/providers/vertex.ts +++ b/packages/types/src/providers/vertex.ts @@ -263,6 +263,27 @@ export const vertexModels = { }, ], }, + "claude-sonnet-4-6@20260114": { + maxTokens: 8192, + contextWindow: 200_000, // Default 200K, extendable to 1M with beta flag 'context-1m-2025-08-07' + supportsImages: true, + supportsPromptCache: true, + inputPrice: 3.0, // $3 per million input tokens (≤200K context) + outputPrice: 15.0, // $15 per million output tokens (≤200K context) + cacheWritesPrice: 3.75, // $3.75 per million tokens + cacheReadsPrice: 0.3, // $0.30 per million tokens + supportsReasoningBudget: true, + // Tiered pricing for extended context (requires beta flag 'context-1m-2025-08-07') + tiers: [ + { + contextWindow: 1_000_000, // 1M tokens with beta flag + inputPrice: 6.0, // $6 per million input tokens (>200K context) + outputPrice: 22.5, // $22.50 per million output tokens (>200K context) + cacheWritesPrice: 7.5, // $7.50 per million tokens (>200K context) + cacheReadsPrice: 0.6, // $0.60 per million tokens (>200K context) + }, + ], + }, "claude-haiku-4-5@20251001": { maxTokens: 8192, contextWindow: 200_000, @@ -491,6 +512,7 @@ export const vertexModels = { export const VERTEX_1M_CONTEXT_MODEL_IDS = [ "claude-sonnet-4@20250514", "claude-sonnet-4-5@20250929", + "claude-sonnet-4-6@20260114", "claude-opus-4-6", ] as const diff --git a/src/api/providers/__tests__/anthropic-vertex.spec.ts b/src/api/providers/__tests__/anthropic-vertex.spec.ts index 3d9798fde91..dc284ab7543 100644 --- a/src/api/providers/__tests__/anthropic-vertex.spec.ts +++ b/src/api/providers/__tests__/anthropic-vertex.spec.ts @@ -899,6 +899,21 @@ describe("VertexHandler", () => { expect(model.betas).toContain("context-1m-2025-08-07") }) + it("should enable 1M context for Claude Sonnet 4.6 when beta flag is set", () => { + const handler = new AnthropicVertexHandler({ + apiModelId: "claude-sonnet-4-6@20260114", + vertexProjectId: "test-project", + vertexRegion: "us-central1", + vertex1MContext: true, + }) + + const model = handler.getModel() + expect(model.info.contextWindow).toBe(1_000_000) + expect(model.info.inputPrice).toBe(6.0) + expect(model.info.outputPrice).toBe(22.5) + expect(model.betas).toContain("context-1m-2025-08-07") + }) + it("should not enable 1M context when flag is disabled", () => { const handler = new AnthropicVertexHandler({ apiModelId: VERTEX_1M_CONTEXT_MODEL_IDS[0], diff --git a/src/api/providers/__tests__/anthropic.spec.ts b/src/api/providers/__tests__/anthropic.spec.ts index 7a107edbc8b..3731f3a068b 100644 --- a/src/api/providers/__tests__/anthropic.spec.ts +++ b/src/api/providers/__tests__/anthropic.spec.ts @@ -187,6 +187,28 @@ describe("AnthropicHandler", () => { // Verify API expect(mockCreate).toHaveBeenCalled() }) + + it("should include 1M context beta header for Claude Sonnet 4.6 when enabled", async () => { + const sonnet46Handler = new AnthropicHandler({ + apiKey: "test-api-key", + apiModelId: "claude-sonnet-4-6", + anthropicBeta1MContext: true, + }) + + const stream = sonnet46Handler.createMessage(systemPrompt, [ + { + role: "user", + content: [{ type: "text" as const, text: "Hello" }], + }, + ]) + + for await (const _chunk of stream) { + // Consume stream + } + + const requestOptions = mockCreate.mock.calls[mockCreate.mock.calls.length - 1]?.[1] + expect(requestOptions?.headers?.["anthropic-beta"]).toContain("context-1m-2025-08-07") + }) }) describe("completePrompt", () => { @@ -286,6 +308,18 @@ describe("AnthropicHandler", () => { expect(model.info.supportsReasoningBudget).toBe(true) }) + it("should handle Claude 4.6 Sonnet model correctly", () => { + const handler = new AnthropicHandler({ + apiKey: "test-api-key", + apiModelId: "claude-sonnet-4-6", + }) + const model = handler.getModel() + expect(model.id).toBe("claude-sonnet-4-6") + expect(model.info.maxTokens).toBe(64000) + expect(model.info.contextWindow).toBe(200000) + expect(model.info.supportsReasoningBudget).toBe(true) + }) + it("should enable 1M context for Claude 4.5 Sonnet when beta flag is set", () => { const handler = new AnthropicHandler({ apiKey: "test-api-key", @@ -297,6 +331,18 @@ describe("AnthropicHandler", () => { expect(model.info.inputPrice).toBe(6.0) expect(model.info.outputPrice).toBe(22.5) }) + + it("should enable 1M context for Claude 4.6 Sonnet when beta flag is set", () => { + const handler = new AnthropicHandler({ + apiKey: "test-api-key", + apiModelId: "claude-sonnet-4-6", + anthropicBeta1MContext: true, + }) + const model = handler.getModel() + expect(model.info.contextWindow).toBe(1000000) + expect(model.info.inputPrice).toBe(6.0) + expect(model.info.outputPrice).toBe(22.5) + }) }) describe("reasoning block filtering", () => { diff --git a/src/api/providers/__tests__/bedrock.spec.ts b/src/api/providers/__tests__/bedrock.spec.ts index 115cb9fb405..4c45a623251 100644 --- a/src/api/providers/__tests__/bedrock.spec.ts +++ b/src/api/providers/__tests__/bedrock.spec.ts @@ -701,6 +701,21 @@ describe("AwsBedrockHandler", () => { expect(model.info.contextWindow).toBe(1_000_000) }) + it("should apply 1M tier pricing when awsBedrock1MContext is true for Claude Sonnet 4.6", () => { + const handler = new AwsBedrockHandler({ + apiModelId: "anthropic.claude-sonnet-4-6-20260114-v1:0", + awsAccessKey: "test", + awsSecretKey: "test", + awsRegion: "us-east-1", + awsBedrock1MContext: true, + }) + + const model = handler.getModel() + expect(model.info.contextWindow).toBe(1_000_000) + expect(model.info.inputPrice).toBe(6.0) + expect(model.info.outputPrice).toBe(22.5) + }) + it("should use default context window when awsBedrock1MContext is false for Claude Sonnet 4", () => { const handler = new AwsBedrockHandler({ apiModelId: BEDROCK_1M_CONTEXT_MODEL_IDS[0], diff --git a/src/api/providers/anthropic.ts b/src/api/providers/anthropic.ts index b2b158f0956..1786a105a5e 100644 --- a/src/api/providers/anthropic.ts +++ b/src/api/providers/anthropic.ts @@ -64,10 +64,11 @@ export class AnthropicHandler extends BaseProvider implements SingleCompletionHa // Filter out non-Anthropic blocks (reasoning, thoughtSignature, etc.) before sending to the API const sanitizedMessages = filterNonAnthropicBlocks(messages) - // Add 1M context beta flag if enabled for supported models (Claude Sonnet 4/4.5, Opus 4.6) + // Add 1M context beta flag if enabled for supported models (Claude Sonnet 4/4.5/4.6, Opus 4.6) if ( (modelId === "claude-sonnet-4-20250514" || modelId === "claude-sonnet-4-5" || + modelId === "claude-sonnet-4-6" || modelId === "claude-opus-4-6") && this.options.anthropicBeta1MContext ) { @@ -80,6 +81,7 @@ export class AnthropicHandler extends BaseProvider implements SingleCompletionHa } switch (modelId) { + case "claude-sonnet-4-6": case "claude-sonnet-4-5": case "claude-sonnet-4-20250514": case "claude-opus-4-6": @@ -145,6 +147,7 @@ export class AnthropicHandler extends BaseProvider implements SingleCompletionHa // Then check for models that support prompt caching switch (modelId) { + case "claude-sonnet-4-6": case "claude-sonnet-4-5": case "claude-sonnet-4-20250514": case "claude-opus-4-6": @@ -336,7 +339,10 @@ export class AnthropicHandler extends BaseProvider implements SingleCompletionHa // If 1M context beta is enabled for supported models, update the model info if ( - (id === "claude-sonnet-4-20250514" || id === "claude-sonnet-4-5" || id === "claude-opus-4-6") && + (id === "claude-sonnet-4-20250514" || + id === "claude-sonnet-4-5" || + id === "claude-sonnet-4-6" || + id === "claude-opus-4-6") && this.options.anthropicBeta1MContext ) { // Use the tier pricing for 1M context diff --git a/src/api/providers/fetchers/__tests__/openrouter.spec.ts b/src/api/providers/fetchers/__tests__/openrouter.spec.ts index 3bcd27716f2..bca54b30781 100644 --- a/src/api/providers/fetchers/__tests__/openrouter.spec.ts +++ b/src/api/providers/fetchers/__tests__/openrouter.spec.ts @@ -266,6 +266,30 @@ describe("OpenRouter API", () => { }) describe("parseOpenRouterModel", () => { + it("sets claude-sonnet-4.6 model to Anthropic max tokens", () => { + const mockModel = { + name: "Claude Sonnet 4.6", + description: "Test model", + context_length: 200000, + max_completion_tokens: 8192, + pricing: { + prompt: "0.000003", + completion: "0.000015", + }, + } + + const result = parseOpenRouterModel({ + id: "anthropic/claude-sonnet-4.6", + model: mockModel, + inputModality: ["text"], + outputModality: ["text"], + maxTokens: 8192, + }) + + expect(result.maxTokens).toBe(64000) + expect(result.contextWindow).toBe(200000) + }) + it("sets horizon-alpha model to 32k max tokens", () => { const mockModel = { name: "Horizon Alpha", diff --git a/src/api/providers/fetchers/openrouter.ts b/src/api/providers/fetchers/openrouter.ts index 9fcf3d49cb5..0cf65fb09c3 100644 --- a/src/api/providers/fetchers/openrouter.ts +++ b/src/api/providers/fetchers/openrouter.ts @@ -243,6 +243,11 @@ export const parseOpenRouterModel = ({ modelInfo.maxTokens = anthropicModels["claude-3-7-sonnet-20250219:thinking"].maxTokens } + // Set claude-sonnet-4.6 model to use the correct configuration + if (id === "anthropic/claude-sonnet-4.6") { + modelInfo.maxTokens = anthropicModels["claude-sonnet-4-6"].maxTokens + } + // Set claude-opus-4.1 model to use the correct configuration if (id === "anthropic/claude-opus-4.1") { modelInfo.maxTokens = anthropicModels["claude-opus-4-1-20250805"].maxTokens diff --git a/webview-ui/src/components/settings/providers/Anthropic.tsx b/webview-ui/src/components/settings/providers/Anthropic.tsx index 58fa81d6bc2..6417e34b8be 100644 --- a/webview-ui/src/components/settings/providers/Anthropic.tsx +++ b/webview-ui/src/components/settings/providers/Anthropic.tsx @@ -26,6 +26,7 @@ export const Anthropic = ({ apiConfiguration, setApiConfigurationField }: Anthro const supports1MContextBeta = selectedModel?.id === "claude-sonnet-4-20250514" || selectedModel?.id === "claude-sonnet-4-5" || + selectedModel?.id === "claude-sonnet-4-6" || selectedModel?.id === "claude-opus-4-6" const handleInputChange = useCallback( diff --git a/webview-ui/src/components/ui/hooks/__tests__/useSelectedModel.spec.ts b/webview-ui/src/components/ui/hooks/__tests__/useSelectedModel.spec.ts index 8925adf5fda..a8dead311fa 100644 --- a/webview-ui/src/components/ui/hooks/__tests__/useSelectedModel.spec.ts +++ b/webview-ui/src/components/ui/hooks/__tests__/useSelectedModel.spec.ts @@ -402,6 +402,38 @@ describe("useSelectedModel", () => { }) }) + describe("anthropic provider with 1M context", () => { + beforeEach(() => { + mockUseRouterModels.mockReturnValue({ + data: undefined, + isLoading: false, + isError: false, + } as any) + + mockUseOpenRouterModelProviders.mockReturnValue({ + data: undefined, + isLoading: false, + isError: false, + } as any) + }) + + it("should apply 1M pricing tier for Claude Sonnet 4.6 when enabled", () => { + const apiConfiguration: ProviderSettings = { + apiProvider: "anthropic", + apiModelId: "claude-sonnet-4-6", + anthropicBeta1MContext: true, + } + + const wrapper = createWrapper() + const { result } = renderHook(() => useSelectedModel(apiConfiguration), { wrapper }) + + expect(result.current.id).toBe("claude-sonnet-4-6") + expect(result.current.info?.contextWindow).toBe(1_000_000) + expect(result.current.info?.inputPrice).toBe(6.0) + expect(result.current.info?.outputPrice).toBe(22.5) + }) + }) + describe("bedrock provider with 1M context", () => { beforeEach(() => { mockUseRouterModels.mockReturnValue({ diff --git a/webview-ui/src/components/ui/hooks/useSelectedModel.ts b/webview-ui/src/components/ui/hooks/useSelectedModel.ts index 0ac82b50627..8a6e49e212f 100644 --- a/webview-ui/src/components/ui/hooks/useSelectedModel.ts +++ b/webview-ui/src/components/ui/hooks/useSelectedModel.ts @@ -341,11 +341,14 @@ function getSelectedModel({ // Apply 1M context beta tier pricing for supported Claude 4 models if ( provider === "anthropic" && - (id === "claude-sonnet-4-20250514" || id === "claude-sonnet-4-5" || id === "claude-opus-4-6") && + (id === "claude-sonnet-4-20250514" || + id === "claude-sonnet-4-5" || + id === "claude-sonnet-4-6" || + id === "claude-opus-4-6") && apiConfiguration.anthropicBeta1MContext && baseInfo ) { - // Type assertion since we know claude-sonnet-4-20250514 and claude-sonnet-4-5 have tiers + // Type assertion since supported Claude 4 models include 1M context pricing tiers. const modelWithTiers = baseInfo as typeof baseInfo & { tiers?: Array<{ contextWindow: number From d4275c37c81c86ab47eb3a70dd5e8b20d8399cb2 Mon Sep 17 00:00:00 2001 From: Hannes Rudolph Date: Tue, 17 Feb 2026 11:53:05 -0700 Subject: [PATCH 2/2] Delete .changeset/soft-carpets-hunt.md --- .changeset/soft-carpets-hunt.md | 6 ------ 1 file changed, 6 deletions(-) delete mode 100644 .changeset/soft-carpets-hunt.md diff --git a/.changeset/soft-carpets-hunt.md b/.changeset/soft-carpets-hunt.md deleted file mode 100644 index a4a52e26ff4..00000000000 --- a/.changeset/soft-carpets-hunt.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"roo-cline": patch ---- - -Add support for Claude Sonnet 4.6 across Anthropic, Bedrock, Vertex, -OpenRouter, and Vercel AI Gateway providers.