fix(cost): honor an explicit zero tier rate instead of the fallback - #36697
fix(cost): honor an explicit zero tier rate instead of the fallback#36697hsusul wants to merge 1 commit into
Conversation
A tier that prices cached reads or reasoning tokens at 0.0 was billed at the fallback rate because calculate_tiered_cost and tier_rate resolved the per-token cost with `tier.get(cost_key) or tier.get(fallback_cost_key, 0)`, whose `or` short-circuits on a falsy 0.0. Distinguish a missing key from a present zero so a free-cache-read or free-reasoning tier is billed at 0. This restores the behavior of BerriAI#30749, which fixed the same short-circuit in the dashscope calculator before the logic moved into this shared helper.
Greptile SummaryThis PR changes tiered-pricing resolution so an explicit zero primary rate remains free while an absent primary rate still uses its fallback.
Confidence Score: 4/5The pricing fix appears safe to merge, with only non-blocking repository-convention issues in the helper typing and test placement. The new resolver consistently distinguishes explicit zero rates from missing values and the added tests cover in-range, overflow, direct-rate, and fallback behavior; the remaining findings concern maintainability conventions rather than incorrect runtime pricing. Files Needing Attention: litellm/litellm_core_utils/llm_cost_calc/tiered_pricing.py; tests/test_litellm/litellm_core_utils/llm_cost_calc/test_tiered_pricing.py
|
| Filename | Overview |
|---|---|
| litellm/litellm_core_utils/llm_cost_calc/tiered_pricing.py | Correctly centralizes explicit-zero rate resolution, but the new helper uses a bare dict parameter contrary to repository typing guidance. |
| tests/test_litellm/litellm_core_utils/llm_cost_calc/test_tiered_pricing.py | Adds focused local regression coverage, but creates a new test module rather than extending the repository’s existing mapped test file. |
Reviews (1): Last reviewed commit: "fix(cost): honor an explicit zero tier r..." | Re-trigger Greptile
| @@ -0,0 +1,72 @@ | |||
| import os | |||
There was a problem hiding this comment.
Fragmented tier-pricing test coverage
This bug fix creates a new test module instead of extending the existing mapped test file, fragmenting tiered-pricing coverage and making the established test mapping harder to maintain and discover.
Context Used: CLAUDE.md (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!
|
|
||
|
|
||
| def _resolve_tier_cost_per_token( | ||
| tier: dict, |
There was a problem hiding this comment.
The new helper declares tier as a bare dict, so static analysis cannot verify the tier key/value contract at this new abstraction boundary; repository guidance requires new function parameters to use strong types.
Context Used: CLAUDE.md (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!
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
TLDR
Problem this solves:
0.0is billed at the fallback rate instead of being freecalculate_tiered_costandtier_rateresolved a tier's per-token cost withtier.get(cost_key) or tier.get(fallback_cost_key, 0), and theorshort-circuits on a falsy0.0, so a real zero price looks like a missing key and falls through to the fallbackHow it solves it:
_resolve_tier_cost_per_token, which returns the primary rate whenever the key is present (including0.0) and only reads the fallback when the key is absent (None)tier_rate) through that helperUser Flow
A user configures a Dashscope (or any tiered) model whose tier sets
cache_read_input_token_cost: 0whileinput_cost_per_tokenis nonzero, then sends a request whose prompt has cached tokens. Before this change every cached token is billed atinput_cost_per_token; after it, the cached tokens are correctly billed at0Relevant issues
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)Screenshots / Proof of Fix
calculate_tiered_costis a pure function, so the before/after is visible without a network call. A tier with free cache reads and a nonzero input rate:Before:
0.01(10000 cached tokens billed at the full input rate). After:0.0End-to-end QA a maintainer can run against a live proxy: register a Dashscope model whose tier carries
cache_read_input_token_cost: 0, thenrun it twice so the second request reports cached prompt tokens, then confirm the logged prompt cost at http://localhost:4000/ui/?page=logs charges those cached tokens at 0 rather than the input rate
Type
🐛 Bug Fix
Changes
_resolve_tier_cost_per_tokeninlitellm/litellm_core_utils/llm_cost_calc/tiered_pricing.py, used bycalculate_tiered_cost(both the in-range and overflow sites) andtier_rate. This restores the behavior of #30749, which removed the sameorshort-circuit from the Dashscope calculator before the logic was extracted into this shared helperCaveats (if any)
QA runbook
Covered by the new regression tests in
tests/test_litellm/litellm_core_utils/llm_cost_calc/test_tiered_pricing.py: an explicit0.0primary rate stays0.0at both the in-range and overflow sites and intier_rate, while a missing key still falls back. The three zero-honoring tests fail on the current code and pass after the fixFinal Attestation