fix(pricing): resolve versioned Bedrock profile IDs
This commit is contained in:
+29
-5
@@ -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
|
||||
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user