Merge pull request #7645 from psamwel77/fix/bedrock-govcloud-us-gov-catalog

fix(catalog): emit AWS GovCloud us-gov Bedrock Claude inference profiles
This commit is contained in:
Can Bölük
2026-08-04 23:16:46 +02:00
committed by GitHub
5 changed files with 416 additions and 10 deletions
+4
View File
@@ -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
+325 -1
View File
@@ -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 @@
}
}
}
}
}
@@ -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)`,
},
];
}
@@ -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
@@ -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.<foundation-id>` 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");
});
});