fix(pricing): resolve versioned Bedrock profile IDs

This commit is contained in:
Osraka
2026-06-22 00:38:43 +03:00
committed by Teknium
parent 9ca8ce4335
commit 54418a888e
2 changed files with 66 additions and 5 deletions
+29 -5
View File
@@ -913,15 +913,25 @@ def _normalize_bedrock_model_name(model: str) -> str:
"""Normalize a Bedrock model id to its bare foundation-model form.
Bedrock cross-region inference profiles prefix the foundation model id
with a region scope (``us.`` / ``global.`` / ``eu.`` / ``ap.`` / ``jp.``),
with a region scope (``us.`` / ``global.`` / ``eu.`` / ``apac.`` / ...),
e.g. ``us.anthropic.claude-opus-4-7``. The pricing table is keyed on the
bare ``anthropic.claude-*`` id, so the prefix must be stripped before the
lookup or every cross-region session prices as unknown. Mirrors the
prefix list in ``bedrock_adapter.is_anthropic_bedrock_model``. Also
normalizes dot-notation version numbers (``4.7`` → ``4-7``).
lookup or every cross-region session prices as unknown. Also normalizes
dot-notation version numbers (``4.7`` → ``4-7``).
"""
name = model.lower().strip()
for prefix in ("us.", "global.", "eu.", "ap.", "jp."):
for prefix in (
"global.",
"us.",
"eu.",
"ap.",
"apac.",
"jp.",
"ca.",
"sa.",
"me.",
"af.",
):
if name.startswith(prefix):
name = name[len(prefix):]
break
@@ -967,6 +977,20 @@ def _lookup_official_docs_pricing(route: BillingRoute) -> Optional[PricingEntry]
entry = _OFFICIAL_DOCS_PRICING.get((route.provider, normalized))
if entry:
return entry
bedrock_entries = (
(known_model, known_entry)
for (provider, known_model), known_entry in _OFFICIAL_DOCS_PRICING.items()
if provider == route.provider
)
for known_model, known_entry in sorted(
bedrock_entries,
key=lambda item: len(item[0]),
reverse=True,
):
if normalized == known_model or normalized.startswith(
(f"{known_model}-", f"{known_model}:")
):
return known_entry
return None
+37
View File
@@ -369,6 +369,43 @@ def test_bedrock_cross_region_profile_prefix_resolves_to_pricing():
assert scoped.cache_read_cost_per_million == bare.cache_read_cost_per_million
def test_bedrock_versioned_inference_profile_resolves_to_bare_pricing():
"""Bedrock profile IDs may include the provider's dated version suffix.
The pricing table intentionally uses shorter model-family IDs, so the
lookup needs a longest-prefix fallback after stripping the region scope.
"""
bare = get_pricing_entry("anthropic.claude-sonnet-4-6", provider="bedrock")
assert bare is not None
for model in (
"us.anthropic.claude-sonnet-4-6-20250514-v1:0",
"global.anthropic.claude-sonnet-4-6-20250514-v1:0",
):
scoped = get_pricing_entry(model, provider="bedrock")
assert scoped is not None, model
assert scoped.input_cost_per_million == bare.input_cost_per_million
assert scoped.output_cost_per_million == bare.output_cost_per_million
assert scoped.cache_read_cost_per_million == bare.cache_read_cost_per_million
assert scoped.cache_write_cost_per_million == bare.cache_write_cost_per_million
def test_bedrock_pricing_supports_less_common_inference_profile_prefixes():
"""AWS also exposes profile scopes beyond us./global./eu.; those should
not silently fall through to unknown pricing.
"""
entry = get_pricing_entry(
"apac.anthropic.claude-haiku-4-5-20251001-v1:0",
provider="bedrock",
)
assert entry is not None
assert float(entry.input_cost_per_million) == 0.8
assert float(entry.output_cost_per_million) == 4.0
assert float(entry.cache_read_cost_per_million) == 0.08
assert float(entry.cache_write_cost_per_million) == 1.0
def test_bedrock_claude_cached_session_estimates_cost_not_unknown():
"""A Bedrock Claude session with cache hits must produce a dollar estimate,
not ``unknown`` — the user-visible symptom in #50295.