From baa3bfa6d1ee3ab2b6d78d6e95341b4954761bb1 Mon Sep 17 00:00:00 2001 From: Christian Rocha Date: Thu, 26 Mar 2026 14:34:11 -0400 Subject: [PATCH] fix(bedrock): inference profile prefix resolution MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Resolve Bedrock model IDs using AWS region-group prefixes with AWS_DEFAULT_REGION fallback, preserve already-prefixed IDs, and default to global for unmapped regions. Add tests to lock in mapping and prefixing behavior. 💘 Generated with Crush Assisted-by: GPT-5.3 Codex via Crush --- providers/anthropic/anthropic_test.go | 30 ++++++++++++++++++++ providers/anthropic/bedrock.go | 40 +++++++++++++++++++++------ 2 files changed, 62 insertions(+), 8 deletions(-) diff --git a/providers/anthropic/anthropic_test.go b/providers/anthropic/anthropic_test.go index 4387a34faf7fe8900383e26859de13d306505664..5f7b1da16ac022ef949ce9fb3a5cf3c4450ec11a 100644 --- a/providers/anthropic/anthropic_test.go +++ b/providers/anthropic/anthropic_test.go @@ -1838,6 +1838,36 @@ func TestGenerate_BetaAPI(t *testing.T) { }) } +func TestBedrockRegionPrefixing(t *testing.T) { + t.Run("uses us prefix when region is unset", func(t *testing.T) { + t.Setenv("AWS_REGION", "") + t.Setenv("AWS_DEFAULT_REGION", "") + require.Equal(t, "us.anthropic.claude-sonnet-4-5-20250929-v1:0", bedrockPrefixModelWithRegion("anthropic.claude-sonnet-4-5-20250929-v1:0")) + }) + + t.Run("uses AWS_DEFAULT_REGION when AWS_REGION is unset", func(t *testing.T) { + t.Setenv("AWS_REGION", "") + t.Setenv("AWS_DEFAULT_REGION", "eu-west-1") + require.Equal(t, "eu.anthropic.claude-sonnet-4-5-20250929-v1:0", bedrockPrefixModelWithRegion("anthropic.claude-sonnet-4-5-20250929-v1:0")) + }) + + t.Run("keeps already-prefixed model IDs", func(t *testing.T) { + t.Setenv("AWS_REGION", "us-east-1") + t.Setenv("AWS_DEFAULT_REGION", "") + require.Equal(t, "global.anthropic.claude-sonnet-4-5-20250929-v1:0", bedrockPrefixModelWithRegion("global.anthropic.claude-sonnet-4-5-20250929-v1:0")) + }) + + t.Run("maps known regions to profile prefixes", func(t *testing.T) { + require.Equal(t, "us", bedrockRegionPrefix("us-west-2")) + require.Equal(t, "us", bedrockRegionPrefix("ca-central-1")) + require.Equal(t, "eu", bedrockRegionPrefix("eu-central-1")) + require.Equal(t, "jp", bedrockRegionPrefix("ap-northeast-1")) + require.Equal(t, "au", bedrockRegionPrefix("ap-southeast-2")) + require.Equal(t, "global", bedrockRegionPrefix("ap-south-1")) + require.Equal(t, "global", bedrockRegionPrefix("sa-east-1")) + }) +} + func TestStream_BetaAPI(t *testing.T) { t.Parallel() diff --git a/providers/anthropic/bedrock.go b/providers/anthropic/bedrock.go index 8d9b94959210e57fde8fa594a67bfc8db8d27415..ff76fbf6bfffce061a4abd9432506a54a37de3ca 100644 --- a/providers/anthropic/bedrock.go +++ b/providers/anthropic/bedrock.go @@ -11,19 +11,43 @@ import ( func bedrockBasicAuthConfig(apiKey string) aws.Config { return aws.Config{ - Region: cmp.Or(os.Getenv("AWS_REGION"), "us-east-1"), + Region: cmp.Or(awsRegion(), "us-east-1"), BearerAuthTokenProvider: bearer.StaticTokenProvider{Token: bearer.Token{Value: apiKey}}, } } func bedrockPrefixModelWithRegion(modelID string) string { - region := os.Getenv("AWS_REGION") - if len(region) < 2 { - region = "us-east-1" - } - prefix := region[:2] + "." - if strings.HasPrefix(modelID, prefix) { + if hasBedrockInferenceProfilePrefix(modelID) { return modelID } - return prefix + modelID + region := cmp.Or(awsRegion(), "us-east-1") + return bedrockRegionPrefix(region) + "." + modelID +} + +func awsRegion() string { + return cmp.Or(os.Getenv("AWS_REGION"), os.Getenv("AWS_DEFAULT_REGION")) +} + +func bedrockRegionPrefix(region string) string { + switch { + case strings.HasPrefix(region, "us-") || region == "ca-central-1": + return "us" + case strings.HasPrefix(region, "eu-"): + return "eu" + case region == "ap-northeast-1": + return "jp" + case region == "ap-southeast-2": + return "au" + default: + return "global" + } +} + +func hasBedrockInferenceProfilePrefix(modelID string) bool { + for _, prefix := range []string{"us.", "eu.", "jp.", "au.", "global."} { + if strings.HasPrefix(modelID, prefix) { + return true + } + } + return false }