Skip to content

fix(ci): fail the cost map guard when a Bedrock regional row drifts from its base row - #43363

Open
devin-ai-integration[bot] wants to merge 3 commits into
mainfrom
litellm_cost_map_guard_bedrock_parity
Open

devin-ai-integration[bot] wants to merge 3 commits into
mainfrom
litellm_cost_map_guard_bedrock_parity

Conversation

@devin-ai-integration

@devin-ai-integration devin-ai-integration Bot commented Sep 26, 2026 •

Copy link
Copy Markdown
Contributor

TLDR

Problem this solves:

How it solves it:

  • The guard's file checks now enforce the tests' base-to-regional supports_* rule
  • A drifting row fails the PR naming the row, the key, and the base value
  • The one gap left on main today (jp.anthropic.claude-opus-4-7) is fixed in both JSON files
  • The cross-region parity test now covers every prefix LiteLLM resolves (global., jp., au. too)

User Flow

Before: a cost-map contributor or the price-sync bot opens a PR adding Bedrock rows, the required check passes, the PR merges, and main goes red

  1. They open a PR into main that adds nvidia.nemotron-nano-3-30b with supports_audio_input: false and its us-gov. copy without that key
  2. The cost-map-guard check on the PR reports cost map guard passed (human PR, file checks only), so the PR is merged
  3. The next CircleCI run of local_testing_part1 on main fails: the us-gov. row lacks a supports_* key its base row carries
  4. Every PR opened afterwards inherits that red run until someone lands a repair commit such as fix: repair seven regressions caught by CircleCI on main #42640

After: the same PR fails the required check before merge, naming the row and key to fix

  1. They open the same PR
  2. The cost-map-guard check fails with us-gov.nvidia.nemotron-nano-3-30b lacks supports_audio_input (false) carried by its base row nvidia.nemotron-nano-3-30b; a Bedrock regional or cross-region row mirrors every supports_* key of its base row
  3. They add the key to the us-gov. row and push, the check passes, and the PR merges
  4. The next CircleCI run of local_testing_part1 on main stays green

Relevant issues

Related: #42254 (merge 00b298a turned main red on 2026-09-21, repaired by #42640) and #42852 (merge 660e674 did the same on 2026-09-24, repaired by #42951)

Pre-Submission checklist

Please complete all items before asking a LiteLLM maintainer to review your PR

  • I have added meaningful tests
  • The handful of test files covering my change pass locally, e.g. uv run pytest tests/unit/<your_test_file>.py -v. Leave the suites (make test-unit-*, make test-unit) to CI: it finishes in ~15 minutes where a laptop takes an hour or more
  • My PR passes all required CI/CD checks (e.g., lint, schema.d.ts sync check, etc.)
  • My PR's scope is as isolated as possible; it only solves 1 specific problem
  • I have received a Greptile Confidence Score of at least 4/5 before requesting a maintainer review (Greptile reviews automatically once the PR is opened; only comment @greptileai to re-request a review after pushing changes)

Delays in PR merge?

If you're seeing a delay in your PR being merged, ping the LiteLLM Team on Slack (#pr-review).

Screenshots / Proof of Fix

Each run is the exact command the cost-map-guard workflow runs on a PR, from the repo root with the two offending merge commits fetched. --head-ref is the PR's branch name (a litellm_cost_map_sync_* head gets the bot contract, anything else the human one). Before runs the guard as it is at the merge base, After runs it as it is at this PR's tip

Before (69d2a3c)

The merge of #42254, which turned main red on 2026-09-21

  1. python ci_cd/cost_map_guard.py --base 00b298a36dd^1 --head 00b298a36dd --head-ref litellm-providers/price-sync-aws-bedrock
  2. Output cost map guard passed (human PR, file checks only), exit 0, although 26 regional rows in that merge lack supports_audio_input, supports_response_schema, supports_vision, or supports_function_calling that their base rows carry

The merge of #42852, which turned main red on 2026-09-24

  1. python ci_cd/cost_map_guard.py --base 660e6746e4a^1 --head 660e6746e4a --head-ref devin/mythos-rows
  2. Output cost map guard passed (human PR, file checks only), exit 0, although three claude-mythos-preview cross-region rows say supports_prompt_caching: true while their base row says false

This PR's own cost map change

  1. python ci_cd/cost_map_guard.py --base 69d2a3c24f9 --head db52939f755 --head-ref litellm_cost_map_guard_bedrock_parity
  2. Output cost map guard passed (human PR, file checks only), exit 0

After (db52939)

The merge of #42254, which turned main red on 2026-09-21

  1. python ci_cd/cost_map_guard.py --base 00b298a36dd^1 --head 00b298a36dd --head-ref litellm-providers/price-sync-aws-bedrock
  2. Output, exit 1, 74 lines naming every missing key (26 rows from that merge plus the pre-existing jp. gap):
cost map guard failed (human PR, file checks only):
- jp.anthropic.claude-opus-4-7 lacks supports_output_config (true) carried by its base row anthropic.claude-opus-4-7; a Bedrock regional or cross-region row mirrors every supports_* key of its base row
- bedrock/ap-northeast-1/deepseek.v3.2 lacks supports_audio_input (false) carried by its base row deepseek.v3.2; a Bedrock regional or cross-region row mirrors every supports_* key of its base row
- bedrock/ap-northeast-1/deepseek.v3.2 lacks supports_response_schema (true) carried by its base row deepseek.v3.2; a Bedrock regional or cross-region row mirrors every supports_* key of its base row
- bedrock/ap-northeast-1/deepseek.v3.2 lacks supports_vision (false) carried by its base row deepseek.v3.2; a Bedrock regional or cross-region row mirrors every supports_* key of its base row
...
- us-gov.nvidia.nemotron-nano-3-30b lacks supports_audio_input (false) carried by its base row nvidia.nemotron-nano-3-30b; a Bedrock regional or cross-region row mirrors every supports_* key of its base row
...
- bedrock/us-gov-east-1/nvidia.nemotron-super-3-120b lacks supports_vision (false) carried by its base row nvidia.nemotron-super-3-120b; a Bedrock regional or cross-region row mirrors every supports_* key of its base row

The merge of #42852, which turned main red on 2026-09-24

  1. python ci_cd/cost_map_guard.py --base 660e6746e4a^1 --head 660e6746e4a --head-ref devin/mythos-rows
  2. Output, exit 1:
cost map guard failed (human PR, file checks only):
- jp.anthropic.claude-opus-4-7 lacks supports_output_config (true) carried by its base row anthropic.claude-opus-4-7; a Bedrock regional or cross-region row mirrors every supports_* key of its base row
- us.anthropic.claude-mythos-preview.supports_prompt_caching is true but anthropic.claude-mythos-preview.supports_prompt_caching is false; a Bedrock regional or cross-region row mirrors every supports_* key of its base row
- apac.anthropic.claude-mythos-preview.supports_prompt_caching is true but anthropic.claude-mythos-preview.supports_prompt_caching is false; a Bedrock regional or cross-region row mirrors every supports_* key of its base row
- au.anthropic.claude-mythos-preview.supports_prompt_caching is true but anthropic.claude-mythos-preview.supports_prompt_caching is false; a Bedrock regional or cross-region row mirrors every supports_* key of its base row

This PR's own cost map change

  1. python ci_cd/cost_map_guard.py --base 69d2a3c24f9 --head db52939f755 --head-ref litellm_cost_map_guard_bedrock_parity
  2. Output cost map guard passed (human PR, file checks only), exit 0: with the jp. row fixed, no Bedrock row on this tip drifts from its base

Type

🐛 Bug Fix
🚄 Infrastructure

Caveats (if any)

Medium

Low

  • The guard now imports litellm for the Bedrock base-model derivation, about 6 s more per run
    • The workflow pins LITELLM_LOCAL_MODEL_COST_MAP so that import reads the checkout's cost map instead of fetching main's over the network, the way the unit-test workflows already do
  • The workflow runs the base branch's guard (pull_request_target), so this PR's own cost-map-guard check still ran the old guard; the parity check first runs on PRs opened or updated after this merges
  • The rule is one-directional, as in the tests: a regional row may carry extra supports_* keys its base lacks
  • invoke/ rows are skipped, as in the tests
  • The guard checks every row whose provider starts with bedrock, a superset of the two CircleCI tests (those split by exact provider and, before this PR, a fixed prefix list); the jp. row is the only extra gap that superset found on main
  • The workflow first executes the new guard on PRs opened or updated after this merges, so the exact step command was run under uv sync --frozen at db52939 instead: it passes on this PR's own change, fails on the merge of chore(prices): sync AWS Bedrock prices: 13 models, 1 new [1 with gaps, enrichment failed: AWS Bedrock, 38 held] #42254 naming the rows, and skips a PR that leaves the cost map untouched
  • The base branch's guard cannot know a region prefix a PR introduces in the same PR, so rows under a brand-new prefix pass as orphans and the CircleCI parity test on main catches any drift once
  • The sibling priced-profile test in tests/local_testing/test_get_model_info.py still uses a fixed prefix tuple without jp.; pricing parity is outside this guard
  • CircleCI has not run at this tip, since the run-ci label goes on next Monday; the two local_testing_part1 parity tests (test_get_model_info_bedrock_cross_region_capability_parity and test_get_model_info_bedrock_priced_cross_region_profile_has_priced_base) pass locally at db52939 with the tip's cost map

Final Attestation

  • The tests check the right things, including the edge cases, and regressions in the respective real-world customer use-cases are not possible after this PR

  • db52939 passes /live-pr-risk

@devin-ai-integration

devin-ai-integration Bot commented Sep 26, 2026 •

Copy link
Copy Markdown
Contributor Author

I'll fix CI failures and address comments from users with write access. I'll skip comments containing "(aside)".

  • Disable automatic comment, CI, and merge conflict monitoring

@greptile-apps

greptile-apps Bot commented Sep 26, 2026 •

Copy link
Copy Markdown
Contributor

RetriggerConfidence Score: 5/5

[High risk] Adds validation rules to the cost map guard for Bedrock model pricing.

The PR appears safe to merge based on the reviewed changes and previous findings

Findings

  1. P1 Regional capability still missing ▶
  2. P2 Bedrock logic outside llms ▶

Summary

The PR adds Bedrock capability-parity checks to the cost-map guard, expands cross-region test coverage, and aligns the jp. cost-map row with its base row. The change since the previous review only reformats a function signature

Reviews (3) · Last reviewed commit: "style(ci): wrap the cost map guard signa..."

"supports_native_structured_output": false,
"supports_max_reasoning_effort": true,
"supports_minimal_reasoning_effort": true,
"supports_output_config": true,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P1 Regional capability still missing Adding supports_output_config does not bring jp.anthropic.claude-opus-4-7 into parity with its base row: the base has supports_adaptive_thinking: true, but the regional row lacks it. The expanded cross-region test will fail, and the new guard will reject the cost map when it runs.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Checked at e1f2d35: jp.anthropic.claude-opus-4-7 carries supports_adaptive_thinking: true like its base row, the guard exits 0, and both CircleCI parity tests pass

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Lines 1245 and 2480 at db52939 both set supports_adaptive_thinking true, so the base row has no supports_ key the jp row lacks

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

You’re right — I misread the surrounding rows. At db52939f755, both the base and jp. rows already have supports_adaptive_thinking: true. With this change adding supports_output_config: true to the regional row, it matches the base row’s supports_* capabilities. The previous finding is invalid; no further change is needed.

Comment thread ci_cd/cost_map_guard.py
Comment on lines +98 to +104
def _bedrock_base_key(key: str, entries: Entries) -> str | None:
candidate: Final = BEDROCK_COMMITMENT_PREFIX.sub("", key.replace("*/", ""))
base: Final = get_bedrock_base_model(candidate)
if base == candidate:
return None
base_key: Final = base if base in entries else f"bedrock/{base}"
return base_key if base_key in entries and base_key != key else None

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2 Bedrock logic outside llms The new guard selects Bedrock rows, normalizes their model names, and compares their capabilities in ci_cd/cost_map_guard.py. The repository requires provider-specific code to stay inside llms/. This also creates a second place to maintain Bedrock model-name handling; the requirement must be satisfied before merging.

Rule Used: What: Avoid writing provider-specific code outside of the llms/ directory. Why: This practice ensures better maintainability and reduces complexity over time. Good: ```python # Handle provider-specific logic within llms/vertex_ai/transformation.py ... (source)

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The model-name derivation delegates to get_bedrock_base_model in litellm/llms/bedrock/common_utils.py. ci_cd only compares cost-map rows, a CI invariant on the JSON, not provider code

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

That’s a fair distinction. Since the guard delegates model-name derivation to the canonical get_bedrock_base_model() implementation and only applies the result to a CI invariant over the cost-map JSON, it is not duplicating provider-specific behavior in ci_cd. I’m withdrawing this finding.

@codspeed

codspeed Bot commented Sep 26, 2026 •

Copy link
Copy Markdown
Contributor

Merging this PR will not alter performance

✅ 31 untouched benchmarks


Comparing litellm_cost_map_guard_bedrock_parity (db52939) with main (849f303)

Open in CodSpeed

@codecov

codecov Bot commented Sep 26, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@mateo-berri mateo-berri added run-ci and removed run-ci labels Sep 26, 2026
@mateo-berri

Copy link
Copy Markdown
Contributor

@greptileai

Comment thread ci_cd/cost_map_guard.py Outdated
@mateo-berri

Copy link
Copy Markdown
Contributor

@greptileai

@mateo-berri

Copy link
Copy Markdown
Contributor

bugbot run

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit db52939. Configure here.

@mateo-berri mateo-berri left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

LGTM

This branch has not been deployed

No deployments
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.

1 participant