Skip to content

fix(cost): bill gpt-5.6 prompt cache reads at the cache read rate - #34957

Merged
mateo-berri merged 6 commits into
litellm_internal_stagingfrom
litellm_gpt56_cache_token_pricing
Aug 5, 2026
Merged

fix(cost): bill gpt-5.6 prompt cache reads at the cache read rate#34957
mateo-berri merged 6 commits into
litellm_internal_stagingfrom
litellm_gpt56_cache_token_pricing

Conversation

@devin-ai-integration

@devin-ai-integration devin-ai-integration Bot commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

TLDR

Problem this solves:

  • gpt-5.6 cache reads billed at full input rate
  • /v1/messages usage dropped cache read/write tokens

How it solves it:

  • Map Responses API cache tokens into Anthropic usage
  • Price Anthropic-shaped usage with the Anthropic usage mapper
  • Pin gpt-5.6 flex/priority cache write rates in tests

Relevant issues

Fixes #34801

Linear ticket

Pre-Submission checklist

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

  • I have added meaningful tests
  • My PR passes all CI/CD checks (e.g., lint, format, unit tests)
  • 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

Live proxy against real OpenAI openai/gpt-5.6-sol with a ~4.5k token system prompt sent twice so the second call hits OpenAI's prompt cache; the deployment advertises /v1/responses, so /v1/messages goes through the Anthropic-to-Responses bridge

PREFIX=$(python3 -c "print('Pack my box with five dozen liquor jugs. ' * 450)")
for run in warm cached; do
  curl -sS -D /tmp/h.txt http://localhost:4000/v1/messages -H "Authorization: Bearer sk-1234" -H "Content-Type: application/json" \
    -d "$(jq -n --arg p "$PREFIX" '{model:"openai-gpt-5.6-sol",max_tokens:16,system:$p,messages:[{role:"user",content:"Reply with the number 1"}]}')" | jq -c '.usage'
  grep -i "^x-litellm-response-cost:" /tmp/h.txt
done

Before, on the base branch at bcce83a17e; the cache fields are dropped from usage and all 4517 prompt tokens are billed at the uncached input rate ($5.00/M) even though 4514 of them were cache reads ($0.50/M), a 9.4x overstatement on this request

{"input_tokens":4517,"output_tokens":5}
x-litellm-response-cost: 0.022735000000000002

After, at 69a8043667; the warm call surfaces the cache write and prices it at the cache write rate (3 * $5.00/M + 4514 * $6.25/M + 5 * $30.00/M) and the cached call prices the reads at the cache read rate (3 * $5.00/M + 4514 * $0.50/M + 5 * $30.00/M), matching what OpenAI bills

{"input_tokens":3,"output_tokens":5,"cache_creation_input_tokens":4514}
x-litellm-response-cost: 0.028377500000000003
{"input_tokens":3,"output_tokens":5,"cache_read_input_tokens":4514}
x-litellm-response-cost: 0.0024219999999999997

Streaming /v1/messages on the same deployment reports the same split in message_delta, also at 69a8043667

curl -sS http://localhost:4000/v1/messages -H "Authorization: Bearer sk-1234" -H "Content-Type: application/json" \
  -d "$(jq -n --arg p "$PREFIX" '{model:"openai-gpt-5.6-sol",max_tokens:16,stream:true,system:$p,messages:[{role:"user",content:"Reply with the number 1"}]}')" | grep -o '{"type": "message_delta".*'
{"type": "message_delta", "delta": {"stop_reason": "end_turn", "stop_sequence": null}, "usage": {"input_tokens": 3, "output_tokens": 5, "cache_read_input_tokens": 4514}}

Type

🐛 Bug Fix

Changes

Two things went wrong on the way from OpenAI usage to spend

The Anthropic Messages to Responses API adapter only copied the aggregate input_tokens and output_tokens, so input_tokens_details.cached_tokens and cache_write_tokens never reached the Anthropic usage object. Both the non-streaming and streaming paths now share one conversion that reuses the existing ResponseAPILoggingUtils and Anthropic usage helpers, so input_tokens excludes cache tokens and the cache counts are reported as cache_read_input_tokens / cache_creation_input_tokens

Cost calculation then misread that Anthropic-shaped usage. _get_usage_object and completion_cost detect Responses API usage by the presence of input_tokens plus output_tokens, which Anthropic usage also has, and that converter only understands nested input_tokens_details; the top-level cache_read_input_tokens and cache_creation_input_tokens were dropped and the whole prompt was billed as fresh input. AnthropicConfig.is_anthropic_usage_object now identifies that shape by its cache keys (and the absence of chat-shaped prompt_tokens), and those usage objects go through AnthropicConfig.calculate_usage, which already splits cache reads, cache writes and fresh input correctly. This also fixes the response cost header and cost_breakdown for native Anthropic /v1/messages traffic, which previously disagreed with the response_cost computed during success logging. Following review feedback, the detection heuristic now documents why requiring a cache key is deliberate, and tests pin that Responses-shaped usage with nested cached tokens is never classified as Anthropic and that a missing usage object maps to zeroed Anthropic usage

The branch originally also added cache_creation_input_token_cost_flex / cache_creation_input_token_cost_priority to ModelInfo, but the base branch has since shipped those fields on its own, so after the merge this PR only keeps a regression test pinning the gpt-5.6 flex and priority cache write rates

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

Link to Devin session: https://app.devin.ai/sessions/f8089b5a5c7f4c55ad317c56d8a632fa

… api usage

Also map gpt-5.6 flex/priority cache_creation rates into ModelInfo so cache writes are not billed at the standard rate on those service tiers
…f full input rate

Anthropic-shaped usage was mapped through the Responses API usage converter, which ignores top-level cache_read_input_tokens/cache_creation_input_tokens, so cache hits on /v1/messages were billed entirely at the uncached input rate
@devin-ai-integration

Copy link
Copy Markdown
Contributor Author

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR. Add '(aside)' to your comment to have me ignore it.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment, CI, and merge conflict monitoring

Comment thread litellm/cost_calculator.py
@greptile-apps

greptile-apps Bot commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR corrects prompt-cache usage propagation and cost calculation for Responses API traffic exposed through Anthropic Messages

  • Converts Responses API cache-read and cache-write token details into Anthropic usage fields for streaming and non-streaming responses
  • Routes Anthropic-shaped usage through the provider-owned usage mapper before calculating cost
  • Adds regression coverage for usage-shape detection, missing usage, cached-token pricing, and GPT-5.6 service-tier cache-write rates

Confidence Score: 5/5

The PR appears safe to merge

No blocking failure remains

Important Files Changed

Filename Overview
litellm/cost_calculator.py Dispatches Anthropic-shaped cache usage to the provider-owned mapper in both cost normalization paths
litellm/llms/anthropic/chat/transformation.py Adds shape detection that distinguishes Anthropic cache usage from chat and Responses API usage
litellm/llms/anthropic/experimental_pass_through/responses_adapters/transformation.py Centralizes conversion of Responses API usage into Anthropic cache-aware usage
litellm/llms/anthropic/experimental_pass_through/responses_adapters/streaming_iterator.py Reuses the shared usage conversion for final streaming message usage

Reviews (2): Last reviewed commit: "chore: keep base field ordering for serv..." | Re-trigger Greptile

@codecov

codecov Bot commented Jul 28, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@CLAassistant

CLAassistant commented Jul 28, 2026

Copy link
Copy Markdown

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you all sign our Contributor License Agreement before we can accept your contribution.
1 out of 2 committers have signed the CLA.

✅ mateo-berri
❌ devin-ai-integration[bot]
You have signed the CLA already but the status is still pending? Let us recheck it.

@ErenAta16 ErenAta16 left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

The billing bug is worth fixing and routing Anthropic-shaped usage through the Anthropic mapper is the right call. One thing about the detection heuristic that I'd want settled before this lands, because it decides which pricing path a request takes.

is_anthropic_usage_object requires a cache key to be present:

if "prompt_tokens" in usage_object or "input_tokens" not in usage_object:
    return False
return any(key in usage_object for key in ("cache_read_input_tokens", "cache_creation_input_tokens"))

Ran it over the shapes it has to separate:

anthropic w/ cache read      -> True
anthropic w/ cache write     -> True
anthropic, no cache activity -> False
openai chat usage            -> False
responses api usage          -> False

The first four rows are what you want. The third is the one I'd question: an Anthropic response that had no cache activity carries no cache_* keys, so it's classified as not-Anthropic and falls through to the Responses mapping, which is the path this PR exists to avoid. That's probably harmless today if the two mappings agree on plain input_tokens/output_tokens, but it means the function's name promises more than it delivers, and the classification depends on a pricing-relevant field being non-empty rather than on the payload's shape.

Concretely it makes the routing state-dependent: the same model on the same endpoint takes one path on a cache hit and the other on a cache miss. If the two mappings ever diverge on anything besides cache tokens, that shows up as an intermittent cost discrepancy which is unpleasant to chase.

"input_tokens" in u and "prompt_tokens" not in u alone would classify on shape rather than content. If the cache-key requirement is deliberate (say, because Responses usage also uses input_tokens and the cache keys are the only discriminator) then that's fine, but it's worth a line in the docstring saying so, since as written the docstring explains why the cache keys matter rather than why they're required for detection.

Second, smaller: completion_cost now has two sequential checks that both rewrite _usage, with the Anthropic one first. Worth confirming a Responses payload that happens to carry cache_read_input_tokens can't be captured by the first branch, since after this change the elif means it never reaches _is_response_api_usage. My table above suggests it can't with current shapes, but it's the kind of ordering that's easy to invalidate later.

The ModelInfo additions for flex/priority cache_creation look mechanical and consistent with the existing input_cost_per_token_flex pattern, no concerns there.

@codspeed-hq

codspeed-hq Bot commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

Merging this PR will not alter performance

✅ 31 untouched benchmarks


Comparing litellm_gpt56_cache_token_pricing (69a8043) with litellm_internal_staging (732bba0)1

Open in CodSpeed

Footnotes

  1. No successful run was found on litellm_internal_staging (69a8043) during the generation of this report, so 732bba0 was used instead as the comparison base. There might be some changes unrelated to this pull request in this report.

@mateo-berri

Copy link
Copy Markdown
Contributor

@greptileai

@mateo-berri

mateo-berri commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

If the cache-key requirement is deliberate (say, because Responses usage also uses input_tokens and the cache keys are the only discriminator) then that's fine, but it's worth a line in the docstring saying so

Deliberate for exactly that reason. The docstring now says so, and a test pins that Responses-shaped usage never matches the Anthropic branch (e8a80b9)

@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

@mateo-berri
mateo-berri merged commit 64f4bed into litellm_internal_staging Aug 5, 2026
76 checks passed
@mateo-berri
mateo-berri deleted the litellm_gpt56_cache_token_pricing branch August 5, 2026 09:30
doonga pushed a commit to greyrock-labs/home-ops that referenced this pull request Aug 17, 2026
…7.0) (#336)

This PR contains the following updates:

| Package | Update | Change |
|---|---|---|
| [ghcr.io/berriai/litellm](https://images.chainguard.dev/directory/image/wolfi-base/overview) ([source](https://github.com/BerriAI/litellm)) | minor | `v1.96.2` → `v1.97.0` |

---

### Release Notes

<details>
<summary>BerriAI/litellm (ghcr.io/berriai/litellm)</summary>

### [`v1.97.0`](https://github.com/BerriAI/litellm/releases/tag/v1.97.0)

[Compare Source](https://github.com/BerriAI/litellm/compare/v1.97.0...v1.97.0)

##### Verify Docker Image Signature

All LiteLLM Docker images are signed with [cosign](https://docs.sigstore.dev/cosign/overview/). Every release is signed with the same key introduced in [commit `0112e53`](https://github.com/BerriAI/litellm/commit/0112e53046018d726492c814b3644b7d376029d0).

**Verify using the pinned commit hash (recommended):**

A commit hash is cryptographically immutable, so this is the strongest way to ensure you are using the original signing key:

```bash
cosign verify \
  --key https://raw.githubusercontent.com/BerriAI/litellm/0112e53046018d726492c814b3644b7d376029d0/cosign.pub \
  ghcr.io/berriai/litellm:v1.97.0
```

**Verify using the release tag (convenience):**

Tags are protected in this repository and resolve to the same key. This option is easier to read but relies on tag protection rules:

```bash
cosign verify \
  --key https://raw.githubusercontent.com/BerriAI/litellm/v1.97.0/cosign.pub \
  ghcr.io/berriai/litellm:v1.97.0
```

Expected output:

```
The following checks were performed on each of these signatures:
  - The cosign claims were validated
  - The signatures were verified against the specified public key
```

***

##### What's Changed

- feat(proxy): resolve Cursor thinking/fast model-name suffixes on /cursor/chat/completions by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;35554](https://github.com/BerriAI/litellm/pull/35554)
- fix(team-callbacks): actually stop logging when disable\_logging is called by [@&#8203;yucheng-berri](https://github.com/yucheng-berri) in [#&#8203;35520](https://github.com/BerriAI/litellm/pull/35520)
- refactor(lint): drop redundant !s f-string conversion flags and fix displaced import-group comments by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;35546](https://github.com/BerriAI/litellm/pull/35546)
- fix(proxy): backfill null user\_email on existing users during JWT auth by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;34588](https://github.com/BerriAI/litellm/pull/34588)
- feat(playground): add non-streaming response toggle by [@&#8203;ryan-crabbe-berri](https://github.com/ryan-crabbe-berri) in [#&#8203;35560](https://github.com/BerriAI/litellm/pull/35560)
- feat(teams): apply default organization to new teams from default team settings by [@&#8203;ryan-crabbe-berri](https://github.com/ryan-crabbe-berri) in [#&#8203;35540](https://github.com/BerriAI/litellm/pull/35540)
- fix(ui): block Playground page for viewer roles on direct URL access by [@&#8203;ryan-crabbe-berri](https://github.com/ryan-crabbe-berri) in [#&#8203;35676](https://github.com/BerriAI/litellm/pull/35676)
- fix(caching): close evicted LLM clients so their connections are reclaimed by [@&#8203;yassin-berriai](https://github.com/yassin-berriai) in [#&#8203;35492](https://github.com/BerriAI/litellm/pull/35492)
- chore(deps): update brace-expansion, postcss, and gitpython to current patch releases by [@&#8203;yuneng-berri](https://github.com/yuneng-berri) in [#&#8203;35692](https://github.com/BerriAI/litellm/pull/35692)
- refactor(ui): rename the create MCP server component to PascalCase by [@&#8203;yuneng-berri](https://github.com/yuneng-berri) in [#&#8203;35686](https://github.com/BerriAI/litellm/pull/35686)
- fix(openai): drop undefined Union from owns\_wrapped\_http\_client annotation by [@&#8203;ryan-crabbe-berri](https://github.com/ryan-crabbe-berri) in [#&#8203;35706](https://github.com/BerriAI/litellm/pull/35706)
- fix(openai): drop the undefined Union from owns\_wrapped\_http\_client by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;35704](https://github.com/BerriAI/litellm/pull/35704)
- chore(ui): note Google's Agent Platform rename in vector store setup by [@&#8203;ryan-crabbe-berri](https://github.com/ryan-crabbe-berri) in [#&#8203;28076](https://github.com/BerriAI/litellm/pull/28076)
- fix(proxy): apply key/team router\_settings.model\_group\_alias by [@&#8203;yassin-berriai](https://github.com/yassin-berriai) in [#&#8203;35486](https://github.com/BerriAI/litellm/pull/35486)
- feat(complexity\_router): default session affinity off and expose it in the UI by [@&#8203;tin-berri](https://github.com/tin-berri) in [#&#8203;35714](https://github.com/BerriAI/litellm/pull/35714)
- fix(datadog): read team callback dd\_\* params from kwargs instead of blocked dynamic params ([#&#8203;35115](https://github.com/BerriAI/litellm/issues/35115) port) by [@&#8203;ryan-crabbe-berri](https://github.com/ryan-crabbe-berri) in [#&#8203;35687](https://github.com/BerriAI/litellm/pull/35687)
- refactor(ui): extract the MCP create form's logic and field groups by [@&#8203;yuneng-berri](https://github.com/yuneng-berri) in [#&#8203;35694](https://github.com/BerriAI/litellm/pull/35694)
- test(ui): tier the MCP create tests into unit and integration by [@&#8203;yuneng-berri](https://github.com/yuneng-berri) in [#&#8203;35697](https://github.com/BerriAI/litellm/pull/35697)
- fix(proxy): redact credential headers from request logging copies by [@&#8203;yucheng-berri](https://github.com/yucheng-berri) in [#&#8203;35678](https://github.com/BerriAI/litellm/pull/35678)
- feat(guardrails/rubrik): prompt moderation, response-text blocking, streaming buffer, failure logging by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;35722](https://github.com/BerriAI/litellm/pull/35722)
- fix(ui): render Responses API request and response in the logs drawer by [@&#8203;yuneng-berri](https://github.com/yuneng-berri) in [#&#8203;35718](https://github.com/BerriAI/litellm/pull/35718)
- fix(ui): hide guardrail review buttons from non-admin users by [@&#8203;ryan-crabbe-berri](https://github.com/ryan-crabbe-berri) in [#&#8203;27535](https://github.com/BerriAI/litellm/pull/27535)
- feat(team): custom metadata validation hook for team create and update by [@&#8203;yuneng-berri](https://github.com/yuneng-berri) in [#&#8203;33353](https://github.com/BerriAI/litellm/pull/33353)
- ci(circleci): install a pinned Rust toolchain on the Linux jobs by [@&#8203;yuneng-berri](https://github.com/yuneng-berri) in [#&#8203;35519](https://github.com/BerriAI/litellm/pull/35519)
- fix(bedrock): stop forwarding no-op toolSpec.strict to Converse by [@&#8203;tin-berri](https://github.com/tin-berri) in [#&#8203;35688](https://github.com/BerriAI/litellm/pull/35688)
- fix(ui): reject an auto-router keyword rule left empty instead of dropping it by [@&#8203;tin-berri](https://github.com/tin-berri) in [#&#8203;35705](https://github.com/BerriAI/litellm/pull/35705)
- fix(guardrails/rubrik): attribute blocked requests to the caller that made them by [@&#8203;yucheng-berri](https://github.com/yucheng-berri) in [#&#8203;35734](https://github.com/BerriAI/litellm/pull/35734)
- fix(responses): forward client headers to the provider on /v1/responses by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;34531](https://github.com/BerriAI/litellm/pull/34531)
- feat(spend): add net auto-router savings to the cost-optimization dashboard by [@&#8203;tin-berri](https://github.com/tin-berri) in [#&#8203;35521](https://github.com/BerriAI/litellm/pull/35521)
- chore(typing): clear basedpyright Any errors in budget reset, access groups, and cache settings by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;35719](https://github.com/BerriAI/litellm/pull/35719)
- fix(spend): read what a request cost from the record instead of pricing it again by [@&#8203;tin-berri](https://github.com/tin-berri) in [#&#8203;35736](https://github.com/BerriAI/litellm/pull/35736)
- perf: install hiredis so redis-py parses replies with its C parser by [@&#8203;Classic298](https://github.com/Classic298) in [#&#8203;35709](https://github.com/BerriAI/litellm/pull/35709)
- feat(ui): show auto-router savings on the cost-optimization dashboard by [@&#8203;tin-berri](https://github.com/tin-berri) in [#&#8203;35522](https://github.com/BerriAI/litellm/pull/35522)
- perf: build log messages lazily so filtered-out log records cost nothing by [@&#8203;Classic298](https://github.com/Classic298) in [#&#8203;35703](https://github.com/BerriAI/litellm/pull/35703)
- fix(proxy): retry model cost map fetch with Retry-After-aware backoff and keep current map on reload failure by [@&#8203;ryan-crabbe-berri](https://github.com/ryan-crabbe-berri) in [#&#8203;35739](https://github.com/BerriAI/litellm/pull/35739)
- feat(otel): stamp service tier attributes on inference spans by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;35679](https://github.com/BerriAI/litellm/pull/35679)
- fix(proxy): log the model cost map reload failure lazily by [@&#8203;tin-berri](https://github.com/tin-berri) in [#&#8203;35750](https://github.com/BerriAI/litellm/pull/35750)
- fix(groq): translate web\_search\_options to the browser\_search tool by [@&#8203;hMED22](https://github.com/hMED22) in [#&#8203;34971](https://github.com/BerriAI/litellm/pull/34971)
- feat(ui): add admin-configurable user banner by [@&#8203;yuneng-berri](https://github.com/yuneng-berri) in [#&#8203;35729](https://github.com/BerriAI/litellm/pull/35729)
- fix(e2e): make spend-counter redis connection env-driven for non-cluster deployments by [@&#8203;yuneng-berri](https://github.com/yuneng-berri) in [#&#8203;35732](https://github.com/BerriAI/litellm/pull/35732)
- fix(proxy): make /cursor/chat/completions work with Cursor agent mode by [@&#8203;tin-berri](https://github.com/tin-berri) in [#&#8203;34029](https://github.com/BerriAI/litellm/pull/34029)
- fix(proxy): propagate user\_email and bind api\_key on JWT auth attribution paths by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;34331](https://github.com/BerriAI/litellm/pull/34331)
- chore(build): move the Admin UI toolchain to Node 24 by [@&#8203;yuneng-berri](https://github.com/yuneng-berri) in [#&#8203;35801](https://github.com/BerriAI/litellm/pull/35801)
- test(e2e): vendor API strategy coverage across endpoints by [@&#8203;mubashir1osmani](https://github.com/mubashir1osmani) in [#&#8203;34649](https://github.com/BerriAI/litellm/pull/34649)
- chore(deps): upgrade cryptography to 50.0.0 by [@&#8203;yuneng-berri](https://github.com/yuneng-berri) in [#&#8203;35803](https://github.com/BerriAI/litellm/pull/35803)
- test(e2e): cover legacy text /completions endpoint by [@&#8203;mubashir1osmani](https://github.com/mubashir1osmani) in [#&#8203;34431](https://github.com/BerriAI/litellm/pull/34431)
- feat(gemini): add gemini-robotics-er-2-preview and gemini-robotics-er-1.6-preview by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;35555](https://github.com/BerriAI/litellm/pull/35555)
- test(e2e): move load/perf testing out of the main suite and drop the vllm passthrough test by [@&#8203;yuneng-berri](https://github.com/yuneng-berri) in [#&#8203;35820](https://github.com/BerriAI/litellm/pull/35820)
- feat(lint): enforce Final on locals and freeze function parameters (LIT010, LIT011) by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;35807](https://github.com/BerriAI/litellm/pull/35807)
- chore: bump litellm-proxy-extras 0.4.81 -> 0.4.82, litellm 1.96.0 -> 1.97.0 by [@&#8203;yuneng-berri](https://github.com/yuneng-berri) in [#&#8203;35810](https://github.com/BerriAI/litellm/pull/35810)
- fix(bedrock): drop conflicting tool\_choice.type when toolConfig.toolChoice is set by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;35738](https://github.com/BerriAI/litellm/pull/35738)
- docs(CLAUDE.md): prefer commas over semicolons when replacing em dashes by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;35825](https://github.com/BerriAI/litellm/pull/35825)
- chore(lint): zero out basedpyright headroom for purely local rules by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;35828](https://github.com/BerriAI/litellm/pull/35828)
- test(e2e): retry provider-transient statuses at the transport with bounded backoff by [@&#8203;yuneng-berri](https://github.com/yuneng-berri) in [#&#8203;35824](https://github.com/BerriAI/litellm/pull/35824)
- chore(ci): promote internal staging to main by [@&#8203;yuneng-berri](https://github.com/yuneng-berri) in [#&#8203;35836](https://github.com/BerriAI/litellm/pull/35836)
- refactor(ui): route MCP session tokens through the shared storage helper by [@&#8203;yuneng-berri](https://github.com/yuneng-berri) in [#&#8203;35835](https://github.com/BerriAI/litellm/pull/35835)
- docs(helm): replace the classic chart's 128Mi resource example with the documented 4Gi sizing by [@&#8203;yassin-berriai](https://github.com/yassin-berriai) in [#&#8203;35830](https://github.com/BerriAI/litellm/pull/35830)
- fix(proxy): persist periodic reload schedule state so status survives restarts and fires without store\_model\_in\_db by [@&#8203;ryan-crabbe-berri](https://github.com/ryan-crabbe-berri) in [#&#8203;35165](https://github.com/BerriAI/litellm/pull/35165)
- fix(router): eagerly fetch Vertex AI deferred stream to surface HTTP errors in \_acompletion fallback path by [@&#8203;deepanshululla](https://github.com/deepanshululla) in [#&#8203;34627](https://github.com/BerriAI/litellm/pull/34627)
- fix(azure\_storage): honor AZURE\_STORAGE\_ENDPOINT\_SUFFIX for sovereign clouds by [@&#8203;yucheng-berri](https://github.com/yucheng-berri) in [#&#8203;35806](https://github.com/BerriAI/litellm/pull/35806)
- fix(proxy): apply key\_alias/key\_hash filters to all /key/list visibility branches by [@&#8203;ryan-crabbe-berri](https://github.com/ryan-crabbe-berri) in [#&#8203;35840](https://github.com/BerriAI/litellm/pull/35840)
- fix(proxy): enforce per-model budgets against resolved cursor model variants by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;35834](https://github.com/BerriAI/litellm/pull/35834)
- feat(ui): reorder Add Auto Router into name + template, with a collapsible detailed config by [@&#8203;tin-berri](https://github.com/tin-berri) in [#&#8203;35746](https://github.com/BerriAI/litellm/pull/35746)
- test: repair three failing suites on litellm\_internal\_staging by [@&#8203;yuneng-berri](https://github.com/yuneng-berri) in [#&#8203;35845](https://github.com/BerriAI/litellm/pull/35845)
- fix(guardrails): scan model output on the /openai/v1/responses alias by [@&#8203;yucheng-berri](https://github.com/yucheng-berri) in [#&#8203;35818](https://github.com/BerriAI/litellm/pull/35818)
- ci: pin Node on the Playwright UI lanes so npm ci meets the engines floor by [@&#8203;yuneng-berri](https://github.com/yuneng-berri) in [#&#8203;35848](https://github.com/BerriAI/litellm/pull/35848)
- fix(pricing): apply OpenAI's gpt-5.6 terra/luna cut to Azure cost map by [@&#8203;mubashir1osmani](https://github.com/mubashir1osmani) in [#&#8203;35481](https://github.com/BerriAI/litellm/pull/35481)
- feat(spend): add caller-scoped key/user/team/organization spend report endpoints by [@&#8203;yuneng-berri](https://github.com/yuneng-berri) in [#&#8203;35725](https://github.com/BerriAI/litellm/pull/35725)
- revert: "fix(caching): close evicted LLM clients so their connections are reclaimed ([#&#8203;35492](https://github.com/BerriAI/litellm/issues/35492))" by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;35856](https://github.com/BerriAI/litellm/pull/35856)
- refactor(repositories): add prisma protocol seams and a spend-reset unit of work by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;35748](https://github.com/BerriAI/litellm/pull/35748)
- perf(streaming): assemble streamed tool-call arguments in linear time by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;35826](https://github.com/BerriAI/litellm/pull/35826)
- fix(s3\_v2): sign S3 object URLs with S3SigV4Auth so encoded paths verify by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;35726](https://github.com/BerriAI/litellm/pull/35726)
- test(e2e): self-seed the ui suite's password-login users in global setup by [@&#8203;yuneng-berri](https://github.com/yuneng-berri) in [#&#8203;35863](https://github.com/BerriAI/litellm/pull/35863)
- fix(claude-code): create-only skill registration with a PUT update route (LIT-4110) by [@&#8203;ryan-crabbe-berri](https://github.com/ryan-crabbe-berri) in [#&#8203;31752](https://github.com/BerriAI/litellm/pull/31752)
- fix(proxy):  fix zguard  httpcode when block input by [@&#8203;jwang-gif](https://github.com/jwang-gif) in [#&#8203;31948](https://github.com/BerriAI/litellm/pull/31948)
- fix(lint): pick the merge-aware base so in-progress merges are not blamed for base drift by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;35868](https://github.com/BerriAI/litellm/pull/35868)
- chore: bump litellm-proxy-extras 0.4.82 -> 0.4.83 by [@&#8203;yuneng-berri](https://github.com/yuneng-berri) in [#&#8203;35877](https://github.com/BerriAI/litellm/pull/35877)
- feat(ui): add Test Routing to the auto router create form by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;35859](https://github.com/BerriAI/litellm/pull/35859)
- fix(ui): derive auto-router preset tests from the bundled preset JSON by [@&#8203;tin-berri](https://github.com/tin-berri) in [#&#8203;35882](https://github.com/BerriAI/litellm/pull/35882)
- revert: "test(e2e): vendor API strategy coverage across endpoints" ([#&#8203;34649](https://github.com/BerriAI/litellm/issues/34649)) by [@&#8203;yuneng-berri](https://github.com/yuneng-berri) in [#&#8203;35881](https://github.com/BerriAI/litellm/pull/35881)
- chore(deps): bump grpc and golang.org/x modules in the terraform provider by [@&#8203;yuneng-berri](https://github.com/yuneng-berri) in [#&#8203;35844](https://github.com/BerriAI/litellm/pull/35844)
- test(e2e): skip view-backed global spend probes pending LIT-5211 by [@&#8203;yuneng-berri](https://github.com/yuneng-berri) in [#&#8203;35875](https://github.com/BerriAI/litellm/pull/35875)
- fix(lint): move the basedpyright heap flag into the type check gate by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;35869](https://github.com/BerriAI/litellm/pull/35869)
- chore(ci): promote internal staging to main by [@&#8203;yuneng-berri](https://github.com/yuneng-berri) in [#&#8203;35876](https://github.com/BerriAI/litellm/pull/35876)
- feat(ui): add role capability gating, migrate Tool Policies route by [@&#8203;yuneng-berri](https://github.com/yuneng-berri) in [#&#8203;35812](https://github.com/BerriAI/litellm/pull/35812)
- refactor(ui): inject the fetch client's base url instead of reading it at import by [@&#8203;yuneng-berri](https://github.com/yuneng-berri) in [#&#8203;35802](https://github.com/BerriAI/litellm/pull/35802)
- chore: remove unused .flake8 config and flake8 dev dependency by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;35888](https://github.com/BerriAI/litellm/pull/35888)
- chore: stop advising pre-commit and bootstrap by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;35884](https://github.com/BerriAI/litellm/pull/35884)
- fix(auth): name enable\_jwt\_auth when a JWT-shaped key is rejected by [@&#8203;yassin-berriai](https://github.com/yassin-berriai) in [#&#8203;35831](https://github.com/BerriAI/litellm/pull/35831)
- feat(auto-router): make reminder marker pair configurable by [@&#8203;akapur99](https://github.com/akapur99) in [#&#8203;35874](https://github.com/BerriAI/litellm/pull/35874)
- fix(UI): update anthropic model presets by [@&#8203;tin-berri](https://github.com/tin-berri) in [#&#8203;35896](https://github.com/BerriAI/litellm/pull/35896)
- fix(bootstrap): switch to the dashboard node floor via nvm or fnm by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;35895](https://github.com/BerriAI/litellm/pull/35895)
- perf(pre-commit): run python, dashboard, and gen-api checks concurrently by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;35903](https://github.com/BerriAI/litellm/pull/35903)
- feat(spend): derive a default auto-router savings baseline from the hardest tier by [@&#8203;tin-berri](https://github.com/tin-berri) in [#&#8203;35907](https://github.com/BerriAI/litellm/pull/35907)
- fix(http\_handler): self-heal handler clients closed after cache eviction by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;35862](https://github.com/BerriAI/litellm/pull/35862)
- fix(cost\_tracking): keep OpenAI prompt cache token details through usage reassembly by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;34812](https://github.com/BerriAI/litellm/pull/34812)
- fix(cost): bill gpt-5.6 prompt cache reads at the cache read rate by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;34957](https://github.com/BerriAI/litellm/pull/34957)
- fix(batches): account for Responses API usage by [@&#8203;rimysore](https://github.com/rimysore) in [#&#8203;35367](https://github.com/BerriAI/litellm/pull/35367)
- ci: retry Codecov uploads and stop failing jobs on OIDC token flakes by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;35251](https://github.com/BerriAI/litellm/pull/35251)
- feat(complexity\_router): let operators rename the four complexity tiers by [@&#8203;akapur99](https://github.com/akapur99) in [#&#8203;35893](https://github.com/BerriAI/litellm/pull/35893)
- chore(lint): zero stale ruff and LIT headroom and strip inert type: ignore comments by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;35928](https://github.com/BerriAI/litellm/pull/35928)
- chore(lint): zero out seven more purely local basedpyright rules by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;35927](https://github.com/BerriAI/litellm/pull/35927)
- chore(ui): zero stale headroom on local dashboard eslint budgets by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;35929](https://github.com/BerriAI/litellm/pull/35929)
- fix(managed-files): skip rows without file objects by [@&#8203;rimysore](https://github.com/rimysore) in [#&#8203;35365](https://github.com/BerriAI/litellm/pull/35365)
- fix(router): redact fallback tracebacks at the call site and cover the sync deferred stream by [@&#8203;yassin-berriai](https://github.com/yassin-berriai) in [#&#8203;35843](https://github.com/BerriAI/litellm/pull/35843)
- fix(migrations): recover from an interrupted Prisma toolchain install by [@&#8203;yassin-berriai](https://github.com/yassin-berriai) in [#&#8203;35832](https://github.com/BerriAI/litellm/pull/35832)
- fix(lint): bring basedpyright rule counts back under their budget limits by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;35962](https://github.com/BerriAI/litellm/pull/35962)
- chore(ui): don't zero out stale headroom except no-console by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;35964](https://github.com/BerriAI/litellm/pull/35964)
- fix(proxy): give proxy\_admin\_viewer read parity with proxy\_admin by [@&#8203;ryan-crabbe-berri](https://github.com/ryan-crabbe-berri) in [#&#8203;35851](https://github.com/BerriAI/litellm/pull/35851)
- refactor(ui): address UI lint budget issues by refactoring UI by [@&#8203;tin-berri](https://github.com/tin-berri) in [#&#8203;35960](https://github.com/BerriAI/litellm/pull/35960)
- fix(ci): make the env-key doc gate see get\_secret\_bool reads by [@&#8203;yassin-berriai](https://github.com/yassin-berriai) in [#&#8203;35833](https://github.com/BerriAI/litellm/pull/35833)
- fix(caching): re-land evicted LLM client closing ([#&#8203;35492](https://github.com/BerriAI/litellm/issues/35492)) atop self-healing handlers by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;35870](https://github.com/BerriAI/litellm/pull/35870)
- fix(proxy): keep the connected DB client when a startup health check fails by [@&#8203;yassin-berriai](https://github.com/yassin-berriai) in [#&#8203;35837](https://github.com/BerriAI/litellm/pull/35837)
- chore(lint): remove litellm/types from the ruff lint exclusion by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;35926](https://github.com/BerriAI/litellm/pull/35926)
- feat(sgr): make the gateway middleware the source of truth for successful requests by [@&#8203;yassin-berriai](https://github.com/yassin-berriai) in [#&#8203;35717](https://github.com/BerriAI/litellm/pull/35717)
- feat(auto-router): let operators replace the LLM classifier's system prompt by [@&#8203;akapur99](https://github.com/akapur99) in [#&#8203;35855](https://github.com/BerriAI/litellm/pull/35855)
- fix(docker): bake the pip image's prisma engines at a world-readable path by [@&#8203;yassin-berriai](https://github.com/yassin-berriai) in [#&#8203;35976](https://github.com/BerriAI/litellm/pull/35976)
- fix(auth): return 403 from the OAuth2 enterprise gate by [@&#8203;yassin-berriai](https://github.com/yassin-berriai) in [#&#8203;35838](https://github.com/BerriAI/litellm/pull/35838)
- fix(router): keep custom model\_info across a price data reload by [@&#8203;yassin-berriai](https://github.com/yassin-berriai) in [#&#8203;35491](https://github.com/BerriAI/litellm/pull/35491)
- fix(proxy): resolve pass-through credentials live from router deployments by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;35916](https://github.com/BerriAI/litellm/pull/35916)
- fix(ci): fetch only head and merge-base in lint jobs instead of every branch by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;35982](https://github.com/BerriAI/litellm/pull/35982)
- fix(autorouter): match CJK keyword\_tier\_rules that regex word boundaries miss by [@&#8203;akapur99](https://github.com/akapur99) in [#&#8203;35984](https://github.com/BerriAI/litellm/pull/35984)
- feat(spend): rebuild the auto-router benchmarks backend as a per-session rollup by [@&#8203;tin-berri](https://github.com/tin-berri) in [#&#8203;35910](https://github.com/BerriAI/litellm/pull/35910)
- refactor(ui): replace hand-rolled query-param routing with nuqs by [@&#8203;ryan-crabbe-berri](https://github.com/ryan-crabbe-berri) in [#&#8203;35871](https://github.com/BerriAI/litellm/pull/35871)
- fix(docker): bake the componentized prisma engines at /opt/prisma so any uid can start by [@&#8203;yassin-berriai](https://github.com/yassin-berriai) in [#&#8203;35989](https://github.com/BerriAI/litellm/pull/35989)
- fix(migrations): keep the toolchain heal from raising on an unreadable nodeenv cache by [@&#8203;yassin-berriai](https://github.com/yassin-berriai) in [#&#8203;35986](https://github.com/BerriAI/litellm/pull/35986)
- fix(bedrock): sign Bedrock managed-file S3 requests with S3SigV4Auth by [@&#8203;yassin-berriai](https://github.com/yassin-berriai) in [#&#8203;35983](https://github.com/BerriAI/litellm/pull/35983)
- chore(typing): replace Any seams with real types across responses, proxy, and provider adapters by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;35809](https://github.com/BerriAI/litellm/pull/35809)
- fix(ai21): resolve the documented AI21\_API\_KEY instead of a misspelled name by [@&#8203;yassin-berriai](https://github.com/yassin-berriai) in [#&#8203;35985](https://github.com/BerriAI/litellm/pull/35985)
- fix(docker): fail the image build when the generated prisma engine paths drift off /opt/prisma by [@&#8203;yassin-berriai](https://github.com/yassin-berriai) in [#&#8203;35979](https://github.com/BerriAI/litellm/pull/35979)
- fix(jina\_ai): resolve the documented JINA\_API\_KEY as a fallback by [@&#8203;yassin-berriai](https://github.com/yassin-berriai) in [#&#8203;35992](https://github.com/BerriAI/litellm/pull/35992)
- fix(proxy): only treat a recoverable database outage as grounds to serve without one by [@&#8203;yassin-berriai](https://github.com/yassin-berriai) in [#&#8203;35864](https://github.com/BerriAI/litellm/pull/35864)
- fix(ci): make every remaining CI checkout shallow by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;35997](https://github.com/BerriAI/litellm/pull/35997)
- fix(auto-router): stop the embedding model's context window from failing long requests by [@&#8203;akapur99](https://github.com/akapur99) in [#&#8203;35956](https://github.com/BerriAI/litellm/pull/35956)
- fix(ci): make the env-key doc gate see bare get\_secret and get\_secret\_str reads by [@&#8203;yassin-berriai](https://github.com/yassin-berriai) in [#&#8203;35996](https://github.com/BerriAI/litellm/pull/35996)
- fix(logging): extend secret redaction to records litellm does not emit directly by [@&#8203;yassin-berriai](https://github.com/yassin-berriai) in [#&#8203;35977](https://github.com/BerriAI/litellm/pull/35977)
- test(utils): pin the register\_model replay test to the recorded half by [@&#8203;yassin-berriai](https://github.com/yassin-berriai) in [#&#8203;35994](https://github.com/BerriAI/litellm/pull/35994)
- fix(ci): run every helm test suite, not just the first one per file by [@&#8203;yassin-berriai](https://github.com/yassin-berriai) in [#&#8203;35993](https://github.com/BerriAI/litellm/pull/35993)
- ci: fail the build when a test file or Dockerfile is invoked by no job by [@&#8203;yassin-berriai](https://github.com/yassin-berriai) in [#&#8203;35991](https://github.com/BerriAI/litellm/pull/35991)
- fix(langfuse): stop a collected httpx handler from closing a shared client by [@&#8203;yassin-berriai](https://github.com/yassin-berriai) in [#&#8203;35981](https://github.com/BerriAI/litellm/pull/35981)
- fix(bedrock): grant bedrock:CountTokens in OIDC session policy by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;33145](https://github.com/BerriAI/litellm/pull/33145)
- feat(pre-commit): save full lint output to a per-worktree log file by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;36004](https://github.com/BerriAI/litellm/pull/36004)
- feat(ui): match auto-router preset models against deployments' underlying model IDs by [@&#8203;tin-berri](https://github.com/tin-berri) in [#&#8203;35972](https://github.com/BerriAI/litellm/pull/35972)
- fix(core\_helpers): map generic 'error' finish\_reason to 'stop' by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;33972](https://github.com/BerriAI/litellm/pull/33972)
- fix(proxy)!: apply request-parameter checks consistently across body, path and form inputs by [@&#8203;yuneng-berri](https://github.com/yuneng-berri) in [#&#8203;36011](https://github.com/BerriAI/litellm/pull/36011)
- fix: rebuild models\_by\_provider in add\_known\_models so cost map reloads reach wildcard expansion by [@&#8203;ryan-crabbe-berri](https://github.com/ryan-crabbe-berri) in [#&#8203;36010](https://github.com/BerriAI/litellm/pull/36010)
- feat(complexity\_router): report LLM classifier cost per request via routing\_decision and x-litellm-classifier-cost header by [@&#8203;tin-berri](https://github.com/tin-berri) in [#&#8203;36015](https://github.com/BerriAI/litellm/pull/36015)
- fix(model-prices): correct replicate model key typo by [@&#8203;AkashNaickar](https://github.com/AkashNaickar) in [#&#8203;34800](https://github.com/BerriAI/litellm/pull/34800)
- fix(proxy): register managed batch output files on terminal retrieve by [@&#8203;Souravrajvi0](https://github.com/Souravrajvi0) in [#&#8203;34092](https://github.com/BerriAI/litellm/pull/34092)
- perf(pre-commit): fetch basedpyright base counts from CI artifacts by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;35970](https://github.com/BerriAI/litellm/pull/35970)
- fix(ui): sync projects list page index to ?page= so back and reload keep the page by [@&#8203;ryan-crabbe-berri](https://github.com/ryan-crabbe-berri) in [#&#8203;36003](https://github.com/BerriAI/litellm/pull/36003)
- fix(ui): link project page keys to their virtual key detail by [@&#8203;ryan-crabbe-berri](https://github.com/ryan-crabbe-berri) in [#&#8203;36002](https://github.com/BerriAI/litellm/pull/36002)
- refactor(ui): drop unreferenced locals from dashboard route components by [@&#8203;yuneng-berri](https://github.com/yuneng-berri) in [#&#8203;35819](https://github.com/BerriAI/litellm/pull/35819)
- fix(ui): opening a project now pushes ?project= so back and deep links work by [@&#8203;ryan-crabbe-berri](https://github.com/ryan-crabbe-berri) in [#&#8203;36001](https://github.com/BerriAI/litellm/pull/36001)
- refactor(ui): drop unreferenced locals from shared dashboard components by [@&#8203;yuneng-berri](https://github.com/yuneng-berri) in [#&#8203;35821](https://github.com/BerriAI/litellm/pull/35821)
- refactor(ui): drop unreferenced locals from tests and narrow destructures by [@&#8203;yuneng-berri](https://github.com/yuneng-berri) in [#&#8203;36025](https://github.com/BerriAI/litellm/pull/36025)
- fix(guardrails): allow litellm\_content\_filter to run on post\_mcp\_call by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;35980](https://github.com/BerriAI/litellm/pull/35980)
- fix(guardrails): scan /v1/messages tool traffic by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;35999](https://github.com/BerriAI/litellm/pull/35999)
- refactor(ui): drop dead locals and unused React state across the dashboard by [@&#8203;yuneng-berri](https://github.com/yuneng-berri) in [#&#8203;36026](https://github.com/BerriAI/litellm/pull/36026)
- feat(ui): add the auto-router usage tab to cost optimization by [@&#8203;tin-berri](https://github.com/tin-berri) in [#&#8203;35995](https://github.com/BerriAI/litellm/pull/35995)
- fix(managed\_files): derive unified output file ids deterministically so concurrent registrations converge by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;36019](https://github.com/BerriAI/litellm/pull/36019)
- fix(proxy): send keepalive pings on anthropic messages SSE streams during upstream silence by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;36024](https://github.com/BerriAI/litellm/pull/36024)
- fix(managed\_files): return unified ids from unscoped file listing by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;36031](https://github.com/BerriAI/litellm/pull/36031)
- fix(arize\_phoenix): lowercase OTLP/gRPC auth metadata key by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;34883](https://github.com/BerriAI/litellm/pull/34883)
- fix(auto-router): accept every reminder marker pair a harness emits by [@&#8203;tin-berri](https://github.com/tin-berri) in [#&#8203;36029](https://github.com/BerriAI/litellm/pull/36029)
- fix(pricing): sync flex/priority tier keys to dated OpenAI snapshot variants by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;35923](https://github.com/BerriAI/litellm/pull/35923)
- fix(cost): bill reasoning tokens at the service tier output rate by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;35925](https://github.com/BerriAI/litellm/pull/35925)
- fix(proxy): include today's UTC bucket when a daily activity range ends at the caller's current day by [@&#8203;tin-berri](https://github.com/tin-berri) in [#&#8203;36051](https://github.com/BerriAI/litellm/pull/36051)
- fix: expired-miss share over all measured turns + cost-optimization tab labels by [@&#8203;tin-berri](https://github.com/tin-berri) in [#&#8203;36037](https://github.com/BerriAI/litellm/pull/36037)
- fix(router): include Bedrock batch/S3 fields and model in deployment credentials by [@&#8203;mpcusack-altos](https://github.com/mpcusack-altos) in [#&#8203;24548](https://github.com/BerriAI/litellm/pull/24548)
- fix(batch): track cost for managed batches with no attributable key/u… by [@&#8203;elinacse](https://github.com/elinacse) in [#&#8203;35468](https://github.com/BerriAI/litellm/pull/35468)
- feat(guardrails): add scan\_only\_tool\_results to scope unified guardrails to tool results by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;36014](https://github.com/BerriAI/litellm/pull/36014)
- fix(cost): stop token-pricing the placeholder input on file content calls by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;35140](https://github.com/BerriAI/litellm/pull/35140)
- fix(proxy): fetch background responses through the router in CheckResponsesCost by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;35137](https://github.com/BerriAI/litellm/pull/35137)
- fix(proxy): yaml store\_prompts\_in\_spend\_logs should take precedence over DB cached value by [@&#8203;Praveena-617](https://github.com/Praveena-617) in [#&#8203;35769](https://github.com/BerriAI/litellm/pull/35769)
- fix(lint): measure the basedpyright budget gate in a gate-owned venv by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;36050](https://github.com/BerriAI/litellm/pull/36050)
- docs: cap all GitHub comments at 15-25 words, curb semicolon splices by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;36059](https://github.com/BerriAI/litellm/pull/36059)
- chore(lint): name MappingProxyType in the mutable-collection fix messages by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;36072](https://github.com/BerriAI/litellm/pull/36072)
- test: roll back runtime model registrations between tests by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;36039](https://github.com/BerriAI/litellm/pull/36039)
- refactor(types): cut 653 implicit and explicit Any diagnostics across 11 modules by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;36054](https://github.com/BerriAI/litellm/pull/36054)
- fix(proxy): stop resolving the UI session sentinel team on /search\_tools/list by [@&#8203;yuneng-berri](https://github.com/yuneng-berri) in [#&#8203;36061](https://github.com/BerriAI/litellm/pull/36061)
- fix(batches): persist managed file ids for cancelled/failed/expired batches by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;36048](https://github.com/BerriAI/litellm/pull/36048)
- fix(batches): register managed output files on batch cancel by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;36034](https://github.com/BerriAI/litellm/pull/36034)
- fix(proxy): allow non-admins to reach /user/daily/activity/aggregated by [@&#8203;yuneng-berri](https://github.com/yuneng-berri) in [#&#8203;36062](https://github.com/BerriAI/litellm/pull/36062)
- fix(anthropic): coerce explicit additionalProperties to false in output\_format schema by [@&#8203;dkindlund](https://github.com/dkindlund) in [#&#8203;35811](https://github.com/BerriAI/litellm/pull/35811)
- fix(batches): prevent managed file fallbacks by [@&#8203;rimysore](https://github.com/rimysore) in [#&#8203;35371](https://github.com/BerriAI/litellm/pull/35371)
- chore: ignore the mechanical lint and typing sweeps in git blame by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;36076](https://github.com/BerriAI/litellm/pull/36076)
- fix(proxy): warn at startup when max\_budget is set but no database is connected by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;36041](https://github.com/BerriAI/litellm/pull/36041)
- fix(proxy): promote caller metadata trace fields into litellm\_metadata by [@&#8203;yucheng-berri](https://github.com/yucheng-berri) in [#&#8203;35866](https://github.com/BerriAI/litellm/pull/35866)
- feat(terraform): sync provider 0.3.0 from the mirror and cut 0.4.0 by [@&#8203;yuneng-berri](https://github.com/yuneng-berri) in [#&#8203;36098](https://github.com/BerriAI/litellm/pull/36098)
- fix(guardrails): honor configured timeout in Zscaler AI Guard by [@&#8203;yucheng-berri](https://github.com/yucheng-berri) in [#&#8203;36110](https://github.com/BerriAI/litellm/pull/36110)
- fix(logging): fall back to litellm\_metadata when metadata is empty by [@&#8203;yucheng-berri](https://github.com/yucheng-berri) in [#&#8203;36105](https://github.com/BerriAI/litellm/pull/36105)
- fix(proxy): re-assert the authenticated identity on passthrough requests by [@&#8203;yucheng-berri](https://github.com/yucheng-berri) in [#&#8203;36121](https://github.com/BerriAI/litellm/pull/36121)
- chore: bump litellm-enterprise 0.1.53 -> 0.1.54, litellm-proxy-extras 0.4.83 -> 0.4.84 by [@&#8203;yuneng-berri](https://github.com/yuneng-berri) in [#&#8203;36139](https://github.com/BerriAI/litellm/pull/36139)
- fix(ui): match auto-router preset models against wildcard-expanded model groups by [@&#8203;tin-berri](https://github.com/tin-berri) in [#&#8203;36111](https://github.com/BerriAI/litellm/pull/36111)
- test(router): assert the auto-router max\_input\_chars kwarg by [@&#8203;yuneng-berri](https://github.com/yuneng-berri) in [#&#8203;36109](https://github.com/BerriAI/litellm/pull/36109)
- fix(ui): allow clearing a key's budget reset from the Edit Key form by [@&#8203;ryan-crabbe-berri](https://github.com/ryan-crabbe-berri) in [#&#8203;36140](https://github.com/BerriAI/litellm/pull/36140)
- fix(managed\_files): skip unparseable rows when listing managed files by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;36021](https://github.com/BerriAI/litellm/pull/36021)
- fix(a2a): stop writing per-caller headers onto the shared cached httpx client by [@&#8203;yassin-berriai](https://github.com/yassin-berriai) in [#&#8203;35978](https://github.com/BerriAI/litellm/pull/35978)
- build(deps): bump h2 to 4.4.1 and js-yaml to 4.3.1 by [@&#8203;yuneng-berri](https://github.com/yuneng-berri) in [#&#8203;36147](https://github.com/BerriAI/litellm/pull/36147)
- chore: promote staging to main by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;36057](https://github.com/BerriAI/litellm/pull/36057)
- fix(azure\_sentinel): respect AZURE\_AUTHORITY\_HOST and derive the Azure Monitor audience per cloud by [@&#8203;yucheng-berri](https://github.com/yucheng-berri) in [#&#8203;36137](https://github.com/BerriAI/litellm/pull/36137)
- fix(bedrock): pass SSE-KMS key through to the batch input-file S3 upload by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;35148](https://github.com/BerriAI/litellm/pull/35148)
- fix(anthropic adapter): stop indexing choices\[0] on choiceless streaming chunks by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;35314](https://github.com/BerriAI/litellm/pull/35314)
- fix(bedrock): normalize /v1/completions and /v1/responses batch records by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;35675](https://github.com/BerriAI/litellm/pull/35675)
- fix(proxy): return the real status code when a credential update is rejected by [@&#8203;yucheng-berri](https://github.com/yucheng-berri) in [#&#8203;36166](https://github.com/BerriAI/litellm/pull/36166)
- fix(proxy): improve Headroom /v1/compress HTTP 404 diagnostics by [@&#8203;aayush598](https://github.com/aayush598) in [#&#8203;35952](https://github.com/BerriAI/litellm/pull/35952)
- fix(proxy): invalidate cached project object on project update and delete by [@&#8203;ryan-crabbe-berri](https://github.com/ryan-crabbe-berri) in [#&#8203;36028](https://github.com/BerriAI/litellm/pull/36028)
- feat(proxy): add apply\_user\_budget\_to\_team\_keys opt-in by [@&#8203;ryan-crabbe-berri](https://github.com/ryan-crabbe-berri) in [#&#8203;36102](https://github.com/BerriAI/litellm/pull/36102)
- fix(proxy): stop alerting on health probes that lose the planned engine-restart race by [@&#8203;yassin-berriai](https://github.com/yassin-berriai) in [#&#8203;36141](https://github.com/BerriAI/litellm/pull/36141)
- test(docker): gate the componentized gateway and backend images on an arbitrary-uid offline boot by [@&#8203;yassin-berriai](https://github.com/yassin-berriai) in [#&#8203;36136](https://github.com/BerriAI/litellm/pull/36136)
- fix(http): stop pooled clients persisting cookies on the aiohttp jar too by [@&#8203;yassin-berriai](https://github.com/yassin-berriai) in [#&#8203;36149](https://github.com/BerriAI/litellm/pull/36149)
- fix(router): bound fallback-walk work and error-log volume by [@&#8203;yassin-berriai](https://github.com/yassin-berriai) in [#&#8203;36148](https://github.com/BerriAI/litellm/pull/36148)
- ci: wire credential\_endpoints tests into the proxy endpoints job by [@&#8203;cursor](https://github.com/cursor)\[bot] in [#&#8203;36187](https://github.com/BerriAI/litellm/pull/36187)
- docs(keys): document /key/info fields and clarify budget\_reset\_at is the next reset by [@&#8203;ryan-crabbe-berri](https://github.com/ryan-crabbe-berri) in [#&#8203;36127](https://github.com/BerriAI/litellm/pull/36127)
- fix(azure\_sentinel): add AZURE\_SENTINEL\_AUTHORITY\_HOST as a Sentinel scoped override by [@&#8203;yucheng-berri](https://github.com/yucheng-berri) in [#&#8203;36165](https://github.com/BerriAI/litellm/pull/36165)
- docs(pr-template): add a User Flow section with authoring instructions by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;36162](https://github.com/BerriAI/litellm/pull/36162)
- fix(proxy): derive config agent ids from agent\_name so grants survive secret rotation by [@&#8203;ryan-crabbe-berri](https://github.com/ryan-crabbe-berri) in [#&#8203;36020](https://github.com/BerriAI/litellm/pull/36020)
- chore(ui): regenerate schema.d.ts for the /key/info docstring update by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;36210](https://github.com/BerriAI/litellm/pull/36210)
- build(deps): bump gitpython to 3.1.58 to clear osv-scan on staging by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;36212](https://github.com/BerriAI/litellm/pull/36212)
- fix(proxy): deny agent access when key and team grants resolve to nothing by [@&#8203;ryan-crabbe-berri](https://github.com/ryan-crabbe-berri) in [#&#8203;36221](https://github.com/BerriAI/litellm/pull/36221)
- build(deps): defer the second pypdf advisory until the 6.15.0 bump by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;36218](https://github.com/BerriAI/litellm/pull/36218)
- fix(a2a): align agent list annotation and test with the tuple return type by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;36217](https://github.com/BerriAI/litellm/pull/36217)
- ci: always run the UI API types sync check so it can be required by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;36213](https://github.com/BerriAI/litellm/pull/36213)
- build(deps): bump nanoid to 3.3.17 in the dashboard lockfile by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;36227](https://github.com/BerriAI/litellm/pull/36227)
- feat(ui): show user email or alias in usage data export by [@&#8203;ryan-crabbe-berri](https://github.com/ryan-crabbe-berri) in [#&#8203;36232](https://github.com/BerriAI/litellm/pull/36232)
- feat(auto-router): track turns per complexity tier (LIT-5302) by [@&#8203;tin-berri](https://github.com/tin-berri) in [#&#8203;36209](https://github.com/BerriAI/litellm/pull/36209)
- fix(websearch): restore snippet text in native web\_search\_tool\_result blocks (LIT-5315) by [@&#8203;tin-berri](https://github.com/tin-berri) in [#&#8203;36228](https://github.com/BerriAI/litellm/pull/36228)
- fix(proxy): resolve entity access groups in the model listing endpoints by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;36230](https://github.com/BerriAI/litellm/pull/36230)
- fix(ui): let access groups be a team's only model source, with hover provenance by [@&#8203;ryan-crabbe-berri](https://github.com/ryan-crabbe-berri) in [#&#8203;36234](https://github.com/BerriAI/litellm/pull/36234)
- fix(managed\_files): return unified output file ids from GET /batches by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;36049](https://github.com/BerriAI/litellm/pull/36049)
- test(proxy): compare empty agent list to the tuple get\_agent\_list returns by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;36225](https://github.com/BerriAI/litellm/pull/36225)
- fix(otel): name the RPC system and upstream on MCP tool-call spans by [@&#8203;yucheng-berri](https://github.com/yucheng-berri) in [#&#8203;35857](https://github.com/BerriAI/litellm/pull/35857)
- fix(guardrails): chunk oversized Bedrock ApplyGuardrail requests instead of failing by [@&#8203;yucheng-berri](https://github.com/yucheng-berri) in [#&#8203;36119](https://github.com/BerriAI/litellm/pull/36119)
- test(e2e): settle control-plane writes across every replica, not just one by [@&#8203;yuneng-berri](https://github.com/yuneng-berri) in [#&#8203;36247](https://github.com/BerriAI/litellm/pull/36247)
- fix(responses): forward allowed\_openai\_params through the chat completions bridge by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;35885](https://github.com/BerriAI/litellm/pull/35885)
- test(proxy): assert the copy \_add\_team\_member\_budget\_table returns by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;36244](https://github.com/BerriAI/litellm/pull/36244)
- chore(ui): regenerate dashboard api types for tier\_turns by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;36243](https://github.com/BerriAI/litellm/pull/36243)
- refactor(types): declare mirrored pricing fields on ModelInfo by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;36215](https://github.com/BerriAI/litellm/pull/36215)
- fix(lint): make strict-gate noqas survive base ruff and flag stale ones by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;36257](https://github.com/BerriAI/litellm/pull/36257)
- fix(vertex\_ai): surface real error/status on vertex batch create instead of IndexError 500 by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;35141](https://github.com/BerriAI/litellm/pull/35141)
- ci: give the remaining pull\_request workflows a concurrency group by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;36252](https://github.com/BerriAI/litellm/pull/36252)
- refactor(lint): graduate zero-violation strict rules and guard the budget ratchet by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;36161](https://github.com/BerriAI/litellm/pull/36161)
- fix(proxy): enforce require\_managed\_files on every route that accepts a raw provider id by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;35551](https://github.com/BerriAI/litellm/pull/35551)
- chore(typing): clear 1.4k basedpyright Any errors across 21 hotspot files by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;36282](https://github.com/BerriAI/litellm/pull/36282)
- test: roll back live router replay membership between tests by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;36278](https://github.com/BerriAI/litellm/pull/36278)
- chore(ci): sync main into internal staging by [@&#8203;yuneng-berri](https://github.com/yuneng-berri) in [#&#8203;36288](https://github.com/BerriAI/litellm/pull/36288)
- build(lint): rename make pre-commit to make check with a working-tree fallback by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;36277](https://github.com/BerriAI/litellm/pull/36277)
- fix(ui): show team BYOK models in team fallback settings by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;36241](https://github.com/BerriAI/litellm/pull/36241)
- fix(otel): mark v2 server spans as failed for pre-call errors by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;34546](https://github.com/BerriAI/litellm/pull/34546)
- fix(websearch\_interception): bill intercepted searches to the calling key by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;35708](https://github.com/BerriAI/litellm/pull/35708)
- chore: remove pre-commit rule by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;36295](https://github.com/BerriAI/litellm/pull/36295)
- docs: clarify guideline priority ordering in CLAUDE.md by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;36296](https://github.com/BerriAI/litellm/pull/36296)
- feat(router): independent, default-on deployment affinity for the auto-router by [@&#8203;tin-berri](https://github.com/tin-berri) in [#&#8203;36146](https://github.com/BerriAI/litellm/pull/36146)
- test: repair stale CircleCI contracts by [@&#8203;yuneng-berri](https://github.com/yuneng-berri) in [#&#8203;36293](https://github.com/BerriAI/litellm/pull/36293)
- chore(ci): promote internal staging to main by [@&#8203;yuneng-berri](https://github.com/yuneng-berri) in [#&#8203;36286](https://github.com/BerriAI/litellm/pull/36286)
- chore: rebuild Admin UI bundle for the 2026-08-08 release by [@&#8203;yuneng-berri](https://github.com/yuneng-berri) in [#&#8203;36297](https://github.com/BerriAI/litellm/pull/36297)
- chore(ci): promote internal staging to main by [@&#8203;yuneng-berri](https://github.com/yuneng-berri) in [#&#8203;36304](https://github.com/BerriAI/litellm/pull/36304)

##### New Contributors

- [@&#8203;rimysore](https://github.com/rimysore) made their first contribution in [#&#8203;35367](https://github.com/BerriAI/litellm/pull/35367)
- [@&#8203;AkashNaickar](https://github.com/AkashNaickar) made their first contribution in [#&#8203;34800](https://github.com/BerriAI/litellm/pull/34800)
- [@&#8203;Souravrajvi0](https://github.com/Souravrajvi0) made their first contribution in [#&#8203;34092](https://github.com/BerriAI/litellm/pull/34092)
- [@&#8203;elinacse](https://github.com/elinacse) made their first contribution in [#&#8203;35468](https://github.com/BerriAI/litellm/pull/35468)
- [@&#8203;aayush598](https://github.com/aayush598) made their first contribution in [#&#8203;35952](https://github.com/BerriAI/litellm/pull/35952)
- [@&#8203;cursor](https://github.com/cursor)\[bot] made their first contribution in [#&#8203;36187](https://github.com/BerriAI/litellm/pull/36187)

**Full Changelog**: <https://github.com/BerriAI/litellm/compare/v1.96.0...v1.97.0>

### [`v1.97.0`](https://github.com/BerriAI/litellm/releases/tag/v1.97.0)

[Compare Source](https://github.com/BerriAI/litellm/compare/v1.96.2...v1.97.0)

##### Verify Docker Image Signature

All LiteLLM Docker images are signed with [cosign](https://docs.sigstore.dev/cosign/overview/). Every release is signed with the same key introduced in [commit `0112e53`](https://github.com/BerriAI/litellm/commit/0112e53046018d726492c814b3644b7d376029d0).

**Verify using the pinned commit hash (recommended):**

A commit hash is cryptographically immutable, so this is the strongest way to ensure you are using the original signing key:

```bash
cosign verify \
  --key https://raw.githubusercontent.com/BerriAI/litellm/0112e53046018d726492c814b3644b7d376029d0/cosign.pub \
  ghcr.io/berriai/litellm:v1.97.0
```

**Verify using the release tag (convenience):**

Tags are protected in this repository and resolve to the same key. This option is easier to read but relies on tag protection rules:

```bash
cosign verify \
  --key https://raw.githubusercontent.com/BerriAI/litellm/v1.97.0/cosign.pub \
  ghcr.io/berriai/litellm:v1.97.0
```

Expected output:

```
The following checks were performed on each of these signatures:
  - The cosign claims were validated
  - The signatures were verified against the specified public key
```

***

##### What's Changed

- feat(proxy): resolve Cursor thinking/fast model-name suffixes on /cursor/chat/completions by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;35554](https://github.com/BerriAI/litellm/pull/35554)
- fix(team-callbacks): actually stop logging when disable\_logging is called by [@&#8203;yucheng-berri](https://github.com/yucheng-berri) in [#&#8203;35520](https://github.com/BerriAI/litellm/pull/35520)
- refactor(lint): drop redundant !s f-string conversion flags and fix displaced import-group comments by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;35546](https://github.com/BerriAI/litellm/pull/35546)
- fix(proxy): backfill null user\_email on existing users during JWT auth by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;34588](https://github.com/BerriAI/litellm/pull/34588)
- feat(playground): add non-streaming response toggle by [@&#8203;ryan-crabbe-berri](https://github.com/ryan-crabbe-berri) in [#&#8203;35560](https://github.com/BerriAI/litellm/pull/35560)
- feat(teams): apply default organization to new teams from default team settings by [@&#8203;ryan-crabbe-berri](https://github.com/ryan-crabbe-berri) in [#&#8203;35540](https://github.com/BerriAI/litellm/pull/35540)
- fix(ui): block Playground page for viewer roles on direct URL access by [@&#8203;ryan-crabbe-berri](https://github.com/ryan-crabbe-berri) in [#&#8203;35676](https://github.com/BerriAI/litellm/pull/35676)
- fix(caching): close evicted LLM clients so their connections are reclaimed by [@&#8203;yassin-berriai](https://github.com/yassin-berriai) in [#&#8203;35492](https://github.com/BerriAI/litellm/pull/35492)
- chore(deps): update brace-expansion, postcss, and gitpython to current patch releases by [@&#8203;yuneng-berri](https://github.com/yuneng-berri) in [#&#8203;35692](https://github.com/BerriAI/litellm/pull/35692)
- refactor(ui): rename the create MCP server component to PascalCase by [@&#8203;yuneng-berri](https://github.com/yuneng-berri) in [#&#8203;35686](https://github.com/BerriAI/litellm/pull/35686)
- fix(openai): drop undefined Union from owns\_wrapped\_http\_client annotation by [@&#8203;ryan-crabbe-berri](https://github.com/ryan-crabbe-berri) in [#&#8203;35706](https://github.com/BerriAI/litellm/pull/35706)
- fix(openai): drop the undefined Union from owns\_wrapped\_http\_client by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;35704](https://github.com/BerriAI/litellm/pull/35704)
- chore(ui): note Google's Agent Platform rename in vector store setup by [@&#8203;ryan-crabbe-berri](https://github.com/ryan-crabbe-berri) in [#&#8203;28076](https://github.com/BerriAI/litellm/pull/28076)
- fix(proxy): apply key/team router\_settings.model\_group\_alias by [@&#8203;yassin-berriai](https://github.com/yassin-berriai) in [#&#8203;35486](https://github.com/BerriAI/litellm/pull/35486)
- feat(complexity\_router): default session affinity off and expose it in the UI by [@&#8203;tin-berri](https://github.com/tin-berri) in [#&#8203;35714](https://github.com/BerriAI/litellm/pull/35714)
- fix(datadog): read team callback dd\_\* params from kwargs instead of blocked dynamic params ([#&#8203;35115](https://github.com/BerriAI/litellm/issues/35115) port) by [@&#8203;ryan-crabbe-berri](https://github.com/ryan-crabbe-berri) in [#&#8203;35687](https://github.com/BerriAI/litellm/pull/35687)
- refactor(ui): extract the MCP create form's logic and field groups by [@&#8203;yuneng-berri](https://github.com/yuneng-berri) in [#&#8203;35694](https://github.com/BerriAI/litellm/pull/35694)
- test(ui): tier the MCP create tests into unit and integration by [@&#8203;yuneng-berri](https://github.com/yuneng-berri) in [#&#8203;35697](https://github.com/BerriAI/litellm/pull/35697)
- fix(proxy): redact credential headers from request logging copies by [@&#8203;yucheng-berri](https://github.com/yucheng-berri) in [#&#8203;35678](https://github.com/BerriAI/litellm/pull/35678)
- feat(guardrails/rubrik): prompt moderation, response-text blocking, streaming buffer, failure logging by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;35722](https://github.com/BerriAI/litellm/pull/35722)
- fix(ui): render Responses API request and response in the logs drawer by [@&#8203;yuneng-berri](https://github.com/yuneng-berri) in [#&#8203;35718](https://github.com/BerriAI/litellm/pull/35718)
- fix(ui): hide guardrail review buttons from non-admin users by [@&#8203;ryan-crabbe-berri](https://github.com/ryan-crabbe-berri) in [#&#8203;27535](https://github.com/BerriAI/litellm/pull/27535)
- feat(team): custom metadata validation hook for team create and update by [@&#8203;yuneng-berri](https://github.com/yuneng-berri) in [#&#8203;33353](https://github.com/BerriAI/litellm/pull/33353)
- ci(circleci): install a pinned Rust toolchain on the Linux jobs by [@&#8203;yuneng-berri](https://github.com/yuneng-berri) in [#&#8203;35519](https://github.com/BerriAI/litellm/pull/35519)
- fix(bedrock): stop forwarding no-op toolSpec.strict to Converse by [@&#8203;tin-berri](https://github.com/tin-berri) in [#&#8203;35688](https://github.com/BerriAI/litellm/pull/35688)
- fix(ui): reject an auto-router keyword rule left empty instead of dropping it by [@&#8203;tin-berri](https://github.com/tin-berri) in [#&#8203;35705](https://github.com/BerriAI/litellm/pull/35705)
- fix(guardrails/rubrik): attribute blocked requests to the caller that made them by [@&#8203;yucheng-berri](https://github.com/yucheng-berri) in [#&#8203;35734](https://github.com/BerriAI/litellm/pull/35734)
- fix(responses): forward client headers to the provider on /v1/responses by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;34531](https://github.com/BerriAI/litellm/pull/34531)
- feat(spend): add net auto-router savings to the cost-optimization dashboard by [@&#8203;tin-berri](https://github.com/tin-berri) in [#&#8203;35521](https://github.com/BerriAI/litellm/pull/35521)
- chore(typing): clear basedpyright Any errors in budget reset, access groups, and cache settings by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;35719](https://github.com/BerriAI/litellm/pull/35719)
- fix(spend): read what a request cost from the record instead of pricing it again by [@&#8203;tin-berri](https://github.com/tin-berri) in [#&#8203;35736](https://github.com/BerriAI/litellm/pull/35736)
- perf: install hiredis so redis-py parses replies with its C parser by [@&#8203;Classic298](https://github.com/Classic298) in [#&#8203;35709](https://github.com/BerriAI/litellm/pull/35709)
- feat(ui): show auto-router savings on the cost-optimization dashboard by [@&#8203;tin-berri](https://github.com/tin-berri) in [#&#8203;35522](https://github.com/BerriAI/litellm/pull/35522)
- perf: build log messages lazily so filtered-out log records cost nothing by [@&#8203;Classic298](https://github.com/Classic298) in [#&#8203;35703](https://github.com/BerriAI/litellm/pull/35703)
- fix(proxy): retry model cost map fetch with Retry-After-aware backoff and keep current map on reload failure by [@&#8203;ryan-crabbe-berri](https://github.com/ryan-crabbe-berri) in [#&#8203;35739](https://github.com/BerriAI/litellm/pull/35739)
- feat(otel): stamp service tier attributes on inference spans by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;35679](https://github.com/BerriAI/litellm/pull/35679)
- fix(proxy): log the model cost map reload failure lazily by [@&#8203;tin-berri](https://github.com/tin-berri) in [#&#8203;35750](https://github.com/BerriAI/litellm/pull/35750)
- fix(groq): translate web\_search\_options to the browser\_search tool by [@&#8203;hMED22](https://github.com/hMED22) in [#&#8203;34971](https://github.com/BerriAI/litellm/pull/34971)
- feat(ui): add admin-configurable user banner by [@&#8203;yuneng-berri](https://github.com/yuneng-berri) in [#&#8203;35729](https://github.com/BerriAI/litellm/pull/35729)
- fix(e2e): make spend-counter redis connection env-driven for non-cluster deployments by [@&#8203;yuneng-berri](https://github.com/yuneng-berri) in [#&#8203;35732](https://github.com/BerriAI/litellm/pull/35732)
- fix(proxy): make /cursor/chat/completions work with Cursor agent mode by [@&#8203;tin-berri](https://github.com/tin-berri) in [#&#8203;34029](https://github.com/BerriAI/litellm/pull/34029)
- fix(proxy): propagate user\_email and bind api\_key on JWT auth attribution paths by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;34331](https://github.com/BerriAI/litellm/pull/34331)
- chore(build): move the Admin UI toolchain to Node 24 by [@&#8203;yuneng-berri](https://g…
Duxl-Ai pushed a commit to Duxl-Ai/litellm that referenced this pull request Aug 20, 2026
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.
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.

[Bug]: OpenAI gpt-5.6 prompt caching: litellm under-counts cache-read tokens vs OpenAI billed usage, overstating cost ~8.5%

3 participants