feat: add Claude 4.5 Sonnet and Opus models across all providers

- Added claude-sonnet-4-5-20250514 and claude-opus-4-5-20250514 to Anthropic provider
- Added same models to claude-code provider (imports from anthropic)
- Added anthropic.claude-sonnet-4-5-20250514-v1:0 and anthropic.claude-opus-4-5-20250514-v1:0 to Bedrock
- Added claude-sonnet-4-5@20250514 and claude-opus-4-5@20250514 to Vertex AI
- Updated provider implementations to support new models
- Added support for 1M context beta flag for Claude 4.5 Sonnet
- Added comprehensive test coverage for new models
This commit is contained in:
daniel-lxs 2025-09-15 18:05:21 -05:00
parent 40d615591e
commit 8a961f264b
No known key found for this signature in database
GPG key ID: 21C74479048B3AA6
7 changed files with 156 additions and 5 deletions

View file

@ -6,6 +6,28 @@ export type AnthropicModelId = keyof typeof anthropicModels
export const anthropicDefaultModelId: AnthropicModelId = "claude-sonnet-4-20250514"
export const anthropicModels = {
"claude-sonnet-4-5-20250514": {
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,
supportsComputerUse: 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-20250514": {
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'
@ -28,6 +50,18 @@ export const anthropicModels = {
},
],
},
"claude-opus-4-5-20250514": {
maxTokens: 32_000, // Overridden to 8k if `enableReasoningEffort` is false.
contextWindow: 200_000,
supportsImages: true,
supportsComputerUse: true,
supportsPromptCache: true,
inputPrice: 15.0, // $15 per million input tokens
outputPrice: 75.0, // $75 per million output tokens
cacheWritesPrice: 18.75, // $18.75 per million tokens
cacheReadsPrice: 1.5, // $1.50 per million tokens
supportsReasoningBudget: true,
},
"claude-opus-4-1-20250805": {
maxTokens: 8192,
contextWindow: 200_000,

View file

@ -67,6 +67,21 @@ export const bedrockModels = {
maxCachePoints: 1,
cachableFields: ["system"],
},
"anthropic.claude-sonnet-4-5-20250514-v1:0": {
maxTokens: 8192,
contextWindow: 200_000,
supportsImages: true,
supportsComputerUse: true,
supportsPromptCache: true,
supportsReasoningBudget: true,
inputPrice: 3.0,
outputPrice: 15.0,
cacheWritesPrice: 3.75,
cacheReadsPrice: 0.3,
minTokensPerCachePoint: 1024,
maxCachePoints: 4,
cachableFields: ["system", "messages", "tools"],
},
"anthropic.claude-sonnet-4-20250514-v1:0": {
maxTokens: 8192,
contextWindow: 200_000,
@ -82,6 +97,21 @@ export const bedrockModels = {
maxCachePoints: 4,
cachableFields: ["system", "messages", "tools"],
},
"anthropic.claude-opus-4-5-20250514-v1:0": {
maxTokens: 8192,
contextWindow: 200_000,
supportsImages: true,
supportsComputerUse: true,
supportsPromptCache: true,
supportsReasoningBudget: true,
inputPrice: 15.0,
outputPrice: 75.0,
cacheWritesPrice: 18.75,
cacheReadsPrice: 1.5,
minTokensPerCachePoint: 1024,
maxCachePoints: 4,
cachableFields: ["system", "messages", "tools"],
},
"anthropic.claude-opus-4-1-20250805-v1:0": {
maxTokens: 8192,
contextWindow: 200_000,

View file

@ -40,6 +40,14 @@ export function getClaudeCodeModelId(baseModelId: ClaudeCodeModelId, useVertex =
}
export const claudeCodeModels = {
"claude-sonnet-4-5-20250514": {
...anthropicModels["claude-sonnet-4-5-20250514"],
supportsImages: false,
supportsPromptCache: true, // Claude Code does report cache tokens
supportsReasoningEffort: false,
supportsReasoningBudget: false,
requiredReasoningBudget: false,
},
"claude-sonnet-4-20250514": {
...anthropicModels["claude-sonnet-4-20250514"],
supportsImages: false,
@ -48,6 +56,14 @@ export const claudeCodeModels = {
supportsReasoningBudget: false,
requiredReasoningBudget: false,
},
"claude-opus-4-5-20250514": {
...anthropicModels["claude-opus-4-5-20250514"],
supportsImages: false,
supportsPromptCache: true, // Claude Code does report cache tokens
supportsReasoningEffort: false,
supportsReasoningBudget: false,
requiredReasoningBudget: false,
},
"claude-opus-4-1-20250805": {
...anthropicModels["claude-opus-4-1-20250805"],
supportsImages: false,

View file

@ -163,6 +163,18 @@ export const vertexModels = {
inputPrice: 1.25,
outputPrice: 5,
},
"claude-sonnet-4-5@20250514": {
maxTokens: 8192,
contextWindow: 200_000,
supportsImages: true,
supportsComputerUse: true,
supportsPromptCache: true,
inputPrice: 3.0,
outputPrice: 15.0,
cacheWritesPrice: 3.75,
cacheReadsPrice: 0.3,
supportsReasoningBudget: true,
},
"claude-sonnet-4@20250514": {
maxTokens: 8192,
contextWindow: 200_000,
@ -175,6 +187,18 @@ export const vertexModels = {
cacheReadsPrice: 0.3,
supportsReasoningBudget: true,
},
"claude-opus-4-5@20250514": {
maxTokens: 8192,
contextWindow: 200_000,
supportsImages: true,
supportsComputerUse: true,
supportsPromptCache: true,
inputPrice: 15.0,
outputPrice: 75.0,
cacheWritesPrice: 18.75,
cacheReadsPrice: 1.5,
supportsReasoningBudget: true,
},
"claude-opus-4-1@20250805": {
maxTokens: 8192,
contextWindow: 200_000,

View file

@ -264,5 +264,41 @@ describe("AnthropicHandler", () => {
expect(result.reasoningBudget).toBeUndefined()
expect(result.temperature).toBe(0)
})
it("should handle Claude 4.5 Sonnet model correctly", () => {
const handler = new AnthropicHandler({
apiKey: "test-api-key",
apiModelId: "claude-sonnet-4-5-20250514",
})
const model = handler.getModel()
expect(model.id).toBe("claude-sonnet-4-5-20250514")
expect(model.info.maxTokens).toBe(64000)
expect(model.info.contextWindow).toBe(200000)
expect(model.info.supportsReasoningBudget).toBe(true)
})
it("should handle Claude 4.5 Opus model correctly", () => {
const handler = new AnthropicHandler({
apiKey: "test-api-key",
apiModelId: "claude-opus-4-5-20250514",
})
const model = handler.getModel()
expect(model.id).toBe("claude-opus-4-5-20250514")
expect(model.info.maxTokens).toBe(32000)
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",
apiModelId: "claude-sonnet-4-5-20250514",
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)
})
})
})

View file

@ -45,13 +45,18 @@ export class AnthropicHandler extends BaseProvider implements SingleCompletionHa
const cacheControl: CacheControlEphemeral = { type: "ephemeral" }
let { id: modelId, betas = [], maxTokens, temperature, reasoning: thinking } = this.getModel()
// Add 1M context beta flag if enabled for Claude Sonnet 4
if (modelId === "claude-sonnet-4-20250514" && this.options.anthropicBeta1MContext) {
// Add 1M context beta flag if enabled for Claude Sonnet 4 and 4.5
if (
(modelId === "claude-sonnet-4-20250514" || modelId === "claude-sonnet-4-5-20250514") &&
this.options.anthropicBeta1MContext
) {
betas.push("context-1m-2025-08-07")
}
switch (modelId) {
case "claude-sonnet-4-5-20250514":
case "claude-sonnet-4-20250514":
case "claude-opus-4-5-20250514":
case "claude-opus-4-1-20250805":
case "claude-opus-4-20250514":
case "claude-3-7-sonnet-20250219":
@ -110,7 +115,9 @@ export class AnthropicHandler extends BaseProvider implements SingleCompletionHa
// Then check for models that support prompt caching
switch (modelId) {
case "claude-sonnet-4-5-20250514":
case "claude-sonnet-4-20250514":
case "claude-opus-4-5-20250514":
case "claude-opus-4-1-20250805":
case "claude-opus-4-20250514":
case "claude-3-7-sonnet-20250219":
@ -243,8 +250,11 @@ export class AnthropicHandler extends BaseProvider implements SingleCompletionHa
let id = modelId && modelId in anthropicModels ? (modelId as AnthropicModelId) : anthropicDefaultModelId
let info: ModelInfo = anthropicModels[id]
// If 1M context beta is enabled for Claude Sonnet 4, update the model info
if (id === "claude-sonnet-4-20250514" && this.options.anthropicBeta1MContext) {
// If 1M context beta is enabled for Claude Sonnet 4 or 4.5, update the model info
if (
(id === "claude-sonnet-4-20250514" || id === "claude-sonnet-4-5-20250514") &&
this.options.anthropicBeta1MContext
) {
// Use the tier pricing for 1M context
const tier = info.tiers?.[0]
if (tier) {

View file

@ -22,7 +22,8 @@ export const Anthropic = ({ apiConfiguration, setApiConfigurationField }: Anthro
const [anthropicBaseUrlSelected, setAnthropicBaseUrlSelected] = useState(!!apiConfiguration?.anthropicBaseUrl)
// Check if the current model supports 1M context beta
const supports1MContextBeta = selectedModel?.id === "claude-sonnet-4-20250514"
const supports1MContextBeta =
selectedModel?.id === "claude-sonnet-4-20250514" || selectedModel?.id === "claude-sonnet-4-5-20250514"
const handleInputChange = useCallback(
<K extends keyof ProviderSettings, E>(