From 3441b80f4f20106d2adb8e3ff638c31e12656d2b Mon Sep 17 00:00:00 2001 From: Teknium <127238744+teknium1@users.noreply.github.com> Date: Mon, 20 Jul 2026 02:51:17 -0700 Subject: [PATCH] feat(pricing): add Bedrock rows for Opus 4.8/4.7, correct Opus 4.6 to $5/$25 Adds current-gen Claude Opus pricing rows on Bedrock keyed to Anthropic's published list price, which commercial Bedrock on-demand mirrors. Also corrects the existing Opus 4.6 row: it carried Claude-3-era Opus pricing ($15/$75); Opus 4.5+ list at $5/$25 with cache write 1.25x / read 0.1x. The AWS Price List API had not published these SKUs machine-readably as of 2026-07, so these are commercial-list snapshots pending an authoritative machine source. Reapplied from PR #62327 (commit authored under a placeholder identity, so cherry-pick was not usable; sonnet-5 row from that PR already landed via #67932). Co-authored-by: pgregg88 <4943027+pgregg88@users.noreply.github.com> --- agent/usage_pricing.py | 40 +++++++++++++++++++++++++++---- tests/agent/test_usage_pricing.py | 37 ++++++++++++++++++++++++++++ 2 files changed, 72 insertions(+), 5 deletions(-) diff --git a/agent/usage_pricing.py b/agent/usage_pricing.py index a8098d5cb70e..2884381bf167 100644 --- a/agent/usage_pricing.py +++ b/agent/usage_pricing.py @@ -545,17 +545,47 @@ _OFFICIAL_DOCS_PRICING: Dict[tuple[str, str], PricingEntry] = { # Bedrock charges the same per-token rates as the model provider but # through AWS billing. These are the on-demand prices (no commitment). # Source: https://aws.amazon.com/bedrock/pricing/ + # Current-gen Claude Opus on Bedrock. Commercial Bedrock on-demand + # mirrors Anthropic's published list price for the Claude line + # ($5/$25 for Opus 4.6/4.7/4.8; cache write = 1.25x input at the + # 5-minute TTL, cache read = 0.1x input). NOTE: the AWS Price List API + # had not published these SKUs machine-readably as of 2026-07 — these + # are commercial-list snapshots pending an authoritative machine source. + ( + "bedrock", + "anthropic.claude-opus-4-8", + ): PricingEntry( + input_cost_per_million=Decimal("5.00"), + output_cost_per_million=Decimal("25.00"), + cache_read_cost_per_million=Decimal("0.50"), + cache_write_cost_per_million=Decimal("6.25"), + source="official_docs_snapshot", + source_url="https://aws.amazon.com/bedrock/pricing/", + pricing_version="anthropic-list-2026-07", + ), + ( + "bedrock", + "anthropic.claude-opus-4-7", + ): PricingEntry( + input_cost_per_million=Decimal("5.00"), + output_cost_per_million=Decimal("25.00"), + cache_read_cost_per_million=Decimal("0.50"), + cache_write_cost_per_million=Decimal("6.25"), + source="official_docs_snapshot", + source_url="https://aws.amazon.com/bedrock/pricing/", + pricing_version="anthropic-list-2026-07", + ), ( "bedrock", "anthropic.claude-opus-4-6", ): PricingEntry( - input_cost_per_million=Decimal("15.00"), - output_cost_per_million=Decimal("75.00"), - cache_read_cost_per_million=Decimal("1.50"), - cache_write_cost_per_million=Decimal("18.75"), + input_cost_per_million=Decimal("5.00"), + output_cost_per_million=Decimal("25.00"), + cache_read_cost_per_million=Decimal("0.50"), + cache_write_cost_per_million=Decimal("6.25"), source="official_docs_snapshot", source_url="https://aws.amazon.com/bedrock/pricing/", - pricing_version="bedrock-pricing-2026-04", + pricing_version="anthropic-list-2026-07", ), ( "bedrock", diff --git a/tests/agent/test_usage_pricing.py b/tests/agent/test_usage_pricing.py index da81d7c589d4..9b82d2e2ad47 100644 --- a/tests/agent/test_usage_pricing.py +++ b/tests/agent/test_usage_pricing.py @@ -348,6 +348,43 @@ def test_bedrock_claude_rows_all_carry_cache_pricing(): assert entry.cache_write_cost_per_million > entry.input_cost_per_million, key +def test_bedrock_current_gen_claude_rows_resolve(): + """Current-gen Claude models (Opus 4.8/4.7, Sonnet 5) must have Bedrock + pricing rows so cached sessions report a dollar cost, not ``unknown``. + Assert each resolves via the bare id and a cross-region inference profile + (us./global. prefix), that every id for a given model resolves to the same + entry, and that the row carries the cache fields a Bedrock Claude session + needs. + + (Version-suffixed IDs like ``...-v1:0`` are covered separately by the + normalizer test in the suffix-strip change; this test intentionally sticks + to id shapes that resolve on ``main`` so it is independent of that PR.) + """ + url = "https://bedrock-runtime.us-east-1.amazonaws.com" + for bare in ( + "anthropic.claude-opus-4-8", + "anthropic.claude-opus-4-7", + "anthropic.claude-sonnet-5", + ): + ref = get_pricing_entry(bare, provider="bedrock", base_url=url) + assert ref is not None, bare + assert ref.input_cost_per_million is not None, bare + assert ref.output_cost_per_million is not None, bare + # Output costs more than input across the Claude line; sanity-check the + # row isn't malformed (input < output). + assert ref.output_cost_per_million > ref.input_cost_per_million, bare + # Cache fields present so cached sessions price correctly (the #50295 + # symptom was unknown cost on cached Bedrock Claude sessions). + assert ref.cache_read_cost_per_million is not None, bare + assert ref.cache_write_cost_per_million is not None, bare + # Cross-region inference profiles resolve to the same entry. + for mid in (f"us.{bare}", f"global.{bare}"): + entry = get_pricing_entry(mid, provider="bedrock", base_url=url) + assert entry is not None, mid + assert entry.input_cost_per_million == ref.input_cost_per_million, mid + assert entry.output_cost_per_million == ref.output_cost_per_million, mid + + def test_bedrock_cross_region_profile_prefix_resolves_to_pricing(): """Cross-region inference profiles (us./global./eu. prefixes) must resolve to the same pricing entry as the bare foundation-model id. Without prefix