Skip to content

fix(pricing): strip Bedrock version/date suffix before cost lookup - #62320

Closed
pgregg88 wants to merge 1 commit into
NousResearch:mainfrom
pgregg88:fix/bedrock-pricing-version-suffix-normalize
Closed

fix(pricing): strip Bedrock version/date suffix before cost lookup#62320
pgregg88 wants to merge 1 commit into
NousResearch:mainfrom
pgregg88:fix/bedrock-pricing-version-suffix-normalize

Conversation

@pgregg88

Copy link
Copy Markdown
Contributor

Problem

Bedrock foundation-model IDs returned by ListFoundationModels and inference profiles carry a trailing revision suffix that the bare _OFFICIAL_DOCS_PRICING keys don't have:

  • a release date — -20250514
  • a Bedrock model version — -v1
  • and/or a minor revision — :0

e.g. anthropic.claude-sonnet-4-5-20250929-v1:0 or anthropic.claude-opus-4-6-v1.

_lookup_official_docs_pricing does an exact dict-key match on the normalized name. _normalize_bedrock_model_name strips the region prefix (us./global./…) and normalizes dot-notation versions, but does not strip that trailing suffix — so any id carrying it misses its bare pricing row and the session reports Total cost: unknown even though the row exists.

Reproduce on main

from agent.usage_pricing import get_pricing_entry
url = "https://bedrock-runtime.us-east-1.amazonaws.com"
# bare id — resolves
get_pricing_entry("anthropic.claude-sonnet-4-5", provider="bedrock", base_url=url)  # -> PricingEntry
# real id AWS actually returns — misses, prices as unknown
get_pricing_entry("anthropic.claude-sonnet-4-5-20250929-v1:0", provider="bedrock", base_url=url)  # -> None
get_pricing_entry("anthropic.claude-opus-4-6-v1", provider="bedrock", base_url=url)  # -> None

Fix

Add a trailing-suffix strip to _normalize_bedrock_model_name, anchored to the end of the string. It only matches an 8-digit date, -vN, and :N — so the model version itself (-4-6 / -4-8) is never eaten, and non-Claude provider IDs (amazon.nova-pro-v1:0amazon.nova-pro) collapse correctly too.

name = re.sub(r"(-\d{8})?(-v\d+)?(:\d+)?$", "", name)

Scope / relation to other work

This is the -v1/date-suffix facet of #50295. It is distinct from and non-overlapping with:

  • fix(bedrock): add prompt-cache pricing to Claude Bedrock entries #46299 (open) — adds cache_read/cache_write cost fields to existing Bedrock Claude rows. That edits existing rows; this fixes key matching. No conflict.
  • The cross-region-prefix facet (us./global./eu.) — already handled in _normalize_bedrock_model_name and covered by test_bedrock_cross_region_profile_prefix_resolves_to_pricing.

It does not add the missing current-gen rows (opus-4-8/4-7, sonnet-5) — that needs authoritative commercial (non-GovCloud) pricing numbers and is left for a separate change / maintainer with those figures.

Tests

Two regression tests in tests/agent/test_usage_pricing.py:

  • test_bedrock_version_suffix_resolves_to_pricing — asserts every suffixed shape (with/without cross-region prefix) resolves to the same entry as the bare id (an invariant, not a frozen dollar value, per the repo's "behavior contracts over snapshots" guidance).
  • test_bedrock_version_suffix_normalizer_preserves_model_version — asserts the stripper preserves the model version and bare provider IDs.

tests/agent/test_usage_pricing.py: 17 passed. Ruff clean on both files.

Bedrock foundation-model IDs returned by ListFoundationModels and
inference profiles carry a trailing revision suffix that the bare
`_OFFICIAL_DOCS_PRICING` keys don't have: a release date (`-20250514`),
a Bedrock model version (`-v1`), and/or a minor revision (`:0`) — e.g.
`anthropic.claude-sonnet-4-5-20250929-v1:0` or `anthropic.claude-opus-4-6-v1`.

`_lookup_official_docs_pricing` does an exact dict-key match on the
normalized name, so any id carrying that suffix misses its bare row and
the session prices as `unknown` even though the row exists. This is the
`-v1` facet of NousResearch#50295 (distinct from the cache-cost-fields facet in
open PR NousResearch#46299 and the cross-region-prefix facet already handled).

`_normalize_bedrock_model_name` already strips the region prefix and
normalizes dot-notation versions; this adds a trailing-suffix strip
anchored to the end. The pattern only matches an 8-digit date, `-vN`,
and `:N`, so the model version itself (`-4-6` / `-4-8`) is never eaten.

Tests: two regression tests in test_usage_pricing.py — one asserting
every suffixed shape (with/without cross-region prefix) resolves to the
same entry as the bare id (invariant, not a frozen dollar value), one
asserting the normalizer preserves the model version and bare provider
IDs. Full file: 17 passed.
@alt-glitch alt-glitch added type/bug Something isn't working comp/agent Core agent runtime: loop, agent_init, prompt builder, context-compression, responses endpoint provider/bedrock AWS Bedrock (boto3, IAM) area/billing Account usage, credit usage, billing (cross-cutting) P3 Low — cosmetic, nice to have labels Jul 10, 2026
@teknium1

Copy link
Copy Markdown
Contributor

Thanks for the focused regression fix. The premise is confirmed on current remote main: agent/usage_pricing.py:696 leaves Bedrock date/version/revision suffixes intact, while agent/usage_pricing.py:732-738 performs the resulting exact-key lookup. Current picker and discovery fixtures contain the affected production ID forms (hermes_cli/models.py:534-539, tests/hermes_cli/test_bedrock_model_picker.py:42-50).

The proposed anchored suffix normalization is appropriately scoped to the existing Bedrock pricing-normalization path, preserves bare model-version components, and the added tests assert lookup equivalence rather than fixed price snapshots. GitHub reports the PR mergeable against current main.

Automated hermes-sweeper review.

@teknium1 teknium1 added sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades sweeper:blast-contained Sweeper blast radius: contained — one narrow path / opt-in / few users labels Jul 11, 2026
@teknium1 teknium1 added the area/usage-cost Token accounting, usage reporting, billing, cost tracking label Jul 19, 2026
@teknium1

Copy link
Copy Markdown
Contributor

Merged via PR #67976. Your suffix-strip fix duplicated PR #50437 (@Osraka, submitted June 21 — the earlier submission, so their commits were cherry-picked as the base), and the sonnet-5 pricing row from your sibling PR #62327 had already landed via #67932.

Note on attribution: your commits were authored under a placeholder identity (hermes@covered-call-strategy.local), which we can't cherry-pick as-is — check git config user.email for future PRs so your commits carry your real identity and survive salvage intact. Thanks for the contribution!

#67976

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/billing Account usage, credit usage, billing (cross-cutting) area/usage-cost Token accounting, usage reporting, billing, cost tracking comp/agent Core agent runtime: loop, agent_init, prompt builder, context-compression, responses endpoint P3 Low — cosmetic, nice to have provider/bedrock AWS Bedrock (boto3, IAM) sweeper:blast-contained Sweeper blast radius: contained — one narrow path / opt-in / few users sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants