From a481a89e628b4cdb151a03868357d73c4e1cee64 Mon Sep 17 00:00:00 2001 From: k1riiiii <128486679+k1riiiii@users.noreply.github.com> Date: Sat, 25 Jul 2026 09:54:26 +0000 Subject: [PATCH] feat(catalog): add Claude Opus 5 entries for Amazon Bedrock Changes: - Add Amazon Bedrock catalog entries for Claude Opus 5 - Exclude unsupported jp. inference profiles during generation - Add Bedrock prompt cache compatibility info, AWS model card sources, and regression tests Reason / background: - Incorporate the new model info from models.dev and align with the official AWS spec Scope of impact: - Model catalog generation, Bedrock compatibility info, catalog tests --- packages/catalog/CHANGELOG.md | 4 + packages/catalog/scripts/generate-models.ts | 2 + .../catalog/scripts/generated-policies.ts | 14 ++ packages/catalog/src/compat/bedrock.ts | 12 ++ packages/catalog/src/models.json | 152 +++++++++++++++++- .../test/amazon-bedrock-opus-5.test.ts | 84 ++++++++++ 6 files changed, 267 insertions(+), 1 deletion(-) create mode 100644 packages/catalog/test/amazon-bedrock-opus-5.test.ts diff --git a/packages/catalog/CHANGELOG.md b/packages/catalog/CHANGELOG.md index 669081f3f..e1d6775e5 100644 --- a/packages/catalog/CHANGELOG.md +++ b/packages/catalog/CHANGELOG.md @@ -2,6 +2,10 @@ ## [Unreleased] +### Added + +- Added Claude Opus 5 model entries for Amazon Bedrock: `anthropic.claude-opus-5` plus its `us.`, `eu.`, `au.`, and `global.` regional/geo IDs. + ## [17.1.3] - 2026-07-24 ### Fixed diff --git a/packages/catalog/scripts/generate-models.ts b/packages/catalog/scripts/generate-models.ts index 20fb72a9c..6971eab37 100644 --- a/packages/catalog/scripts/generate-models.ts +++ b/packages/catalog/scripts/generate-models.ts @@ -52,6 +52,7 @@ import { applyCanonicalLimitFallback, applyGeneratedModelPolicies, CLOUDFLARE_FALLBACK_MODEL, + dropUnsupportedBedrockGeoIds, linkOpenAIPromotionTargets, } from "./generated-policies"; @@ -634,6 +635,7 @@ async function generateModels() { allModels = dropFireworksWireIds(allModels); allModels = dropUnusableZaiContextTierIds(allModels); allModels = dropXiaomiAudioOnlyIds(allModels); + allModels = dropUnsupportedBedrockGeoIds(allModels); allModels = normalizeAntigravityEndpoint(allModels); // Normalize display names: gateway author prefixes ("OpenAI: …"), alias // markers ("(latest)"), provider attribution ("(Antigravity)"), and diff --git a/packages/catalog/scripts/generated-policies.ts b/packages/catalog/scripts/generated-policies.ts index ecde56894..77a0bab37 100644 --- a/packages/catalog/scripts/generated-policies.ts +++ b/packages/catalog/scripts/generated-policies.ts @@ -51,6 +51,20 @@ export const CLOUDFLARE_FALLBACK_MODEL: ModelSpec<"anthropic-messages"> = { maxTokens: 64000, }; +/** + * `models.dev` currently lists `jp.anthropic.claude-opus-5`, but AWS's own + * Bedrock model card documents only `anthropic.claude-opus-5` plus the `us.`, + * `eu.`, `au.`, and `global.` Geo/Global inference-profile IDs under + * Programmatic Access; Japan regions are marked unsupported for Geo inference + * in the same card's regional-availability table. Bedrock rejects an + * undocumented inference-profile ID outright, so drop this specific upstream + * row rather than ship a selector that 4xxs on first use (PR #6591 review). + * https://docs.aws.amazon.com/bedrock/latest/userguide/model-card-anthropic-claude-opus-5.html + */ +export function dropUnsupportedBedrockGeoIds(models: readonly ModelSpec[]): ModelSpec[] { + return models.filter(model => !(model.provider === "amazon-bedrock" && model.id === "jp.anthropic.claude-opus-5")); +} + const CODEX_GPT_5_4_PRIORITY_BY_VARIANT: Partial> = { base: 0, mini: 1, diff --git a/packages/catalog/src/compat/bedrock.ts b/packages/catalog/src/compat/bedrock.ts index 76fb35516..d8258c193 100644 --- a/packages/catalog/src/compat/bedrock.ts +++ b/packages/catalog/src/compat/bedrock.ts @@ -42,6 +42,15 @@ const EXPLICIT_CHECKPOINTS_4096_1H: ResolvedBedrockCompat = { promptCacheMaximumCheckpoints: 4, }; +// AWS モデルカード: 512 トークン、最大 4 個のキャッシュチェックポイント、5 分と 1 時間の TTL。 +// https://docs.aws.amazon.com/bedrock/latest/userguide/model-card-anthropic-claude-opus-5.html +const EXPLICIT_CHECKPOINTS_512_1H: ResolvedBedrockCompat = { + promptCacheMode: "explicit", + supportsLongPromptCacheRetention: true, + promptCacheMinimumTokens: 512, + promptCacheMaximumCheckpoints: 4, +}; + /** * Explicit Nova cache points complement Bedrock's automatic prefix caching: * AWS recommends them for consistent cache hits and input-cost savings. Keep @@ -82,6 +91,9 @@ function detectedBedrockCompat(modelId: string): ResolvedBedrockCompat { ) { return EXPLICIT_CHECKPOINTS_4096_1H; } + if (id.includes("anthropic.claude-opus-5")) { + return EXPLICIT_CHECKPOINTS_512_1H; + } if (id.includes("anthropic.claude-opus-4-6")) { return EXPLICIT_CHECKPOINTS_4096_5M; } diff --git a/packages/catalog/src/models.json b/packages/catalog/src/models.json index 00f76c7da..a184329fc 100644 --- a/packages/catalog/src/models.json +++ b/packages/catalog/src/models.json @@ -7966,6 +7966,36 @@ "supportsDisplay": true } }, + "anthropic.claude-opus-5": { + "id": "anthropic.claude-opus-5", + "name": "Claude Opus 5", + "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 + } + }, "anthropic.claude-sonnet-5": { "id": "anthropic.claude-sonnet-5", "name": "Claude Sonnet 5", @@ -8084,6 +8114,36 @@ "supportsDisplay": true } }, + "au.anthropic.claude-opus-5": { + "id": "au.anthropic.claude-opus-5", + "name": "Claude Opus 5 (AU)", + "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 + } + }, "au.anthropic.claude-sonnet-4-5-20250929-v1:0": { "id": "au.anthropic.claude-sonnet-4-5-20250929-v1:0", "name": "Claude Sonnet 4.5 (AU)", @@ -8669,6 +8729,36 @@ "supportsDisplay": true } }, + "eu.anthropic.claude-opus-5": { + "id": "eu.anthropic.claude-opus-5", + "name": "Claude Opus 5 (EU)", + "api": "bedrock-converse-stream", + "provider": "amazon-bedrock", + "baseUrl": "https://bedrock-runtime.us-east-1.amazonaws.com", + "reasoning": true, + "input": [ + "text", + "image" + ], + "cost": { + "input": 5.5, + "output": 27.5, + "cacheRead": 0.55, + "cacheWrite": 6.875 + }, + "contextWindow": 1000000, + "maxTokens": 128000, + "thinking": { + "mode": "anthropic-adaptive", + "efforts": [ + "low", + "medium", + "high", + "max" + ], + "supportsDisplay": true + } + }, "eu.anthropic.claude-sonnet-4-20250514-v1:0": { "id": "eu.anthropic.claude-sonnet-4-20250514-v1:0", "name": "Claude Sonnet 4 (EU)", @@ -8992,6 +9082,36 @@ "supportsDisplay": true } }, + "global.anthropic.claude-opus-5": { + "id": "global.anthropic.claude-opus-5", + "name": "Claude Opus 5 (Global)", + "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 + } + }, "global.anthropic.claude-sonnet-4-20250514-v1:0": { "id": "global.anthropic.claude-sonnet-4-20250514-v1:0", "name": "Claude Sonnet 4 (Global)", @@ -10620,6 +10740,36 @@ "supportsDisplay": true } }, + "us.anthropic.claude-opus-5": { + "id": "us.anthropic.claude-opus-5", + "name": "Claude Opus 5 (US)", + "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.anthropic.claude-sonnet-4-20250514-v1:0": { "id": "us.anthropic.claude-sonnet-4-20250514-v1:0", "name": "Claude Sonnet 4 (US)", @@ -94800,4 +94950,4 @@ } } } -} \ No newline at end of file +} diff --git a/packages/catalog/test/amazon-bedrock-opus-5.test.ts b/packages/catalog/test/amazon-bedrock-opus-5.test.ts new file mode 100644 index 000000000..df243eb4e --- /dev/null +++ b/packages/catalog/test/amazon-bedrock-opus-5.test.ts @@ -0,0 +1,84 @@ +import { describe, expect, test } from "bun:test"; +import { buildBedrockCompat } from "@oh-my-pi/pi-catalog/compat/bedrock"; +import { getBundledModels } from "@oh-my-pi/pi-catalog/models"; +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 +// 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 +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", +]; + +describe("Amazon Bedrock Claude Opus 5", () => { + test("bundles exactly the AWS-documented inference-profile IDs", () => { + const bedrockOpus5Ids = getBundledModels("amazon-bedrock") + .map(model => model.id) + .filter(id => id.endsWith("anthropic.claude-opus-5")); + + expect(new Set(bedrockOpus5Ids)).toEqual(new Set(AWS_DOCUMENTED_OPUS_5_IDS)); + // `models.dev` currently also lists `jp.anthropic.claude-opus-5`; Bedrock + // has no such inference profile for this model and would reject it. + expect(bedrockOpus5Ids).not.toContain("jp.anthropic.claude-opus-5"); + }); + + test("dropUnsupportedBedrockGeoIds filters the undocumented jp. profile without touching other providers/ids", () => { + const bareSpec = (provider: string, id: string): ModelSpec<"bedrock-converse-stream"> => ({ + id, + name: id, + api: "bedrock-converse-stream", + provider, + baseUrl: "https://bedrock-runtime.us-east-1.amazonaws.com", + reasoning: true, + input: ["text"], + cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, + contextWindow: 200000, + maxTokens: 64000, + }); + const input = [ + bareSpec("amazon-bedrock", "jp.anthropic.claude-opus-5"), + bareSpec("amazon-bedrock", "us.anthropic.claude-opus-5"), + // A `jp.` id on a different Bedrock model, or on a different provider, + // must survive — only this exact (provider, id) pair is undocumented. + bareSpec("amazon-bedrock", "jp.anthropic.claude-opus-4-8"), + bareSpec("some-other-provider", "jp.anthropic.claude-opus-5"), + ]; + + expect(dropUnsupportedBedrockGeoIds(input).map(model => model.id)).toEqual([ + "us.anthropic.claude-opus-5", + "jp.anthropic.claude-opus-4-8", + "jp.anthropic.claude-opus-5", + ]); + }); + + test("resolves the AWS-documented 512-token/four-checkpoint/1h prompt-cache capability", () => { + for (const id of AWS_DOCUMENTED_OPUS_5_IDS) { + const spec: ModelSpec<"bedrock-converse-stream"> = { + id, + name: id, + 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: 1_000_000, + maxTokens: 128_000, + }; + expect(buildBedrockCompat(spec)).toEqual({ + promptCacheMode: "explicit", + supportsLongPromptCacheRetention: true, + promptCacheMinimumTokens: 512, + promptCacheMaximumCheckpoints: 4, + }); + } + }); +});