feat: Global Inference for Bedrock models (#8750) (#8940)

Co-authored-by: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com>
Co-authored-by: Roo Code <roomote@roocode.com>
This commit is contained in:
Hannes Rudolph 2025-11-05 13:56:19 -07:00 committed by GitHub
parent 39448f4010
commit 65230f1f5c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
24 changed files with 104 additions and 13 deletions

View file

@ -220,6 +220,7 @@ const bedrockSchema = apiModelIdProviderModelSchema.extend({
awsSessionToken: z.string().optional(),
awsRegion: z.string().optional(),
awsUseCrossRegionInference: z.boolean().optional(),
awsUseGlobalInference: z.boolean().optional(), // Enable Global Inference profile routing when supported
awsUsePromptCache: z.boolean().optional(),
awsProfile: z.string().optional(),
awsUseProfile: z.boolean().optional(),

View file

@ -401,17 +401,22 @@ export const BEDROCK_DEFAULT_CONTEXT = 128_000
// https://docs.aws.amazon.com/bedrock/latest/userguide/inference-profiles-support.html
// This mapping is pre-ordered by pattern length (descending) to ensure more specific patterns match first
export const AWS_INFERENCE_PROFILE_MAPPING: Array<[string, string]> = [
// US Government Cloud → ug. inference profile (most specific prefix first)
// Australia regions (Sydney and Melbourne) → au. inference profile (most specific - 14 chars)
["ap-southeast-2", "au."],
["ap-southeast-4", "au."],
// Japan regions (Tokyo and Osaka) → jp. inference profile (13 chars)
["ap-northeast-", "jp."],
// US Government Cloud → ug. inference profile (7 chars)
["us-gov-", "ug."],
// Americas regions → us. inference profile
// Americas regions → us. inference profile (3 chars)
["us-", "us."],
// Europe regions → eu. inference profile
// Europe regions → eu. inference profile (3 chars)
["eu-", "eu."],
// Asia Pacific regions → apac. inference profile
// Asia Pacific regions → apac. inference profile (3 chars)
["ap-", "apac."],
// Canada regions → ca. inference profile
// Canada regions → ca. inference profile (3 chars)
["ca-", "ca."],
// South America regions → sa. inference profile
// South America regions → sa. inference profile (3 chars)
["sa-", "sa."],
]
@ -448,3 +453,14 @@ export const BEDROCK_1M_CONTEXT_MODEL_IDS = [
"anthropic.claude-sonnet-4-20250514-v1:0",
"anthropic.claude-sonnet-4-5-20250929-v1:0",
] as const
// Amazon Bedrock models that support Global Inference profiles
// As of Oct 2025, AWS supports Global Inference for:
// - Claude Sonnet 4
// - Claude Sonnet 4.5
// - Claude Haiku 4.5
export const BEDROCK_GLOBAL_INFERENCE_MODEL_IDS = [
"anthropic.claude-sonnet-4-20250514-v1:0",
"anthropic.claude-sonnet-4-5-20250929-v1:0",
"anthropic.claude-haiku-4-5-20251001-v1:0",
] as const

View file

@ -30,6 +30,9 @@ describe("Amazon Bedrock Inference Profiles", () => {
describe("AWS_INFERENCE_PROFILE_MAPPING constant", () => {
it("should contain all expected region mappings", () => {
expect(AWS_INFERENCE_PROFILE_MAPPING).toEqual([
["ap-southeast-2", "au."],
["ap-southeast-4", "au."],
["ap-northeast-", "jp."],
["us-gov-", "ug."],
["us-", "us."],
["eu-", "eu."],
@ -47,7 +50,7 @@ describe("Amazon Bedrock Inference Profiles", () => {
it("should have valid inference profile prefixes", () => {
AWS_INFERENCE_PROFILE_MAPPING.forEach(([regionPattern, inferenceProfile]) => {
expect(regionPattern).toMatch(/^[a-z-]+$/)
expect(regionPattern).toMatch(/^[a-z0-9-]+$/)
expect(inferenceProfile).toMatch(/^[a-z]+\.$/)
})
})
@ -77,8 +80,14 @@ describe("Amazon Bedrock Inference Profiles", () => {
it("should return correct prefix for Asia Pacific regions", () => {
const handler = createHandler()
// Australia regions (Sydney and Melbourne) get au. prefix
expect((handler as any).constructor.getPrefixForRegion("ap-southeast-2")).toBe("au.")
expect((handler as any).constructor.getPrefixForRegion("ap-southeast-4")).toBe("au.")
// Japan regions (Tokyo and Osaka) get jp. prefix
expect((handler as any).constructor.getPrefixForRegion("ap-northeast-1")).toBe("jp.")
expect((handler as any).constructor.getPrefixForRegion("ap-northeast-3")).toBe("jp.")
// Other APAC regions get apac. prefix
expect((handler as any).constructor.getPrefixForRegion("ap-southeast-1")).toBe("apac.")
expect((handler as any).constructor.getPrefixForRegion("ap-northeast-1")).toBe("apac.")
expect((handler as any).constructor.getPrefixForRegion("ap-south-1")).toBe("apac.")
expect((handler as any).constructor.getPrefixForRegion("ap-east-1")).toBe("apac.")
})

View file

@ -114,8 +114,14 @@ describe("AwsBedrockHandler", () => {
it("should return correct prefix for APAC regions", () => {
const getPrefixForRegion = (AwsBedrockHandler as any).getPrefixForRegion
// Australia regions (Sydney and Melbourne) get au. prefix
expect(getPrefixForRegion("ap-southeast-2")).toBe("au.")
expect(getPrefixForRegion("ap-southeast-4")).toBe("au.")
// Japan regions (Tokyo and Osaka) get jp. prefix
expect(getPrefixForRegion("ap-northeast-1")).toBe("jp.")
expect(getPrefixForRegion("ap-northeast-3")).toBe("jp.")
// Other APAC regions get apac. prefix
expect(getPrefixForRegion("ap-southeast-1")).toBe("apac.")
expect(getPrefixForRegion("ap-northeast-1")).toBe("apac.")
expect(getPrefixForRegion("ap-south-1")).toBe("apac.")
})

View file

@ -22,6 +22,7 @@ import {
BEDROCK_DEFAULT_CONTEXT,
AWS_INFERENCE_PROFILE_MAPPING,
BEDROCK_1M_CONTEXT_MODEL_IDS,
BEDROCK_GLOBAL_INFERENCE_MODEL_IDS,
} from "@roo-code/types"
import { ApiStream } from "../transform/stream"
@ -887,6 +888,11 @@ export class AwsBedrockHandler extends BaseProvider implements SingleCompletionH
}
}
// Also strip Global Inference profile prefix if present
if (modelId.startsWith("global.")) {
return modelId.substring("global.".length)
}
// Return the model ID as-is for all other cases
return modelId
}
@ -964,8 +970,16 @@ export class AwsBedrockHandler extends BaseProvider implements SingleCompletionH
//a model was selected from the drop down
modelConfig = this.getModelById(this.options.apiModelId as string)
// Add cross-region inference prefix if enabled
if (this.options.awsUseCrossRegionInference && this.options.awsRegion) {
// Apply Global Inference prefix if enabled and supported (takes precedence over cross-region)
const baseIdForGlobal = this.parseBaseModelId(modelConfig.id)
if (
this.options.awsUseGlobalInference &&
BEDROCK_GLOBAL_INFERENCE_MODEL_IDS.includes(baseIdForGlobal as any)
) {
modelConfig.id = `global.${baseIdForGlobal}`
}
// Otherwise, add cross-region inference prefix if enabled
else if (this.options.awsUseCrossRegionInference && this.options.awsRegion) {
const prefix = AwsBedrockHandler.getPrefixForRegion(this.options.awsRegion)
if (prefix) {
modelConfig.id = `${prefix}${modelConfig.id}`

View file

@ -2,7 +2,13 @@ import { useCallback, useState, useEffect } from "react"
import { Checkbox } from "vscrui"
import { VSCodeTextField } from "@vscode/webview-ui-toolkit/react"
import { type ProviderSettings, type ModelInfo, BEDROCK_REGIONS, BEDROCK_1M_CONTEXT_MODEL_IDS } from "@roo-code/types"
import {
type ProviderSettings,
type ModelInfo,
BEDROCK_REGIONS,
BEDROCK_1M_CONTEXT_MODEL_IDS,
BEDROCK_GLOBAL_INFERENCE_MODEL_IDS,
} from "@roo-code/types"
import { useAppTranslation } from "@src/i18n/TranslationContext"
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, StandardTooltip } from "@src/components/ui"
@ -23,6 +29,11 @@ export const Bedrock = ({ apiConfiguration, setApiConfigurationField, selectedMo
const supports1MContextBeta =
!!apiConfiguration?.apiModelId && BEDROCK_1M_CONTEXT_MODEL_IDS.includes(apiConfiguration.apiModelId as any)
// Check if the selected model supports Global Inference profile routing
const supportsGlobalInference =
!!apiConfiguration?.apiModelId &&
BEDROCK_GLOBAL_INFERENCE_MODEL_IDS.includes(apiConfiguration.apiModelId as any)
// Update the endpoint enabled state when the configuration changes
useEffect(() => {
setAwsEndpointSelected(!!apiConfiguration?.awsBedrockEndpointEnabled)
@ -138,9 +149,25 @@ export const Bedrock = ({ apiConfiguration, setApiConfigurationField, selectedMo
</SelectContent>
</Select>
</div>
{supportsGlobalInference && (
<Checkbox
checked={apiConfiguration?.awsUseGlobalInference || false}
disabled={apiConfiguration?.awsUseCrossRegionInference || false}
onChange={(checked: boolean) => {
// Enabling Global Inference should disable cross-region inference
setApiConfigurationField("awsUseGlobalInference", checked)
if (checked) setApiConfigurationField("awsUseCrossRegionInference", false)
}}>
{t("settings:providers.awsGlobalInference")}
</Checkbox>
)}
<Checkbox
checked={apiConfiguration?.awsUseCrossRegionInference || false}
onChange={handleInputChange("awsUseCrossRegionInference", noTransform)}>
disabled={apiConfiguration?.awsUseGlobalInference || false}
onChange={(checked: boolean) => {
setApiConfigurationField("awsUseCrossRegionInference", checked)
if (checked) setApiConfigurationField("awsUseGlobalInference", false)
}}>
{t("settings:providers.awsCrossRegion")}
</Checkbox>
{selectedModelInfo?.supportsPromptCache && (

View file

@ -344,6 +344,7 @@
"awsSessionToken": "Token de sessió d'AWS",
"awsRegion": "Regió d'AWS",
"awsCrossRegion": "Utilitzar inferència entre regions",
"awsGlobalInference": "Utilitzar la inferència global (selecció automàtica de la regió òptima d'AWS)",
"awsBedrockVpc": {
"useCustomVpcEndpoint": "Utilitzar punt final VPC personalitzat",
"vpcEndpointUrlPlaceholder": "Introduïu l'URL del punt final VPC (opcional)",

View file

@ -344,6 +344,7 @@
"awsSessionToken": "AWS Sitzungstoken",
"awsRegion": "AWS Region",
"awsCrossRegion": "Regionsübergreifende Inferenz verwenden",
"awsGlobalInference": "Globale Inferenz verwenden (optimale AWS-Region automatisch auswählen)",
"awsBedrockVpc": {
"useCustomVpcEndpoint": "Benutzerdefinierten VPC-Endpunkt verwenden",
"vpcEndpointUrlPlaceholder": "VPC-Endpunkt-URL eingeben (optional)",

View file

@ -349,6 +349,7 @@
"awsSessionToken": "AWS Session Token",
"awsRegion": "AWS Region",
"awsCrossRegion": "Use cross-region inference",
"awsGlobalInference": "Use Global inference (auto-select optimal AWS Region)",
"awsBedrockVpc": {
"useCustomVpcEndpoint": "Use custom VPC endpoint",
"vpcEndpointUrlPlaceholder": "Enter VPC Endpoint URL (optional)",

View file

@ -344,6 +344,7 @@
"awsSessionToken": "Token de sesión de AWS",
"awsRegion": "Región de AWS",
"awsCrossRegion": "Usar inferencia entre regiones",
"awsGlobalInference": "Usar inferencia global (selección automática de la región óptima de AWS)",
"awsBedrockVpc": {
"useCustomVpcEndpoint": "Usar punto de conexión VPC personalizado",
"vpcEndpointUrlPlaceholder": "Ingrese URL del punto de conexión VPC (opcional)",

View file

@ -344,6 +344,7 @@
"awsSessionToken": "Jeton de session AWS",
"awsRegion": "Région AWS",
"awsCrossRegion": "Utiliser l'inférence inter-régions",
"awsGlobalInference": "Utiliser l'inférence globale (sélection automatique de la région AWS optimale)",
"awsBedrockVpc": {
"useCustomVpcEndpoint": "Utiliser un point de terminaison VPC personnalisé",
"vpcEndpointUrlPlaceholder": "Entrer l'URL du point de terminaison VPC (optionnel)",

View file

@ -344,6 +344,7 @@
"awsSessionToken": "AWS सत्र टोकन",
"awsRegion": "AWS क्षेत्र",
"awsCrossRegion": "क्रॉस-क्षेत्र अनुमान का उपयोग करें",
"awsGlobalInference": "वैश्विक अनुमान का उपयोग करें (स्वचालित रूप से श्रेष्ठ AWS क्षेत्र चुनें)",
"awsBedrockVpc": {
"useCustomVpcEndpoint": "कस्टम VPC एंडपॉइंट का उपयोग करें",
"vpcEndpointUrlPlaceholder": "VPC एंडपॉइंट URL दर्ज करें (वैकल्पिक)",

View file

@ -348,6 +348,7 @@
"awsSessionToken": "AWS Session Token",
"awsRegion": "AWS Region",
"awsCrossRegion": "Gunakan cross-region inference",
"awsGlobalInference": "Gunakan inferensi Global (pilih Wilayah AWS optimal secara otomatis)",
"awsBedrockVpc": {
"useCustomVpcEndpoint": "Gunakan VPC endpoint kustom",
"vpcEndpointUrlPlaceholder": "Masukkan VPC Endpoint URL (opsional)",

View file

@ -344,6 +344,7 @@
"awsSessionToken": "Token di sessione AWS",
"awsRegion": "Regione AWS",
"awsCrossRegion": "Usa inferenza cross-regione",
"awsGlobalInference": "Usa l'inferenza globale (selezione automatica della regione AWS ottimale)",
"awsBedrockVpc": {
"useCustomVpcEndpoint": "Usa endpoint VPC personalizzato",
"vpcEndpointUrlPlaceholder": "Inserisci URL endpoint VPC (opzionale)",

View file

@ -344,6 +344,7 @@
"awsSessionToken": "AWSセッショントークン",
"awsRegion": "AWSリージョン",
"awsCrossRegion": "クロスリージョン推論を使用",
"awsGlobalInference": "グローバル推論を使用する最適なAWSリージョンを自動選択",
"awsBedrockVpc": {
"useCustomVpcEndpoint": "カスタムVPCエンドポイントを使用",
"vpcEndpointUrlPlaceholder": "VPCエンドポイントURLを入力任意",

View file

@ -344,6 +344,7 @@
"awsSessionToken": "AWS 세션 토큰",
"awsRegion": "AWS 리전",
"awsCrossRegion": "교차 리전 추론 사용",
"awsGlobalInference": "글로벌 추론 사용(최적의 AWS 리전 자동 선택)",
"awsBedrockVpc": {
"useCustomVpcEndpoint": "사용자 지정 VPC 엔드포인트 사용",
"vpcEndpointUrlPlaceholder": "VPC 엔드포인트 URL 입력 (선택사항)",

View file

@ -344,6 +344,7 @@
"awsSessionToken": "AWS-sessietoken",
"awsRegion": "AWS-regio",
"awsCrossRegion": "Gebruik cross-region inference",
"awsGlobalInference": "Gebruik wereldwijde inferentie (automatische selectie van optimale AWS-regio)",
"awsBedrockVpc": {
"useCustomVpcEndpoint": "Aangepast VPC-eindpunt gebruiken",
"vpcEndpointUrlPlaceholder": "Voer VPC-eindpunt URL in (optioneel)",

View file

@ -344,6 +344,7 @@
"awsSessionToken": "Token sesji AWS",
"awsRegion": "Region AWS",
"awsCrossRegion": "Użyj wnioskowania międzyregionalnego",
"awsGlobalInference": "Użyj globalnej inferencji (automatyczny wybór optymalnego regionu AWS)",
"awsBedrockVpc": {
"useCustomVpcEndpoint": "Użyj niestandardowego punktu końcowego VPC",
"vpcEndpointUrlPlaceholder": "Wprowadź URL punktu końcowego VPC (opcjonalnie)",

View file

@ -344,6 +344,7 @@
"awsSessionToken": "Token de Sessão AWS",
"awsRegion": "Região AWS",
"awsCrossRegion": "Usar inferência entre regiões",
"awsGlobalInference": "Usar inferência global (selecionar automaticamente a região ideal da AWS)",
"awsBedrockVpc": {
"useCustomVpcEndpoint": "Usar endpoint VPC personalizado",
"vpcEndpointUrlPlaceholder": "Digite a URL do endpoint VPC (opcional)",

View file

@ -344,6 +344,7 @@
"awsSessionToken": "AWS Session Token",
"awsRegion": "Регион AWS",
"awsCrossRegion": "Использовать кросс-региональный вывод",
"awsGlobalInference": "Использовать глобальный вывод (автоматический выбор оптимального региона AWS)",
"awsBedrockVpc": {
"useCustomVpcEndpoint": "Использовать пользовательскую конечную точку VPC",
"vpcEndpointUrlPlaceholder": "Введите URL конечной точки VPC (опционально)",

View file

@ -344,6 +344,7 @@
"awsSessionToken": "AWS Oturum Belirteci",
"awsRegion": "AWS Bölgesi",
"awsCrossRegion": "Bölgeler arası çıkarım kullan",
"awsGlobalInference": "Genel çıkarımı kullan (en uygun AWS Bölgesini otomatik seç)",
"awsBedrockVpc": {
"useCustomVpcEndpoint": "Özel VPC uç noktası kullan",
"vpcEndpointUrlPlaceholder": "VPC uç noktası URL'sini girin (isteğe bağlı)",

View file

@ -344,6 +344,7 @@
"awsSessionToken": "Token phiên AWS",
"awsRegion": "Vùng AWS",
"awsCrossRegion": "Sử dụng suy luận liên vùng",
"awsGlobalInference": "Sử dụng suy luận toàn cầu (tự động chọn Khu vực AWS tối ưu)",
"awsBedrockVpc": {
"useCustomVpcEndpoint": "Sử dụng điểm cuối VPC tùy chỉnh",
"vpcEndpointUrlPlaceholder": "Nhập URL điểm cuối VPC (tùy chọn)",

View file

@ -344,6 +344,7 @@
"awsSessionToken": "AWS 会话Token",
"awsRegion": "AWS 区域",
"awsCrossRegion": "使用跨区域推理",
"awsGlobalInference": "使用全局推理(自动选择最佳 AWS 区域)",
"awsBedrockVpc": {
"useCustomVpcEndpoint": "使用自定义 VPC 端点",
"vpcEndpointUrlPlaceholder": "输入 VPC 端点 URL可选",

View file

@ -344,6 +344,7 @@
"awsSessionToken": "AWS 工作階段權杖",
"awsRegion": "AWS 區域",
"awsCrossRegion": "使用跨區域推論",
"awsGlobalInference": "使用全域推論 (自動選取最佳 AWS 區域)",
"awsBedrockVpc": {
"useCustomVpcEndpoint": "使用自訂 VPC 端點",
"vpcEndpointUrlPlaceholder": "輸入 VPC 端點 URL選填",