fix(pricing): sync flex/priority tier keys to dated OpenAI snapshot variants - #35923
Conversation
…ariants Dated snapshots like o4-mini-2025-04-16 were missing the flex and priority cost keys their base alias carries, so service-tier requests against pinned snapshots were billed at standard rates. Sync the tier keys wherever the snapshot's anchor prices match the base alias, and add a drift regression test.
Greptile SummaryThe PR synchronizes flex and priority pricing metadata from OpenAI base aliases to price-matched dated snapshots and adds a regression test for future drift.
Confidence Score: 5/5The PR appears safe to merge. No blocking failure remains.
|
| Filename | Overview |
|---|---|
| model_prices_and_context_window.json | Adds service-tier pricing fields to the canonical entries for nine dated OpenAI snapshots. |
| litellm/model_prices_and_context_window_backup.json | Mirrors the canonical service-tier pricing additions in the backup pricing map. |
| tests/test_litellm/test_model_prices_schema.py | Adds a regression test that checks price-matched dated variants for base-alias flex and priority fields. |
Reviews (2): Last reviewed commit: "fix(pricing): sync flex/priority tier ke..." | Re-trigger Greptile
| "cache_read_input_token_cost": 5e-07, | ||
| "cache_read_input_token_cost_priority": 8.75e-07, | ||
| "input_cost_per_token": 2e-06, | ||
| "input_cost_per_token_priority": 3.5e-06, |
There was a problem hiding this comment.
Medium: Priority pricing bypasses budget reservation
These _priority rates are used during final cost calculation, while budget_reservation.py estimates requests exclusively from input_cost_per_token and output_cost_per_token. A user can send priority requests against these models that pass admission using the lower standard estimate but consume up to roughly twice the reserved key or team budget. Update the reservation estimator to select the service-tier-specific input, output, cache, and reasoning rates from request_body["service_tier"], with the same fallback behavior as final cost calculation.
There was a problem hiding this comment.
Reservation already ignored service_tier for the base aliases' existing priority keys; this sync doesn't widen that pre-existing gap: tier-aware reservation deserves its own PR
PR overviewThis pull request updates OpenAI pricing metadata so flex and priority service-tier keys align with dated model snapshot variants. One security issue remains open: priority-tier requests are admitted using lower standard-rate budget estimates but charged at higher priority rates, allowing users to exceed reserved key or team budgets by roughly twofold. The reservation logic still needs to account for service-tier-specific pricing, and no issues have yet been addressed. Open issues (1)
Fixed/addressed: 0 · PR risk: 5/10 |
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
Seven live e2e tests covering cost-tracking regressions that currently ship unnoticed: cache-write tokens billed at the cache-creation rate (BerriAI#34046), per-component cost_breakdown on the spend row (BerriAI#31686), cache reads billed at the cache-read discount on streamed calls (BerriAI#34812), cache tokens surviving the anthropic-messages to Responses bridge (BerriAI#34957), priority-tier rates applied to input, output and reasoning (BerriAI#35923, BerriAI#35925), the per-component response cost headers summing to the total (BerriAI#36965), and cost injected into the final usage frame of an /openai passthrough stream (BerriAI#36503). Every test registers its own deployment with a distinct custom rate per component, so a component billed at the wrong rate cannot pass. The shared helpers in cost_rows.py encode the one thing the two surfaces disagree on: the spend row's input_cost is gross of cache while the response's cost-input header is net of it.
TLDR
Problem this solves:
How it solves it:
User Flow
Before: pinning a dated snapshot silently bills service-tier traffic at standard rates, undercharging priority and overcharging flex
gpt-4.1-2025-04-14for reproducible evals and sendsPOST https://litellm-domain/v1/chat/completionswith"service_tier": "priority"under their virtual key"service_tier": "priority"x-litellm-response-costheader reads the standard rate, roughly half of what OpenAI invoices for priority processingo4-mini-2025-04-16with"service_tier": "flex"is billed double what OpenAI charges, since the 50% flex discount never applieshttps://litellm-domain/ui/?page=usagedrift further from the provider invoice with every tiered callAfter: the same pinned snapshots bill the tier's real price
gpt-4.1-2025-04-14for reproducible evals and sendsPOST https://litellm-domain/v1/chat/completionswith"service_tier": "priority"under their virtual key"service_tier": "priority"x-litellm-response-costheader reads the snapshot's priority rate, matching what the base aliasgpt-4.1charges and what OpenAI invoicesRelevant issues
Supersedes #22086
Linear ticket
Pre-Submission checklist
Please complete all items before asking a LiteLLM maintainer to review your PR
@greptileaito 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
Both legs hit the real OpenAI API through a local proxy booted with
LITELLM_LOCAL_MODEL_COST_MAP=Trueand this config:Priority tier on a pinned gpt-4.1 snapshot (same request against each proxy):
Before (bcce83a, base branch): OpenAI confirms
"service_tier": "priority"with usage 12 prompt + 1 completion tokens, yet the proxy bills standard ratesAfter (629c228, this PR): identical request, identical usage (12 + 1), now billed at the snapshot's synced priority keys
Flex tier on a pinned o4-mini snapshot, same curl with
"model":"o4-mini-2025-04-16","service_tier":"flex". Both legs returned"service_tier": "flex"with usage 11 prompt + 83 completion (64 reasoning) tokensType
🐛 Bug Fix
Changes
OpenAI publishes flex and priority prices per model family, and LiteLLM carries them on the base aliases (gpt-4.1, gpt-4o, o3, o4-mini, gpt-5-nano, and friends), but most dated snapshot entries never received the keys. Anyone pinning a snapshot, which is the recommended practice for reproducible evals and batch jobs, got service-tier traffic billed at standard rates: undercharged for priority, overcharged for flex
This PR syncs the missing
*_flexand*_prioritykeys from each base alias to its dated variants inmodel_prices_and_context_window.jsonand the backup copy: gpt-4.1-2025-04-14, gpt-4.1-mini-2025-04-14, gpt-4.1-nano-2025-04-14, gpt-4o-2024-08-06, gpt-4o-2024-11-20, gpt-4o-mini-2024-07-18, gpt-5-nano-2025-08-07, o3-2025-04-16, and o4-mini-2025-04-16. A key is copied only when the variant's corresponding standard-rate key exists and exactly matches the base alias, so snapshots with genuinely different pricing are left alone (gpt-4o-2024-05-13 is intentionally skipped for this reason)tests/test_litellm/test_model_prices_schema.pygainstest_dated_variants_carry_base_alias_service_tier_pricing, which walks every<name>-YYYY-MM-DDentry and fails whenever a base alias gains a tier key its price-matched snapshot lacks, so the drift cannot reappear as new tier prices landFinal Attestation