Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions packages/types/src/providers/bedrock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -565,6 +565,30 @@ export const BEDROCK_1M_CONTEXT_MODEL_IDS = [
"anthropic.claude-sonnet-4-5-20250929-v1:0",
] as const

// Amazon Bedrock models that support cross-region inference profiles
// Based on AWS documentation: https://docs.aws.amazon.com/bedrock/latest/userguide/inference-profiles-support.html
// Cross-region inference is primarily supported for Anthropic Claude models
export const BEDROCK_CROSS_REGION_INFERENCE_MODEL_IDS = [
// Claude 4.x models
"anthropic.claude-sonnet-4-5-20250929-v1:0",
"anthropic.claude-sonnet-4-20250514-v1:0",
"anthropic.claude-opus-4-1-20250805-v1:0",
"anthropic.claude-opus-4-5-20251101-v1:0",
"anthropic.claude-opus-4-20250514-v1:0",
// Claude 3.7 models
"anthropic.claude-3-7-sonnet-20250219-v1:0",
// Claude 3.5 models
"anthropic.claude-3-5-sonnet-20241022-v2:0",
"anthropic.claude-3-5-haiku-20241022-v1:0",
"anthropic.claude-3-5-sonnet-20240620-v1:0",
// Claude Haiku 4.5
"anthropic.claude-haiku-4-5-20251001-v1:0",
// Claude 3 models
"anthropic.claude-3-opus-20240229-v1:0",
"anthropic.claude-3-sonnet-20240229-v1:0",
"anthropic.claude-3-haiku-20240307-v1:0",
] as const

// Amazon Bedrock models that support Global Inference profiles
// As of Nov 2025, AWS supports Global Inference for:
// - Claude Sonnet 4
Expand Down
64 changes: 59 additions & 5 deletions src/api/providers/__tests__/bedrock-inference-profiles.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// npx vitest run src/api/providers/__tests__/bedrock-inference-profiles.spec.ts

import { AWS_INFERENCE_PROFILE_MAPPING } from "@roo-code/types"
import { AWS_INFERENCE_PROFILE_MAPPING, BEDROCK_CROSS_REGION_INFERENCE_MODEL_IDS } from "@roo-code/types"
import { AwsBedrockHandler } from "../bedrock"
import { ApiHandlerOptions } from "../../../shared/api"

Expand Down Expand Up @@ -56,6 +56,37 @@ describe("Amazon Bedrock Inference Profiles", () => {
})
})

describe("BEDROCK_CROSS_REGION_INFERENCE_MODEL_IDS constant", () => {
it("should contain only Anthropic Claude models", () => {
BEDROCK_CROSS_REGION_INFERENCE_MODEL_IDS.forEach((modelId) => {
expect(modelId).toMatch(/^anthropic\.claude/)
})
})

it("should not contain non-Claude models", () => {
const nonClaudePatterns = ["qwen", "amazon", "meta", "deepseek", "openai"]
BEDROCK_CROSS_REGION_INFERENCE_MODEL_IDS.forEach((modelId) => {
nonClaudePatterns.forEach((pattern) => {
expect(modelId.toLowerCase()).not.toContain(pattern)
})
})
})

it("should include common Claude models that support cross-region inference", () => {
const expectedModels = [
"anthropic.claude-3-sonnet-20240229-v1:0",
"anthropic.claude-3-haiku-20240307-v1:0",
"anthropic.claude-3-opus-20240229-v1:0",
"anthropic.claude-3-5-sonnet-20241022-v2:0",
"anthropic.claude-3-5-haiku-20241022-v1:0",
]

expectedModels.forEach((modelId) => {
expect(BEDROCK_CROSS_REGION_INFERENCE_MODEL_IDS).toContain(modelId)
})
})
})

describe("getPrefixForRegion function", () => {
it("should return correct prefix for US government regions", () => {
const handler = createHandler()
Expand Down Expand Up @@ -213,23 +244,46 @@ describe("Amazon Bedrock Inference Profiles", () => {
expect(model.id).toBe("anthropic.claude-3-sonnet-20240229-v1:0")
})

it("should work with different model IDs", () => {
const testModels = [
it("should apply cross-region prefix only to supported Claude models", () => {
// Test Claude models that DO support cross-region inference
const supportedModels = [
"anthropic.claude-3-haiku-20240307-v1:0",
"anthropic.claude-3-opus-20240229-v1:0",
"anthropic.claude-3-sonnet-20240229-v1:0",
"anthropic.claude-3-5-sonnet-20241022-v2:0",
]

supportedModels.forEach((modelId) => {
const handler = createHandler({
awsUseCrossRegionInference: true,
awsRegion: "eu-west-1",
apiModelId: modelId,
})

const model = handler.getModel()
expect(model.id).toBe(`eu.${modelId}`)
})
})

it("should NOT apply cross-region prefix to unsupported models", () => {
// Test models that do NOT support cross-region inference
const unsupportedModels = [
"qwen.qwen3-coder-480b-a35b-v1:0",
"amazon.nova-pro-v1:0",
"meta.llama3-1-70b-instruct-v1:0",
"deepseek.r1-v1:0",
]

testModels.forEach((modelId) => {
unsupportedModels.forEach((modelId) => {
const handler = createHandler({
awsUseCrossRegionInference: true,
awsRegion: "eu-west-1",
apiModelId: modelId,
})

const model = handler.getModel()
expect(model.id).toBe(`eu.${modelId}`)
// Should remain unchanged - no prefix applied
expect(model.id).toBe(modelId)
})
})

Expand Down
10 changes: 6 additions & 4 deletions src/api/providers/__tests__/bedrock.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1084,13 +1084,15 @@ describe("AwsBedrockHandler", () => {
})

describe("service tier with cross-region inference", () => {
it("should apply service tier pricing with cross-region inference prefix", () => {
it("should apply service tier pricing without cross-region prefix for unsupported models", () => {
// amazon.nova-lite-v1:0 supports service tiers but NOT cross-region inference
// Cross-region inference is only supported for Anthropic Claude models
const handler = new AwsBedrockHandler({
apiModelId: supportedModelId,
awsAccessKey: "test",
awsSecretKey: "test",
awsRegion: "us-east-1",
awsUseCrossRegionInference: true,
awsUseCrossRegionInference: true, // This should be ignored for non-Claude models
awsBedrockServiceTier: "FLEX",
})

Expand All @@ -1100,8 +1102,8 @@ describe("AwsBedrockHandler", () => {
outputPrice: number
}

// Model ID should have cross-region prefix
expect(model.id).toBe(`us.${supportedModelId}`)
// Model ID should NOT have cross-region prefix because amazon.nova-lite-v1:0 doesn't support it
expect(model.id).toBe(supportedModelId)

// FLEX tier pricing should still be applied
expect(model.info.inputPrice).toBe(baseModel.inputPrice * 0.5)
Expand Down
14 changes: 10 additions & 4 deletions src/api/providers/bedrock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import {
AWS_INFERENCE_PROFILE_MAPPING,
BEDROCK_1M_CONTEXT_MODEL_IDS,
BEDROCK_GLOBAL_INFERENCE_MODEL_IDS,
BEDROCK_CROSS_REGION_INFERENCE_MODEL_IDS,
BEDROCK_SERVICE_TIER_MODEL_IDS,
BEDROCK_SERVICE_TIER_PRICING,
ApiProviderError,
Expand Down Expand Up @@ -1105,11 +1106,16 @@ export class AwsBedrockHandler extends BaseProvider implements SingleCompletionH
) {
modelConfig.id = `global.${baseIdForGlobal}`
}
// Otherwise, add cross-region inference prefix if enabled
// Otherwise, add cross-region inference prefix if enabled and model supports it
else if (this.options.awsUseCrossRegionInference && this.options.awsRegion) {
const prefix = AwsBedrockHandler.getPrefixForRegion(this.options.awsRegion)
if (prefix) {
modelConfig.id = `${prefix}${modelConfig.id}`
// Only apply cross-region inference prefix to models that support it
// This prevents invalid model identifiers for models like Qwen that don't support cross-region inference
const baseIdForCrossRegion = this.parseBaseModelId(modelConfig.id)
if (BEDROCK_CROSS_REGION_INFERENCE_MODEL_IDS.includes(baseIdForCrossRegion as any)) {
const prefix = AwsBedrockHandler.getPrefixForRegion(this.options.awsRegion)
if (prefix) {
modelConfig.id = `${prefix}${modelConfig.id}`
}
}
}
}
Expand Down
Loading