Skip to content

fix(router): bind per-request routing_strategy override selectors to the request's callbacks - #41178

Merged
yassin-berriai merged 1 commit into
mainfrom
litellm_request_override_selector_callbacks
Sep 15, 2026
Merged

yassin-berriai merged 1 commit into
mainfrom
litellm_request_override_selector_callbacks

Conversation

@devin-ai-integration

@devin-ai-integration devin-ai-integration Bot commented Sep 15, 2026 •

Copy link
Copy Markdown
Contributor

TLDR

Problem this solves:

How it solves it:

  • Attach the override selector to that request's own callback list
  • It gets pre-call, success and failure for that request only
  • Global litellm.*callback lists stay untouched, so no cross-request leak

User Flow

Before: a key whose router_settings say least-busy keeps landing on the deployment that is already streaming

  1. They send POST http://localhost:4000/v1/chat/completions with "stream": true against lb-group using a key whose router_settings set routing_strategy: least-busy; the response header says x-litellm-model-id: lb-d1
  2. While that stream is still running they send three short POST http://localhost:4000/v1/chat/completions calls to the same group with the same key
  3. All three come back 200 with x-litellm-model-id: lb-d1, the one deployment that is busy
  4. With routing_strategy: latency-based-routing on a group where one deployment times out (408) and one answers, eight calls in a row keep going back to the timing-out deployment: 408, 408, 200, 200, 200, 408, 408, 408

After: the same requests avoid the busy deployment and settle on the fast one

  1. They send the same streaming POST http://localhost:4000/v1/chat/completions; the response header says x-litellm-model-id: lb-d1
  2. While that stream is still running they send the same three short calls
  3. All three come back 200 with x-litellm-model-id: lb-d2, an idle deployment
  4. Once the stream finishes, short calls go back to lb-d1, so the busy mark is released
  5. With routing_strategy: latency-based-routing, one 408 on the first pick, then seven 200s in a row from the deployment that answers

Relevant issues

Follow-up to #40229

Affected release

regression since v1.102.0-dev.1 (#40229), present in v1.102.0-rc.1

Linear ticket

Resolves LIT-7682

Root cause and fix

#40229 builds the per-request override selector with register_callbacks=False, which correctly keeps a per-request strategy out of the global litellm.input_callback / success_callback / failure_callback lists. Nothing replaced that registration with a request-scoped one, so LeastBusyLoggingHandler never got log_pre_api_call (in-flight +1) or success/failure (in-flight -1), and LowestLatencyLoggingHandler never got a success or failure timing sample. Both selectors then ranked deployments on an empty map and picked the first one every time

The fix binds the selector to the request:

# litellm/router.py, in _get_routing_context on the override branch
override_selector = self._get_override_strategy_selector(override)
self._bind_override_selector_to_request(override, override_selector, request_kwargs)

def _bind_override_selector_to_request(self, strategy, selector, request_kwargs):
    if selector is None or request_kwargs is None or strategy in self._globally_registered_strategies():
        return
    logging_obj = request_kwargs.get("litellm_logging_obj")
    if isinstance(logging_obj, LiteLLMLogging):
        logging_obj.add_dynamic_callback(selector)

def _globally_registered_strategies(self) -> frozenset[str]:
    # the router's default strategy plus every routing group's strategy: those selectors
    # are already in the global callback lists, so binding a second one would double count

# litellm/litellm_core_utils/litellm_logging.py
def add_dynamic_callback(self, callback: CustomLogger) -> None:
    # appends `callback` (once) to dynamic_input / success / async_success / failure / async_failure callbacks
    # by building fresh lists, never mutating the existing ones

The Logging object already merges litellm.<x>_callback + dynamic_<x>_callbacks at every lifecycle point (pre-call, sync and async success, sync and async failure), so the selector now gets exactly the events it would have received from global registration, scoped to this one request. When the override equals the router's configured strategy, or the strategy of any explicit routing group, a selector for that strategy is already globally registered, so nothing is bound (no double count; a group's selector shares the same per-model-group cache keys as the override selector, so a second one would record every request twice). _get_routing_context is shared by get_available_deployment, async_get_available_deployment and both pass-through variants, so all four entry points are covered. The same binding restores success-time usage recording for the other overridable strategies (usage-based-routing, usage-based-routing-v2, cost-based-routing); only least-busy and latency-based were verified live below

Tests

tests/test_litellm/router_strategy/test_router_routing_groups.py (mapped file) gains eight tests that build the request the way the proxy does (Logging object created before the router sees it):

  • async least-busy: a held stream marks d1 busy, override picks d2, draining the stream releases d1
  • sync least-busy: same, through router.completion(stream=True)
  • least-busy failure path: a failing call releases the in-flight count
  • async latency-based: after a timing-out d1, override converges on d2 and every pick has a fresh sample
  • the selector is bound only to the request and is absent from every global callback list
  • an override equal to the configured strategy binds nothing
  • an override equal to a routing group's strategy (simple-shuffle default, latency-based-routing group) binds nothing and the request lands in the latency map exactly once
  • binding the same selector twice keeps one copy and requests without a Logging object are left alone

Mutation matrix (one fix line removed at a time, tree restored with cp and checked with cmp -s, focused run -k override, 25 tests): no binding call in the router 5 failed; no configured-strategy guard 1 failed; dropping the input, success, async success, failure or async failure dynamic list 4, 3, 3, 1 and 3 failed respectively. Every mutant is killed; with the fix in place the focused run and the full mapped file (80 tests) pass. Second round, after the group-aware guard: reverting the guard to the default-strategy-only check makes the new routing-group test fail 3 out of 3 runs with assert 2 == 1 (two identical latency samples for one request), and it passes 3 out of 3 with the guard. scripts/pre_commit_lint.sh passes with no budget file changes

tests/test_litellm/litellm_core_utils/test_litellm_logging.py (mapped file) gains one test that calls add_dynamic_callback twice on a Logging object whose success list is caller-owned and checks the caller's list is untouched, every dynamic list holds the callback once, and _with_dynamic_callback handles None and an already-present callback

Taxonomy audit (A-BB)

  • W1, W4: _with_dynamic_callback builds a new list from a tuple snapshot, never mutates the caller's list; request_kwargs is read only
  • B6: the callback in existing guard means a request that hits _get_routing_context twice (retry helper plus selection) binds the selector once, so one pre-call increment and one release. Review round 1 found the sibling case: a routing group whose strategy matches the override already has a global selector on the same cache keys, so the guard now covers group strategies too (test above)
  • F3, O4: sync and async, streaming and non-streaming, success and failure all covered by tests; all four router selection entry points share the changed helper
  • C1-C7: no default change; requests without an override never reach the binding (early return), verified live with plain calls still shuffling across all three deployments
  • X1: callbacks or () treats None and [] the same on purpose; both mean "no dynamic callbacks yet"
  • A1: no new cache; the selector's own state (in-flight counts, latency map) lives in the router cache exactly as it does for the configured strategy
  • H: no new source comments, X | None unions, Mapping / Sequence instead of bare dict / list, no docs or dashboard change needed
  • T1-T5, T17: every new test fails on unfixed code; assertions are on the served model_id and on cache counters, not on structure; conftest autouse fixtures reset global callbacks

House-rules review of the final diff at a933424 (override string is normalized before the group guard compares it, Mapping / Sequence parameters, Final locals, no mutation of caller state, no new imports into hub modules) found no blocker or major item

Regression sweep

The changed symbols are Logging.add_dynamic_callback (new), Logging._with_dynamic_callback (new), Router._bind_override_selector_to_request (new), Router._globally_registered_strategies (new) and Router._get_routing_context (one extra call). Readers of dynamic_*_callbacks outside litellm_logging.py are litellm/llms/openai/openai.py, litellm/llms/custom_httpx/llm_http_handler.py and litellm/litellm_core_utils/chat_completion_agentic_loop.py (agentic hook discovery over litellm.callbacks + dynamic_success_callbacks), the Rust lifecycle bridge (phase gating), and the two producers that seed the lists before the router runs: function_setup in litellm/utils.py (per-request success_callback / failure_callback kwargs) and the pass-through endpoints (team callbacks). The producers keep owning their lists because the binding builds a new list instead of appending. All of them already iterate router selectors today whenever the configured strategy registers one in litellm.callbacks, so a selector arriving through the dynamic list is not a new shape for them.

/live-pr-risk dependency walk (base 94f0863, head a933424):

  • _get_routing_context callers: get_available_deployment, async_get_available_deployment and both pass-through variants (all four go through the one changed line); _get_request_routing_strategy_override is unchanged and still reads routing_strategy from request kwargs, which is what router_settings_override and the key/team router_settings path forward
  • dynamic_*_callbacks readers outside the logging module: agentic hook discovery in llm_http_handler.py, openai.py and chat_completion_agentic_loop.py (_has_pre_call_deployment_hook-style checks over litellm.callbacks + dynamic_success_callbacks), the Rust lifecycle bridge phase gating, and _should_run_sync_callbacks_for_async_calls. Each only asks whether a callback overrides a hook method; the router selectors do not override those hooks, so their answers are unchanged with the selector in the list. Verified live: every leg below ran through these readers
  • function_setup reuses a litellm_logging_obj already present in kwargs, so the dynamic lists set by the router survive into litellm.acompletion (that is how the live legs receive the events). Retries and fallbacks reuse the same Logging object; the callback in existing guard keeps the binding to one entry
  • No config key, response field, DB column or dashboard contract changes; the sibling docs checkout has no reference to these private helpers
  • Live A/B at base 94f0863 vs head a933424, both booted from their own tree (PYTHONPATH asserted, MARKER add_dynamic_callback 0 vs 1) with --num_workers 2, one Postgres, real OpenAI, byte-identical fixtures in the same order. Least-busy with a stream held on one worker: base sends all six short calls to the busy lb-d1; head sends the calls that land on the worker holding the stream to lb-d2 (calls 3 and 6) and the ones on the other worker to lb-d1, because least-busy counts are per process without Redis, which is the same shape the configured strategy has today. Latency-based: base 408, 408, 200, 200, 200, 408, 408, 408; head 408, 200, 408, 200, 200, 200, 200, 200 (one cold pick per worker, then every pick on lat-fast); the simple-shuffle control returned 408 on both sides. usage-based-routing, usage-based-routing-v2 and cost-based-routing overrides: nine 200s with real content on each side and spend rows written; on head usage-based-routing now spreads picks (lb-d1, lb-d2, lb-d1) where base pinned lb-d1, which is the restored usage signal. Default routing without an override: six 200s spread over the three deployments on both sides
  • Not verified live: the SDK-only path where router.acompletion(..., routing_strategy=...) is called without a pre-built Logging object; there the logging object is created after deployment selection, so the override still runs without its signal exactly as before this PR (no regression, not fixed here)

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 proxy (litellm --config config.yaml --port 20682 --use_prisma_db_push, Postgres behind it, PYTHONPATH pinned to the checkout, served tree asserted at launch), real OpenAI calls to gpt-4.1-nano. Same config and byte-identical request files on both sides (sha256 printed by the run). The build that served each side is identified by grep -c add_dynamic_callback litellm/router.py at launch: 0 before, 1 after

model_list:
  - model_name: lb-group
    litellm_params: {model: openai/gpt-4.1-nano, api_key: os.environ/OPENAI_API_KEY}
    model_info: {id: lb-d1}
  - model_name: lb-group
    litellm_params: {model: openai/gpt-4.1-nano, api_key: os.environ/OPENAI_API_KEY}
    model_info: {id: lb-d2}
  - model_name: lb-group
    litellm_params: {model: openai/gpt-4.1-nano, api_key: os.environ/OPENAI_API_KEY}
    model_info: {id: lb-d3}
  - model_name: lat-group
    litellm_params: {model: openai/gpt-4.1-nano, api_key: os.environ/OPENAI_API_KEY, timeout: 0.001, weight: 1}
    model_info: {id: lat-slow}
  - model_name: lat-group
    litellm_params: {model: openai/gpt-4.1-nano, api_key: os.environ/OPENAI_API_KEY, weight: 0}
    model_info: {id: lat-fast}
router_settings:
  routing_strategy: simple-shuffle
  num_retries: 0
  disable_cooldowns: true
general_settings:
  master_key: sk-litfix-7682
lb_stream.json   {"model":"lb-group","messages":[{"role":"user","content":"Write a 1500 word essay on the history of the telegraph."}],"max_tokens":3000,"stream":true,"router_settings_override":{"routing_strategy":"least-busy"}}
lb_short.json    {"model":"lb-group","messages":[{"role":"user","content":"say hi"}],"max_tokens":5,"router_settings_override":{"routing_strategy":"least-busy"}}
lat_pick.json    {"model":"lat-group","messages":[{"role":"user","content":"say hi"}],"max_tokens":5,"router_settings_override":{"routing_strategy":"latency-based-routing","num_retries":0}}
lat_control.json {"model":"lat-group","messages":[{"role":"user","content":"say hi"}],"max_tokens":5,"router_settings_override":{"routing_strategy":"simple-shuffle","num_retries":0}}
lb_plain.json    {"model":"lb-group","messages":[{"role":"user","content":"say hi"}],"max_tokens":5}

The run script is plain sequential curls: open the stream in the background, wait for its x-litellm-model-id header, fire the three short calls, wait for the stream to drain; then eight latency-based calls and one control call

URL=http://127.0.0.1:20682/v1/chat/completions; KEY=sk-litfix-7682
curl -sS -N -D stream_head.txt -o stream_body.txt -H "Authorization: Bearer $KEY" -H "Content-Type: application/json" --data-binary @lb_stream.json "$URL" &
for i in 1 2 3; do curl -sS -o /dev/null -D lb_head_$i.txt -w "%{http_code}" -H "Authorization: Bearer $KEY" -H "Content-Type: application/json" --data-binary @lb_short.json "$URL"; done
wait
for i in $(seq 1 8); do curl -sS -o lat_$i.json -D lat_head_$i.txt -w "%{http_code}" -H "Authorization: Bearer $KEY" -H "Content-Type: application/json" --data-binary @lat_pick.json "$URL"; done
curl -sS -o /dev/null -w "%{http_code}" -H "Authorization: Bearer $KEY" -H "Content-Type: application/json" --data-binary @lat_control.json "$URL"

Before (d2859e1, main at capture time; the two source files this PR touches and the routing path they feed are byte-identical between d2859e1 and the merge base 94f0863)

least-busy override while one deployment is streaming

  1. Launch: serving tree: /home/ubuntu/repos/litellm/litellm/__init__.py, MARKER add_dynamic_callback occurrences in router.py: 0
  2. Output:
== fixtures (sha256) ==
c745efc8a8e7ec49151fb8cd5930e01644f6339b04247b6b15492883c0531582  lb_stream.json
03c188bb317a926b745bfbce03d01611582ae15d76d3cc30665fb266c87edf62  lb_short.json
df2806fde799c5a7b895a10ac582d4c45c79cd63979a4dc0093ac651f604d888  lat_pick.json
5894a98d4d2d3265d7157a8bcad74119800c1e6945faccc9951720ae31e2981f  lat_control.json

stream opened: x-litellm-model-id=lb-d1  (this deployment is BUSY while the stream runs)
least-busy short call 1 -> HTTP 200  x-litellm-model-id=lb-d1
least-busy short call 2 -> HTTP 200  x-litellm-model-id=lb-d1
least-busy short call 3 -> HTTP 200  x-litellm-model-id=lb-d1
stream status: HTTP/1.1 200 OK
stream drained: 1301 data lines, terminator present: 1
  1. All three short calls land on lb-d1, the deployment that is busy streaming

latency-based override with one deployment timing out

  1. Output:
latency-based call 1 -> HTTP 408  x-litellm-model-id=
latency-based call 2 -> HTTP 408  x-litellm-model-id=
latency-based call 3 -> HTTP 200  x-litellm-model-id=lat-fast
latency-based call 4 -> HTTP 200  x-litellm-model-id=lat-fast
latency-based call 5 -> HTTP 200  x-litellm-model-id=lat-fast
latency-based call 6 -> HTTP 408  x-litellm-model-id=
latency-based call 7 -> HTTP 408  x-litellm-model-id=
latency-based call 8 -> HTTP 408  x-litellm-model-id=
control (simple-shuffle, weight sits on lat-slow) -> HTTP 408 (expected 408: lat-slow still routable, so fast picks above were not a cooldown)
  1. The override keeps returning to lat-slow (408) because no latency sample was ever recorded; the 200s are the unsignaled tie-break happening to land on lat-fast

After (re-captured at the PR tip a933424 with the same fixtures)

least-busy override while one deployment is streaming

  1. Launch: serving tree: /home/ubuntu/repos/litellm/litellm/__init__.py, MARKER add_dynamic_callback occurrences in router.py: 1; MARKER _globally_registered_strategies: 2; tip: a933424ed5
  2. Output:
== fixtures (sha256) ==
c745efc8a8e7ec49151fb8cd5930e01644f6339b04247b6b15492883c0531582  lb_stream.json
03c188bb317a926b745bfbce03d01611582ae15d76d3cc30665fb266c87edf62  lb_short.json
df2806fde799c5a7b895a10ac582d4c45c79cd63979a4dc0093ac651f604d888  lat_pick.json
5894a98d4d2d3265d7157a8bcad74119800c1e6945faccc9951720ae31e2981f  lat_control.json

stream opened: x-litellm-model-id=lb-d1  (this deployment is BUSY while the stream runs)
least-busy short call 1 -> HTTP 200  x-litellm-model-id=lb-d2
least-busy short call 2 -> HTTP 200  x-litellm-model-id=lb-d2
least-busy short call 3 -> HTTP 200  x-litellm-model-id=lb-d2
stream status: HTTP/1.1 200 OK
stream drained: 1700 data lines, terminator present: 1
  1. All three short calls avoid lb-d1 while it streams
  2. Three more short calls after the stream drained (in-flight count released):
least-busy short call 1 (stream drained, nothing in flight) -> HTTP 200  x-litellm-model-id=lb-d1
least-busy short call 2 (stream drained, nothing in flight) -> HTTP 200  x-litellm-model-id=lb-d1
least-busy short call 3 (stream drained, nothing in flight) -> HTTP 200  x-litellm-model-id=lb-d1

latency-based override with one deployment timing out

  1. Output:
latency-based call 1 -> HTTP 200  x-litellm-model-id=lat-fast
latency-based call 2 -> HTTP 408  x-litellm-model-id=
latency-based call 3 -> HTTP 200  x-litellm-model-id=lat-fast
latency-based call 4 -> HTTP 200  x-litellm-model-id=lat-fast
latency-based call 5 -> HTTP 200  x-litellm-model-id=lat-fast
latency-based call 6 -> HTTP 200  x-litellm-model-id=lat-fast
latency-based call 7 -> HTTP 200  x-litellm-model-id=lat-fast
latency-based call 8 -> HTTP 200  x-litellm-model-id=lat-fast
control (simple-shuffle, weight sits on lat-slow) -> HTTP 408 (expected 408: lat-slow still routable, so fast picks above were not a cooldown)
  1. One 408 on the second pick (the first two picks are unsignaled, one per deployment), then the timeout is recorded as a slow sample and every later pick goes to lat-fast. The control call proves lat-slow is still routable, so this is latency learning and not a cooldown

default routing unchanged

  1. Twelve calls with lb_plain.json (no override, router default simple-shuffle):
plain call 1 -> lb-d1   plain call 5 -> lb-d2   plain call 9  -> lb-d1
plain call 2 -> lb-d2   plain call 6 -> lb-d2   plain call 10 -> lb-d3
plain call 3 -> lb-d1   plain call 7 -> lb-d2   plain call 11 -> lb-d3
plain call 4 -> lb-d2   plain call 8 -> lb-d1   plain call 12 -> lb-d1
  1. All 200, spread across the three deployments as before

Scope of the live proof: /v1/chat/completions through the proxy's router_settings_override body field (the same kwarg the key/team router_settings path forwards), least-busy and latency-based only. The other overridable strategies share the binding but were verified by the unit tests only

Type

🐛 Bug Fix

Caveats (if any)

Low

  • Latency-based needs one sample per deployment before it can rank; the first pick after a cold start is still unsignaled
  • Selector state for an override still lives in the router-lifetime selector cache from fix(router): keep per-request routing_strategy override selectors out of global callbacks #40229, so counts and latency accumulate across requests on purpose
  • usage-based-routing, usage-based-routing-v2 and cost-based-routing overrides were exercised live only for status and pick spread (nine 200s each side, see the regression sweep), not for their ranking math
  • The SDK-only override path (no proxy, no pre-built Logging object) is out of scope, see the regression sweep. The per-request override is the proxy's router_settings_override / key and team router_settings feature from fix(router): keep per-request routing_strategy override selectors out of global callbacks #40229, and the ticket's user flow is POST /v1/chat/completions. Making router.acompletion(..., routing_strategy=...) carry its signal in the SDK would mean building the Logging object before deployment selection on every router entry point (chat, embeddings, images, audio, and the rest), which is a separate change with its own blast radius
  • The two e2e cells this ticket names (test_least_busy_avoids_deployment_with_request_in_flight, test_latency_based_routes_around_deployment_that_times_out) live in tests/e2e/router/test_reliability_routing_strategies_e2e.py on the still-open test(e2e): cover the reliability retry, cooldown, fallback, and routing-strategy cells #39857, so their skip markers come off there once this lands; the proxy legs above are that scenario replayed against a local proxy

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/d766c096f7614da2b7ecad93fbc71621
Requested by: @yassin-berriai

ran /live-pr-risk and found no regressions/backward incompatible risks


Note

Medium Risk
Changes request-scoped router callback wiring and affects deployment selection for per-request strategy overrides; guards limit double registration but routing behavior is business-critical.

Overview
Fixes a regression where per-request routing_strategy overrides (e.g. from key/team router_settings) could pick deployments without seeing in-flight load or latency, because override selectors were built with global callback registration disabled and nothing wired them to the request lifecycle.

When routing resolves to a request override, the router now attaches that override’s strategy selector to the request’s LiteLLMLogging object via new add_dynamic_callback, so pre-call, success, and failure hooks run for that request only. Binding is skipped if the override strategy is already registered globally (router default or any routing group), avoiding double-counting on shared cache keys.

add_dynamic_callback appends the selector once across all dynamic_* callback lists using fresh lists (_with_dynamic_callback), so caller-owned lists are not mutated.

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

@devin-ai-integration

Copy link
Copy Markdown
Contributor Author

🤖 Devin AI Engineer

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

✅ I will automatically:

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

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

⚙️ Control Options:

  • Disable automatic comment, CI, and merge conflict monitoring

@devin-ai-integration devin-ai-integration Bot added the backport-stable P0 regression fix only (Urgent ticket): cherry-pick onto the baking rc line before the stable tag label Sep 15, 2026
@codspeed

codspeed Bot commented Sep 15, 2026 •

Copy link
Copy Markdown
Contributor

Merging this PR will not alter performance

✅ 31 untouched benchmarks


Comparing litellm_request_override_selector_callbacks (f808c68) with main (94f0863)1

Open in CodSpeed

Footnotes

  1. No successful run was found on main (b4cff58) during the generation of this report, so 94f0863 was used instead as the comparison base. There might be some changes unrelated to this pull request in this report. ↩

@greptile-apps

greptile-apps Bot commented Sep 15, 2026 •

Copy link
Copy Markdown
Contributor

Greptile Summary

Binds per-request routing-strategy selectors to the request’s logging callbacks so overrides receive lifecycle signals without changing global callback lists.

  • Skips request binding when the strategy is already registered through the router default or a routing group.
  • Adds coverage for routing signals, callback deduplication, and preservation of caller-owned lists.
  • The latest revision only annotates the logging test’s fixture parameter; production code and test assertions are unchanged.
  • No new actionable findings remain.

Confidence Score: 5/5

The PR appears safe to merge, with no outstanding findings.

The latest revision resolves the remaining fixture-annotation issue without changing runtime behavior or weakening assertions. The routing-group duplicate-accounting and helper-typing findings are fixed. The SDK-only logging limitation was correctly conceded as pre-existing and outside this fix’s scope.

Important Files Changed

Filename Overview
litellm/router.py Request-scoped selector binding includes the group-aware guard that resolves the previous duplicate-accounting finding.
litellm/litellm_core_utils/litellm_logging.py Adds selectors once to each dynamic lifecycle callback list without modifying caller-owned lists.
tests/test_litellm/router_strategy/test_router_routing_groups.py Covers override lifecycle signals and duplicate-registration guards; previously flagged helper parameters are typed.
tests/test_litellm/litellm_core_utils/test_litellm_logging.py The latest change annotates the fixture with the already-imported LitellmLogging class, resolving the remaining typing finding.

Reviews (3): Last reviewed commit: "fix(router): bind per-request routing_st..." | Re-trigger Greptile

Comment thread litellm/router.py Outdated
Comment thread litellm/router.py
Comment thread tests/test_litellm/router_strategy/test_router_routing_groups.py
@devin-ai-integration
devin-ai-integration Bot force-pushed the litellm_request_override_selector_callbacks branch from 65d8b78 to 9512ace Compare September 15, 2026 03:54
@CLAassistant

Copy link
Copy Markdown

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.
You have signed the CLA already but the status is still pending? Let us recheck it.

@codecov

codecov Bot commented Sep 15, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@devin-ai-integration
devin-ai-integration Bot force-pushed the litellm_request_override_selector_callbacks branch from 9512ace to ab33fa1 Compare September 15, 2026 04:03
@devin-ai-integration
devin-ai-integration Bot force-pushed the litellm_request_override_selector_callbacks branch 2 times, most recently from 7097324 to a933424 Compare September 15, 2026 04:19
@devin-ai-integration

Copy link
Copy Markdown
Contributor Author

@greptileai please re-review a933424: group-aware guard, typed test helpers, and the multi-worker live A/B are in this head.

@mateo-berri

Copy link
Copy Markdown
Contributor

bugbot run

Comment thread tests/test_litellm/litellm_core_utils/test_litellm_logging.py Outdated

@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.

Stale Bugbot comment from a previous run.

…the request's callbacks

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
@devin-ai-integration
devin-ai-integration Bot force-pushed the litellm_request_override_selector_callbacks branch from a933424 to f808c68 Compare September 15, 2026 04:42
@devin-ai-integration

Copy link
Copy Markdown
Contributor Author

@greptileai

@mateo-berri

Copy link
Copy Markdown
Contributor

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 f808c68. Configure here.

@yassin-berriai
yassin-berriai merged commit 1ca4579 into main Sep 15, 2026
93 of 94 checks passed
@yassin-berriai
yassin-berriai deleted the litellm_request_override_selector_callbacks branch September 15, 2026 19:39
mateo-berri added a commit that referenced this pull request Sep 18, 2026
…rc_1_102_0

fix: backport eight backport-stable fixes to rc/1.102.0 (#40596, #41046, #41086, #41171, #41178, #41283, #41495, #41689)
tech-carrement pushed a commit to tech-carrement/litellm that referenced this pull request Sep 20, 2026
…the request's callbacks

Backport of BerriAI#41178 to rc/1.102.0.
Cherry-picked from merge commit 1ca4579 (main), originally by app/devin-ai-integration.
@mateo-berri mateo-berri removed the backport-stable P0 regression fix only (Urgent ticket): cherry-pick onto the baking rc line before the stable tag label Sep 26, 2026
doonga pushed a commit to greyrock-labs/home-ops that referenced this pull request Sep 28, 2026
…103.0) (#290)

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.102.1` → `v1.103.0` |

---

### Release Notes

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

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

[Compare Source](https://github.com/BerriAI/litellm/compare/v1.102.1...v1.103.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.103.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.103.0/cosign.pub \
  ghcr.io/berriai/litellm:v1.103.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): translate the reasoning object into a chat-completion reasoning effort by [@&#8203;joshgarnett](https://github.com/joshgarnett) in [#&#8203;36363](https://github.com/BerriAI/litellm/pull/36363)
- fix(proxy): bound tool and guardrail index create\_many by the spend-log statement budgets by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;40561](https://github.com/BerriAI/litellm/pull/40561)
- fix(mcp): require admission for delegated OAuth by [@&#8203;joshua-berri](https://github.com/joshua-berri) in [#&#8203;40923](https://github.com/BerriAI/litellm/pull/40923)
- fix(logging): log one bounded summary for a burst of timed-out LoggingWorker callbacks by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;40912](https://github.com/BerriAI/litellm/pull/40912)
- fix(fireworks): resolve short model names to long cost map keys by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;40929](https://github.com/BerriAI/litellm/pull/40929)
- ci: remove main branch source guard by [@&#8203;yuneng-berri](https://github.com/yuneng-berri) in [#&#8203;40172](https://github.com/BerriAI/litellm/pull/40172)
- chore(ci): promote internal staging to main by [@&#8203;yuneng-berri](https://github.com/yuneng-berri) in [#&#8203;40942](https://github.com/BerriAI/litellm/pull/40942)
- fix(spend\_logs): store litellm\_call\_id and match it in request\_id lookups by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;39068](https://github.com/BerriAI/litellm/pull/39068)
- fix(auth): refresh lite login session token grants from the live user and team rows by [@&#8203;ryan-crabbe-berri](https://github.com/ryan-crabbe-berri) in [#&#8203;40657](https://github.com/BerriAI/litellm/pull/40657)
- feat(bedrock): support file delete and list for S3-backed managed files by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;39836](https://github.com/BerriAI/litellm/pull/39836)
- fix(proxy): gate the webhook test alert on proxy admins by [@&#8203;ryan-crabbe-berri](https://github.com/ryan-crabbe-berri) in [#&#8203;40814](https://github.com/BerriAI/litellm/pull/40814)
- fix(ui): hide admin write-form tabs on the models page from view-only admins by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;38867](https://github.com/BerriAI/litellm/pull/38867)
- fix(anthropic-adapter): surface mid-stream provider errors as Anthropic error events by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;33352](https://github.com/BerriAI/litellm/pull/33352)
- docs(github): add an Affected release section to the PR template by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;40618](https://github.com/BerriAI/litellm/pull/40618)
- docs(e2e): ban unit tests under tests/e2e by [@&#8203;yassin-berriai](https://github.com/yassin-berriai) in [#&#8203;33852](https://github.com/BerriAI/litellm/pull/33852)
- fix(router): preserve Azure Entra ID params in reusable credentials by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;40889](https://github.com/BerriAI/litellm/pull/40889)
- docs(user endpoints): remove unsupported soft\_budget param from user docstrings by [@&#8203;shivamrawat1](https://github.com/shivamrawat1) in [#&#8203;36585](https://github.com/BerriAI/litellm/pull/36585)
- feat(friendli): auto-sync Friendli model metadata into price registry by [@&#8203;Lee-Si-Yoon](https://github.com/Lee-Si-Yoon) in [#&#8203;35918](https://github.com/BerriAI/litellm/pull/35918)
- build(deps): bump smol-toml to 1.8.0 to clear GHSA-7w5x-hrqm-74c2 in osv-scan by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;40478](https://github.com/BerriAI/litellm/pull/40478)
- fix(bedrock\_mantle): price GovCloud regions from the regional cost row and accept region-prefixed model names by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;39846](https://github.com/BerriAI/litellm/pull/39846)
- chore(ci): remerge internal staging by [@&#8203;yuneng-berri](https://github.com/yuneng-berri) in [#&#8203;40943](https://github.com/BerriAI/litellm/pull/40943)
- test(auth): freeze the cache clock in auth prefetch tests by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;40996](https://github.com/BerriAI/litellm/pull/40996)
- feat(jwt): allow virtual\_key\_claim\_field per issuer by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;40927](https://github.com/BerriAI/litellm/pull/40927)
- fix(cost): bill cached realtime audio tokens at the audio cache-read rate by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;40627](https://github.com/BerriAI/litellm/pull/40627)
- perf(logging): skip correlation contextvar stamping when request\_correlation\_in\_logs is off by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;41054](https://github.com/BerriAI/litellm/pull/41054)
- feat(pricing): add azure gpt-chat-latest rates and drop retired friendliai llama-3.1 entries by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;40976](https://github.com/BerriAI/litellm/pull/40976)
- build(deps): re-suppress GHSA-h7x2-h6g9-p789 in osv-scan on main, mlflow still has no fixed release by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;41104](https://github.com/BerriAI/litellm/pull/41104)
- fix(otel): cap per-index OpenInference message attributes span-wide by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;40562](https://github.com/BerriAI/litellm/pull/40562)
- feat(proxy): add general\_settings.allowed\_file\_extensions for /v1/files uploads by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;41106](https://github.com/BerriAI/litellm/pull/41106)
- fix(proxy): forward provider request id headers on mapped error responses by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;40925](https://github.com/BerriAI/litellm/pull/40925)
- fix(router): name the all-deployments-in-cooldown error on 429 responses by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;40995](https://github.com/BerriAI/litellm/pull/40995)
- fix(ui): show the team alias on the model info page and in its raw JSON by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;40992](https://github.com/BerriAI/litellm/pull/40992)
- feat(proxy): honor LITELLM\_DISABLE\_ACCESS\_LOG\_PATHS to drop noisy uvicorn access log lines by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;41096](https://github.com/BerriAI/litellm/pull/41096)
- fix(prometheus): label pre-call rate limit failures with the resolved api\_provider by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;41059](https://github.com/BerriAI/litellm/pull/41059)
- perf(proxy): serialize /model/info listing once with orjson by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;41114](https://github.com/BerriAI/litellm/pull/41114)
- fix(utils): stop wrapper\_async submitting the sync success handler twice by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;41115](https://github.com/BerriAI/litellm/pull/41115)
- fix(redis): log a timeout streak once per interval instead of one line per cache call by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;40817](https://github.com/BerriAI/litellm/pull/40817)
- fix(router): record flat retry attempts and cap retries from attempted\_retries by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;40930](https://github.com/BerriAI/litellm/pull/40930)
- refactor(prometheus): source PROXY\_LLM\_PROVIDER\_FALLBACK from litellm.constants by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;41118](https://github.com/BerriAI/litellm/pull/41118)
- fix(proxy): hide default credentials login hint when UI\_PASSWORD is set by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;41107](https://github.com/BerriAI/litellm/pull/41107)
- fix(cli): show routed models and session stats for LLM API keys by [@&#8203;tin-berri](https://github.com/tin-berri) in [#&#8203;41116](https://github.com/BerriAI/litellm/pull/41116)
- fix(bedrock/realtime): propagate deferred Nova Sonic stream failures to the router by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;41064](https://github.com/BerriAI/litellm/pull/41064)
- fix(proxy): keep org admins' own team memberships in other orgs visible on team list by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;41086](https://github.com/BerriAI/litellm/pull/41086)
- feat(model\_info): provider-scoped fill\_missing\_for\_providers backfill from fallback generalization rules by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;41093](https://github.com/BerriAI/litellm/pull/41093)
- fix(auth): load team membership once per request and skip prisma on an L1 hit by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;41102](https://github.com/BerriAI/litellm/pull/41102)
- refactor(harness): expand independent trace coverage by [@&#8203;yujonglee-berri](https://github.com/yujonglee-berri) in [#&#8203;41120](https://github.com/BerriAI/litellm/pull/41120)
- fix(proxy): release max\_parallel\_requests slot when a realtime session ends without LLM callbacks by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;41113](https://github.com/BerriAI/litellm/pull/41113)
- fix(router): cool down team deployments on 429 when a sibling serves the same public model by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;40991](https://github.com/BerriAI/litellm/pull/40991)
- fix(ui): move tags typed into key metadata JSON into the Tags field by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;41023](https://github.com/BerriAI/litellm/pull/41023)
- fix(ui): let team admins grant a team all proxy models by [@&#8203;ryan-crabbe-berri](https://github.com/ryan-crabbe-berri) in [#&#8203;40196](https://github.com/BerriAI/litellm/pull/40196)
- chore(lint): graduate 12 rules from the strict-gate ratchet by [@&#8203;HUAHAODIA](https://github.com/HUAHAODIA) in [#&#8203;41048](https://github.com/BerriAI/litellm/pull/41048)
- test: add dedicated CircleCI integration contract foundation by [@&#8203;yuneng-berri](https://github.com/yuneng-berri) in [#&#8203;41066](https://github.com/BerriAI/litellm/pull/41066)
- fix(utils): keep litellm params out of provider request bodies by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;41018](https://github.com/BerriAI/litellm/pull/41018)
- fix(openai): keep extra\_headers out of the chat request body on the httpx handler path by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;41141](https://github.com/BerriAI/litellm/pull/41141)
- test: cover persisted updates and warmed authorization policies by [@&#8203;yuneng-berri](https://github.com/yuneng-berri) in [#&#8203;41070](https://github.com/BerriAI/litellm/pull/41070)
- fix(proxy): resolve x-litellm-call-id from response metadata when routes omit call\_id by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;41056](https://github.com/BerriAI/litellm/pull/41056)
- chore(prices): sync Vertex AI prices: 14 models by [@&#8203;berriai-litellm-provider-info-sync](https://github.com/berriai-litellm-provider-info-sync)\[bot] in [#&#8203;40955](https://github.com/BerriAI/litellm/pull/40955)
- ci(codeql): exclude noisy Python quality queries by [@&#8203;yuneng-berri](https://github.com/yuneng-berri) in [#&#8203;41142](https://github.com/BerriAI/litellm/pull/41142)
- feat(proxy): predict prompt-cache costs across deployments by [@&#8203;tin-berri](https://github.com/tin-berri) in [#&#8203;40877](https://github.com/BerriAI/litellm/pull/40877)
- fix(prompt\_security): keep polling file sanitization through non-terminal statuses by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;41131](https://github.com/BerriAI/litellm/pull/41131)
- fix(health): skip background health check DB writes when the latest-row read fails by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;41145](https://github.com/BerriAI/litellm/pull/41145)
- feat(model\_armor): logging\_only mode scans completed streams after delivery by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;40702](https://github.com/BerriAI/litellm/pull/40702)
- fix(bedrock guardrails): derive contextual grounding source and query from plain messages by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;41132](https://github.com/BerriAI/litellm/pull/41132)
- fix(cli): drop enum.StrEnum so the CLI imports on Python 3.10 by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;41046](https://github.com/BerriAI/litellm/pull/41046)
- fix(responses): route mid-stream error events through exception\_type so content\_policy\_fallbacks fire by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;40988](https://github.com/BerriAI/litellm/pull/40988)
- fix(cost): bill gemini-embedding-2 per token and stop double charging audio by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;41157](https://github.com/BerriAI/litellm/pull/41157)
- test: bind management E2E callers and isolate JWT actors by [@&#8203;yuneng-berri](https://github.com/yuneng-berri) in [#&#8203;40892](https://github.com/BerriAI/litellm/pull/40892)
- fix(headroom): protect cache\_control-marked rows anywhere in history by [@&#8203;rad-p44](https://github.com/rad-p44) in [#&#8203;40315](https://github.com/BerriAI/litellm/pull/40315)
- test: add strict stateless provider replay identity by [@&#8203;yuneng-berri](https://github.com/yuneng-berri) in [#&#8203;41149](https://github.com/BerriAI/litellm/pull/41149)
- fix(ci): test checked-out model pricing in unit jobs by [@&#8203;yuneng-berri](https://github.com/yuneng-berri) in [#&#8203;41181](https://github.com/BerriAI/litellm/pull/41181)
- fix(guardrails): write per-message guardrail rewrites back onto Responses input items by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;40939](https://github.com/BerriAI/litellm/pull/40939)
- fix(proxy): log the provider usage on deferred /v1/messages calls and price cache writes without a creation rate by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;41172](https://github.com/BerriAI/litellm/pull/41172)
- fix(guardrails): record not\_run evaluation when scoping leaves nothing to scan by [@&#8203;yucheng-berri](https://github.com/yucheng-berri) in [#&#8203;39050](https://github.com/BerriAI/litellm/pull/39050)
- fix(responses): preserve provider affinity by [@&#8203;AaronHowell](https://github.com/AaronHowell) in [#&#8203;40228](https://github.com/BerriAI/litellm/pull/40228)
- fix(sdk): keep body and proxy headers on BadRequestError mapped from a litellm\_proxy 400 by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;40994](https://github.com/BerriAI/litellm/pull/40994)
- fix(responses): hoist Codex additional\_tools input items into the chat bridge tools by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;40989](https://github.com/BerriAI/litellm/pull/40989)
- fix(router): honor team and key provider weights by [@&#8203;tin-berri](https://github.com/tin-berri) in [#&#8203;41072](https://github.com/BerriAI/litellm/pull/41072)
- test(e2e): verify streamed answers and tool continuation by [@&#8203;yuneng-berri](https://github.com/yuneng-berri) in [#&#8203;41194](https://github.com/BerriAI/litellm/pull/41194)
- fix(cli): label router costs and simplify the routed-model header by [@&#8203;tin-berri](https://github.com/tin-berri) in [#&#8203;41186](https://github.com/BerriAI/litellm/pull/41186)
- test(spend): reconcile concurrent requests and daily activity by [@&#8203;yuneng-berri](https://github.com/yuneng-berri) in [#&#8203;41188](https://github.com/BerriAI/litellm/pull/41188)
- fix(guardrails): scan the Anthropic top-level system prompt and tool\_use arguments by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;40984](https://github.com/BerriAI/litellm/pull/40984)
- fix(router): count num\_retries\_per\_request across fallback hops by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;41191](https://github.com/BerriAI/litellm/pull/41191)
- fix(bedrock): grant rerank, retrieve, agent, and agentcore actions in the web identity session policy by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;41168](https://github.com/BerriAI/litellm/pull/41168)
- fix(vertex-live): bill Gemini Live sessions end to end (internal copy of [#&#8203;37075](https://github.com/BerriAI/litellm/issues/37075)) by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;40915](https://github.com/BerriAI/litellm/pull/40915)
- fix(health): resolve litellm\_credential\_name in realtime health checks by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;41173](https://github.com/BerriAI/litellm/pull/41173)
- feat(proxy): unified custom\_key\_policy hook for key generate, update and regenerate by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;40921](https://github.com/BerriAI/litellm/pull/40921)
- fix(proxy): enforce custom\_key\_update policy on /key/regenerate by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;40695](https://github.com/BerriAI/litellm/pull/40695)
- fix(router): preserve session model choice within each complexity tier by [@&#8203;tin-berri](https://github.com/tin-berri) in [#&#8203;41174](https://github.com/BerriAI/litellm/pull/41174)
- test(pricing): let synced GovCloud Bedrock rows cite the AWS price list by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;41263](https://github.com/BerriAI/litellm/pull/41263)
- docs(github): ask for interactive coding-tool proof in the PR template by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;41257](https://github.com/BerriAI/litellm/pull/41257)
- feat(proxy): add POST /management/v1/users/bulk for batched user and team membership creation by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;41028](https://github.com/BerriAI/litellm/pull/41028)
- fix(credentials): answer 409 on a credential name collision, make Terraform adoption opt-in by [@&#8203;ryan-crabbe-berri](https://github.com/ryan-crabbe-berri) in [#&#8203;40917](https://github.com/BerriAI/litellm/pull/40917)
- feat(proxy): add POST /management/v1/users/bulk\_delete and POST /management/v1/teams/{team\_id}/members/bulk\_delete by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;41039](https://github.com/BerriAI/litellm/pull/41039)
- fix(proxy): list directly assigned team models in model access errors by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;41256](https://github.com/BerriAI/litellm/pull/41256)
- feat(auto-router): allow opted-in team members to manage their routers by [@&#8203;tin-berri](https://github.com/tin-berri) in [#&#8203;41175](https://github.com/BerriAI/litellm/pull/41175)
- build(rust-bridge): add typed \_native stub and validate it with mypy.stubtest by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;41180](https://github.com/BerriAI/litellm/pull/41180)
- feat(guardrails): add new upstream presidio pii entities including german set by [@&#8203;MvdB](https://github.com/MvdB) in [#&#8203;36775](https://github.com/BerriAI/litellm/pull/36775)
- fix(responses): filter bridged kwargs like the native Responses path by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;41144](https://github.com/BerriAI/litellm/pull/41144)
- test(e2e): cover the reliability retry, cooldown, fallback, and routing-strategy cells by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;39857](https://github.com/BerriAI/litellm/pull/39857)
- fix(anthropic): add the per-turn-control beta when a message carries output\_config by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;41189](https://github.com/BerriAI/litellm/pull/41189)
- fix(router): bind per-request routing\_strategy override selectors to the request's callbacks by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;41178](https://github.com/BerriAI/litellm/pull/41178)
- feat(proxy): bind JWT claims to registered agents via agent\_id\_jwt\_field by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;40904](https://github.com/BerriAI/litellm/pull/40904)
- fix(proxy): enforce organization budgets when max\_budget is 0 by [@&#8203;yassin-berriai](https://github.com/yassin-berriai) in [#&#8203;41271](https://github.com/BerriAI/litellm/pull/41271)
- fix(alerting): send llm\_exceptions Slack alert for 5xx HTTPException and ProxyException by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;41125](https://github.com/BerriAI/litellm/pull/41125)
- fix(headroom): protect the cached prefix through the last cache\_control breakpoint by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;41161](https://github.com/BerriAI/litellm/pull/41161)
- fix(utils): cache custom HuggingFace tokenizers across /utils/token\_counter requests by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;41216](https://github.com/BerriAI/litellm/pull/41216)
- fix(router): keep weighted routing when a deployment id equals a model\_name by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;41156](https://github.com/BerriAI/litellm/pull/41156)
- feat(router): add capability classifier as Fuse foundation by [@&#8203;tin-berri](https://github.com/tin-berri) in [#&#8203;41270](https://github.com/BerriAI/litellm/pull/41270)
- fix(proxy): keep access-group raw SQL writes on the writer while writer\_unavailable is stale by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;41283](https://github.com/BerriAI/litellm/pull/41283)
- fix(prometheus): count 401 auth failures in litellm\_proxy\_failed\_requests\_metric by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;41170](https://github.com/BerriAI/litellm/pull/41170)
- test: drop tests that pin vendor facts and add the CLAUDE.md rule by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;41269](https://github.com/BerriAI/litellm/pull/41269)
- fix(proxy): run the remaining inline token counts off the event loop by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;40262](https://github.com/BerriAI/litellm/pull/40262)
- fix(proxy): log blocked streaming guardrail responses as failures, not success by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;40191](https://github.com/BerriAI/litellm/pull/40191)
- feat(proxy): add tpd\_limit (tokens per day) for batch submissions by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;40997](https://github.com/BerriAI/litellm/pull/40997)
- fix(proxy): reconcile budget reservation before enqueuing spend to the DB by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;40310](https://github.com/BerriAI/litellm/pull/40310)
- fix(xai): stop sending web\_search\_options to xAI's retired Live Search path by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;38278](https://github.com/BerriAI/litellm/pull/38278)
- feat(terraform): add tpm\_limit, rpm\_limit, budget\_duration, allowed\_models to litellm\_team\_member\_add by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;38682](https://github.com/BerriAI/litellm/pull/38682)
- fix(rerank): bill Vertex search\_units from input records and give every rerank response a unique id by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;35180](https://github.com/BerriAI/litellm/pull/35180)
- fix(router): stop counting caller-set timeout 408s toward deployment cooldown by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;41230](https://github.com/BerriAI/litellm/pull/41230)
- feat(router): add Fuse V2 classifier after capability forecasting by [@&#8203;tin-berri](https://github.com/tin-berri) in [#&#8203;41272](https://github.com/BerriAI/litellm/pull/41272)
- fix(proxy): keep client User-Agent on auth failure spend logs by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;41291](https://github.com/BerriAI/litellm/pull/41291)
- fix(proxy): reset budgets by decrementing pre-reset spend instead of zeroing rows by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;41279](https://github.com/BerriAI/litellm/pull/41279)
- fix(xai): honor nested web\_search filters on the xAI Responses API by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;38268](https://github.com/BerriAI/litellm/pull/38268)
- fix(router): stop registering a caller-supplied credential as a router deployment by [@&#8203;yassin-berriai](https://github.com/yassin-berriai) in [#&#8203;41289](https://github.com/BerriAI/litellm/pull/41289)
- fix(router): accept custom\_provider\_map providers before the first completion call by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;41300](https://github.com/BerriAI/litellm/pull/41300)
- fix(proxy): return 400 instead of 500 for lone surrogate escapes in request body by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;41297](https://github.com/BerriAI/litellm/pull/41297)
- fix(langsmith): keep events appended during an in-flight flush instead of clearing them by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;41288](https://github.com/BerriAI/litellm/pull/41288)
- fix(logging): track spend for streams a deployment hook converted to non-streaming by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;41171](https://github.com/BerriAI/litellm/pull/41171)
- fix(bedrock): sanitize client tool\_call ids to Bedrock toolUseId constraints by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;40872](https://github.com/BerriAI/litellm/pull/40872)
- fix(passthrough): attribute Vertex passthrough successes to the resolved router deployment by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;41307](https://github.com/BerriAI/litellm/pull/41307)
- feat(ui): persist Models table search, filters, sort and page in the URL by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;41296](https://github.com/BerriAI/litellm/pull/41296)
- fix(jwt-auth): scope JWT key mappings by issuer to prevent cross-issuer collisions by [@&#8203;yassin-berriai](https://github.com/yassin-berriai) in [#&#8203;41281](https://github.com/BerriAI/litellm/pull/41281)
- feat(openai): add openai\_system\_messages\_first to put system messages first for prompt caching by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;41304](https://github.com/BerriAI/litellm/pull/41304)
- feat(ui): add custom request headers to the API Playground by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;41309](https://github.com/BerriAI/litellm/pull/41309)
- feat(cli): sync Codex /model picker from proxy /v1/models in lite codex by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;40476](https://github.com/BerriAI/litellm/pull/40476)
- chore: bump litellm-enterprise 0.1.67 -> 0.1.68, litellm-proxy-extras 0.4.97 -> 0.4.98, litellm 1.102.0 -> 1.103.0 by [@&#8203;yuneng-berri](https://github.com/yuneng-berri) in [#&#8203;41321](https://github.com/BerriAI/litellm/pull/41321)
- feat: add aihubmix provider pricing entries by [@&#8203;IToSSc](https://github.com/IToSSc) in [#&#8203;41179](https://github.com/BerriAI/litellm/pull/41179)
- feat(auto-router): add per-model Fast mode toggle by [@&#8203;tin-berri](https://github.com/tin-berri) in [#&#8203;41282](https://github.com/BerriAI/litellm/pull/41282)
- fix(proxy): include litellm\_call\_id in LLM API exception logs by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;41205](https://github.com/BerriAI/litellm/pull/41205)
- fix(proxy): keep yaml pass-through endpoints visible to auth after db overlay by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;41303](https://github.com/BerriAI/litellm/pull/41303)
- fix(proxy): resolve router\_settings.model\_group\_alias before key/team model auth by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;41308](https://github.com/BerriAI/litellm/pull/41308)
- fix(ui): block usage export and flag the range when a spend page fails by [@&#8203;ryan-crabbe-berri](https://github.com/ryan-crabbe-berri) in [#&#8203;41294](https://github.com/BerriAI/litellm/pull/41294)
- fix(vertex\_ai): bill Gemini Omni Interactions usage and Veo sampleCount on passthrough by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;41322](https://github.com/BerriAI/litellm/pull/41322)
- fix(proxy): honor LITELLM\_LOG for uvicorn and proxy extras loggers by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;41306](https://github.com/BerriAI/litellm/pull/41306)
- fix(cost): price native Responses WebSocket turns at their returned service\_tier by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;41318](https://github.com/BerriAI/litellm/pull/41318)
- fix(proxy): key model rpm/tpm override takes precedence over team model limit by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;41302](https://github.com/BerriAI/litellm/pull/41302)
- fix(proxy): track per-member organization spend by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;41255](https://github.com/BerriAI/litellm/pull/41255)
- feat(proxy): add /nvidia\_nim passthrough route for NIM object detection and OCR /v1/infer by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;41316](https://github.com/BerriAI/litellm/pull/41316)
- feat(model\_info): add provider-neutral Gemini 2.5+ chat baseline fallback generalization by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;41320](https://github.com/BerriAI/litellm/pull/41320)
- fix(spend): sum multi-round session duration in logs UI by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;35388](https://github.com/BerriAI/litellm/pull/35388)
- feat(router): limit unlicensed Capability and Fuse v2 routers to one each by [@&#8203;tin-berri](https://github.com/tin-berri) in [#&#8203;41326](https://github.com/BerriAI/litellm/pull/41326)
- fix(guardrails): resolve caller identity from metadata buckets in custom code guardrail by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;41126](https://github.com/BerriAI/litellm/pull/41126)
- fix(e2e): onboard dashboard users through invitations by [@&#8203;yuneng-berri](https://github.com/yuneng-berri) in [#&#8203;41319](https://github.com/BerriAI/litellm/pull/41319)
- feat(guardrails): add Microsoft Agent 365 MCP tool-call guardrail by [@&#8203;yucheng-berri](https://github.com/yucheng-berri) in [#&#8203;38241](https://github.com/BerriAI/litellm/pull/38241)
- test: drop remaining tests that pin cost-map vendor facts by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;41298](https://github.com/BerriAI/litellm/pull/41298)
- feat(ui): show average response time per model in usage model activity by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;41313](https://github.com/BerriAI/litellm/pull/41313)
- fix(proxy): preserve Anthropic pricing modifiers in router savings by [@&#8203;tin-berri](https://github.com/tin-berri) in [#&#8203;41341](https://github.com/BerriAI/litellm/pull/41341)
- feat(guardrails): support pre\_call and during\_call modes for llm\_as\_a\_judge by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;41128](https://github.com/BerriAI/litellm/pull/41128)
- fix(gemini): propagate the provider's modelVersion to the response model by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;41338](https://github.com/BerriAI/litellm/pull/41338)
- fix(fireworks-ai): bill cache-write, reasoning and audio tokens via the shared cost calculator by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;41339](https://github.com/BerriAI/litellm/pull/41339)
- feat(guardrails): singulr v2 API contract with logging\_only, pre\_mcp\_call and post\_mcp\_call by [@&#8203;yucheng-berri](https://github.com/yucheng-berri) in [#&#8203;41329](https://github.com/BerriAI/litellm/pull/41329)
- ci(image-scan): ignore zlib CVE-2026-85091 until Wolfi ships the fix by [@&#8203;yuneng-berri](https://github.com/yuneng-berri) in [#&#8203;41353](https://github.com/BerriAI/litellm/pull/41353)
- feat(e2e): reuse exact provider responses for 24 hours by [@&#8203;yuneng-berri](https://github.com/yuneng-berri) in [#&#8203;41346](https://github.com/BerriAI/litellm/pull/41346)
- fix(xai): keep 'instructions' on the xAI Responses API so system messages survive web search by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;38254](https://github.com/BerriAI/litellm/pull/38254)
- feat(ui): configure capability and Fuse v2 classifiers by [@&#8203;tin-berri](https://github.com/tin-berri) in [#&#8203;41315](https://github.com/BerriAI/litellm/pull/41315)
- fix(anthropic): tolerate message\_delta events without usage when streaming by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;41336](https://github.com/BerriAI/litellm/pull/41336)
- test(router): ignore deployment-selection logs in the fallback log assertion by [@&#8203;yuneng-berri](https://github.com/yuneng-berri) in [#&#8203;41358](https://github.com/BerriAI/litellm/pull/41358)
- test(proxy): assert budget resets decrement the cleared spend by [@&#8203;yuneng-berri](https://github.com/yuneng-berri) in [#&#8203;41359](https://github.com/BerriAI/litellm/pull/41359)
- fix(e2e): expect models filters to persist after reload by [@&#8203;yuneng-berri](https://github.com/yuneng-berri) in [#&#8203;41348](https://github.com/BerriAI/litellm/pull/41348)
- fix(e2e): record cookie-setting provider responses and keep prompt-caching tests live by [@&#8203;yuneng-berri](https://github.com/yuneng-berri) in [#&#8203;41366](https://github.com/BerriAI/litellm/pull/41366)
- fix(responses): recount tokens when a streamed response completes without usage by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;41337](https://github.com/BerriAI/litellm/pull/41337)
- fix(ui): simplify Capability and Fuse advanced routing options by [@&#8203;tin-berri](https://github.com/tin-berri) in [#&#8203;41371](https://github.com/BerriAI/litellm/pull/41371)
- fix(mcp): authorize JWT OAuth credential persistence by [@&#8203;joshua-berri](https://github.com/joshua-berri) in [#&#8203;41314](https://github.com/BerriAI/litellm/pull/41314)
- feat(router): stream shadow traffic and fan out silent\_model to multiple targets by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;41368](https://github.com/BerriAI/litellm/pull/41368)
- perf(content\_filter): scan a bounded window per streamed chunk by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;41407](https://github.com/BerriAI/litellm/pull/41407)
- fix(proxy): hide model allowlist from client-facing model access denied errors by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;41310](https://github.com/BerriAI/litellm/pull/41310)
- feat(http): opt-in outbound HTTP/2 for httpx clients by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;41268](https://github.com/BerriAI/litellm/pull/41268)
- refactor(rust): remove gateway, config, router, realtime, and Rust trace-parity instrumentation by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;41432](https://github.com/BerriAI/litellm/pull/41432)
- fix(guardrails): don't add post\_call output scan for MCP-only Presidio modes by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;40571](https://github.com/BerriAI/litellm/pull/40571)
- chore(prices): sync Azure, Azure AI, Gemini, OpenAI, Bedrock, Together AI, Fireworks and Vertex prices: 278 models, 59 new, 30 deprecated by [@&#8203;berriai-litellm-provider-info-sync](https://github.com/berriai-litellm-provider-info-sync)\[bot] in [#&#8203;41154](https://github.com/BerriAI/litellm/pull/41154)
- fix(rag): forward retrieval\_filter from retrieval\_config to vector store search by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;34427](https://github.com/BerriAI/litellm/pull/34427)
- refactor(rust): extract auth and cache crates by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;41464](https://github.com/BerriAI/litellm/pull/41464)
- fix(proxy): default litellm\_trace\_id to the OTel server span trace id by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;41386](https://github.com/BerriAI/litellm/pull/41386)
- chore(codeowners): add ryan and kerry as owners of the cost map by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;41333](https://github.com/BerriAI/litellm/pull/41333)
- fix(responses): guard empty-choices chunks in the Responses API streaming bridge by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;34455](https://github.com/BerriAI/litellm/pull/34455)
- chore(prices): sync Google Gemini prices: 22 models by [@&#8203;berriai-litellm-provider-info-sync](https://github.com/berriai-litellm-provider-info-sync)\[bot] in [#&#8203;41457](https://github.com/BerriAI/litellm/pull/41457)
- fix(bedrock): forward userContext in Knowledge Base Retrieve requests by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;41475](https://github.com/BerriAI/litellm/pull/41475)
- ci(rust): split rust jobs, use nextest and Swatinem/rust-cache by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;41480](https://github.com/BerriAI/litellm/pull/41480)
- fix(fireworks\_ai): flatten dict-form reasoning\_effort to its effort string by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;41335](https://github.com/BerriAI/litellm/pull/41335)
- fix(proxy): never forward the LiteLLM virtual key to Anthropic on the /anthropic passthrough by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;41340](https://github.com/BerriAI/litellm/pull/41340)
- fix(proxy): rename AWS Secrets Manager secret when key alias changes by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;41468](https://github.com/BerriAI/litellm/pull/41468)
- feat(otel): promote nested request metadata keys to litellm.metadata.\* span attributes by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;41462](https://github.com/BerriAI/litellm/pull/41462)
- fix(proxy): sync AWS Secrets Manager on body-less key regenerate and key alias changes by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;41458](https://github.com/BerriAI/litellm/pull/41458)
- fix(http\_handler): keep a handler alive while a response it issued is still reading by [@&#8203;max-sixty](https://github.com/max-sixty) in [#&#8203;34829](https://github.com/BerriAI/litellm/pull/34829)
- fix(bedrock): make prompt caching work on the Nova InvokeModel route by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;41343](https://github.com/BerriAI/litellm/pull/41343)
- ci(migrations): flag defaulted ADD COLUMN on request-log tables by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;41460](https://github.com/BerriAI/litellm/pull/41460)
- feat(prometheus): add customer (end\_user) budget gauges by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;41472](https://github.com/BerriAI/litellm/pull/41472)
- fix(otel): drop None metric and event attributes before OTLP export by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;36815](https://github.com/BerriAI/litellm/pull/36815)
- fix(anthropic): carry the served model from message\_start onto stream chunks by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;41446](https://github.com/BerriAI/litellm/pull/41446)
- fix(models): rolling registry audit: Gemini latest aliases, Nova cache pricing, OpenRouter/Together sync, Mistral GLM 5.3, Azure snapshots, Grok caching by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;41112](https://github.com/BerriAI/litellm/pull/41112)
- fix(router): count TPM/RPM usage before building rate-limit headers by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;41474](https://github.com/BerriAI/litellm/pull/41474)
- feat(guardrails): release buffered stream chunks after each passing scan by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;41425](https://github.com/BerriAI/litellm/pull/41425)
- fix!: re-check budget on router fallback targets by [@&#8203;runjivu](https://github.com/runjivu) in [#&#8203;41379](https://github.com/BerriAI/litellm/pull/41379)
- refactor(ocr): move file preparation from the python bridge into litellm-core by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;41489](https://github.com/BerriAI/litellm/pull/41489)
- feat(s3): add s3\_log\_prompts\_only option to log prompts without responses by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;41327](https://github.com/BerriAI/litellm/pull/41327)
- feat(team): team-level model\_max\_budget with key-level overrides by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;41330](https://github.com/BerriAI/litellm/pull/41330)
- feat(keys): filter /key/list by active, expired, revoked or deleted status and serve deleted keys from /key/info by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;41311](https://github.com/BerriAI/litellm/pull/41311)
- feat(proxy): expose lifetime total\_spend on virtual keys by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;41403](https://github.com/BerriAI/litellm/pull/41403)
- fix(proxy): release completed max-parallel slots promptly by [@&#8203;elifozdamar](https://github.com/elifozdamar) in [#&#8203;40843](https://github.com/BerriAI/litellm/pull/40843)
- feat(ui): accept ssh clone urls when registering a skill by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;35418](https://github.com/BerriAI/litellm/pull/35418)
- fix(prices): dedupe Nova cache\_read\_input\_token\_cost keys left by a text merge by [@&#8203;yuneng-berri](https://github.com/yuneng-berri) in [#&#8203;41496](https://github.com/BerriAI/litellm/pull/41496)
- fix(otel): propagate W3C trace context on HTTP and WebSocket passthrough by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;40669](https://github.com/BerriAI/litellm/pull/40669)
- fix(proxy): remove duplicate user budget hook that 429'd zero-cost models by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;41345](https://github.com/BerriAI/litellm/pull/41345)
- test(logging): pick this test's own records out of the shared log batch by [@&#8203;yuneng-berri](https://github.com/yuneng-berri) in [#&#8203;41487](https://github.com/BerriAI/litellm/pull/41487)
- test(together\_ai): move request-shape checks to the mapped file, drop the live ones by [@&#8203;yuneng-berri](https://github.com/yuneng-berri) in [#&#8203;41360](https://github.com/BerriAI/litellm/pull/41360)
- feat(ui): shared URL-state layer for tables and tabs by [@&#8203;ryan-crabbe-berri](https://github.com/ryan-crabbe-berri) in [#&#8203;41331](https://github.com/BerriAI/litellm/pull/41331)
- feat(e2e): make the provider cache reusable across builds and mount Bedrock behind it by [@&#8203;yuneng-berri](https://github.com/yuneng-berri) in [#&#8203;41402](https://github.com/BerriAI/litellm/pull/41402)
- fix(mcp): fail closed on missing upstream credentials by [@&#8203;joshua-berri](https://github.com/joshua-berri) in [#&#8203;41364](https://github.com/BerriAI/litellm/pull/41364)
- feat(rust): scaffold Redis cache crate by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;41501](https://github.com/BerriAI/litellm/pull/41501)
- fix(dashscope): forward reasoning\_effort to the provider by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;37506](https://github.com/BerriAI/litellm/pull/37506)
- fix(proxy): carry litellm\_call\_id through endpoint specific error logs and failure responses by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;41356](https://github.com/BerriAI/litellm/pull/41356)
- fix(proxy): retry rate-limit fallbacks from a pristine request snapshot by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;40596](https://github.com/BerriAI/litellm/pull/40596)
- fix(gemini): map minimal thinking to low for Gemini 3.7 and 3.8 Flash by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;41201](https://github.com/BerriAI/litellm/pull/41201)
- fix(proxy): stop forwarding LiteLLM credential headers on Bedrock agent-runtime passthrough by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;41504](https://github.com/BerriAI/litellm/pull/41504)
- fix(streaming): estimate interrupted Anthropic stream usage from reasoning\_content by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;41503](https://github.com/BerriAI/litellm/pull/41503)
- fix(azure\_ai): route Responses API to native /openai/v1/responses for Foundry Models by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;33856](https://github.com/BerriAI/litellm/pull/33856)
- fix(proxy): show all model groups to proxy admins in /model\_group/info by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;41094](https://github.com/BerriAI/litellm/pull/41094)
- feat(proxy): let proxy admins choose which team fields team admins may edit by [@&#8203;ryan-crabbe-berri](https://github.com/ryan-crabbe-berri) in [#&#8203;39996](https://github.com/BerriAI/litellm/pull/39996)
- fix(bedrock): neutralize orphaned tool blocks instead of raising or injecting a dummy tool (internal copy of [#&#8203;31400](https://github.com/BerriAI/litellm/issues/31400)) by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;41513](https://github.com/BerriAI/litellm/pull/41513)
- feat(ui): persist organizations and projects list, detail tab and key table state in the URL by [@&#8203;ryan-crabbe-berri](https://github.com/ryan-crabbe-berri) in [#&#8203;41445](https://github.com/BerriAI/litellm/pull/41445)
- fix(bedrock\_mantle): accept and forward verbosity on gpt-5.x chat completions by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;41509](https://github.com/BerriAI/litellm/pull/41509)
- test: cover database transactions and persisted accounting by [@&#8203;yuneng-berri](https://github.com/yuneng-berri) in [#&#8203;41073](https://github.com/BerriAI/litellm/pull/41073)
- test: provider wire contracts, streaming and recovery by [@&#8203;yuneng-berri](https://github.com/yuneng-berri) in [#&#8203;41075](https://github.com/BerriAI/litellm/pull/41075)
- fix(mcp): count admin static headers as api\_key credential slots by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;41514](https://github.com/BerriAI/litellm/pull/41514)
- ci: auto-merge provider-info-sync PRs when CI, Greptile and Bugbot are clean by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;41494](https://github.com/BerriAI/litellm/pull/41494)
- feat(rust): add standalone framing crate by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;41500](https://github.com/BerriAI/litellm/pull/41500)
- fix(proxy): enforce tag budgets for tags added by guardrails by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;40842](https://github.com/BerriAI/litellm/pull/40842)
- fix(utils): run post-call deployment hook on converted chat streams by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;41495](https://github.com/BerriAI/litellm/pull/41495)
- fix(e2e): bind provider-cache recordings to the deployment's test, not the serving process by [@&#8203;yuneng-berri](https://github.com/yuneng-berri) in [#&#8203;41520](https://github.com/BerriAI/litellm/pull/41520)
- test: add extension and browser integration contracts by [@&#8203;yuneng-berri](https://github.com/yuneng-berri) in [#&#8203;41078](https://github.com/BerriAI/litellm/pull/41078)
- fix(logging): scan each log record once and collapse base64 payloads before the secret regex by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;40934](https://github.com/BerriAI/litellm/pull/40934)
- fix(spend\_tracking): attribute router-rejected requests to the model group provider by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;41507](https://github.com/BerriAI/litellm/pull/41507)
- feat(router): discover token limits for hosted OpenAI-compatible models by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;41508](https://github.com/BerriAI/litellm/pull/41508)
- feat(proxy): let team admins edit rpm\_limit and max\_budget when enabled by [@&#8203;ryan-crabbe-berri](https://github.com/ryan-crabbe-berri) in [#&#8203;41525](https://github.com/BerriAI/litellm/pull/41525)
- fix(otel): fit per-index OpenInference messages to the span's remaining attribute budget by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;41498](https://github.com/BerriAI/litellm/pull/41498)
- test(aws): verify rotated secret value by [@&#8203;yuneng-berri](https://github.com/yuneng-berri) in [#&#8203;41524](https://github.com/BerriAI/litellm/pull/41524)
- test(e2e): read a deleted key back as deleted, not as a 404 by [@&#8203;yuneng-berri](https://github.com/yuneng-berri) in [#&#8203;41551](https://github.com/BerriAI/litellm/pull/41551)
- fix(otel v2): map the caller's Langfuse user, session and tags onto the root and generation spans by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;41140](https://github.com/BerriAI/litellm/pull/41140)
- test: fix seven tests left stale by [#&#8203;41311](https://github.com/BerriAI/litellm/issues/41311), [#&#8203;41337](https://github.com/BerriAI/litellm/issues/41337), [#&#8203;39996](https://github.com/BerriAI/litellm/issues/39996), [#&#8203;41310](https://github.com/BerriAI/litellm/issues/41310), [#&#8203;41289](https://github.com/BerriAI/litellm/issues/41289) and [#&#8203;41315](https://github.com/BerriAI/litellm/issues/41315) by [@&#8203;yuneng-berri](https://github.com/yuneng-berri) in [#&#8203;41527](https://github.com/BerriAI/litellm/pull/41527)
- test(budgets): cover management null handling by [@&#8203;yuneng-berri](https://github.com/yuneng-berri) in [#&#8203;41563](https://github.com/BerriAI/litellm/pull/41563)
- test(e2e): drop the auto-router select "opens below" spec by [@&#8203;yuneng-berri](https://github.com/yuneng-berri) in [#&#8203;41568](https://github.com/BerriAI/litellm/pull/41568)
- fix(guardrails): stream Prompt Security post\_call redactions in incremental\_diff mode by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;41558](https://github.com/BerriAI/litellm/pull/41558)
- fix(guardrails): give post-call scans the scoped request conversation and tools by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;41220](https://github.com/BerriAI/litellm/pull/41220)
- feat(openrouter): add stealth/union-alpha to the model cost map by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;41576](https://github.com/BerriAI/litellm/pull/41576)
- test(management): cover project authorization lifecycle by [@&#8203;yuneng-berri](https://github.com/yuneng-berri) in [#&#8203;41573](https://github.com/BerriAI/litellm/pull/41573)
- feat(rust): map Anthropic Messages transformations by [@&#8203;yujonglee-berri](https://github.com/yujonglee-berri) in [#&#8203;41531](https://github.com/BerriAI/litellm/pull/41531)
- fix(e2e): clear the three standing errors in the scheduled Buildkite suite by [@&#8203;yuneng-berri](https://github.com/yuneng-berri) in [#&#8203;41616](https://github.com/BerriAI/litellm/pull/41616)
- refactor(rust\_bridge): declarative route catalog and shared runtime selection by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;41479](https://github.com/BerriAI/litellm/pull/41479)
- fix(mock\_completion): keep the resolved provider so router custom pricing resolves for azure\_ai deployments by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;41623](https://github.com/BerriAI/litellm/pull/41623)
- fix(mcp): restrict health discovery to virtual key grants by [@&#8203;joshua-berri](https://github.com/joshua-berri) in [#&#8203;41609](https://github.com/BerriAI/litellm/pull/41609)
- fix(mcp): preserve request-selected guardrails during tool execution by [@&#8203;joshua-berri](https://github.com/joshua-berri) in [#&#8203;41619](https://github.com/BerriAI/litellm/pull/41619)
- refactor(ocr): mirror Python provider layout and preserve tests by [@&#8203;yujonglee-berri](https://github.com/yujonglee-berri) in [#&#8203;41550](https://github.com/BerriAI/litellm/pull/41550)
- test(fireworks\_ai): stop pinning vision support on minimax-m3 by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;41627](https://github.com/BerriAI/litellm/pull/41627)
- perf(spend\_tracking): index LiteLLM\_SpendLogs by (api\_key, startTime) by [@&#8203;etiennechabert](https://github.com/etiennechabert) in [#&#8203;37983](https://github.com/BerriAI/litellm/pull/37983)
- fix(proxy): reject non-string model with 400 and log its spend as unknown-model by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;41633](https://github.com/BerriAI/litellm/pull/41633)
- test(together\_ai): stop pinning successor deprecation status by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;41635](https://github.com/BerriAI/litellm/pull/41635)
- chore(prices): sync Together AI prices: 6 models, 6 deprecated \[sync failed: Google Gemini] by [@&#8203;berriai-litellm-provider-info-sync](https://github.com/berriai-litellm-provider-info-sync)\[bot] in [#&#8203;41570](https://github.com/BerriAI/litellm/pull/41570)
- fix(budgets): page end-user cache invalidation after a budget reset by [@&#8203;ryan-crabbe-berri](https://github.com/ryan-crabbe-berri) in [#&#8203;41488](https://github.com/BerriAI/litellm/pull/41488)
- chore: bump litellm-proxy-extras 0.4.98 -> 0.4.99 by [@&#8203;yuneng-berri](https://github.com/yuneng-berri) in [#&#8203;41659](https://github.com/BerriAI/litellm/pull/41659)
- fix(tests): resolve the integration support package without run.py's PYTHONPATH by [@&#8203;yuneng-berri](https://github.com/yuneng-berri) in [#&#8203;41373](https://github.com/BerriAI/litellm/pull/41373)
- fix(ui): keep untimed guardrail entries on the request lifecycle by [@&#8203;yuneng-berri](https://github.com/yuneng-berri) in [#&#8203;41374](https://github.com/BerriAI/litellm/pull/41374)
- fix(anthropic-bridge): convert mid-conversation system turns to user turns on /v1/messages to chat completions by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;41493](https://github.com/BerriAI/litellm/pull/41493)
- fix(bedrock): support aws-sdk-bedrock-runtime 0.10/0.11 in Bedrock Realtime by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;41542](https://github.com/BerriAI/litellm/pull/41542)
- feat(cli): deprecate the litellm-proxy entrypoint in favour of lite by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;41673](https://github.com/BerriAI/litellm/pull/41673)
- fix(scim): align pagination `count` validation with RFC 7644 by [@&#8203;zachbernstein-sdx](https://github.com/zachbernstein-sdx) in [#&#8203;41444](https://github.com/BerriAI/litellm/pull/41444)
- fix(bedrock): never emit Converse cachePoint for OpenAI-family models by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;41419](https://github.com/BerriAI/litellm/pull/41419)
- fix(images): stop forwarding the raw image\[] and mask\[] form keys by [@&#8203;mateo-berri](https://github.com/mateo-berri) in [#&#8203;39512](https://github.com/BerriAI/litellm/pull/39512)
- feat(management\_v1): bulk update team member budgets by [@&#8203;ryan-crabbe-berri](https://github.com/ryan-crabbe-berri) in [#&#8203;41632](https://github.com/BerriAI/litellm/pull/41632)
- refactor(rust): extract provider translations by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;41690](https://github.com/BerriAI/litellm/pull/41690)
- feat(cli): rename lite autoroute up/down to start/stop, keeping the old names as deprecated aliases by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;41672](https://github.com/BerriAI/litellm/pull/41672)
- fix(responses): keep the addressed response id off bridged provider requests by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;41689](https://github.com/BerriAI/litellm/pull/41689)
- fix(license): let a wildcard allowed\_features license grant the auto\_router feature by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;41684](https://github.com/BerriAI/litellm/pull/41684)
- fix(ui): list every provider in the cache leakage by-model table by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;40875](https://github.com/BerriAI/litellm/pull/40875)
- fix(team): keep a forked member budget's reset window and audit bulk member budget writes by [@&#8203;ryan-crabbe-berri](https://github.com/ryan-crabbe-berri) in [#&#8203;41686](https://github.com/BerriAI/litellm/pull/41686)
- feat(proxy): add TypeSafe AI Jev evaluate passthrough with registry-priced spend tracking by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;41607](https://github.com/BerriAI/litellm/pull/41607)
- test(e2e): cover bedrock batch file upload and create in the us-gov-west-1 partition by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;41536](https://github.com/BerriAI/litellm/pull/41536)
- feat(grafana): add all-metrics dashboard and fix stale dashboard\_v2 gauges by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;41578](https://github.com/BerriAI/litellm/pull/41578)
- fix(cost): price Azure PTU spillover requests at standard token rates by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;41569](https://github.com/BerriAI/litellm/pull/41569)
- build(deps): bump soupsieve to 2.9.2 to clear the osv-scan advisories by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;41703](https://github.com/BerriAI/litellm/pull/41703)
- fix(fireworks\_ai): restore supports\_vision on minimax-m3 in the cost map by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;41699](https://github.com/BerriAI/litellm/pull/41699)
- feat(policy\_engine): explicit priority for policy attachment execution order by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;41571](https://github.com/BerriAI/litellm/pull/41571)
- feat(router): add TypeSafe Jev as a complexity router classifier by [@&#8203;devin-ai-integration](https://github.com/devin-ai-integration)\[bot] in [#&#8203;41615](https://github.com…
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.

3 participants