From fce059930ef46779a6b1a4cfd410da219f25cce7 Mon Sep 17 00:00:00 2001 From: Pete Samwel Date: Tue, 4 Aug 2026 13:13:18 -0500 Subject: [PATCH] fix(catalog): emit AWS GovCloud us-gov Bedrock Claude inference profiles Bare anthropic.claude-* Bedrock rows already derived eu.* selectors; also emit us-gov.* so GovCloud accounts can resolve system inference profiles without requiring a full partition ARN. --- packages/catalog/CHANGELOG.md | 4 + packages/catalog/src/models.json | 326 +++++++++++++++++- .../src/provider-models/openai-compat.ts | 15 +- .../test/amazon-bedrock-opus-5.test.ts | 19 +- .../test/amazon-bedrock-us-gov.test.ts | 62 ++++ 5 files changed, 416 insertions(+), 10 deletions(-) create mode 100644 packages/catalog/test/amazon-bedrock-us-gov.test.ts diff --git a/packages/catalog/CHANGELOG.md b/packages/catalog/CHANGELOG.md index cab9afb53..1bc5a62ed 100644 --- a/packages/catalog/CHANGELOG.md +++ b/packages/catalog/CHANGELOG.md @@ -2,6 +2,10 @@ ## [Unreleased] +### Fixed + +- Fixed Amazon Bedrock catalog generation omitting AWS GovCloud `us-gov.*` Claude inference-profile IDs, so selectors like `amazon-bedrock/us-gov.anthropic.claude-sonnet-4-5-…` resolve instead of failing model lookup (or misrouting commercial `us.*` geos onto `us-east-1` with GovCloud credentials). + ## [17.2.7] - 2026-08-03 ### Fixed diff --git a/packages/catalog/src/models.json b/packages/catalog/src/models.json index 07a28ec00..99910f606 100644 --- a/packages/catalog/src/models.json +++ b/packages/catalog/src/models.json @@ -10488,6 +10488,330 @@ "contextWindow": 262000, "maxTokens": 262000 }, + "us-gov.anthropic.claude-fable-5": { + "id": "us-gov.anthropic.claude-fable-5", + "name": "Claude Fable 5 (GovCloud)", + "api": "bedrock-converse-stream", + "provider": "amazon-bedrock", + "baseUrl": "https://bedrock-runtime.us-east-1.amazonaws.com", + "reasoning": true, + "input": [ + "text", + "image" + ], + "cost": { + "input": 10, + "output": 50, + "cacheRead": 1, + "cacheWrite": 12.5 + }, + "contextWindow": 1000000, + "maxTokens": 128000, + "thinking": { + "mode": "anthropic-adaptive", + "efforts": [ + "low", + "medium", + "high", + "max" + ], + "supportsDisplay": true + } + }, + "us-gov.anthropic.claude-haiku-4-5-20251001-v1:0": { + "id": "us-gov.anthropic.claude-haiku-4-5-20251001-v1:0", + "name": "Claude Haiku 4.5 (GovCloud)", + "api": "bedrock-converse-stream", + "provider": "amazon-bedrock", + "baseUrl": "https://bedrock-runtime.us-east-1.amazonaws.com", + "reasoning": true, + "input": [ + "text", + "image" + ], + "cost": { + "input": 1, + "output": 5, + "cacheRead": 0.1, + "cacheWrite": 1.25 + }, + "contextWindow": 200000, + "maxTokens": 64000, + "thinking": { + "mode": "budget", + "efforts": [ + "minimal", + "low", + "medium", + "high" + ] + } + }, + "us-gov.anthropic.claude-opus-4-1-20250805-v1:0": { + "id": "us-gov.anthropic.claude-opus-4-1-20250805-v1:0", + "name": "Claude Opus 4.1 (GovCloud)", + "api": "bedrock-converse-stream", + "provider": "amazon-bedrock", + "baseUrl": "https://bedrock-runtime.us-east-1.amazonaws.com", + "reasoning": true, + "input": [ + "text", + "image" + ], + "cost": { + "input": 15, + "output": 75, + "cacheRead": 1.5, + "cacheWrite": 18.75 + }, + "contextWindow": 200000, + "maxTokens": 32000, + "thinking": { + "mode": "budget", + "efforts": [ + "minimal", + "low", + "medium", + "high" + ] + } + }, + "us-gov.anthropic.claude-opus-4-5-20251101-v1:0": { + "id": "us-gov.anthropic.claude-opus-4-5-20251101-v1:0", + "name": "Claude Opus 4.5 (GovCloud)", + "api": "bedrock-converse-stream", + "provider": "amazon-bedrock", + "baseUrl": "https://bedrock-runtime.us-east-1.amazonaws.com", + "reasoning": true, + "input": [ + "text", + "image" + ], + "cost": { + "input": 5, + "output": 25, + "cacheRead": 0.5, + "cacheWrite": 6.25 + }, + "contextWindow": 200000, + "maxTokens": 64000, + "thinking": { + "mode": "anthropic-budget-effort", + "efforts": [ + "minimal", + "low", + "medium", + "high" + ] + } + }, + "us-gov.anthropic.claude-opus-4-6-v1": { + "id": "us-gov.anthropic.claude-opus-4-6-v1", + "name": "Claude Opus 4.6 (GovCloud)", + "api": "bedrock-converse-stream", + "provider": "amazon-bedrock", + "baseUrl": "https://bedrock-runtime.us-east-1.amazonaws.com", + "reasoning": true, + "input": [ + "text", + "image" + ], + "cost": { + "input": 5, + "output": 25, + "cacheRead": 0.5, + "cacheWrite": 6.25 + }, + "contextWindow": 1000000, + "maxTokens": 128000, + "thinking": { + "mode": "anthropic-adaptive", + "efforts": [ + "low", + "medium", + "high", + "max" + ] + } + }, + "us-gov.anthropic.claude-opus-4-7": { + "id": "us-gov.anthropic.claude-opus-4-7", + "name": "Claude Opus 4.7 (GovCloud)", + "api": "bedrock-converse-stream", + "provider": "amazon-bedrock", + "baseUrl": "https://bedrock-runtime.us-east-1.amazonaws.com", + "reasoning": true, + "input": [ + "text", + "image" + ], + "cost": { + "input": 5, + "output": 25, + "cacheRead": 0.5, + "cacheWrite": 6.25 + }, + "contextWindow": 1000000, + "maxTokens": 128000, + "thinking": { + "mode": "anthropic-adaptive", + "efforts": [ + "low", + "medium", + "high", + "max" + ], + "supportsDisplay": true + } + }, + "us-gov.anthropic.claude-opus-4-8": { + "id": "us-gov.anthropic.claude-opus-4-8", + "name": "Claude Opus 4.8 (GovCloud)", + "api": "bedrock-converse-stream", + "provider": "amazon-bedrock", + "baseUrl": "https://bedrock-runtime.us-east-1.amazonaws.com", + "reasoning": true, + "input": [ + "text", + "image" + ], + "cost": { + "input": 5, + "output": 25, + "cacheRead": 0.5, + "cacheWrite": 6.25 + }, + "contextWindow": 1000000, + "maxTokens": 128000, + "thinking": { + "mode": "anthropic-adaptive", + "efforts": [ + "low", + "medium", + "high", + "max" + ], + "supportsDisplay": true + } + }, + "us-gov.anthropic.claude-opus-5": { + "id": "us-gov.anthropic.claude-opus-5", + "name": "Claude Opus 5 (GovCloud)", + "api": "bedrock-converse-stream", + "provider": "amazon-bedrock", + "baseUrl": "https://bedrock-runtime.us-east-1.amazonaws.com", + "reasoning": true, + "input": [ + "text", + "image" + ], + "cost": { + "input": 5, + "output": 25, + "cacheRead": 0.5, + "cacheWrite": 6.25 + }, + "contextWindow": 1000000, + "maxTokens": 128000, + "thinking": { + "mode": "anthropic-adaptive", + "efforts": [ + "low", + "medium", + "high", + "max" + ], + "supportsDisplay": true + } + }, + "us-gov.anthropic.claude-sonnet-4-5-20250929-v1:0": { + "id": "us-gov.anthropic.claude-sonnet-4-5-20250929-v1:0", + "name": "Claude Sonnet 4.5 (GovCloud)", + "api": "bedrock-converse-stream", + "provider": "amazon-bedrock", + "baseUrl": "https://bedrock-runtime.us-east-1.amazonaws.com", + "reasoning": true, + "input": [ + "text", + "image" + ], + "cost": { + "input": 3, + "output": 15, + "cacheRead": 0.3, + "cacheWrite": 3.75 + }, + "contextWindow": 200000, + "maxTokens": 64000, + "thinking": { + "mode": "budget", + "efforts": [ + "minimal", + "low", + "medium", + "high" + ] + } + }, + "us-gov.anthropic.claude-sonnet-4-6": { + "id": "us-gov.anthropic.claude-sonnet-4-6", + "name": "Claude Sonnet 4.6 (GovCloud)", + "api": "bedrock-converse-stream", + "provider": "amazon-bedrock", + "baseUrl": "https://bedrock-runtime.us-east-1.amazonaws.com", + "reasoning": true, + "input": [ + "text", + "image" + ], + "cost": { + "input": 3, + "output": 15, + "cacheRead": 0.3, + "cacheWrite": 3.75 + }, + "contextWindow": 1000000, + "maxTokens": 64000, + "thinking": { + "mode": "budget", + "efforts": [ + "minimal", + "low", + "medium", + "high" + ] + } + }, + "us-gov.anthropic.claude-sonnet-5": { + "id": "us-gov.anthropic.claude-sonnet-5", + "name": "Claude Sonnet 5 (GovCloud)", + "api": "bedrock-converse-stream", + "provider": "amazon-bedrock", + "baseUrl": "https://bedrock-runtime.us-east-1.amazonaws.com", + "reasoning": true, + "input": [ + "text", + "image" + ], + "cost": { + "input": 2, + "output": 10, + "cacheRead": 0.2, + "cacheWrite": 2.5 + }, + "contextWindow": 1000000, + "maxTokens": 128000, + "thinking": { + "mode": "anthropic-adaptive", + "efforts": [ + "low", + "medium", + "high", + "max" + ], + "supportsDisplay": true + } + }, "us.amazon.nova-lite-v1:0": { "id": "us.amazon.nova-lite-v1:0", "name": "Nova Lite", @@ -105772,4 +106096,4 @@ } } } -} \ No newline at end of file +} diff --git a/packages/catalog/src/provider-models/openai-compat.ts b/packages/catalog/src/provider-models/openai-compat.ts index 9153c208b..d6a948bda 100644 --- a/packages/catalog/src/provider-models/openai-compat.ts +++ b/packages/catalog/src/provider-models/openai-compat.ts @@ -5608,14 +5608,25 @@ const MODELS_DEV_PROVIDER_DESCRIPTORS_BEDROCK: readonly ModelsDevProviderDescrip id: crossRegionId, name: toModelName(m.name, crossRegionId), }; - // Also emit EU variants for Claude models + // Also emit EU and AWS GovCloud (`us-gov.`) geo inference-profile + // variants for Claude models. GovCloud accounts list system profiles + // under the `us-gov.` prefix (e.g. us-gov.anthropic.claude-sonnet-4-5-…); + // without these rows the catalog only has commercial geos (`us.`/`eu.`/…) + // and model resolution rejects the GovCloud id (or misroutes commercial + // geos onto us-east-1 with GovCloud credentials → 403). if (modelId.startsWith("anthropic.claude-")) { + const displayName = toModelName(m.name, modelId); return [ bedrockModel, { ...bedrockModel, id: `eu.${modelId}`, - name: `${toModelName(m.name, modelId)} (EU)`, + name: `${displayName} (EU)`, + }, + { + ...bedrockModel, + id: `us-gov.${modelId}`, + name: `${displayName} (GovCloud)`, }, ]; } diff --git a/packages/catalog/test/amazon-bedrock-opus-5.test.ts b/packages/catalog/test/amazon-bedrock-opus-5.test.ts index d1e54e6ca..4b4d9591e 100644 --- a/packages/catalog/test/amazon-bedrock-opus-5.test.ts +++ b/packages/catalog/test/amazon-bedrock-opus-5.test.ts @@ -4,18 +4,23 @@ import { MODELS_DEV_PROVIDER_DESCRIPTORS, mapModelsDevToModels } from "@oh-my-pi import type { ModelSpec } from "@oh-my-pi/pi-catalog/types"; import { dropUnsupportedBedrockGeoIds } from "../scripts/generated-policies"; -// AWS's Bedrock model card for Claude Opus 5 lists exactly these Programmatic -// Access IDs — the bare model ID plus the us./eu./au. Geo and global. -// inference profiles. Japan is explicitly marked unsupported for Geo +// AWS's Bedrock model card for Claude Opus 5 lists these commercial/geo +// Programmatic Access IDs — the bare model ID plus the us./eu./au. Geo and +// global inference profiles. Japan is explicitly marked unsupported for Geo // inference in the same card's regional-availability table, so no `jp.` // profile exists for this model (unlike several Opus 4.x generations). // https://docs.aws.amazon.com/bedrock/latest/userguide/model-card-anthropic-claude-opus-5.html +// +// The catalog also synthesizes `us-gov.*` Claude geo profiles for AWS GovCloud +// (same path as the derived `eu.*` row) so GovCloud selectors resolve without +// requiring a full inference-profile ARN. const AWS_DOCUMENTED_OPUS_5_IDS = [ "anthropic.claude-opus-5", "us.anthropic.claude-opus-5", "eu.anthropic.claude-opus-5", "au.anthropic.claude-opus-5", "global.anthropic.claude-opus-5", + "us-gov.anthropic.claude-opus-5", ]; // A representative `stencil.so` "amazon-bedrock" payload for Claude Opus 5. @@ -78,10 +83,10 @@ describe("Amazon Bedrock Claude Opus 5", () => { ); const opus5Ids = dropUnsupportedBedrockGeoIds(mapped).map(model => model.id); - // Set semantics: the descriptor also derives an `eu.` variant from the - // bare `anthropic.` row, so `eu.` legitimately arrives from both that - // derivation and the standalone stencil.so row (deduped downstream by - // the generator). We assert the documented ID coverage, not row count. + // Set semantics: the descriptor also derives `eu.` and `us-gov.` variants + // from the bare `anthropic.` row, so `eu.` legitimately arrives from both + // that derivation and the standalone stencil.so row (deduped downstream + // by the generator). We assert the documented ID coverage, not row count. expect(new Set(opus5Ids)).toEqual(new Set(AWS_DOCUMENTED_OPUS_5_IDS)); // `stencil.so` lists `jp.anthropic.claude-opus-5`, but Bedrock has no such // inference profile for this model and would reject it, so the generation diff --git a/packages/catalog/test/amazon-bedrock-us-gov.test.ts b/packages/catalog/test/amazon-bedrock-us-gov.test.ts new file mode 100644 index 000000000..7904fe56d --- /dev/null +++ b/packages/catalog/test/amazon-bedrock-us-gov.test.ts @@ -0,0 +1,62 @@ +import { describe, expect, test } from "bun:test"; +import { MODELS_DEV_PROVIDER_DESCRIPTORS, mapModelsDevToModels } from "@oh-my-pi/pi-catalog/provider-models"; + +/** + * Contract: bare Anthropic Claude foundation rows from models.dev/stencil.so + * must produce a `us-gov.` Bedrock inference-profile selector. + * GovCloud accounts expose system profiles under that geo prefix; without it, + * `omp --model amazon-bedrock/us-gov.…` fails model resolution even though + * AWS CLI and ARN-based selectors work. + */ +const CLAUDE_FOUNDATION_ID = "anthropic.claude-sonnet-4-5-20250929-v1:0"; + +const BEDROCK_CLAUDE_FIXTURE = { + "amazon-bedrock": { + models: { + [CLAUDE_FOUNDATION_ID]: { + name: "Claude Sonnet 4.5", + tool_call: true, + reasoning: true, + limit: { context: 200_000, output: 64_000 }, + cost: { input: 3, output: 15, cache_read: 0.3, cache_write: 3.75 }, + modalities: { input: ["text", "image"] }, + }, + // Non-Claude Bedrock model must not get a us-gov sibling from the Claude transform. + "amazon.nova-pro-v1:0": { + name: "Nova Pro", + tool_call: true, + reasoning: false, + limit: { context: 300_000, output: 10_000 }, + cost: { input: 0.8, output: 3.2, cache_read: 0, cache_write: 0 }, + modalities: { input: ["text", "image"] }, + }, + }, + }, +}; + +describe("Amazon Bedrock GovCloud (us-gov) catalog mapping", () => { + test("bare Claude foundation ids emit a us-gov geo inference-profile selector", () => { + const mapped = mapModelsDevToModels(BEDROCK_CLAUDE_FIXTURE, MODELS_DEV_PROVIDER_DESCRIPTORS).filter( + model => model.provider === "amazon-bedrock", + ); + const ids = mapped.map(model => model.id); + + expect(ids).toContain(`us-gov.${CLAUDE_FOUNDATION_ID}`); + expect(ids).toContain(`eu.${CLAUDE_FOUNDATION_ID}`); + + const gov = mapped.find(model => model.id === `us-gov.${CLAUDE_FOUNDATION_ID}`); + expect(gov).toBeDefined(); + expect(gov?.api).toBe("bedrock-converse-stream"); + expect(gov?.name).toContain("GovCloud"); + }); + + test("non-Claude Bedrock models do not receive synthesized us-gov variants", () => { + const mapped = mapModelsDevToModels(BEDROCK_CLAUDE_FIXTURE, MODELS_DEV_PROVIDER_DESCRIPTORS).filter( + model => model.provider === "amazon-bedrock", + ); + const ids = mapped.map(model => model.id); + + expect(ids.some(id => id.startsWith("us-gov.amazon."))).toBe(false); + expect(ids).not.toContain("us-gov.amazon.nova-pro-v1:0"); + }); +});