Skip to content

Fix #373: Bedrock pricing keys never match live spans — normalize provider + model id in get_rates#385

Merged
anilmurty merged 3 commits into
mainfrom
fix/373-bedrock-pricing-normalization
Jul 2, 2026
Merged

Fix #373: Bedrock pricing keys never match live spans — normalize provider + model id in get_rates#385
anilmurty merged 3 commits into
mainfrom
fix/373-bedrock-pricing-normalization

Conversation

@anilmurty

Copy link
Copy Markdown
Contributor

Every [aws.*] pricing entry — the original Nova rows plus the rates added in #366/#370 — was unreachable for real Bedrock traffic, so every Bedrock call silently billed at the $0.50/$2.00 default. This makes those keys live by normalizing inside the rate lookup.

Closes #373

Summary

  • get_rates() now aliases provider aws.bedrock / aws_bedrock / bedrock → the table's aws key for the provider-keyed lookup.
  • For that provider, it additionally tries the modelId in table-key form: strip an optional bedrock/ prefix (LiteLLM-routed form), strip a trailing :<digits> version, flatten dots to hyphens (us.amazon.nova-micro-v1:0us-amazon-nova-micro-v1).
  • Lookup-only change: stored span provider/model stay raw, models.toml is untouched.

Symptom, root cause, fix

Symptom: all Bedrock spans cost out at the default flat rate; the [aws.*] table entries never match.

Root cause: two simultaneous mismatches. Live spans carry provider = "aws.bedrock" (set verbatim by BedrockIntegration) or "bedrock" (LiteLLM), and model = "us.amazon.nova-micro-v1:0" (raw boto3 modelId). The table keys are [aws.us-amazon-nova-micro-v1] — provider aws, dots flattened, :0 stripped. get_rates("aws.bedrock", "us.amazon.nova-micro-v1:0") looked under table["aws.bedrock"], missed, and returned None.

Fix: normalize in get_rates (tokenjam/core/pricing.py) per the issue's preferred approach — one home covering every ingest path (direct boto3, LiteLLM-Bedrock, OTLP HTTP), slotted alongside the existing _strip_date_suffix fallback. The normalized model key is tried only after the exact and date-stripped forms miss, and only when the resolved provider is aws, so no other provider's lookup changes. The :N strip is anchored (:\d+$) — only a trailing all-digit version segment is removed; mid-string dates in Anthropic-on-Bedrock ids (...-20250805-v1) survive intact. No cache changes — the LRU-cached layers are untouched; only the post-load lookup logic changed.

Tests / Verification

  • tests/unit/test_cost.py (where get_rates tests live — there is no test_pricing.py): 6 new tests covering
    • get_rates("aws.bedrock", "us.amazon.nova-micro-v1:0") → packaged Nova Micro rate (0.035/0.14, non-default)
    • provider "bedrock" and the LiteLLM bedrock/us.amazon... model form
    • the existing Nova Pro entry and an Anthropic-on-Bedrock id (mid-string date preserved)
    • :N strip applies only to a trailing :digits, not :latest or mid-string colons
    • regression guard: non-Bedrock providers unaffected (anthropic still resolves; openai + a Bedrock id still misses; unknown pair still None)
  • python3 -m pytest tests/unit/ -q → 1313 passed; tests/integration/ → 344 passed
  • ruff check and mypy clean on both touched files

What's NOT in this PR

🤖 Generated with Claude Code

https://claude.ai/code/session_015e3DZGhb1R5sXX2x52Y2Ar

anilmurty and others added 3 commits July 2, 2026 14:08
Every [aws.*] entry in models.toml was dead for live traffic: Bedrock
spans carry provider "aws.bedrock" (direct boto3) or "bedrock"
(LiteLLM-routed) and the raw boto3 modelId ("us.amazon.nova-micro-v1:0",
dots and trailing ":0" intact), while the table keys are provider "aws"
with dot-flattened, unversioned model names. get_rates() missed on both
axes and every Bedrock call silently fell back to the $0.50/$2.00
default rate.

Fix inside get_rates() so one home covers all ingest paths (direct
boto3, LiteLLM-Bedrock, OTLP HTTP): alias aws.bedrock / aws_bedrock /
bedrock -> aws for the table lookup, and for that provider also try the
modelId in table-key form (strip a "bedrock/" prefix and a trailing
":<digits>" version, flatten dots to hyphens). The normalization is
lookup-only -- stored spans keep the raw provider/model strings, and
models.toml is unchanged; the existing #366/#370 keys simply become
reachable.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015e3DZGhb1R5sXX2x52Y2Ar
@anilmurty anilmurty merged commit baaa6ae into main Jul 2, 2026
4 checks passed
@anilmurty anilmurty deleted the fix/373-bedrock-pricing-normalization branch July 2, 2026 22:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Bedrock pricing keys never match live spans — normalize provider + model id in the rate lookup

1 participant