From 63d19690a35d54f5c959ef4a096d8cc2928e7bdd Mon Sep 17 00:00:00 2001 From: sharon wang <25834218+sharon-wang@users.noreply.github.com> Date: Wed, 8 Jul 2026 10:08:46 -0400 Subject: [PATCH] Fix Bedrock inference-profile prefix for AWS GovCloud MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit getInferenceProfilePrefix matched any region starting with "us-" to the commercial "us." prefix. GovCloud regions (us-gov-west-1, us-gov-east-1) also start with "us-", so their discovered models came out as us.anthropic.claude-... — a commercial inference profile that doesn't exist in GovCloud, causing the runtime call to fail with a ValidationException / model-not-found. Add a us-gov- case ahead of the general us- check so GovCloud regions map to the "us-gov" partition. Export the helper and add unit tests covering the GovCloud regions plus the existing commercial/eu/apac cases as an ordering regression guard. --- .../__tests__/bedrock-provider.test.ts | 30 +++++++++++++++++++ .../src/providers/bedrock-provider.ts | 10 ++++++- 2 files changed, 39 insertions(+), 1 deletion(-) create mode 100644 packages/ai-provider-bridge/src/providers/__tests__/bedrock-provider.test.ts diff --git a/packages/ai-provider-bridge/src/providers/__tests__/bedrock-provider.test.ts b/packages/ai-provider-bridge/src/providers/__tests__/bedrock-provider.test.ts new file mode 100644 index 0000000..01df5e0 --- /dev/null +++ b/packages/ai-provider-bridge/src/providers/__tests__/bedrock-provider.test.ts @@ -0,0 +1,30 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (C) 2026 Posit Software, PBC. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +import { describe, expect, it } from "vitest"; + +import { getInferenceProfilePrefix } from "../bedrock-provider"; + +describe("getInferenceProfilePrefix", () => { + it("uses the us-gov partition for AWS GovCloud regions", () => { + // Regression: GovCloud regions also start with "us-", so they must be + // matched before the general us- case or they'd get the commercial "us." + // prefix, whose inference profiles don't exist in GovCloud. + expect(getInferenceProfilePrefix("us-gov-west-1")).toBe("us-gov"); + expect(getInferenceProfilePrefix("us-gov-east-1")).toBe("us-gov"); + }); + + it("maps commercial regions to their partition prefixes", () => { + expect(getInferenceProfilePrefix("us-east-1")).toBe("us"); + expect(getInferenceProfilePrefix("us-west-2")).toBe("us"); + expect(getInferenceProfilePrefix("eu-west-1")).toBe("eu"); + expect(getInferenceProfilePrefix("eu-central-1")).toBe("eu"); + expect(getInferenceProfilePrefix("ap-northeast-1")).toBe("apac"); + expect(getInferenceProfilePrefix("ap-southeast-1")).toBe("apac"); + }); + + it("defaults unknown regions to us", () => { + expect(getInferenceProfilePrefix("ca-central-1")).toBe("us"); + }); +}); diff --git a/packages/ai-provider-bridge/src/providers/bedrock-provider.ts b/packages/ai-provider-bridge/src/providers/bedrock-provider.ts index 9aaf9b0..6b14918 100644 --- a/packages/ai-provider-bridge/src/providers/bedrock-provider.ts +++ b/packages/ai-provider-bridge/src/providers/bedrock-provider.ts @@ -58,11 +58,19 @@ const MODEL_CACHE_TTL = 60 * 60 * 1000; * Claude 4.x and newer models require inference profiles, not direct model IDs. * * AWS cross-region inference profiles use these prefixes: + * - us-gov.* for AWS GovCloud regions (us-gov-west-1, us-gov-east-1) * - us.* for US regions (us-east-1, us-west-2, etc.) * - eu.* for EU regions (eu-west-1, eu-central-1, etc.) * - apac.* for Asia-Pacific regions (ap-northeast-1, ap-southeast-1, etc.) + * + * GovCloud must be checked before the general `us-` case: `us-gov-west-1` + * also starts with `us-`, but its profiles live under the `us-gov` partition + * and the commercial `us.` profiles don't exist there. */ -function getInferenceProfilePrefix(region: string): string { +export function getInferenceProfilePrefix(region: string): string { + if (region.startsWith("us-gov-")) { + return "us-gov"; + } if (region.startsWith("us-")) { return "us"; }