Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 51 additions & 0 deletions agent/usage_pricing.py
Original file line number Diff line number Diff line change
Expand Up @@ -560,6 +560,57 @@ class CostResult:
source_url="https://aws.amazon.com/bedrock/pricing/",
pricing_version="bedrock-pricing-2026-04",
),
# Current-gen Claude on Bedrock. Rates keyed to Anthropic's published
# list price (https://docs.anthropic.com/en/docs/about-claude/pricing +
# https://claude.com/pricing), which commercial Bedrock on-demand mirrors
# for the Claude line — the existing sonnet-4-5/4-6 rows above ($3/$15,
# cache $0.30/$3.75) already match Anthropic list exactly. NOTE: AWS
# GovCloud carries a ~20% premium (Opus 4.8 = $6/$30 there), and the AWS
# Price List API had NOT published these SKUs machine-readably as of the
# 2026-07-07 us-east-1 offer, so these are the commercial-list figures
# pending an authoritative AWS machine source. cache_write is the 5-minute
# TTL rate (1.25x input); cache_read is 0.1x input, per Anthropic's table.
(
"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://docs.anthropic.com/en/docs/about-claude/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://docs.anthropic.com/en/docs/about-claude/pricing",
pricing_version="anthropic-list-2026-07",
),
# Sonnet 5 launched 2026-06-30. Promotional launch pricing of $2/$10 is in
# effect through 2026-08-31; standard pricing of $3/$15 takes effect
# 2026-09-01. This snapshot uses the STANDARD rate so it does not silently
# under-report after the promo ends — the same convention as every other
# steady-state row here.
(
"bedrock",
"anthropic.claude-sonnet-5",
): PricingEntry(
input_cost_per_million=Decimal("3.00"),
output_cost_per_million=Decimal("15.00"),

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AWS's Bedrock pricing page says Sonnet 5 is currently $2/$10 per million input/output tokens through 2026-08-31. This $3.00/$15.00 standard-rate row will overstate /usage until then; please use the active rate (and corresponding confirmed cache rates) or defer this row until the promotion ends.

cache_read_cost_per_million=Decimal("0.30"),
cache_write_cost_per_million=Decimal("3.75"),
source="official_docs_snapshot",
source_url="https://docs.anthropic.com/en/docs/about-claude/pricing",
pricing_version="anthropic-list-2026-07",
),
(
"bedrock",
"amazon.nova-pro",
Expand Down
37 changes: 37 additions & 0 deletions tests/agent/test_usage_pricing.py
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,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
Expand Down