Skip to content

Commit e41e692

Browse files
committed
feat: add Bedrock Claude Opus 4.7 support
1 parent d191fe0 commit e41e692

3 files changed

Lines changed: 117 additions & 13 deletions

File tree

packages/types/src/providers/bedrock.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,21 @@ export const bedrockModels = {
167167
},
168168
],
169169
},
170+
"anthropic.claude-opus-4-7": {
171+
maxTokens: 128_000,
172+
contextWindow: 1_000_000,
173+
supportsImages: true,
174+
supportsPromptCache: true,
175+
supportsReasoningBudget: true,
176+
supportsTemperature: false,
177+
inputPrice: 5.0,
178+
outputPrice: 25.0,
179+
cacheWritesPrice: 6.25,
180+
cacheReadsPrice: 0.5,
181+
minTokensPerCachePoint: 1024,
182+
maxCachePoints: 4,
183+
cachableFields: ["system", "messages", "tools"],
184+
},
170185
"anthropic.claude-opus-4-5-20251101-v1:0": {
171186
maxTokens: 8192,
172187
contextWindow: 200_000,
@@ -535,13 +550,15 @@ export const BEDROCK_1M_CONTEXT_MODEL_IDS = [
535550
// - Claude Haiku 4.5
536551
// - Claude Opus 4.5
537552
// - Claude Opus 4.6
553+
// - Claude Opus 4.7
538554
export const BEDROCK_GLOBAL_INFERENCE_MODEL_IDS = [
539555
"anthropic.claude-sonnet-4-20250514-v1:0",
540556
"anthropic.claude-sonnet-4-5-20250929-v1:0",
541557
"anthropic.claude-sonnet-4-6",
542558
"anthropic.claude-haiku-4-5-20251001-v1:0",
543559
"anthropic.claude-opus-4-5-20251101-v1:0",
544560
"anthropic.claude-opus-4-6-v1",
561+
"anthropic.claude-opus-4-7",
545562
] as const
546563

547564
// Amazon Bedrock Service Tier types

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

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,24 @@ describe("AwsBedrockHandler", () => {
7373
expect(modelInfo.info.contextWindow).toBeDefined()
7474
})
7575

76+
it("should return the correct model info for Claude Opus 4.7", () => {
77+
const opusHandler = new AwsBedrockHandler({
78+
apiModelId: "anthropic.claude-opus-4-7",
79+
awsAccessKey: "test-access-key",
80+
awsSecretKey: "test-secret-key",
81+
awsRegion: "us-east-1",
82+
modelTemperature: 0.2,
83+
})
84+
85+
const modelInfo = opusHandler.getModel()
86+
87+
expect(modelInfo.id).toBe("anthropic.claude-opus-4-7")
88+
expect(modelInfo.info.contextWindow).toBe(1_000_000)
89+
expect(modelInfo.info.maxTokens).toBe(128_000)
90+
expect(modelInfo.info.supportsTemperature).toBe(false)
91+
expect(modelInfo.temperature).toBeUndefined()
92+
})
93+
7694
it("should use custom ARN when provided", () => {
7795
// This test is incompatible with the refactored implementation
7896
// The implementation now extracts the model ID from the ARN instead of using the ARN directly
@@ -843,6 +861,53 @@ describe("AwsBedrockHandler", () => {
843861
expect(commandArg.additionalModelRequestFields.anthropic_beta).not.toContain("context-1m-2025-08-07")
844862
})
845863

864+
it("should use adaptive thinking and omit temperature for Claude Opus 4.7", async () => {
865+
const handler = new AwsBedrockHandler({
866+
apiModelId: "anthropic.claude-opus-4-7",
867+
awsAccessKey: "test",
868+
awsSecretKey: "test",
869+
awsRegion: "us-east-1",
870+
enableReasoningEffort: true,
871+
reasoningEffort: "medium",
872+
modelTemperature: 0.4,
873+
})
874+
875+
const messages: Anthropic.Messages.MessageParam[] = [
876+
{
877+
role: "user",
878+
content: "Test message",
879+
},
880+
]
881+
882+
const generator = handler.createMessage("", messages)
883+
await generator.next()
884+
885+
expect(mockConverseStreamCommand).toHaveBeenCalled()
886+
const commandArg = mockConverseStreamCommand.mock.calls[0][0] as any
887+
888+
expect(commandArg.additionalModelRequestFields).toBeDefined()
889+
expect(commandArg.additionalModelRequestFields.thinking).toEqual({
890+
type: "adaptive",
891+
effort: "medium",
892+
})
893+
expect(commandArg.additionalModelRequestFields.thinking.budget_tokens).toBeUndefined()
894+
expect(commandArg.inferenceConfig.temperature).toBeUndefined()
895+
})
896+
897+
it("should use global inference for Claude Opus 4.7 when enabled", () => {
898+
const handler = new AwsBedrockHandler({
899+
apiModelId: "anthropic.claude-opus-4-7",
900+
awsAccessKey: "test",
901+
awsSecretKey: "test",
902+
awsRegion: "us-east-1",
903+
awsUseGlobalInference: true,
904+
})
905+
906+
const model = handler.getModel()
907+
908+
expect(model.id).toBe("global.anthropic.claude-opus-4-7")
909+
})
910+
846911
it("should enable 1M context window with cross-region inference for Claude Sonnet 4", () => {
847912
const handler = new AwsBedrockHandler({
848913
apiModelId: BEDROCK_1M_CONTEXT_MODEL_IDS[0],

src/api/providers/bedrock.ts

Lines changed: 35 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -61,10 +61,15 @@ interface BedrockInferenceConfig {
6161
// Define interface for Bedrock additional model request fields
6262
// This includes thinking configuration, 1M context beta, and other model-specific parameters
6363
interface BedrockAdditionalModelFields {
64-
thinking?: {
65-
type: "enabled"
66-
budget_tokens: number
67-
}
64+
thinking?:
65+
| {
66+
type: "enabled"
67+
budget_tokens: number
68+
}
69+
| {
70+
type: "adaptive"
71+
effort?: "low" | "medium" | "high" | "max"
72+
}
6873
anthropic_beta?: string[]
6974
[key: string]: any // Add index signature to be compatible with DocumentType
7075
}
@@ -389,15 +394,34 @@ export class AwsBedrockHandler extends BaseProvider implements SingleCompletionH
389394
shouldUseReasoningBudget({ model: modelConfig.info, settings: this.options }) &&
390395
modelConfig.reasoning &&
391396
modelConfig.reasoningBudget
397+
const baseModelId = this.parseBaseModelId(modelConfig.id)
398+
const usesAdaptiveThinking = baseModelId === "anthropic.claude-opus-4-7"
392399

393400
if ((isThinkingExplicitlyEnabled || isThinkingEnabledBySettings) && modelConfig.info.supportsReasoningBudget) {
394401
thinkingEnabled = true
395-
additionalModelRequestFields = {
396-
thinking: {
397-
type: "enabled",
398-
budget_tokens: metadata?.thinking?.maxThinkingTokens || modelConfig.reasoningBudget || 4096,
399-
},
400-
}
402+
const adaptiveThinkingEffort = (() => {
403+
switch (this.options.reasoningEffort) {
404+
case "low":
405+
case "medium":
406+
case "high":
407+
return this.options.reasoningEffort
408+
default:
409+
return undefined
410+
}
411+
})()
412+
additionalModelRequestFields = usesAdaptiveThinking
413+
? {
414+
thinking: {
415+
type: "adaptive",
416+
...(adaptiveThinkingEffort ? { effort: adaptiveThinkingEffort } : {}),
417+
},
418+
}
419+
: {
420+
thinking: {
421+
type: "enabled",
422+
budget_tokens: metadata?.thinking?.maxThinkingTokens || modelConfig.reasoningBudget || 4096,
423+
},
424+
}
401425
logger.info("Extended thinking enabled for Bedrock request", {
402426
ctx: "bedrock",
403427
modelId: modelConfig.id,
@@ -407,12 +431,10 @@ export class AwsBedrockHandler extends BaseProvider implements SingleCompletionH
407431

408432
const inferenceConfig: BedrockInferenceConfig = {
409433
maxTokens: modelConfig.maxTokens || (modelConfig.info.maxTokens as number),
410-
temperature: modelConfig.temperature ?? (this.options.modelTemperature as number),
434+
temperature: modelConfig.temperature,
411435
}
412436

413437
// Check if 1M context is enabled for supported Claude 4 models
414-
// Use parseBaseModelId to handle cross-region inference prefixes
415-
const baseModelId = this.parseBaseModelId(modelConfig.id)
416438
const is1MContextEnabled =
417439
BEDROCK_1M_CONTEXT_MODEL_IDS.includes(baseModelId as any) && this.options.awsBedrock1MContext
418440

0 commit comments

Comments
 (0)