Skip to content

fix(anthropic): buffer streamed responses carrying server-fulfilled tools so retrieval tool calls never reach the client - #36245

Merged
mateo-berri merged 12 commits into
litellm_internal_stagingfrom
litellm_fix_headroom_stream_leak
Aug 26, 2026
Merged

mateo-berri merged 12 commits into
litellm_internal_stagingfrom
litellm_fix_headroom_stream_leak

Conversation

@mateo-berri

@mateo-berri mateo-berri commented Aug 8, 2026

Copy link
Copy Markdown
Contributor

TLDR

Problem this solves:

  • Headroom compresses a streaming /v1/messages turn and injects headroom_retrieve
  • The model's headroom_retrieve tool_use streams straight to the client
  • Claude Code fails the turn with No such tool available: headroom_retrieve
  • The server-side retrieval rerun lands after message_stop, where no client reads
  • The user pays for that rerun and never sees its answer

How it solves it:

  • Callbacks declare the tools they answer server-side via server_fulfilled_tool_names
  • Streams carrying such a tool are buffered until the agentic loop finishes
  • ping events every 15s keep client stall watchdogs quiet meanwhile
  • Only the follow-up answer streams; the buffered tool_use message is dropped
  • With no interception fired, the buffer replays byte-identical
  • Retrieval leaving a server-fulfilled tool_use buffered ends on an SSE error, never the tool call
  • Requests without such a tool keep true live streaming
  • Ping-only disconnects release the budget reservation instead of holding worst case
  • The router forwards that leading ping live and passes the retrieval error through instead of falling back to another deployment
  • The withheld-output flag rides through the router, the streaming wrappers, and the stream cache writer, so disconnect accounting holds in production, not just on the bare iterator

User Flow

Before: the flow fails at step 4, where the session errors on a tool the user never configured

  1. A Claude Code user points ANTHROPIC_BASE_URL at a LiteLLM gateway that has the Headroom compression guardrail enabled; every turn is POST https://litellm-domain/v1/messages with "stream": true
  2. Once the conversation grows, the gateway compresses older history into markers; turns keep streaming normally
  3. On a later turn the assistant says it will recover compressed context, and the stream ends with stop_reason: "tool_use" naming headroom_retrieve
  4. The session shows Error: No such tool available: headroom_retrieve, the turn is wasted, and the model re-derives the lost context by re-reading files
  5. The user is also billed for a follow-up model call whose corrected answer never appears anywhere in their session

After: the flow succeeds at step 3 with one clean streamed answer

  1. A Claude Code user points ANTHROPIC_BASE_URL at a LiteLLM gateway that has the Headroom compression guardrail enabled; every turn is POST https://litellm-domain/v1/messages with "stream": true
  2. Once the conversation grows, the gateway compresses older history into markers; turns keep streaming normally
  3. On a later turn the connection carries only ping events for a few seconds while the gateway recovers the compressed content server-side
  4. The reply arrives as a single normal message that already incorporates the recovered context; no unknown-tool error and nothing billed that the user cannot see

Relevant issues

Linear ticket

Pre-Submission checklist

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

  • I have added meaningful tests
  • The handful of test files covering my change pass locally, e.g. uv run pytest tests/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
  • My PR passes all required CI/CD checks (e.g., lint, schema.d.ts sync check, etc.)
  • My PR's scope is as isolated as possible; it only solves 1 specific problem
  • I have received a Greptile Confidence Score of at least 4/5 before requesting a maintainer review (Greptile reviews automatically once the PR is opened; only comment @greptileai to re-request a review after pushing changes)

Delays in PR merge?

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

Screenshots / Proof of Fix

Real Claude Code 2.1.246 driven interactively in tmux against a local proxy at each commit (2 uvicorn workers, no DB), real Anthropic API (claude-haiku-4-5-20251001), and a stub standing in for the private Headroom compression service. The stub answers POST /v1/compress by replacing unprotected user and assistant rows with [COMPRESSED by Headroom. Recover the original text by calling the headroom_retrieve tool with hash=<sha1[:24]>] (same row count) and GET /v1/retrieve/<hash> with {"original_content": <the original row text>}

Proxy config, identical on both sides:

model_list:
  - model_name: claude-*
    litellm_params:
      model: anthropic/claude-*
      api_key: os.environ/ANTHROPIC_API_KEY

guardrails:
  - guardrail_name: headroom-compress
    litellm_params:
      guardrail: headroom
      mode: pre_call
      default_on: true
      api_base: http://127.0.0.1:<stub-port>

general_settings:
  master_key: os.environ/LITELLM_MASTER_KEY

Steps, identical on both sides:

  1. python litellm/proxy/proxy_cli.py --config config.yaml --port <proxy-port> --num_workers 2 --detailed_debug
  2. In a fresh HOME and an empty project directory: ANTHROPIC_BASE_URL=http://127.0.0.1:<proxy-port> ANTHROPIC_AUTH_TOKEN=<master-key> claude --model claude-haiku-4-5-20251001
  3. Turn 1: For later in this conversation: the launch code is OCTOPUS-7734.
  4. Turn 2: What is the launch code? Reply with only the code. If the earlier message shows a compression marker instead of the original text, call the headroom_retrieve tool with its hash to recover it first.

On turn 2 the guardrail compresses the first user row (the stub log shows compress: 1 rows in, replaced 1 followed by GET /v1/retrieve/<hash> on both sides), so the model asks for headroom_retrieve and the proxy fulfils it server-side either way. What differs is what the user sees

Before (04818a3)

Claude Code screen after turn 2:

❯ What is the launch code? Reply with only the code. If the earlier message shows a compression marker instead of the original text, call the headroom_retrieve tool with its hash to recover it first.

  Thought for 2s (ctrl+o to expand)
  ⎿  Error: No such tool available: headroom_retrieve

⏺ OCTOPUS-7734

  Thought for 1s (ctrl+o to expand)

⏺ I'm ready to help! What would you like to work on?

✻ Cogitated for 5s · done 4:11 PM
  • Client sees the server-fulfilled tool call and errors
  • The answer arrives as a stray second message
  • A third, unprompted assistant message follows
  • Leaked tool rows persist: next stub call had 5 rows

After (8d87798)

Claude Code screen after turn 2:

❯ What is the launch code? Reply with only the code. If the earlier message shows a compression marker instead of the original text, call the headroom_retrieve tool with its hash to recover it first.

⏺ OCTOPUS-7734

✻ Cogitated for 3s · done 5:32 PM
  • One clean assistant message, no error line
  • No tool call visible to the client
  • Turn took 4s wall clock, no visible stall
  • Stub log shows the same compress then retrieve pair

Controls on the same after proxy: the same three-row conversation sent with x-headroom-bypass: true streams live (first byte at 0.80s, text deltas spread across the stream), and a request with nothing to compress (no hash, so no tool injected) streams live with the same event sequence as the base proxy

Hold-back pacing, measured on the same after proxy with a raw SSE client on a long held-back turn (a 2500 word story request declaring headroom_retrieve): headers and the first ping arrive at 0.55s, keepalive pings continue every 15s while the turn is held, and the buffered turn replays in a burst ending with message_stop at 38.4s (133 events, largest quiet gap 15.0s), so nothing in the path buffers past the ping interval

Disconnect during hold-back still bills: the same held-back request cut client-side at 8s (one ping received, zero content) lands in /spend/logs as a single row charging the key $0.00345 for the 575 prompt and 575 completion tokens the drain finished upstream after the client left

Type

🐛 Bug Fix

Caveats (if any)

Medium

Low

  • A hook crash or a rerun that changes nothing ends the turn on an SSE error, so the user retries
  • Nested reruns re-enter the same hold-back; a depth or fingerprint guard trip takes the SSE error path
  • The follow-up turn shares the first turn's request id, so /spend/logs keeps one row per request (the first turn's tokens) while key and team totals include both turns
  • A proxy that also injects keepalive pings (anthropic_sse_ping_interval_seconds) shows two ping events per 15s interval during a hold-back, which clients ignore

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/a11f814e7c18431fad858ea4e7953f0f
Requested by: @mateo-berri


Note

Medium Risk
Changes Anthropic streaming, agentic reruns, router fallback, and proxy spend/disconnect accounting on a hot path; mitigated by broad tests but hold-back defers time-to-first-token and only covers streaming /v1/messages.

Overview
Fixes streaming /v1/messages turns where server-side hooks (Headroom, compression interception) inject tools like headroom_retrieve or litellm_content_retrieve—the model’s tool_use was reaching clients that cannot run them, while the corrected answer only arrived after message_stop.

Callbacks now declare server_fulfilled_tool_names; when those tools are in the request, AgenticAnthropicStreamingIterator runs in hold-back mode: provider SSE is buffered, 15s SSE ping keepalives keep the connection alive, agentic hooks run, then the client gets the follow-up stream only (dropping the buffered tool message), a byte-identical replay if nothing intercepted, or an SSE error if a server-fulfilled tool_use would still leak (hook failure or no rerun). Requests without those tools keep live streaming.

Proxy and router behavior is aligned: shared keepalive ping constants; has_buffered_provider_output propagates through stream wrappers so disconnect handling treats pings as non-delivery (budget refund on ping-only cancel) but keeps reservations when real output was withheld; the router forwards a leading ping during hold-back and does not retry on the gateway’s retrieval-failure error frame.

Reviewed by Cursor Bugbot for commit 8d87798. Bugbot is set up for automated code reviews on this repo. Configure here.

…ools so retrieval tool calls never reach the client
@greptile-apps

greptile-apps Bot commented Aug 8, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

The PR prevents callback-owned Anthropic tool calls from escaping through streamed Messages responses and preserves the corrected response path through routing and proxy accounting.

  • Declares callback-owned tools and enables selective stream hold-back only when those tools are present.
  • Emits keepalive pings while draining the initial response, running agentic hooks, and waiting for follow-up chunks.
  • Propagates withheld-output state through wrappers for disconnect accounting.
  • Treats retrieval-failure frames as terminal gateway results rather than fallback candidates.
  • Adds focused coverage for buffering, hook failures, keepalives, routing, caching, and budget reservations.

Confidence Score: 5/5

The PR appears safe to merge.

No blocking failure remains; the previously reported keepalive gaps, hidden-tool replay, and terminal-error fallback behavior are addressed by the current code.

Important Files Changed

Filename Overview
litellm/llms/anthropic/experimental_pass_through/messages/agentic_streaming_iterator.py Implements held-back streaming, periodic keepalives, safe hook/follow-up task cleanup, and terminal handling that prevents server-owned tool calls from reaching clients.
litellm/llms/custom_httpx/llm_http_handler.py Detects callback-owned tools in Anthropic requests and enables hold-back only for affected streams.
litellm/router.py Forwards leading keepalives, preserves buffered-output state across fallback wrappers, and delivers retrieval failures without launching another deployment.
litellm/proxy/common_request_processing.py Distinguishes keepalive-only delivery from withheld provider output when reconciling reservations after disconnects.
litellm/integrations/custom_logger.py Adds the callback contract for declaring tools fulfilled by server-side agentic processing.
litellm/proxy/guardrails/guardrail_hooks/headroom/headroom.py Declares Headroom retrieval as server-fulfilled so affected Anthropic streams use hold-back.
litellm/integrations/compression_interception/handler.py Declares compression retrieval as server-fulfilled for the same protected streaming path.

Reviews (13): Last reviewed commit: "fix(caching): carry has_buffered_provide..." | Re-trigger Greptile

@codecov

codecov Bot commented Aug 8, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 99.28058% with 1 line in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
...ass_through/messages/agentic_streaming_iterator.py 98.90% 1 Missing ⚠️

📢 Thoughts on this report? Let us know!

@codspeed

codspeed Bot commented Aug 8, 2026

Copy link
Copy Markdown
Contributor

Merging this PR will not alter performance

✅ 31 untouched benchmarks


Comparing litellm_fix_headroom_stream_leak (8d87798) with litellm_internal_staging (ba8d8b6)1

Open in CodSpeed

Footnotes

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

… replaying server-fulfilled tool_use

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
@mateo-berri

Copy link
Copy Markdown
Contributor Author

@greptileai

…content expression

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
@devin-ai-integration

Copy link
Copy Markdown
Contributor

@greptileai keepalives now cover the hooks, failures emit an SSE error instead of replaying the tool_use, and the docstring is trimmed

@devin-ai-integration

Copy link
Copy Markdown
Contributor

Summary's second concern was legit too: f994068 now emits an SSE error instead of replaying a buffered server-fulfilled tool_use, so a hook crash cannot recreate the unknown-tool failure. A client-owned tool_use still replays verbatim.

@greptileai

@greptile-apps

greptile-apps Bot commented Aug 8, 2026

Copy link
Copy Markdown
Contributor

Option 1 (error on the whole message) is what's currently implemented. _buffer_holds_server_fulfilled_tool_use finds any server-fulfilled tool_use block in the buffer and _anext_held_back emits the error SSE unconditionally — it does not check whether client-owned tool_use blocks are also present.

Here's a concrete suggestion for option 2. It needs two changes:

1. Add a helper that rebuilds a filtered iterator (add after _buffer_holds_server_fulfilled_tool_use):

def _make_filtered_response_iterator(self) -> "AsyncIterator | None":
    """
    Rebuild the buffered response with server-fulfilled tool_use blocks stripped.
    Returns a FakeAnthropicMessagesStreamIterator over the filtered content,
    or None if stripping leaves no content blocks (pure server-fulfilled message).
    """
    rebuilt = self._rebuild_anthropic_response_from_sse(self._collected_bytes)
    if rebuilt is None:
        return None

    filtered_content = [
        block for block in rebuilt.get("content", [])
        if not (
            block.get("type") == "tool_use"
            and block.get("name") in self._server_fulfilled_tool_names
        )
    ]
    if not filtered_content:
        return None

    rebuilt["content"] = filtered_content
    # If every tool_use was stripped, the stop_reason is no longer "tool_use"
    if rebuilt.get("stop_reason") == "tool_use" and not any(
        b.get("type") == "tool_use" for b in filtered_content
    ):
        rebuilt["stop_reason"] = "end_turn"

    from litellm.llms.anthropic.experimental_pass_through.messages.fake_stream_iterator import (
        FakeAnthropicMessagesStreamIterator,
    )
    from litellm.types.llms.anthropic_messages.anthropic_response import AnthropicMessagesResponse

    return FakeAnthropicMessagesStreamIterator(
        response=cast(AnthropicMessagesResponse, rebuilt)
    ).__aiter__()

2. Replace the error block in _anext_held_back to try filtered replay first:

The existing block is:

        if self._buffer_holds_server_fulfilled_tool_use():
            if self._error_emitted:
                raise StopAsyncIteration
            self._error_emitted = True
            verbose_logger.error(
                "AgenticStreamingIterator: hooks did not replace a message containing a server-fulfilled "
                "tool_use [model=%s]; emitting an SSE error instead of leaking the tool call to the client",
                self._model,
            )
            return SERVER_FULFILLED_TOOL_LEAK_ERROR_SSE_BYTES

Replace with:

        if self._buffer_holds_server_fulfilled_tool_use():
            # Try to salvage the message by stripping server-fulfilled blocks
            # and replaying only client-owned content (mixed-tool case).
            filtered = self._make_filtered_response_iterator()
            if filtered is not None:
                self._follow_up_iterator = filtered
                return await self._follow_up_iterator.__anext__()
            # Nothing survives stripping — emit an error rather than leaking
            # the server-fulfilled tool_use to a client that cannot run it.
            if self._error_emitted:
                raise StopAsyncIteration
            self._error_emitted = True
            verbose_logger.error(
                "AgenticStreamingIterator: hooks did not replace a message containing a server-fulfilled "
                "tool_use [model=%s]; emitting an SSE error instead of leaking the tool call to the client",
                self._model,
            )
            return SERVER_FULFILLED_TOOL_LEAK_ERROR_SSE_BYTES

The key behavior changes:

  • Mixed-tool message (both headroom_retrieve and a client tool_use): strips the server-fulfilled block, fixes stop_reason if needed, and re-streams via FakeAnthropicMessagesStreamIterator. Subsequent __anext__ calls fall into the existing if self._follow_up_iterator is not None branch.
  • Pure server-fulfilled message: behavior unchanged — emits the SSE error.

The stop_reason handling covers both sub-cases correctly: if the server-fulfilled tool was the only tool_use but a text block remains, stop_reason becomes "end_turn"; if client-owned tool_use blocks remain, stop_reason stays "tool_use".

…in flight

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
@devin-ai-integration

Copy link
Copy Markdown
Contributor

Staying with option 1: rewriting stop_reason and dropping a block the model emitted silently changes semantics on an already degraded path, and headroom's loop covers the mixed case before we get there.

@greptileai keepalives now also wrap the follow-up stream in cbefb1c, with tests for slow follow-up chunks, follow-up errors, and cancellation on close

@veria-ai

veria-ai Bot commented Aug 8, 2026

Copy link
Copy Markdown
Contributor

PR overview

All previously flagged issues have been addressed. No open security concerns remain on this pull request.

Security review

No open security issues remain on this pull request.

Fixed/addressed: 2 · PR risk: 0/10

@devin-ai-integration

Copy link
Copy Markdown
Contributor

@greptileai please review the latest commit cbefb1c, which extends the keepalive loop over the follow-up stream

…ervation refund on client disconnect

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
@devin-ai-integration

Copy link
Copy Markdown
Contributor

Good catch, fixed in bb0bb48: a keepalive ping no longer counts as a delivered chunk, so a ping-only disconnect still reconciles the reservation.

@greptileai please review bb0bb48

Comment thread litellm/proxy/common_request_processing.py
…ider output is held back

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
@devin-ai-integration

Copy link
Copy Markdown
Contributor

Also fair, fixed in 2d1ee3a: a disconnect while the buffer already holds provider output keeps the reservation instead of reconciling to input cost.

@greptileai please review 2d1ee3a

@devin-ai-integration

Copy link
Copy Markdown
Contributor

🚅 Hi, thanks for the PR! I'm Agent Shin, the automated triage bot for this repository. What's this and why am I getting it?

I read the description against our contribution rubric. Here's how it lined up:

What you got right:

  • ✅ Clear problem description
  • ✅ Expected vs. actual behavior

What's still missing:

  • linked GitHub issue or explicit issue reference
  • end-to-end QA proof with real screenshot/video or commands plus real output

The body clearly explains the bug and expected vs. actual behavior, so context is present. However, the only QA evidence is pasted command text and narrative output without a real screenshot/video or verifiable command output, and there is no linked GitHub issue.

If the description isn't updated in the next 24 hours, I'll auto-close this PR. That's not us saying we don't care about the change; we want the open-PR list to mirror what a maintainer can act on right now, so contributors don't get lost in a backlog. A closed PR is a soft "park this for later," not a rejection. Take your time; everything below still works after the close.

During the grace period: just update the PR description with the missing pieces. No need to ping me; I'll re-check on the next sweep and skip the auto-close if it now passes. See what counts as QA proof for the full rubric (a linked issue alone isn't enough; it covers context, not proof).

If the PR does get auto-closed in 24 hours, you still have easy recovery paths:

  • Comment @agent-shin reconsider after updating the description. I'll re-evaluate and reopen the PR if it now passes.
  • Comment @greptileai to request a fresh Greptile review; that still works even after the PR is closed, and a stronger score is one of the signals that lifts the PR back into the queue. So a low Greptile score isn't a blocker either.

Internal BerriAI contributors: this rubric doesn't apply to you; ping a maintainer.

(I'm an LLM, so I'm not infallible. If you think I got this wrong, ping a maintainer; they'll override me.)

@mateo-berri

Copy link
Copy Markdown
Contributor Author

@greptileai

@mateo-berri

Copy link
Copy Markdown
Contributor Author

bugbot run

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Autofix Details

Bugbot Autofix prepared a fix for the issue found in the latest run.

  • ✅ Fixed: Withheld check misses wrapper type
    • Updated _withheld_provider_output to unwrap AnthropicMessagesStreamingResponse.completion_stream before the AgenticAnthropicStreamingIterator isinstance check, and updated the regression test to wrap the iterator like production so it fails without the fix.

Create PR

Or push these changes by commenting:

@cursor push 817c38842a
Preview (817c38842a)
diff --git a/litellm/proxy/common_request_processing.py b/litellm/proxy/common_request_processing.py
--- a/litellm/proxy/common_request_processing.py
+++ b/litellm/proxy/common_request_processing.py
@@ -51,6 +51,9 @@
 from litellm.llms.anthropic.experimental_pass_through.messages.agentic_streaming_iterator import (
     AgenticAnthropicStreamingIterator,
 )
+from litellm.llms.anthropic.experimental_pass_through.messages.streaming_iterator import (
+    AnthropicMessagesStreamingResponse,
+)
 from litellm.proxy._types import ProxyException, UserAPIKeyAuth
 from litellm.proxy.auth.auth_checks import can_key_call_resolved_model
 from litellm.proxy.auth.auth_utils import check_response_size_is_safe
@@ -207,7 +210,10 @@
 
 
 def _withheld_provider_output(response: object) -> bool:
-    return isinstance(response, AgenticAnthropicStreamingIterator) and response.has_buffered_provider_output
+    inner: Final = (
+        response.completion_stream if isinstance(response, AnthropicMessagesStreamingResponse) else response
+    )
+    return isinstance(inner, AgenticAnthropicStreamingIterator) and inner.has_buffered_provider_output
 
 
 def _should_return_raw_model_name(request_data: dict[str, object]) -> bool:

diff --git a/tests/test_litellm/proxy/test_budget_reservation.py b/tests/test_litellm/proxy/test_budget_reservation.py
--- a/tests/test_litellm/proxy/test_budget_reservation.py
+++ b/tests/test_litellm/proxy/test_budget_reservation.py
@@ -13,6 +13,10 @@
 from litellm.llms.anthropic.experimental_pass_through.messages.agentic_streaming_iterator import (
     AgenticAnthropicStreamingIterator,
 )
+from litellm.llms.anthropic.experimental_pass_through.messages.streaming_iterator import (
+    AnthropicMessagesStreamHiddenParams,
+    AnthropicMessagesStreamingResponse,
+)
 from litellm.proxy._types import (
     LiteLLM_BudgetTable,
     LiteLLM_EndUserTable,
@@ -2527,10 +2531,17 @@
         server_fulfilled_tool_names=frozenset({"headroom_retrieve"}),
         ping_interval_seconds=0.01,
     )
+    # Match production wiring: llm_http_handler wraps the agentic iterator in
+    # AnthropicMessagesStreamingResponse before handing it to the proxy stream
+    # generator. The withheld-output check must unwrap that to see the buffer.
+    wrapped_held_back = AnthropicMessagesStreamingResponse(
+        completion_stream=held_back,
+        hidden_params=AnthropicMessagesStreamHiddenParams(additional_headers={}),
+    )
 
     async def ping_then_cancel(user_api_key_dict, response, request_data):
         yield await response.__anext__()
-        while not response.has_buffered_provider_output:
+        while not response.completion_stream.has_buffered_provider_output:
             yield await response.__anext__()
         raise asyncio.CancelledError()
 
@@ -2538,7 +2549,7 @@
     streaming_logging_obj.async_post_call_streaming_iterator_hook = ping_then_cancel
     streaming_logging_obj._arelease_max_parallel_requests_on_disconnect = AsyncMock()
     generator = ProxyBaseLLMRequestProcessing.async_streaming_data_generator(
-        response=held_back,
+        response=wrapped_held_back,
         user_api_key_dict=valid_token,
         request_data=_request_body(),
         proxy_logging_obj=streaming_logging_obj,

You can send follow-ups to the cloud agent here.

Comment thread litellm/proxy/common_request_processing.py Outdated
…reaming response wrapper

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
@devin-ai-integration

Copy link
Copy Markdown
Contributor

@greptileai please review 1bc441c

bugbot run

…withheld-output flag through the stream wrappers

The router's pre-content ping filter dropped AgenticAnthropicStreamingIterator's
hold-back keepalive, so a held-back turn sent the client nothing until the buffer
settled. A ping that no lifecycle frame precedes is now forwarded live, since a
fallback's message_start can still follow it without overlapping lifecycles

The proxy's cancel-refund guard checked isinstance against the iterator, but the
proxy only ever sees it behind FallbackAwareAnthropicMessagesStream and
AnthropicMessagesStreamingResponse, so a disconnect during hold-back refunded the
budget reservation anyway. Both wrappers now forward a duck-typed
has_buffered_provider_output flag, and the router wrapper follows a fallback
source so the flag tracks the stream actually being consumed
@mateo-berri

Copy link
Copy Markdown
Contributor Author

@greptileai

…' into litellm_fix_headroom_stream_leak

# Conflicts:
#	litellm/proxy/common_request_processing.py
#	tests/test_litellm/proxy/test_budget_reservation.py
@mateo-berri

Copy link
Copy Markdown
Contributor Author

@greptileai

@devin-ai-integration

Copy link
Copy Markdown
Contributor

@greptileai please review 1aca5a9

bugbot run

@mateo-berri

Copy link
Copy Markdown
Contributor Author

@greptileai

@devin-ai-integration

Copy link
Copy Markdown
Contributor

@greptileai please review 64d8b24

bugbot run

@mateo-berri

Copy link
Copy Markdown
Contributor Author

bugbot run

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.

Autofix Details

Bugbot Autofix prepared a fix for the issue found in the latest run.

  • ✅ Fixed: Cache writer drops withheld flag
    • Added a has_buffered_provider_output property on AnthropicMessagesStreamCacheWriter that forwards the flag from its wrapped stream, so the router property no longer falls through to False when Anthropic Messages caching wraps the stream.

Create PR

Or push these changes by commenting:

@cursor push af8f25fdc4
Preview (af8f25fdc4)
diff --git a/litellm/llms/anthropic/experimental_pass_through/messages/response_cache.py b/litellm/llms/anthropic/experimental_pass_through/messages/response_cache.py
--- a/litellm/llms/anthropic/experimental_pass_through/messages/response_cache.py
+++ b/litellm/llms/anthropic/experimental_pass_through/messages/response_cache.py
@@ -46,6 +46,10 @@
             stream._hidden_params if isinstance(stream, AnthropicMessagesStreamingResponse) else _EMPTY_MAPPING
         )
 
+    @property
+    def has_buffered_provider_output(self) -> bool:
+        return getattr(self.stream, "has_buffered_provider_output", False) is True
+
     def __aiter__(self) -> "AnthropicMessagesStreamCacheWriter":
         return self
 

diff --git a/tests/test_litellm/llms/anthropic/experimental_pass_through/messages/test_response_cache.py b/tests/test_litellm/llms/anthropic/experimental_pass_through/messages/test_response_cache.py
--- a/tests/test_litellm/llms/anthropic/experimental_pass_through/messages/test_response_cache.py
+++ b/tests/test_litellm/llms/anthropic/experimental_pass_through/messages/test_response_cache.py
@@ -262,3 +262,37 @@
         await asyncio.sleep(0)
 
     mock_route.assert_called_once()
+
+
+def test_cache_writer_forwards_has_buffered_provider_output():
+    """The cache writer sits between the provider stream and the router, so
+    it must forward `has_buffered_provider_output` or disconnect billing on
+    ping-only streams incorrectly refunds withheld provider tokens."""
+    from litellm.llms.anthropic.experimental_pass_through.messages.response_cache import (
+        AnthropicMessagesStreamCacheWriter,
+    )
+
+    class _HoldingBack:
+        has_buffered_provider_output = True
+
+        def __aiter__(self):
+            return self
+
+        async def __anext__(self) -> bytes:
+            raise StopAsyncIteration
+
+    class _NotHoldingBack:
+        def __aiter__(self):
+            return self
+
+        async def __anext__(self) -> bytes:
+            raise StopAsyncIteration
+
+    assert (
+        AnthropicMessagesStreamCacheWriter(stream=_HoldingBack(), caching_handler=None).has_buffered_provider_output
+        is True
+    )
+    assert (
+        AnthropicMessagesStreamCacheWriter(stream=_NotHoldingBack(), caching_handler=None).has_buffered_provider_output
+        is False
+    )

You can send follow-ups to the cloud agent here.

Comment thread litellm/router.py
@mateo-berri

Copy link
Copy Markdown
Contributor Author

@greptileai

@devin-ai-integration

Copy link
Copy Markdown
Contributor

@greptileai please review 8d87798

bugbot run

@mateo-berri

Copy link
Copy Markdown
Contributor Author

bugbot run

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

✅ Bugbot reviewed your changes and found no new issues!

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

Reviewed by Cursor Bugbot for commit 8d87798. Configure here.

@mateo-berri
mateo-berri enabled auto-merge August 26, 2026 00:47
@mateo-berri
mateo-berri merged commit d0c527f into litellm_internal_staging Aug 26, 2026
83 checks passed
@mateo-berri
mateo-berri deleted the litellm_fix_headroom_stream_leak branch August 26, 2026 00:48
doonga pushed a commit to greyrock-labs/home-ops that referenced this pull request Sep 6, 2026
…00.0) (#124)

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.99.1` → `v1.100.0` |

---

### Release Notes

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

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

[Compare Source](https://github.com/BerriAI/litellm/compare/v1.99.1...v1.100.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.100.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.100.0/cosign.pub \
  ghcr.io/berriai/litellm:v1.100.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

- fix(responses): keep the conversation when chaining previous\_response\_id on the bridge by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;37956](https://github.com/BerriAI/litellm/pull/37956)
- feat(newrelic): per-team New Relic trace routing via team callbacks by [@&#8203;yucheng-berri](https://github.com/yucheng-berri) in [#&#8203;37603](https://github.com/BerriAI/litellm/pull/37603)
- perf(ci): cache uv dependencies in the lint job by [@&#8203;yuneng-berri](https://github.com/yuneng-berri) in [#&#8203;37783](https://github.com/BerriAI/litellm/pull/37783)
- perf(ci): fan the budget checkers out across cores by [@&#8203;yuneng-berri](https://github.com/yuneng-berri) in [#&#8203;37784](https://github.com/BerriAI/litellm/pull/37784)
- ci: port the Postgres suites off CircleCI onto service containers by [@&#8203;yuneng-berri](https://github.com/yuneng-berri) in [#&#8203;37785](https://github.com/BerriAI/litellm/pull/37785)
- feat(ci): gate patching of SDK internals in tests as TQ008 by [@&#8203;yuneng-berri](https://github.com/yuneng-berri) in [#&#8203;37787](https://github.com/BerriAI/litellm/pull/37787)
- ci: measure enterprise/ coverage by [@&#8203;yuneng-berri](https://github.com/yuneng-berri) in [#&#8203;37788](https://github.com/BerriAI/litellm/pull/37788)
- ci: run the keyless caching tests that ran in no job by [@&#8203;yuneng-berri](https://github.com/yuneng-berri) in [#&#8203;37790](https://github.com/BerriAI/litellm/pull/37790)
- fix(ci): run the migration DDL guard, and stop it reading comments as SQL by [@&#8203;yuneng-berri](https://github.com/yuneng-berri) in [#&#8203;37791](https://github.com/BerriAI/litellm/pull/37791)
- ci: run the enterprise package suite in GitHub Actions by [@&#8203;yuneng-berri](https://github.com/yuneng-berri) in [#&#8203;37798](https://github.com/BerriAI/litellm/pull/37798)
- perf(ci): give the two longest unit shards the runner's spare cores by [@&#8203;yuneng-berri](https://github.com/yuneng-berri) in [#&#8203;37804](https://github.com/BerriAI/litellm/pull/37804)
- test(exception-mapping): pin the status and error-shape table every provider maps to by [@&#8203;yuneng-berri](https://github.com/yuneng-berri) in [#&#8203;37807](https://github.com/BerriAI/litellm/pull/37807)
- fix(terraform): add soft\_budget, tags, and soft\_budget\_alerting\_emails to litellm\_team by [@&#8203;yuneng-berri](https://github.com/yuneng-berri) in [#&#8203;37918](https://github.com/BerriAI/litellm/pull/37918)
- fix(ui): theme the created-key box so it follows dark mode by [@&#8203;yuneng-berri](https://github.com/yuneng-berri) in [#&#8203;37985](https://github.com/BerriAI/litellm/pull/37985)
- fix(ui): restore the public model name tooltip layout in the add model flow by [@&#8203;yuneng-berri](https://github.com/yuneng-berri) in [#&#8203;37986](https://github.com/BerriAI/litellm/pull/37986)
- fix(ui): render team and org tpm/rpm limits of 0 as 0 instead of Unlimited by [@&#8203;yuneng-berri](https://github.com/yuneng-berri) in [#&#8203;37916](https://github.com/BerriAI/litellm/pull/37916)
- fix(ui): repoint the key detail URL to the rotated hash after regenerating by [@&#8203;yuneng-berri](https://github.com/yuneng-berri) in [#&#8203;37968](https://github.com/BerriAI/litellm/pull/37968)
- fix(ui): make playground chat bubbles theme-aware by [@&#8203;yuneng-berri](https://github.com/yuneng-berri) in [#&#8203;37978](https://github.com/BerriAI/litellm/pull/37978)
- fix(UI): correct skill install command and marketplace setup UX by [@&#8203;ozolam](https://github.com/ozolam) in [#&#8203;33514](https://github.com/BerriAI/litellm/pull/33514)
- fix(proxy): skip health checks for strategy routers by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;37966](https://github.com/BerriAI/litellm/pull/37966)
- fix(databricks): bill cached tokens at cache rates and add missing Claude pricing by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;37975](https://github.com/BerriAI/litellm/pull/37975)
- fix(anthropic): round-trip thinking blocks to OpenAI backends on /v1/messages by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;37953](https://github.com/BerriAI/litellm/pull/37953)
- fix(a2a): normalize agent card protocolBinding casing before transport match by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;37917](https://github.com/BerriAI/litellm/pull/37917)
- fix(interactions): track cost and spend for Google Interactions API requests by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;33310](https://github.com/BerriAI/litellm/pull/33310)
- fix(bedrock): stop emitting an empty assistant delta after the finish\_reason chunk by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;36806](https://github.com/BerriAI/litellm/pull/36806)
- fix(anthropic): reconcile enum with declared type in output\_format schema by [@&#8203;dkindlund](https://github.com/dkindlund) in [#&#8203;37882](https://github.com/BerriAI/litellm/pull/37882)
- feat(azure\_ai): support entra id / oauth auth on every azure ai foundry route by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;35415](https://github.com/BerriAI/litellm/pull/35415)
- fix(ui): boot the UI image as an arbitrary uid by anchoring nginx writes under /tmp by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;37982](https://github.com/BerriAI/litellm/pull/37982)
- fix(proxy): parse form-encoded video edit/extension bodies after auth by [@&#8203;Souravrajvi0](https://github.com/Souravrajvi0) in [#&#8203;36513](https://github.com/BerriAI/litellm/pull/36513)
- fix(anthropic): keep legacy thinking budget\_tokens on Claude 4.6 models on /v1/messages by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;38108](https://github.com/BerriAI/litellm/pull/38108)
- fix(utils): make prompt\_token\_calculator count claude models again by [@&#8203;ryan-crabbe-berri](https://github.com/ryan-crabbe-berri) in [#&#8203;38130](https://github.com/BerriAI/litellm/pull/38130)
- fix(proxy): keep every value of a repeated form key, and gate the tests that hid it by [@&#8203;ryan-crabbe-berri](https://github.com/ryan-crabbe-berri) in [#&#8203;37908](https://github.com/BerriAI/litellm/pull/37908)
- fix(health): apply model\_info.health\_check\_params to health check probes by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;38101](https://github.com/BerriAI/litellm/pull/38101)
- fix(runwayml): route every generation endpoint and fix video cost tracking by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;38115](https://github.com/BerriAI/litellm/pull/38115)
- fix(passthrough): attribute spend and release budget reservation on router-model /vllm and /azure routes by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;38111](https://github.com/BerriAI/litellm/pull/38111)
- fix: match OpenAI SDK wire format on image/video routes by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;38104](https://github.com/BerriAI/litellm/pull/38104)
- fix(ci): give three unit shards a job deadline that outlasts their pytest budget by [@&#8203;tin-berri](https://github.com/tin-berri) in [#&#8203;38139](https://github.com/BerriAI/litellm/pull/38139)
- feat(ui): add Gemini Family auto-router preset by [@&#8203;tin-berri](https://github.com/tin-berri) in [#&#8203;38138](https://github.com/BerriAI/litellm/pull/38138)
- fix(logging\_worker): carry queued tasks across event-loop change instead of dropping them by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;38144](https://github.com/BerriAI/litellm/pull/38144)
- feat(proxy): enforce vector-store upload security controls on /v1/rag/ingest by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;38135](https://github.com/BerriAI/litellm/pull/38135)
- test(e2e): pin require\_managed\_files enforcement behind a marker-gated stack phase by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;38117](https://github.com/BerriAI/litellm/pull/38117)
- refactor(ui): move the dashboard onto class-variance-authority by [@&#8203;yuneng-berri](https://github.com/yuneng-berri) in [#&#8203;38125](https://github.com/BerriAI/litellm/pull/38125)
- refactor(utils)!: delete prompt\_token\_calculator by [@&#8203;ryan-crabbe-berri](https://github.com/ryan-crabbe-berri) in [#&#8203;38132](https://github.com/BerriAI/litellm/pull/38132)
- fix(auto-router): list configured auto-routers in the usage picker before they have traffic by [@&#8203;tin-berri](https://github.com/tin-berri) in [#&#8203;38129](https://github.com/BerriAI/litellm/pull/38129)
- refactor(ui): install the shadcn field primitive by [@&#8203;yuneng-berri](https://github.com/yuneng-berri) in [#&#8203;38126](https://github.com/BerriAI/litellm/pull/38126)
- fix(complexity\_router): keep both ends of a clipped classifier context turn by [@&#8203;tin-berri](https://github.com/tin-berri) in [#&#8203;38141](https://github.com/BerriAI/litellm/pull/38141)
- fix(ci): ignore-list recursive form-field flatteners in recursive\_detector by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;38149](https://github.com/BerriAI/litellm/pull/38149)
- fix(passthrough): stop leaking the caller's virtual key on credential-less Vertex passthrough by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;38114](https://github.com/BerriAI/litellm/pull/38114)
- fix(router): stop copying forwarded credentials into retry breadcrumbs by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;38133](https://github.com/BerriAI/litellm/pull/38133)
- feat(e2e): record and replay streamed provider responses chunk-for-chunk by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;38136](https://github.com/BerriAI/litellm/pull/38136)
- fix: tolerate stream chunks without a choices key in stream\_chunk\_builder by [@&#8203;AkshaySasi](https://github.com/AkshaySasi) in [#&#8203;34382](https://github.com/BerriAI/litellm/pull/34382)
- fix(files): decode x-litellm-model encoded file\_id in chat + responses by [@&#8203;hclsys](https://github.com/hclsys) in [#&#8203;29832](https://github.com/BerriAI/litellm/pull/29832)
- fix(videos): forward uploaded source file on /v1/videos/edits to the provider by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;38155](https://github.com/BerriAI/litellm/pull/38155)
- fix(s3\_v2): percent-encode object keys once so signed and sent URLs match by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;38005](https://github.com/BerriAI/litellm/pull/38005)
- feat(ui): add error-code drilldown for failed requests on caching page by [@&#8203;ryan-crabbe-berri](https://github.com/ryan-crabbe-berri) in [#&#8203;38156](https://github.com/BerriAI/litellm/pull/38156)
- feat(search): add Grounding with Bing Search (bing\_grounding) as a search provider by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;38119](https://github.com/BerriAI/litellm/pull/38119)
- ci: ban row-rewriting DML from prisma migrations by [@&#8203;yucheng-berri](https://github.com/yucheng-berri) in [#&#8203;37899](https://github.com/BerriAI/litellm/pull/37899)
- fix(langsmith): keep root-run ids self-consistent so batch ingest stops rejecting header-tagged requests by [@&#8203;yucheng-berri](https://github.com/yucheng-berri) in [#&#8203;38116](https://github.com/BerriAI/litellm/pull/38116)
- ci(e2e): record the e2e suite weekly and replay it on weekdays with zero egress by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;38163](https://github.com/BerriAI/litellm/pull/38163)
- chore(codeowners): unown ui container plumbing and generated files by [@&#8203;ryan-crabbe-berri](https://github.com/ryan-crabbe-berri) in [#&#8203;38124](https://github.com/BerriAI/litellm/pull/38124)
- fix(logging): skip parsing redacted tool call arguments by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;38169](https://github.com/BerriAI/litellm/pull/38169)
- feat(complexity\_router): bound the classifier context block, not each turn in it by [@&#8203;tin-berri](https://github.com/tin-berri) in [#&#8203;38145](https://github.com/BerriAI/litellm/pull/38145)
- fix(http\_handler): dispose aiohttp session when AsyncHTTPHandler is finalized without a running loop by [@&#8203;anmolg1997](https://github.com/anmolg1997) in [#&#8203;36670](https://github.com/BerriAI/litellm/pull/36670)
- fix(proxy): reset a stuck team member's budget by [@&#8203;yassin-berriai](https://github.com/yassin-berriai) in [#&#8203;37971](https://github.com/BerriAI/litellm/pull/37971)
- fix(anthropic/bedrock): request summarized adaptive thinking for reasoning\_effort and use provider thinking token counts by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;37979](https://github.com/BerriAI/litellm/pull/37979)
- fix(completion\_extras): forward reasoning\_effort=max through the Responses API bridge by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;38222](https://github.com/BerriAI/litellm/pull/38222)
- feat(vertex\_ai): add native Vertex AI Interactions API support by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;38229](https://github.com/BerriAI/litellm/pull/38229)
- test(mcp): drain the logging worker after each test so queued callbacks cannot leak into the next test by [@&#8203;ryan-crabbe-berri](https://github.com/ryan-crabbe-berri) in [#&#8203;38228](https://github.com/BerriAI/litellm/pull/38228)
- fix(ui): forward OAuth issuer/authorization/token/registration URLs from the MCP server edit form by [@&#8203;yassin-berriai](https://github.com/yassin-berriai) in [#&#8203;38154](https://github.com/BerriAI/litellm/pull/38154)
- fix(together\_ai): default endpoints to api.together.ai instead of api.together.xyz by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;38233](https://github.com/BerriAI/litellm/pull/38233)
- fix(bedrock\_mantle): register a Bedrock runtime passthrough config so /bedrock/model/<deployment>/invoke works by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;38231](https://github.com/BerriAI/litellm/pull/38231)
- fix(router): resolve provider from api\_base in deployment validation and acompletion by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;38235](https://github.com/BerriAI/litellm/pull/38235)
- fix(model\_prices): raise bedrock\_mantle gpt-5.6 max\_input\_tokens to Mantle's enforced [`1050000`](https://github.com/BerriAI/litellm/commit/1050000) by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;38225](https://github.com/BerriAI/litellm/pull/38225)
- fix(bedrock\_mantle): normalize Codex input item types Mantle rejects by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;38227](https://github.com/BerriAI/litellm/pull/38227)
- fix(proxy): store the actual selected model in spend logs for Azure Model Router by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;37770](https://github.com/BerriAI/litellm/pull/37770)
- feat(router): per-group supported reasoning efforts with the max level by [@&#8203;tin-berri](https://github.com/tin-berri) in [#&#8203;37897](https://github.com/BerriAI/litellm/pull/37897)
- fix(proxy): stop expected 4xx responses from saturating worker CPU on failure logging by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;38102](https://github.com/BerriAI/litellm/pull/38102)
- fix(caching): use upstream RedisCluster on redis-py with per-connection recovery by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;38171](https://github.com/BerriAI/litellm/pull/38171)
- perf(auth): drop guaranteed-miss internal-cache Redis read from team object lookup by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;38073](https://github.com/BerriAI/litellm/pull/38073)
- fix(together\_ai): route chat completions through a dedicated TogetherAIChatConfig by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;38248](https://github.com/BerriAI/litellm/pull/38248)
- fix(ui): read reasoning tokens from Responses API output\_tokens\_details by [@&#8203;yassin-berriai](https://github.com/yassin-berriai) in [#&#8203;37952](https://github.com/BerriAI/litellm/pull/37952)
- fix(dashboard): don't show a stale provider prompt-cache chip on a response-cache hit by [@&#8203;yassin-berriai](https://github.com/yassin-berriai) in [#&#8203;37951](https://github.com/BerriAI/litellm/pull/37951)
- fix(ui): render tag-based guardrail mode instead of crashing the guardrails page by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;37493](https://github.com/BerriAI/litellm/pull/37493)
- fix(scim): return user\_id as Group members\[].value on transformed group responses by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;38161](https://github.com/BerriAI/litellm/pull/38161)
- fix(scim): preserve existing team memberships when POST /Users adoption carries no groups by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;38166](https://github.com/BerriAI/litellm/pull/38166)
- fix(router): support mid-stream fallback for anthropic\_messages route type by [@&#8203;yassin-berriai](https://github.com/yassin-berriai) in [#&#8203;38153](https://github.com/BerriAI/litellm/pull/38153)
- fix(auth): support wildcard prefixes in jwt team\_allowed\_routes by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;37756](https://github.com/BerriAI/litellm/pull/37756)
- feat(models): add missing Together AI serverless models to the cost map by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;38230](https://github.com/BerriAI/litellm/pull/38230)
- fix(cerebras)!: add max\_retries and extra\_headers to get\_supported\_openai\_params by [@&#8203;deepanshululla](https://github.com/deepanshululla) in [#&#8203;36601](https://github.com/BerriAI/litellm/pull/36601)
- fix(anthropic): translate tool\_result document blocks in the /v1/messages bridge by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;38251](https://github.com/BerriAI/litellm/pull/38251)
- fix(team): serialize member\_add, member\_delete, and delete under the team's advisory lock by [@&#8203;yassin-berriai](https://github.com/yassin-berriai) in [#&#8203;37969](https://github.com/BerriAI/litellm/pull/37969)
- docs(pr-template): split Caveats bullets into severity tiers and call for plain engineering language by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;38252](https://github.com/BerriAI/litellm/pull/38252)
- fix(anthropic): carry tool\_result document blocks through the /v1/messages responses bridge by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;38261](https://github.com/BerriAI/litellm/pull/38261)
- fix(together\_ai): pass tools through for models missing from the registry by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;38265](https://github.com/BerriAI/litellm/pull/38265)
- fix(anthropic): carry user-content document blocks through the /v1/messages responses bridge by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;38267](https://github.com/BerriAI/litellm/pull/38267)
- fix(rerank): emit latency and cost headers on /rerank by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;35419](https://github.com/BerriAI/litellm/pull/35419)
- perf(streaming): add shared JSONFragmentAccumulator for Vertex and Anthropic by [@&#8203;deepanshululla](https://github.com/deepanshululla) in [#&#8203;36610](https://github.com/BerriAI/litellm/pull/36610)
- fix(together\_ai): strip internal thinking fields from outbound messages, keep reasoning\_content by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;38275](https://github.com/BerriAI/litellm/pull/38275)
- fix(router): persist attempted\_fallbacks and original\_model\_group into spend logs metadata by [@&#8203;yucheng-berri](https://github.com/yucheng-berri) in [#&#8203;38107](https://github.com/BerriAI/litellm/pull/38107)
- fix(logging): redact tool call arguments to valid JSON and preserve null content by [@&#8203;yucheng-berri](https://github.com/yucheng-berri) in [#&#8203;38182](https://github.com/BerriAI/litellm/pull/38182)
- fix(ui): stack policy flow builder below the popup layer so guardrail options render by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;38273](https://github.com/BerriAI/litellm/pull/38273)
- test: gate the test tree on B003 so a test cannot swap os.environ for a plain dict by [@&#8203;ryan-crabbe-berri](https://github.com/ryan-crabbe-berri) in [#&#8203;38274](https://github.com/BerriAI/litellm/pull/38274)
- refactor(repositories): type prisma table access with one generic protocol by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;38205](https://github.com/BerriAI/litellm/pull/38205)
- fix(anthropic): buffer streamed responses carrying server-fulfilled tools so retrieval tool calls never reach the client by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;36245](https://github.com/BerriAI/litellm/pull/36245)
- test(together\_ai): regression suite across chat, responses, and messages surfaces by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;38283](https://github.com/BerriAI/litellm/pull/38283)
- feat(logging): add async\_post\_call\_failure\_deployment\_hook by [@&#8203;deepanshululla](https://github.com/deepanshululla) in [#&#8203;36657](https://github.com/BerriAI/litellm/pull/36657)
- chore: bump litellm-enterprise 0.1.59 -> 0.1.60, litellm 1.99.0 -> 1.100.0 by [@&#8203;yuneng-berri](https://github.com/yuneng-berri) in [#&#8203;38243](https://github.com/BerriAI/litellm/pull/38243)
- test(e2e): cover Together AI reasoning, tool calls, template kwargs, and cost through a live proxy by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;38286](https://github.com/BerriAI/litellm/pull/38286)
- fix(logging): keep tracebacks for provider-originated 4xx errors by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;38296](https://github.com/BerriAI/litellm/pull/38296)
- chore(ci): promote internal staging to main by [@&#8203;yuneng-berri](https://github.com/yuneng-berri) in [#&#8203;38293](https://github.com/BerriAI/litellm/pull/38293)
- refactor(ui): install the shadcn alert primitive by [@&#8203;yuneng-berri](https://github.com/yuneng-berri) in [#&#8203;38300](https://github.com/BerriAI/litellm/pull/38300)
- refactor(ui): re-pull label, textarea, separator and skeleton from the registry by [@&#8203;yuneng-berri](https://github.com/yuneng-berri) in [#&#8203;38302](https://github.com/BerriAI/litellm/pull/38302)
- feat(prometheus): configure deployment caller identity by [@&#8203;mphilippnv](https://github.com/mphilippnv) in [#&#8203;38221](https://github.com/BerriAI/litellm/pull/38221)
- test(e2e): let the Together replayed-reasoning case survive a single provider miss by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;38314](https://github.com/BerriAI/litellm/pull/38314)
- fix(otel): map /v1/messages provider errors before failure logging by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;38310](https://github.com/BerriAI/litellm/pull/38310)
- fix(exceptions): map upstream status codes for providers with no exception\_type branch by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;38318](https://github.com/BerriAI/litellm/pull/38318)
- fix(passthrough): record ownership of streamed responses under managed ids by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;38320](https://github.com/BerriAI/litellm/pull/38320)
- fix(proxy): encrypt streamed responses ids on /openai/v1/responses and /responses aliases by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;38325](https://github.com/BerriAI/litellm/pull/38325)
- test(cost-calc): pin the rate fallbacks inside a tiered-pricing tier by [@&#8203;yuneng-berri](https://github.com/yuneng-berri) in [#&#8203;38327](https://github.com/BerriAI/litellm/pull/38327)
- test(e2e): cover the Bedrock provider-feature cells customers run by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;38232](https://github.com/BerriAI/litellm/pull/38232)
- fix(together\_ai): fail open on response\_format instead of dropping it for unregistered models by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;38269](https://github.com/BerriAI/litellm/pull/38269)
- fix(proxy): honor DATABASE\_DISABLE\_PREPARED\_STATEMENTS in componentized entrypoints by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;38363](https://github.com/BerriAI/litellm/pull/38363)
- fix(anthropic-responses): preserve structured output strictness by [@&#8203;eugene-yao-zocdoc](https://github.com/eugene-yao-zocdoc) in [#&#8203;38211](https://github.com/BerriAI/litellm/pull/38211)
- chore(typing): roll up the daily tech debt cleanups from Aug 20 to Aug 26 by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;37922](https://github.com/BerriAI/litellm/pull/37922)
- fix(router): resolve hidden aliases for explicit lookup by [@&#8203;daniel-meismer-zocdoc](https://github.com/daniel-meismer-zocdoc) in [#&#8203;38272](https://github.com/BerriAI/litellm/pull/38272)
- fix(ui): keep focus in the add model public name input while typing by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;38366](https://github.com/BerriAI/litellm/pull/38366)
- fix(model\_prices): price 1-hour cache writes on claude-3-haiku and claude-3-opus at 2x input by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;38371](https://github.com/BerriAI/litellm/pull/38371)
- fix(proxy): keep the caller's Google token on credential-less Vertex passthrough under custom auth by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;38299](https://github.com/BerriAI/litellm/pull/38299)
- fix(mcp): preserve provider access token lifetime by [@&#8203;daniel-meismer-zocdoc](https://github.com/daniel-meismer-zocdoc) in [#&#8203;38271](https://github.com/BerriAI/litellm/pull/38271)
- chore(ui): remove stale "New" badges from the dashboard by [@&#8203;yuneng-berri](https://github.com/yuneng-berri) in [#&#8203;38374](https://github.com/BerriAI/litellm/pull/38374)
- test(cost-estimate): pin the prices and period totals /cost/estimate returns by [@&#8203;yuneng-berri](https://github.com/yuneng-berri) in [#&#8203;38315](https://github.com/BerriAI/litellm/pull/38315)
- fix(ci): let the mutation workflow find covered lines so it generates mutants by [@&#8203;yuneng-berri](https://github.com/yuneng-berri) in [#&#8203;38305](https://github.com/BerriAI/litellm/pull/38305)
- fix(model\_prices): raise bedrock\_mantle gpt-5.5 and gpt-5.4 max\_input\_tokens to Mantle's enforced [`1050000`](https://github.com/BerriAI/litellm/commit/1050000) by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;38368](https://github.com/BerriAI/litellm/pull/38368)
- fix(azure/realtime): authenticate realtime websocket with Azure AD token when no api-key by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;34658](https://github.com/BerriAI/litellm/pull/34658)
- fix(bedrock): map reasoning\_effort to reasoning.effort for OpenAI GPT-5.x on Converse by [@&#8203;6matt](https://github.com/6matt) in [#&#8203;38279](https://github.com/BerriAI/litellm/pull/38279)
- test(prometheus): cover caller-identity config failure cases by [@&#8203;yucheng-berri](https://github.com/yucheng-berri) in [#&#8203;38380](https://github.com/BerriAI/litellm/pull/38380)
- fix(redis): support credential providers across clients by [@&#8203;eugene-yao-zocdoc](https://github.com/eugene-yao-zocdoc) in [#&#8203;38094](https://github.com/BerriAI/litellm/pull/38094)
- fix(health): support `mode: image_edit` in health checks by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;38291](https://github.com/BerriAI/litellm/pull/38291)
- fix(cost-map): add US data residency uplift to claude-sonnet-4-6 and mythos entries by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;38369](https://github.com/BerriAI/litellm/pull/38369)
- fix(anthropic): raise missing-credential error on /v1/messages passthrough by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;38240](https://github.com/BerriAI/litellm/pull/38240)
- fix(mcp): complete DCR bridge OAuth challenges by [@&#8203;daniel-meismer-zocdoc](https://github.com/daniel-meismer-zocdoc) in [#&#8203;37384](https://github.com/BerriAI/litellm/pull/37384)
- test(proxy): pin the request-validation contracts in proxy/\_types.py by [@&#8203;yuneng-berri](https://github.com/yuneng-berri) in [#&#8203;38307](https://github.com/BerriAI/litellm/pull/38307)
- docs(CLAUDE.md): add pull-before-work rule by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;38386](https://github.com/BerriAI/litellm/pull/38386)
- fix(anthropic): scale cache costs by fast mode and trust served speed by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;38378](https://github.com/BerriAI/litellm/pull/38378)
- fix(pricing): add azure gpt-5.6 cache write rates and correct data zone priority by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;38370](https://github.com/BerriAI/litellm/pull/38370)
- docs: tighten the pull-before-work rule in CLAUDE.md by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;38389](https://github.com/BerriAI/litellm/pull/38389)
- fix(health): strip credential fields from GET /health output by [@&#8203;Siraj637909](https://github.com/Siraj637909) in [#&#8203;37090](https://github.com/BerriAI/litellm/pull/37090)
- fix(minimax): attach MINIMAX\_API\_KEY on anthropic messages requests by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;38393](https://github.com/BerriAI/litellm/pull/38393)
- refactor(ui): replace hand-picked z-index values with one named scale and lint it by [@&#8203;ryan-crabbe-berri](https://github.com/ryan-crabbe-berri) in [#&#8203;38282](https://github.com/BerriAI/litellm/pull/38282)
- fix(health): probe Azure GA realtime path for transcription-only models by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;38390](https://github.com/BerriAI/litellm/pull/38390)
- fix(bedrock): parse cacheDetails for Converse 1h/5m cache write cost split by [@&#8203;danielva-monday](https://github.com/danielva-monday) in [#&#8203;36762](https://github.com/BerriAI/litellm/pull/36762)
- fix(caching): flush async cache writes cancelled at event loop shutdown by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;38385](https://github.com/BerriAI/litellm/pull/38385)
- fix(router): resolve model\_group\_alias before pre-routing strategy dispatch by [@&#8203;tin-berri](https://github.com/tin-berri) in [#&#8203;38382](https://github.com/BerriAI/litellm/pull/38382)
- feat(proxy): enforce rpm/tpm on model add + fix validation error title in UI by [@&#8203;kunal2002](https://github.com/kunal2002) in [#&#8203;36518](https://github.com/BerriAI/litellm/pull/36518)
- refactor(ui): move every page header onto the shared PageHeader by [@&#8203;yuneng-berri](https://github.com/yuneng-berri) in [#&#8203;38306](https://github.com/BerriAI/litellm/pull/38306)
- fix(proxy): stop cache eviction errors from failing /key/update by [@&#8203;yuneng-berri](https://github.com/yuneng-berri) in [#&#8203;38308](https://github.com/BerriAI/litellm/pull/38308)
- fix(aiohttp): honor global ssl\_verify on the aiohttp\_openai handler path by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;38400](https://github.com/BerriAI/litellm/pull/38400)
- fix(logging\_worker): rescue dequeued logging tasks lost at event loop close by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;38394](https://github.com/BerriAI/litellm/pull/38394)
- fix(caching): require the namespace delimiter when checking already-namespaced redis keys by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;38403](https://github.com/BerriAI/litellm/pull/38403)
- fix(prompts): reject keyed prompt\_data with prompt\_id and populate prompt version by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;38404](https://github.com/BerriAI/litellm/pull/38404)
- fix(cost\_calculator): resolve real cost key when model\_name alias contains '/' by [@&#8203;ksk2023](https://github.com/ksk2023) in [#&#8203;38344](https://github.com/BerriAI/litellm/pull/38344)
- fix(cost-map): correct prompt\_cache\_min\_tokens for Claude Fable 5 and backfill Anthropic re-export entries by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;38405](https://github.com/BerriAI/litellm/pull/38405)
- test(azure-ai): pin the 422 retry that drops the field the provider rejected by [@&#8203;yuneng-berri](https://github.com/yuneng-berri) in [#&#8203;38309](https://github.com/BerriAI/litellm/pull/38309)
- refactor(ui): read the auto-router tier set through one row list by [@&#8203;tin-berri](https://github.com/tin-berri) in [#&#8203;38408](https://github.com/BerriAI/litellm/pull/38408)
- fix(proxy): stop empty DB router\_settings lists from clobbering yaml fallbacks by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;38406](https://github.com/BerriAI/litellm/pull/38406)
- fix(team): allow no-reset default budgets for team members by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;37708](https://github.com/BerriAI/litellm/pull/37708)
- fix: forward image content lists to DeepSeek vision models by [@&#8203;yucheng-berri](https://github.com/yucheng-berri) in [#&#8203;38397](https://github.com/BerriAI/litellm/pull/38397)
- fix(fireworks\_ai): stop using the trace id as the session affinity key by [@&#8203;Hamjaster](https://github.com/Hamjaster) in [#&#8203;35754](https://github.com/BerriAI/litellm/pull/35754)
- fix(gemini-realtime): keep the client's voice on Vertex AI native-audio Live by [@&#8203;yucheng-berri](https://github.com/yucheng-berri) in [#&#8203;38395](https://github.com/BerriAI/litellm/pull/38395)
- fix(vertex\_ai): bill Gemini grounding per unique web search query by [@&#8203;ousamabenyounes](https://github.com/ousamabenyounes) in [#&#8203;36397](https://github.com/BerriAI/litellm/pull/36397)
- fix(health): make the image\_edit health probe moderation-safe by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;38417](https://github.com/BerriAI/litellm/pull/38417)
- test: gate the test tree on fifteen assertion and handler rules it already satisfies by [@&#8203;ryan-crabbe-berri](https://github.com/ryan-crabbe-berri) in [#&#8203;38361](https://github.com/BerriAI/litellm/pull/38361)
- fix(proxy): key lazy openapi stubs off registered features, not sys.modules by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;38416](https://github.com/BerriAI/litellm/pull/38416)
- fix(proxy): derive auto-router health from its underlying models by [@&#8203;tin-berri](https://github.com/tin-berri) in [#&#8203;38174](https://github.com/BerriAI/litellm/pull/38174)
- fix(responses): let cache-control injection reach the system prompt from instructions by [@&#8203;tin-berri](https://github.com/tin-berri) in [#&#8203;38120](https://github.com/BerriAI/litellm/pull/38120)
- fix(gemini): bill Google Maps grounding as its own SKU by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;38418](https://github.com/BerriAI/litellm/pull/38418)
- fix(speech): keep proxy metadata and completion cost through the TTS completion bridge by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;38414](https://github.com/BerriAI/litellm/pull/38414)
- fix: map Gemini ON\_DEMAND\_FLEX traffic type to flex service tier by [@&#8203;bisma-nawaz](https://github.com/bisma-nawaz) in [#&#8203;37724](https://github.com/BerriAI/litellm/pull/37724)
- feat(langfuse): support langfuse\_environment as a per-key dynamic callback param by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;38264](https://github.com/BerriAI/litellm/pull/38264)
- feat(proxy): hide unhealthy models from model listings, opt-in by [@&#8203;yuneng-berri](https://github.com/yuneng-berri) in [#&#8203;38313](https://github.com/BerriAI/litellm/pull/38313)
- fix(mcp): honor admin-entered OAuth URLs on authorize after issuer yield by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;38379](https://github.com/BerriAI/litellm/pull/38379)
- fix(model\_prices): correct gemini-3.5-flash-lite flex cache-read pricing by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;38422](https://github.com/BerriAI/litellm/pull/38422)
- fix(cost): price gemini-live-2.5-flash-native-audio realtime sessions by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;38419](https://github.com/BerriAI/litellm/pull/38419)
- fix(cost-map): correct Gemini TTS and native-audio rates by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;38412](https://github.com/BerriAI/litellm/pull/38412)
- fix(prompts): propagate PATCHed prompt templates to every worker and pod by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;38411](https://github.com/BerriAI/litellm/pull/38411)
- fix(model\_prices): bill gemini -latest/preview alias cache reads at 10% of input by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;38423](https://github.com/BerriAI/litellm/pull/38423)
- fix(proxy): sync search tools into the router on management writes by [@&#8203;yuneng-berri](https://github.com/yuneng-berri) in [#&#8203;38392](https://github.com/BerriAI/litellm/pull/38392)
- feat(guardrails): track Azure Prompt Shield usage and cost with spend isolation by [@&#8203;yucheng-berri](https://github.com/yucheng-berri) in [#&#8203;38387](https://github.com/BerriAI/litellm/pull/38387)
- fix(prompts): apply prompt templates before routing on /v1/responses and honor ignore\_prompt\_manager\_model by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;38407](https://github.com/BerriAI/litellm/pull/38407)
- fix(cost): make cost-breakdown headers respect service tier by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;38424](https://github.com/BerriAI/litellm/pull/38424)
- fix(mcp): add litellm\[mcp] extra and actionable error when streamable\_http\_client is missing by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;38399](https://github.com/BerriAI/litellm/pull/38399)
- revert(proxy): remove router\_model\_name from auto-routed response bodies by [@&#8203;tin-berri](https://github.com/tin-berri) in [#&#8203;38429](https://github.com/BerriAI/litellm/pull/38429)
- fix(google\_genai): price streamed generateContent with the provider that served it by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;36055](https://github.com/BerriAI/litellm/pull/36055)
- fix(logging): stop billing and logging response reads as LLM calls by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;36890](https://github.com/BerriAI/litellm/pull/36890)
- fix(budget): serialize model\_max\_budget before the /budget/update write by [@&#8203;yuneng-berri](https://github.com/yuneng-berri) in [#&#8203;38430](https://github.com/BerriAI/litellm/pull/38430)
- fix(ui): block the auto-router submit on a missing classifier model and an orphaned keyword rule by [@&#8203;tin-berri](https://github.com/tin-berri) in [#&#8203;38427](https://github.com/BerriAI/litellm/pull/38427)
- feat(complexity\_router): heuristic-first classifier chaining by [@&#8203;tin-berri](https://github.com/tin-berri) in [#&#8203;38428](https://github.com/BerriAI/litellm/pull/38428)
- test(e2e): un-skip the per-model budget update case by [@&#8203;yuneng-berri](https://github.com/yuneng-berri) in [#&#8203;38437](https://github.com/BerriAI/litellm/pull/38437)
- fix(cost): stop double-billing cached tokens that overlap a modality by [@&#8203;Srivatsa03](https://github.com/Srivatsa03) in [#&#8203;37407](https://github.com/BerriAI/litellm/pull/37407)
- feat(ui): add Teams list CSV export with budgets, model grants, and rate limits by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;38436](https://github.com/BerriAI/litellm/pull/38436)
- fix(mcp): accept raw x-litellm-api-key on streamable HTTP admission by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;38364](https://github.com/BerriAI/litellm/pull/38364)
- fix: bound row count on GET /spend/logs to stop unbounded LiteLLM\_SpendLogs scans by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;38420](https://github.com/BerriAI/litellm/pull/38420)
- fix(scim): apply default\_team\_params (incl. models) to SCIM-created teams by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;38433](https://github.com/BerriAI/litellm/pull/38433)
- fix(prompts): propagate prompt deletes to every worker and pod by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;38434](https://github.com/BerriAI/litellm/pull/38434)
- fix(anthropic\_adapter): carry web search cost into /v1/messages breakdown headers by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;38439](https://github.com/BerriAI/litellm/pull/38439)
- fix(ui): show custom technical keywords on every router whose scorer runs by [@&#8203;tin-berri](https://github.com/tin-berri) in [#&#8203;38451](https://github.com/BerriAI/litellm/pull/38451)
- fix(e2e): move the vertex realtime suite off the retired Live preview model by [@&#8203;yuneng-berri](https://github.com/yuneng-berri) in [#&#8203;38454](https://github.com/BerriAI/litellm/pull/38454)
- feat(newrelic): per-team cost and usage metrics via team callbacks by [@&#8203;yucheng-berri](https://github.com/yucheng-berri) in [#&#8203;37610](https://github.com/BerriAI/litellm/pull/37610)
- fix(ui): carry a preset's per-tier litellm\_params through the prefill by [@&#8203;tin-berri](https://github.com/tin-berri) in [#&#8203;38453](https://github.com/BerriAI/litellm/pull/38453)
- fix(e2e): size the mid-conversation-system cache prefix above the minimum deterministically by [@&#8203;yuneng-berri](https://github.com/yuneng-berri) in [#&#8203;38468](https://github.com/BerriAI/litellm/pull/38468)
- fix(e2e): disable thinking on the gemini chat cost test instead of racing its budget by [@&#8203;yuneng-berri](https://github.com/yuneng-berri) in [#&#8203;38469](https://github.com/BerriAI/litellm/pull/38469)
- feat(ui): put the auto-router savings hero on a spend rail and a four-tile row by [@&#8203;tin-berri](https://github.com/tin-berri) in [#&#8203;38470](https://github.com/BerriAI/litellm/pull/38470)
- feat(ui): toggle internal health check visibility in request logs by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;38391](https://github.com/BerriAI/litellm/pull/38391)
- fix(mcp): canonicalize bearer scheme on bridge egress by [@&#8203;daniel-meismer-zocdoc](https://github.com/daniel-meismer-zocdoc) in [#&#8203;38398](https://github.com/BerriAI/litellm/pull/38398)
- refactor: clean up fresh tech debt from 2026-08-27 window by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;38484](https://github.com/BerriAI/litellm/pull/38484)
- fix(exception\_mapping\_utils): map unmapped exceptions when model and provider are unset by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;38496](https://github.com/BerriAI/litellm/pull/38496)
- fix(ui\_sso): resolve highest privilege Entra app role, not first in claim by [@&#8203;imranismail](https://github.com/imranismail) in [#&#8203;36728](https://github.com/BerriAI/litellm/pull/36728)
- fix(proxy): regenerate lazy OpenAPI snapshot and guard it in CI by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;38410](https://github.com/BerriAI/litellm/pull/38410)
- feat(ui): add cache hit/miss filter to Request Logs by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;38432](https://github.com/BerriAI/litellm/pull/38432)
- fix(bedrock): sign rerank requests with the shared header-filtered SigV4 helper (internal copy of [#&#8203;36462](https://github.com/BerriAI/litellm/issues/36462)) by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;38093](https://github.com/BerriAI/litellm/pull/38093)
- fix(bedrock): sign rerank requests with the shared, header-filtered SigV4 helper by [@&#8203;noahnistler](https://github.com/noahnistler) in [#&#8203;36462](https://github.com/BerriAI/litellm/pull/36462)
- fix(ui): order the auto-routers table newest first so a new router lands on page one by [@&#8203;tin-berri](https://github.com/tin-berri) in [#&#8203;38545](https://github.com/BerriAI/litellm/pull/38545)
- feat(ui): run the Anthropic Family preset's reasoning tier on Opus 5 at high thinking by [@&#8203;tin-berri](https://github.com/tin-berri) in [#&#8203;38490](https://github.com/BerriAI/litellm/pull/38490)
- build(ui): bump nginx to 1.31-alpine by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;38541](https://github.com/BerriAI/litellm/pull/38541)
- feat(otel): support per-team/per-key service.name for OTel v2 destinations by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;38532](https://github.com/BerriAI/litellm/pull/38532)
- test(e2e): de-flake the cost-header cache read and the router fallback control by [@&#8203;yuneng-berri](https://github.com/yuneng-berri) in [#&#8203;38435](https://github.com/BerriAI/litellm/pull/38435)
- feat(gemini): day-0 support for gemini-3.5-transcribe and transcribe-live by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;38540](https://github.com/BerriAI/litellm/pull/38540)
- feat(health): opt-in model-group allowlist for background health checks and health-check routing by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;38539](https://github.com/BerriAI/litellm/pull/38539)
- fix(mcp): keep upstream OAuth Authorization when jwt signer hook injects one on tools/call by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;38555](https://github.com/BerriAI/litellm/pull/38555)
- fix: suppress misleading register\_model unresolved-cost warnings for entries without custom pricing by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;38542](https://github.com/BerriAI/litellm/pull/38542)
- feat(proxy): opt-in budget rollover carrying overage into the next window by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;38514](https://github.com/BerriAI/litellm/pull/38514)
- fix(auth): skip guaranteed-miss team lookup for the litellm-dashboard sentinel by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;38471](https://github.com/BerriAI/litellm/pull/38471)
- fix(key\_management): allow /key/update to keep or shrink MCP server grants the key already holds by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;38463](https://github.com/BerriAI/litellm/pull/38463)
- fix: keep schema reconciliation from fighting a partitioned LiteLLM\_SpendLogs by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;38452](https://github.com/BerriAI/litellm/pull/38452)
- fix(ui): open select popups below the trigger instead of over it by [@&#8203;tin-berri](https://github.com/tin-berri) in [#&#8203;38554](https://github.com/BerriAI/litellm/pull/38554)
- fix(realtime): bill trailing audio when a Gemini transcribe Live session closes by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;38563](https://github.com/BerriAI/litellm/pull/38563)
- test(e2e): cover key generate and update on the Admin UI path by [@&#8203;yuneng-berri](https://github.com/yuneng-berri) in [#&#8203;38448](https://github.com/BerriAI/litellm/pull/38448)
- chore: bump litellm-enterprise 0.1.60 -> 0.1.61, litellm-proxy-extras 0.4.89 -> 0.4.90 by [@&#8203;yuneng-berri](https://github.com/yuneng-berri) in [#&#8203;38566](https://github.com/BerriAI/litellm/pull/38566)
- fix(ui): let the paginated search select keep what the user types by [@&#8203;yuneng-berri](https://github.com/yuneng-berri) in [#&#8203;38475](https://github.com/BerriAI/litellm/pull/38475)
- fix(otel): anchor MCP tool-call spans to the gateway's own trace, link the client's context by [@&#8203;yucheng-berri](https://github.com/yucheng-berri) in [#&#8203;38317](https://github.com/BerriAI/litellm/pull/38317)
- fix: roll up the open deflake fixes for the MCP logging queue, PTU rollup, license gate, and pricing test isolation by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;37833](https://github.com/BerriAI/litellm/pull/37833)
- fix(model\_prices): rolling registry audit - verified models and rates for Novita, DeepInfra, W\&B, Bedrock Sol, Gemini, Fireworks, Azure gpt-5.6, Mistral, Together by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;38207](https://github.com/BerriAI/litellm/pull/38207)
- test(together\_ai): assert fail-open supported params for models missing from the registry by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;38487](https://github.com/BerriAI/litellm/pull/38487)
- test(e2e): let the together tool tests accept parallel calls by [@&#8203;yuneng-berri](https://github.com/yuneng-berri) in [#&#8203;38567](https://github.com/BerriAI/litellm/pull/38567)
- feat(mcp): let a resolved OAuth token target a custom upstream header by [@&#8203;tin-berri](https://github.com/tin-berri) in [#&#8203;38456](https://github.com/BerriAI/litellm/pull/38456)
- feat(together\_ai): map reasoning\_effort per model class by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;38263](https://github.com/BerriAI/litellm/pull/38263)
- feat(dashscope): support qwen-image-3.0 and qwen-image-3.0-pro image generation by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;38449](https://github.com/BerriAI/litellm/pull/38449)
- fix(cost): apply Together AI cache read pricing and per-model registry rates by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;38280](https://github.com/BerriAI/litellm/pull/38280)
- fix(guardrails): forward aws\_external\_id when the bedrock guardrail assumes a role by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;38376](https://github.com/BerriAI/litellm/pull/38376)
- fix(transcription): synthesize srt/vtt output for adapters without native subtitle formats by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;38561](https://github.com/BerriAI/litellm/pull/38561)
- fix(streaming): preserve provider service-tier metadata so Vertex flex streams bill at flex rates by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;38458](https://github.com/BerriAI/litellm/pull/38458)
- fix(realtime): bill Gemini Live native-audio output tokens at the audio rate by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;38457](https://github.com/BerriAI/litellm/pull/38457)
- fix(anthropic): carry tool\_reference tool results through the guardrail translation round trip by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;38465](https://github.com/BerriAI/litellm/pull/38465)
- fix(anthropic-adapter): pass provider-native and OpenAI-format tools through on /v1/messages by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;38431](https://github.com/BerriAI/litellm/pull/38431)
- test(e2e): serve the vision image from our own fixture by [@&#8203;yuneng-berri](https://github.com/yuneng-berri) in [#&#8203;38575](https://github.com/BerriAI/litellm/pull/38575)
- feat(together\_ai): add zai-org/GLM-5.3-Flash to the model registry by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;38486](https://github.com/BerriAI/litellm/pull/38486)
- fix(ui): stop server-searched comboboxes from clobbering picks and queries by [@&#8203;ryan-crabbe-berri](https://github.com/ryan-crabbe-berri) in [#&#8203;38574](https://github.com/BerriAI/litellm/pull/38574)
- feat(model\_prices): let a map entry declare its exact reasoning\_effort levels by [@&#8203;tin-berri](https://github.com/tin-berri) in [#&#8203;38481](https://github.com/BerriAI/litellm/pull/38481)
- fix(anthropic): carry the adaptive effort tier to every bridged Claude target by [@&#8203;tin-berri](https://github.com/tin-berri) in [#&#8203;38533](https://github.com/BerriAI/litellm/pull/38533)
- feat(alerting): add native Microsoft Teams alerting destination by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;38367](https://github.com/BerriAI/litellm/pull/38367)
- chore(proxy): resync the generated API artifacts with the current models by [@&#8203;tin-berri](https://github.com/tin-berri) in [#&#8203;38587](https://github.com/BerriAI/litellm/pull/38587)
- fix(router): reject complexity-router settings written outside complexity\_router\_config by [@&#8203;tin-berri](https://github.com/tin-berri) in [#&#8203;38570](https://github.com/BerriAI/litellm/pull/38570)
- feat(ui): session-level cache observability in request logs by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;38442](https://github.com/BerriAI/litellm/pull/38442)
- fix(ui): link Virtual Keys hint through the migrated /ui route by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;38596](https://github.com/BerriAI/litellm/pull/38596)
- fix(anthropic): carry the effort tier only where the target declares reasoning\_effort by [@&#8203;tin-berri](https://github.com/tin-berri) in [#&#8203;38592](https://github.com/BerriAI/litellm/pull/38592)
- fix(presidio): chunk oversized text before /analyze so large content blocks do not fail by [@&#8203;yucheng-berri](https://github.com/yucheng-berri) in [#&#8203;38483](https://github.com/BerriAI/litellm/pull/38483)
- fix(logging): stop stream-based log collectors classifying INFO logs as errors by [@&#8203;yucheng-berri](https://github.com/yucheng-berri) in [#&#8203;38476](https://github.com/BerriAI/litellm/pull/38476)
- feat(ui): dry-run an auto-router config against the backend before saving it by [@&#8203;tin-berri](https://github.com/tin-berri) in [#&#8203;38595](https://github.com/BerriAI/litellm/pull/38595)
- fix(guardrails): add fail-open mode to CrowdStrike AIDR guardrail by [@&#8203;yucheng-berri](https://github.com/yucheng-berri) in [#&#8203;38568](https://github.com/BerriAI/litellm/pull/38568)
- fix(router): copy instead of mutating caller metadata when scrubbing fallback stamp keys by [@&#8203;yucheng-berri](https://github.com/yucheng-berri) in [#&#8203;38586](https://github.com/BerriAI/litellm/pull/38586)
- feat(proxy): opt-in enforce\_fallback\_model\_access authorizes router fallbacks against the calling key by [@&#8203;ryan-crabbe-berri](https://github.com/ryan-crabbe-berri) in [#&#8203;38572](https://github.com/BerriAI/litellm/pull/38572)
- fix(langfuse): warn and drop invalid LANGFUSE\_TRACING\_ENVIRONMENT instead of failing requests by [@&#8203;yucheng-berri](https://github.com/yucheng-berri) in [#&#8203;38582](https://github.com/BerriAI/litellm/pull/38582)
- fix(tencent): route thinking through extra\_body in chat completions by [@&#8203;FelipeRodriguesGare](https://github.com/FelipeRodriguesGare) in [#&#8203;38100](https://github.com/BerriAI/litellm/pull/38100)
- test-check-commits by [@&#8203;nickhac](https://github.com/nickhac) in [#&#8203;36344](https://github.com/BerriAI/litellm/pull/36344)
- feat(proxy): dry-run a real request body on /auto\_router/test\_routing by [@&#8203;tin-berri](https://github.com/tin-berri) in [#&#8203;38590](https://github.com/BerriAI/litellm/pull/38590)
- fix(shadow\_eval): refuse a judge model that also serves one of the arms it grades by [@&#8203;tin-berri](https://github.com/tin-berri) in [#&#8203;38589](https://github.com/BerriAI/litellm/pull/38589)
- fix(anthropic): resolve /v1/messages effort tiers through the capability owner by [@&#8203;tin-berri](https://github.com/tin-berri) in [#&#8203;38492](https://github.com/BerriAI/litellm/pull/38492)
- fix(router): fall over on raised mid-stream errors in /v1/messages streams by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;38606](https://github.com/BerriAI/litellm/pull/38606)
- feat(models): add daily Together AI model registry sync script and workflow by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;38257](https://github.com/BerriAI/litellm/pull/38257)
- feat(ui): the model and wire layer for operator-defined auto-router tier sets by [@&#8203;tin-berri](https://github.com/tin-berri) in [#&#8203;38602](https://github.com/BerriAI/litellm/pull/38602)
- fix(moonshot, together\_ai): send the reasoning effort Kimi K3 accepts by [@&#8203;tin-berri](https://github.com/tin-berri) in [#&#8203;38611](https://github.com/BerriAI/litellm/pull/38611)
- fix(ui): one-click theme toggle and matching Docs/Blog styling in the top bar by [@&#8203;ryan-crabbe-berri](https://github.com/ryan-crabbe-berri) in [#&#8203;38601](https://github.com/BerriAI/litellm/pull/38601)
- feat(proxy): opt-in flags to require rpm/tpm on model and project create by [@&#8203;ansh-agrawal](https://github.com/ansh-agrawal) in [#&#8203;36514](https://github.com/BerriAI/litellm/pull/36514)
- fix(exceptions): keep a refused connection an APIConnectionError by [@&#8203;yuneng-berri](https://github.com/yuneng-berri) in [#&#8203;38624](https://github.com/BerriAI/litellm/pull/38624)
- chore(ci): promote internal staging to main by [@&#8203;yuneng-berri](https://github.com/yuneng-berri) in [#&#8203;38616](https://github.com/BerriAI/litellm/pull/38616)
- fix(anthropic): drop and self-heal empty thinking blocks on /v1/messages by [@&#8203;tin-berri](https://github.com/tin-berri) in [#&#8203;38625](https://github.com/BerriAI/litellm/pull/38625)
- fix(anthropic): handle per-level reasoning\_effort flags without supports\_reasoning by [@&#8203;tin-berri](https://github.com/tin-berri) in [#&#8203;38618](https://github.com/BerriAI/litellm/pull/38618)
- fix(complexity\_router): route client housekeeping calls to the cheapest tier by [@&#8203;tin-berri](https://github.com/tin-berri) in [#&#8203;38598](https://github.com/BerriAI/litellm/pull/38598)
- test: fix staging CI regressions from [#&#8203;38182](https://github.com/BerriAI/litellm/issues/38182), [#&#8203;38144](https://github.com/BerriAI/litellm/issues/38144), [#&#8203;38265](https://github.com/BerriAI/litellm/issues/38265), [#&#8203;37962](https://github.com/BerriAI/litellm/issues/37962), and [#&#8203;37969](https://github.com/BerriAI/litellm/issues/37969) by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;38304](https://github.com/BerriAI/litellm/pull/38304)
- feat(spend): report prompt caching savings as total and gateway-attributed by [@&#8203;tin-berri](https://github.com/tin-berri) in [#&#8203;38134](https://github.com/BerriAI/litellm/pull/38134)
- fix(proxy): let llm\_api virtual keys read /model\_group/info by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;38662](https://github.com/BerriAI/litellm/pull/38662)
- feat(ui): edit the auto-router tier set with custom classifier-defined tiers by [@&#8203;tin-berri](https://github.com/tin-berri) in [#&#8203;38603](https://github.com/BerriAI/litellm/pull/38603)
- fix(proxy): count tools, system, and Anthropic image and document blocks in the count\_tokens fallback (internal copy of [#&#8203;36671](https://github.com/BerriAI/litellm/issues/36671)) by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;38657](https://github.com/BerriAI/litellm/pull/38657)
- test: refresh the suites that drifted from langfuse and OpenAI's retired Assistants API by [@&#8203;yuneng-berri](https://github.com/yuneng-berri) in [#&#8203;38637](https://github.com/BerriAI/litellm/pull/38637)
- test(e2e): unskip four tests whose blockers no longer hold by [@&#8203;yuneng-berri](https://github.com/yuneng-berri) in [#&#8203;38640](https://github.com/BerriAI/litellm/pull/38640)
- feat(proxy): add paginated GET /public/v1/model\_hub by [@&#8203;yuneng-berri](https://github.com/yuneng-berri) in [#&#8203;38636](https://github.com/BerriAI/litellm/pull/38636)
- refactor(ui): type search tool params from the generated schema by [@&#8203;yuneng-berri](https://github.com/yuneng-berri) in [#&#8203;38633](https://github.com/BerriAI/litellm/pull/38633)
- feat(a2a): semantic search over the agent registry via GET /v1/agents?query and an agent\_search MCP tool by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;38609](https://github.com/BerriAI/litellm/pull/38609)
- fix(model\_prices): add bedrock\_mantle gpt-5.5/5.4 272K tiers, align sol with AWS invoice by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;38615](https://github.com/BerriAI/litellm/pull/38615)
- fix(ui): keep the usage filter visible when the caller's scope is empty by [@&#8203;yuneng-berri](https://github.com/yuneng-berri) in [#&#8203;38581](https://github.com/BerriAI/litellm/pull/38581)
- fix(registry): add Gemini Omni 1.1 Flash, xAI grok-imagine image models, Mistral cache-read pricing, GLM 5.3 Flash + Kimi K2.7 Code entries by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;38560](https://github.com/BerriAI/litellm/pull/38560)
- fix(logging): preserve null end user in callbacks by [@&#8203;yucheng-berri](https://github.com/yucheng-berri) in [#&#8203;38642](https://github.com/BerriAI/litellm/pull/38642)
- test: close mutation-testing gaps in container, skills and openai-like config factories by [@&#8203;yuneng-berri](https://github.com/yuneng-berri) in [#&#8203;38677](https://github.com/BerriAI/litellm/pull/38677)
- fix: enforce MCP toolsets attached to a team, org, or internal user by [@&#8203;yucheng-berri](https://github.com/yucheng-berri) in [#&#8203;38488](https://github.com/BerriAI/litellm/pull/38488)
- fix(tests): drain the global logging worker in RAG aquery billing tests by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;38653](https://github.com/BerriAI/litellm/pull/38653)
- chore(techdebt): type new signatures and drop slop comments from the last 24h by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;38644](https://github.com/Be…
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.

2 participants