Repository navigation
fix(cost): bill cache-read tokens at the input rate when the map has no cache-read rate - #41832
Conversation
…no cache-read rate Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
🤖 Devin AI EngineerI'll be helping with this pull request! Here's what you should know: ✅ I will automatically:
Note: I can only respond to comments from users who have write access to this repository. ⚙️ Control Options:
|
|
|
Bugbot is paused — on-demand spend limit reachedBugbot uses usage-based billing for this team and has hit its on-demand spend limit. A team admin can raise the spend limit in the Cursor dashboard, or wait for the next billing cycle to continue. |
|
…e at the input rate Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Bugbot is paused — on-demand spend limit reachedBugbot uses usage-based billing for this team and has hit its on-demand spend limit. A team admin can raise the spend limit in the Cursor dashboard, or wait for the next billing cycle to continue. |
|
Pushed af61d92 updating the cost estimate test that pinned $0 cache reads. Rebutted the ungated billing finding as intentional |
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
* chore: upgrade LiteLLM to v1.104.0 (#177, PR 1) LiteLLM v1.104.0 refuses a call over a key, team or user budget with HTTP 422 and error type budget_exceeded instead of 429 (BerriAI/litellm#42097), and bills cached input tokens of a model without a cache price at the input price instead of 0 (BerriAI/litellm#41832). - docker-compose: ghcr.io/berriai/litellm:v1.104.0 (tag, ADR-M17) - litellm-live test: a budget block is 422 + budget_exceeded, never 429 alone; cost per stub call 0.0012 - ADR-M24 0.3: §2.2 facts checked on v1.104.0; ADR-M17 version row - CHANGELOG, CLAUDE.md No platform code read the 429: the runner's budget stop reads the key's spend (C07). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * ci: run CI again (#177) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
TLDR
Problem this solves:
How it solves it:
cache_read_input_token_cost: 0.0still means freemissing_cache_read_uses_inputflag, so both paths agreeUser Flow
Before: a team routing Bedrock traffic to a model whose map entry lists only input and output prices sees cached prompt tokens billed as free
input_cost_per_tokenandoutput_cost_per_tokenbut nocache_read_input_token_costx-litellm-response-cost: 0.0005222, which is the fresh input plus output only, and no cache-read headerAfter: the same request bills the cached tokens as ordinary input
x-litellm-response-cost: 0.00347132withx-litellm-response-cost-cache-read: 0.00294912Relevant issues
Surfaced by the deterministic cost suite in #41328, whose two
meta.llama4-maverick-17b-instruct-v1:0cache-read cells go green with this fixAffected release
Linear ticket
Resolves LIT-8111
Pre-Submission checklist
Please complete all items before asking a LiteLLM maintainer to review your PR
uv run pytest tests/test_litellm/<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@greptileaito re-request a review after pushing changes)Screenshots / Proof of Fix
Two live proxies on the same Postgres and the same config (
tests/e2e/gateway/cost_calculation_ci_config.yml,LITELLM_MODEL_COST_MAP_URLpointing at the test-ownedtests/e2e/cost_map.json,MODEL_COST_MAP_MIN_MODEL_COUNT=1,MODEL_COST_MAP_MAX_SHRINK_RATIO=0). The map entry formeta.llama4-maverick-17b-instruct-v1:0hasinput_cost_per_token2.4e-7 andoutput_cost_per_token9.7e-7 and no cache keys. The upstream is the scripted Bedrock Converse sidecar from #41328 replaying a response with 640 fresh input, 12288 cache-read and 380 output tokens, because Bedrock does not offer prompt caching on that model, which is exactly why the real map has no cache-read rate for itShared setup on each proxy:
Before (0bd8b7f)
curl -i http://localhost:4000/v1/chat/completions -H "Authorization: Bearer $LITELLM_MASTER_KEY" -H 'Content-Type: application/json' -d '{"model":"lit8111-llama","messages":[{"role":"user","content":"say hi"}]}'spend=0.00052220 prompt_tokens=12928 completion_tokens=380, so 12288 of the 12928 prompt tokens were billed at $0After (af61d92)
http://localhost:4002/v1/chat/completionsspend=0.00347132 prompt_tokens=12928 completion_tokens=380. The difference from Before is exactly12288 * 2.4e-7 = 0.00294912Type
🐛 Bug Fix
Caveats (if any)
Medium
cache_read_input_token_cost: 0.0Low
test_missing_cache_read_policy_preserves_billingpinned the $0 behavior and was rewritten to the new invariant/cost/estimateendpoint now reports the input rate as the effective cache-read rate for such entries; its test that pinned 0.0 was updatedFinal Attestation
Link to Devin session: https://app.devin.ai/sessions/977f8f8050c749b2b52ca0d077a3196e
Open in Devin Desktop: https://app.devin.ai/desktop/session/977f8f8050c749b2b52ca0d077a3196e?variant=devin