Commit graph

11767 commits

Author SHA1 Message Date
ryan-crabbe-berri
60d3796497
Merge pull request #26139 from BerriAI/litellm_fix-retired-haiku-model
chore: update retired claude-3-haiku-20240307 to claude-haiku-4-5-20251001
2026-04-20 16:30:19 -07:00
Krrish Dholakia
e7bc316db0
Litellm krrish staging 04 20 2026 (#26138)
* feat(router): add auto_router/quality_router for quality-tier routing (#25987)

* feat(router): add auto_router/quality_router for quality-tier routing

Adds a new auto-router type that routes a request to a model at a target
quality tier. The quality tier is inferred by re-using the existing
ComplexityRouter's classification, then mapped through an admin-configured
complexity_to_quality table. Each candidate model declares its own
quality_tier in model_info.litellm_routing_preferences.

Resolution strategy: exact tier match, else round up to the next higher
tier, else fall back to default_model.

Co-Authored-By: Claude Opus 4 (1M context) <noreply@anthropic.com>

* feat(quality_router): add capability-based filtering

Each deployment can declare a `capabilities: List[str]` field in
`model_info.litellm_routing_preferences` (e.g. ["vision",
"function_calling"]). Requests can pass `litellm_capabilities` in
`request_kwargs` to require specific capabilities — the router will only
route to deployments whose declared capabilities are a superset.

Resolution still walks tier (exact → round up), but at each tier filters
by capability before picking. Falls back to default_model only when it
also satisfies the required capabilities; otherwise raises rather than
silently routing to a model that lacks a required capability.

Co-Authored-By: Claude Opus 4 (1M context) <noreply@anthropic.com>

* feat(quality_router): expose routing decision in response headers

For transparency, expose the QualityRouter's routing decision in the
proxy response headers:

  x-litellm-quality-router-model       → picked model_name (e.g. "haiku-vision")
  x-litellm-quality-router-tier        → resolved quality tier (e.g. "1")
  x-litellm-quality-router-complexity  → ComplexityTier name (e.g. "SIMPLE")

Mechanism: the pre-routing hook stashes the decision in
request_kwargs["metadata"]["quality_router_decision"]. After the call
returns, Router.set_response_headers lifts the decision into
response._hidden_params["additional_headers"] alongside the existing
x-litellm-model-group / x-litellm-model-id headers. Existing metadata
keys (trace_id, user_id, etc.) are preserved.

Co-Authored-By: Claude Opus 4 (1M context) <noreply@anthropic.com>

* feat(quality_router): replace capabilities with keyword override

Drops the capability-based filtering in favor of a keyword-based override
for v0:

- RoutingPreferences.keywords: List[str] (replaces capabilities) — each
  deployment can declare substring keywords.
- If any declared keyword (case-insensitive) appears in the user message,
  the router short-circuits the complexity-classification flow and routes
  to the matching deployment.
- Tiebreaker for overlapping keyword matches: quality_tier DESC, then
  cheapest model_info.input_cost_per_token ASC. Unpriced models lose ties
  to priced ones.

Decision metadata + headers now expose the override:
  x-litellm-quality-router-via       → "keyword" | "quality_tier"
  x-litellm-quality-router-keyword   → matched keyword (only on keyword route)
  x-litellm-quality-router-complexity → complexity tier (only on tier route)

Removes:
- request_kwargs["litellm_capabilities"] reading
- _model_capabilities, _model_supports_capabilities,
  _first_capable_model_at_tier, capability filter in
  _resolve_model_for_quality_tier

Co-Authored-By: Claude Opus 4 (1M context) <noreply@anthropic.com>

* feat(quality_router): add explicit `order` to RoutingPreferences

Adds an explicit priority field to RoutingPreferences for resolving
collisions deterministically:

  RoutingPreferences.order: Optional[int]   # lower wins; unset = +inf

Used as the PRIMARY tiebreaker in two places:

1. Keyword overlap: when multiple deployments declare the same matching
   keyword, sort by (order ASC, quality_tier DESC, input_cost_per_token
   ASC, model_name ASC). Explicit always beats implicit.

2. Tier resolution: when multiple deployments share a quality tier,
   `_resolve_model_for_quality_tier` picks the one with the lowest
   order. The tier list is now sorted at index-build time.

This lets admins make routing decisions explicit when the natural
quality-and-price ordering would pick the wrong model.

Co-Authored-By: Claude Opus 4 (1M context) <noreply@anthropic.com>

* feat(quality_router): reorder tiebreak to (quality, order, price)

Changes the tiebreak ordering so quality_tier always wins first, then
explicit `order` is used to break ties within the same tier, then price
breaks the rest:

  1. quality_tier DESC      ← best model wins first
  2. order ASC              ← explicit priority within a tier
  3. input_cost_per_token ASC
  4. model_name ASC

Previously `order` was the primary key — that meant a tier-2 model with
`order=1` would beat a tier-3 model with no `order`, which is the wrong
default. Now `order` only resolves collisions among same-tier candidates.

Tier resolution (within a single tier) keeps the same key minus quality:
(order ASC, cost ASC, name).

Test renames + flips:
  - test_explicit_order_overrides_quality_tier → test_quality_wins_over_explicit_order
  - new: test_order_breaks_tie_within_same_quality_tier

Co-Authored-By: Claude Opus 4 (1M context) <noreply@anthropic.com>

* fix(quality_router): resolve Greptile review feedback

Addresses four P1 findings from PR review plus test coverage:

1. set_model_list missing quality_routers reset
   - Hot-reloading the Router would leave stale QualityRouter instances
     pointing at the old model_list. `set_model_list` now clears
     `self.quality_routers` alongside the other indices.

2. Round-down fallback before default_model
   - `_resolve_model_for_quality_tier` now rounds DOWN to the closest
     lower tier after round-up fails, before falling back to
     `default_model`. Degrades gracefully rather than jumping straight
     off-tier.

3. RoutingPreferences validation bypass
   - `_build_tier_index` now instantiates `RoutingPreferences(**prefs)`
     so invalid shapes (e.g. non-int quality_tier) raise a clear
     ValueError instead of silently succeeding.

4. Config-ordering dependency
   - `_tier_to_models` is now built lazily on first access. Previously,
     eager construction in `__init__` meant a QualityRouter deployment
     had to appear AFTER all its referenced models in config.yaml,
     because `Router._create_deployment` populates `model_list`
     incrementally. Any `available_models` defined after the router
     entry would silently be reported as missing.

Also adds 6 new tests covering each fix:
- test_invalid_quality_tier_type_raises_clear_error
- test_router_can_be_instantiated_before_its_targets_exist
- test_set_model_list_clears_quality_routers_registry
- test_rounds_down_when_no_higher_tier_exists
- test_rounds_down_prefers_closest_lower_tier
- test_prefers_round_up_over_round_down

Co-Authored-By: Claude Opus 4 (1M context) <noreply@anthropic.com>

* style: apply black 24.10.0 formatting to pre-existing offenders

Unblocks the LiteLLM Linting check for this PR — these 12 files are already
failing `black --check` on main (the lint workflow only runs on PRs, so main
drifts). No behavior changes; formatting-only.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Update litellm/router.py

Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>

---------

Co-authored-by: Claude Opus 4 (1M context) <noreply@anthropic.com>
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>

* Support /v1/responses in complexity router (#26137)

* feat(proxy): add --reload flag for uvicorn hot reload (dev only)

Opt-in CLI flag, off by default, no env var. Only affects the uvicorn
run path; gunicorn/hypercorn paths and prod (which doesn't pass the
flag) are unaffected.

* Feature/add audio support for scaleway (#26110)

* feat(scaleway): add SCALEWAY to LlmProviders enum

* feat(scaleway): add audio transcription config and dispatch wiring

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* test(scaleway): add behavior tests for audio transcription config

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* chore(scaleway): advertise audio_transcriptions in endpoint-support JSON

* docs(scaleway): document audio transcription support

* fix(scaleway): address PR review — plain-text response_format + missing-key fail-fast

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* test(scaleway): cover new response paths, drop gettysburg.wav coupling

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>

* Prompt Compression - add it to the proxy (#25729)

* refactor: new agentic loop event hook

simplifies how to create logic for tool based multi llm calls

* fix: compress - make it work on anthropic input as well

* fix(compress.py): working prompt compression for claude code

ensures claude code messages can run through proxy easily

* docs: add agentic loop hook guide

* docs: add agentic_loop_hook to sidebar

* fix: fix multiple arguments error

* fix: fix tool call loop for compression on streaming /v1/messages

* fix: fix linting errors

* fix: fix ci/cd errors

* feat(litellm_pre_call_utils.py): use claude code session for litellm session id

allows claude code logs to be stitched together, making it easy to know they were all part of the same conversation

* fix: suppress incorrect mypy warning rE: module

* revert: drop PR's changes to litellm/proxy/_experimental/out/

Restores the 34 HTML files under _experimental/out/ to their pre-PR
paths (X/index.html -> X.html). All renames are R100 (content
unchanged); no other files are touched.

* fix: address greptile review comments on PR #25729

- Skip ``kwargs["tools"] = []`` injection when compression is a no-op —
  Anthropic Messages rejects empty tool arrays on requests that did not
  originally declare tools.
- Move agentic-loop safety guards (fingerprint cycle / max depth) out of
  the per-callback try/except so they propagate instead of being swallowed
  by the generic exception handler. Extracted _check_agentic_loop_safety.
- Gate generic ``x-<vendor>-session-id`` capture behind the
  LITELLM_CAPTURE_VENDOR_SESSION_HEADERS env var (off by default) to
  preserve backwards compatibility; explicit x-litellm-* headers are
  unaffected.
- Fix monkeypatch target in pre-call-hook test to patch the actual
  module-level binding
  (litellm.integrations.compression_interception.handler.compress).
- Add regression tests for empty-tools skip and opt-in session capture.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* revert: drop LITELLM_CAPTURE_VENDOR_SESSION_HEADERS flag

Generic x-<vendor>-session-id header capture is a new feature and only
runs *after* the explicit x-litellm-trace-id / x-litellm-session-id
checks, so it does not change behavior for any existing caller that was
already using the LiteLLM headers — no backwards-incompatibility to gate.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* refactor(compress): replace input_type with CallTypes call_type

Drop the bespoke ``CompressionInputType`` literal and use the existing
``litellm.types.utils.CallTypes`` enum instead.  ``litellm.compress()``
now takes ``call_type: Union[CallTypes, str]`` (default
``CallTypes.completion``) — no new concept to learn, and the enum is
already the way the rest of the codebase talks about request shapes.

Supported values: ``completion`` / ``acompletion`` (OpenAI chat-completions
shape) and ``anthropic_messages`` (Anthropic structured content blocks).

Updated: compress(), the compression_interception handler, tests, docs,
and the two eval scripts.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>

* Support /v1/responses in complexity router

Adds cross-format support to the complexity router via the guardrail
translation handler dispatch. Adds get_structured_messages to base
translation plus OpenAI chat, Responses, and Anthropic handlers.
Auto-router helper _extract_text_from_messages handles tool-call and
multimodal messages. Widens async_pre_routing_hook messages type to
Dict[str, Any].

Fixes https://github.com/BerriAI/litellm/issues/25134

* chore: apply black formatting

* fix: fallback to trying each handler when route inference fails

---------

Co-authored-by: Ryan Crabbe <ryan@berri.ai>
Co-authored-by: nhyy244 <106547304+nhyy244@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>

* test: cover _is_quality_router_deployment and init_quality_router_deployment

* fix: reset auto_routers on set_model_list to prevent hot-reload ValueError

* style: apply black formatting to websearch_interception and agentic_streaming_iterator

---------

Co-authored-by: yuneng-jiang <yuneng@berri.ai>
Co-authored-by: Claude Opus 4 (1M context) <noreply@anthropic.com>
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
Co-authored-by: Ryan Crabbe <ryan@berri.ai>
Co-authored-by: nhyy244 <106547304+nhyy244@users.noreply.github.com>
2026-04-20 16:22:12 -07:00
Ryan Crabbe
eee51a99ad
replace retired claude-3-haiku-20240307 with claude-haiku-4-5-20251001 in local_testing part1 and router fallback tests 2026-04-20 16:10:45 -07:00
Ryan Crabbe
74169b114a
replace retired claude-3-haiku-20240307 with claude-haiku-4-5-20251001 in streaming tests 2026-04-20 16:04:54 -07:00
Krrish Dholakia
e99955ac52 test(adaptive_router/hooks): align stale tests with current hook API
Six tests in test_hooks.py were written against an older API and had been
failing in CI. Updated:

- test_resolve_session_key_* (4 tests): _resolve_session_key now requires
  at least SIGNAL_GATE_MIN_MESSAGES messages before deriving a hash (it
  returns None on shorter convos to match the signal-processing gate).
  Switched the tests to use _long_messages() so they hit the hash path.

- test_post_call_success_hook_* (2 tests): the hook was migrated from
  async_post_call_success_hook (mutates response._hidden_params) to
  async_post_call_response_headers_hook (returns a headers dict) because
  the former fires too late for streaming responses. Rewrote the tests
  against the new API; added a metadata-not-dict noop case.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-20 16:03:32 -07:00
Ryan Crabbe
3745ba2ea7
replace retired claude-3-haiku-20240307 with claude-haiku-4-5-20251001 in anthropic messages passthrough test
Anthropic retired claude-3-haiku-20240307 on 2026-04-20, causing the
test_anthropic_messages_litellm_router_non_streaming_with_logging
test to 404. Update the model references in this file to the current
pinned haiku version.
2026-04-20 15:44:11 -07:00
ishaan-berri
9aee0da7d8
fix: /health/readiness 503 loop when DB is unreachable (#26134)
* fix: /health/readiness returns 503 when DB is unreachable due to handle_db_exception re-raising

handle_db_exception() re-raises the Prisma exception inside _db_health_readiness_check's
except block, which propagates out to health_readiness() and gets wrapped in a 503.
The health endpoint never reached the reconnect path and the service never recovered.

Fix:
- Remove handle_db_exception() call from _db_health_readiness_check — that helper is
  for API request handlers (allow_requests_on_db_unavailable flag), not health checks
- Replace raw disconnect()+connect() with attempt_db_reconnect(), which uses the proper
  lock, cooldown, escalation, and heavy-reconnect (recreate_prisma_client) machinery

* test: update health readiness tests for handle_db_exception removal

- Remove tests that expected handle_db_exception to re-raise (old buggy behaviour)
- Remove tests asserting disconnect()/connect() calls (replaced by attempt_db_reconnect)
- Add regression tests covering the 503 loop fix:
  - transport errors never raise (ClientNotConnectedError, httpx.ConnectError, etc.)
  - reconnect success path returns 'connected'
  - reconnect failure path returns 'disconnected' without raising
  - non-transport errors return 'disconnected', skip reconnect

---------

Co-authored-by: yuneng-jiang <yuneng@berri.ai>
2026-04-20 15:29:43 -07:00
Krrish Dholakia
b6fc75b3ce
Merge branch 'litellm_internal_staging' into litellm_adaptive_routing 2026-04-20 15:28:08 -07:00
Krrish Dholakia
0cfcec68e9 fix(adaptive_router/hooks): populate tool_results so failure signal fires
The post-call hook was hardcoding tool_results=[] on every Turn, so the
failure detector never saw tool errors and the bandit only learned from
satisfaction — never from negative tool outcomes.

Added _recent_tool_results(messages): walks the request messages from the
tail and collects the contiguous run of role=='tool' entries — those are
the results from the most recent assistant tool_calls round. Normalizes
each to {content, is_error}, the only fields signals._detect_failure /
_detect_exhaustion read.

Tests: 6 new covering empty input, trailing-run extraction, is_error
propagation, boundary at first non-tool message, no-trailing-tool case,
and the end-to-end path from hook -> Turn.tool_results.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-20 15:25:51 -07:00
Krrish Dholakia
fba736ca3c fix(adaptive_router): 3 P1 review defects
- Use 'auto_router/adaptive_router' prefix in example yaml, docs, and
  README — the old 'adaptive_router/...' and 'openai/gpt-4o-mini' values
  silently skipped adaptive-router init because detection requires the
  'auto_router/adaptive_router' prefix.

- Read x-litellm-min-quality-tier from request headers (and the
  'min_quality_tier' metadata key as fallback) in async_pre_routing_hook.
  Previously the documented header was defined but never extracted, so
  the quality-floor feature was inert.

- Evict expired entries from _session_states. The cache grew without
  bound — added a parallel expiry map (same TTL as _owner_cache) and an
  opportunistic bulk sweep when the cache crosses a size threshold.

- Align adaptive-router migration SQL with Prisma schema: all count
  columns and the 'clean_credit_awarded' / 'last_processed_turn' fields
  are NOT NULL in the data model, so the migration now declares them
  NOT NULL. Fixes test_aaaasschema_migration_check.

Tests: 8 new covering header/metadata/precedence/invalid-value paths for
min_quality_tier and TTL-based eviction of _session_states.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-20 15:22:18 -07:00
Krrish Dholakia
386f334fee
Prompt Compression - add it to the proxy (#25729)
* refactor: new agentic loop event hook

simplifies how to create logic for tool based multi llm calls

* fix: compress - make it work on anthropic input as well

* fix(compress.py): working prompt compression for claude code

ensures claude code messages can run through proxy easily

* docs: add agentic loop hook guide

* docs: add agentic_loop_hook to sidebar

* fix: fix multiple arguments error

* fix: fix tool call loop for compression on streaming /v1/messages

* fix: fix linting errors

* fix: fix ci/cd errors

* feat(litellm_pre_call_utils.py): use claude code session for litellm session id

allows claude code logs to be stitched together, making it easy to know they were all part of the same conversation

* fix: suppress incorrect mypy warning rE: module

* revert: drop PR's changes to litellm/proxy/_experimental/out/

Restores the 34 HTML files under _experimental/out/ to their pre-PR
paths (X/index.html -> X.html). All renames are R100 (content
unchanged); no other files are touched.

* fix: address greptile review comments on PR #25729

- Skip ``kwargs["tools"] = []`` injection when compression is a no-op —
  Anthropic Messages rejects empty tool arrays on requests that did not
  originally declare tools.
- Move agentic-loop safety guards (fingerprint cycle / max depth) out of
  the per-callback try/except so they propagate instead of being swallowed
  by the generic exception handler. Extracted _check_agentic_loop_safety.
- Gate generic ``x-<vendor>-session-id`` capture behind the
  LITELLM_CAPTURE_VENDOR_SESSION_HEADERS env var (off by default) to
  preserve backwards compatibility; explicit x-litellm-* headers are
  unaffected.
- Fix monkeypatch target in pre-call-hook test to patch the actual
  module-level binding
  (litellm.integrations.compression_interception.handler.compress).
- Add regression tests for empty-tools skip and opt-in session capture.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* revert: drop LITELLM_CAPTURE_VENDOR_SESSION_HEADERS flag

Generic x-<vendor>-session-id header capture is a new feature and only
runs *after* the explicit x-litellm-trace-id / x-litellm-session-id
checks, so it does not change behavior for any existing caller that was
already using the LiteLLM headers — no backwards-incompatibility to gate.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* refactor(compress): replace input_type with CallTypes call_type

Drop the bespoke ``CompressionInputType`` literal and use the existing
``litellm.types.utils.CallTypes`` enum instead.  ``litellm.compress()``
now takes ``call_type: Union[CallTypes, str]`` (default
``CallTypes.completion``) — no new concept to learn, and the enum is
already the way the rest of the codebase talks about request shapes.

Supported values: ``completion`` / ``acompletion`` (OpenAI chat-completions
shape) and ``anthropic_messages`` (Anthropic structured content blocks).

Updated: compress(), the compression_interception handler, tests, docs,
and the two eval scripts.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-20 15:08:00 -07:00
Krrish Dholakia
24a2e3e89e fix: address CI violations for adaptive router
- Use LoggingCallbackManager.add_litellm_callback instead of
  litellm.callbacks.append (required by callback_manager_test)
- init_adaptive_router_deployment now uses model_name_to_deployment_indices
  for O(k) lookup instead of scanning model_list
- Rephrase comment in set_model_list to avoid the 'in self.model_list'
  substring that the linear-scan test greps for
- Whitelist _finalize_adaptive_router_if_configured in
  test_no_linear_scans_in_router — prefix match on 'auto_router/adaptive_router'
  has no supporting index; runs once at init

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-20 15:07:18 -07:00
nhyy244
a19bff4ca6
Feature/add audio support for scaleway (#26110)
* feat(scaleway): add SCALEWAY to LlmProviders enum

* feat(scaleway): add audio transcription config and dispatch wiring

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* test(scaleway): add behavior tests for audio transcription config

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* chore(scaleway): advertise audio_transcriptions in endpoint-support JSON

* docs(scaleway): document audio transcription support

* fix(scaleway): address PR review — plain-text response_format + missing-key fail-fast

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* test(scaleway): cover new response paths, drop gettysburg.wav coupling

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-20 14:49:41 -07:00
harish-berri
017b6d7a5c Merge branch 'litellm_internal_staging' into litellm_metrics_auth
Some checks failed
Unit Tests: Proxy DB Operations / proxy-db (auth-checks, tests/proxy_unit_tests/test_auth_checks.py tests/proxy_unit_tests/test_user_api_key_auth.py, 20, 8) (push) Has been cancelled
Unit Tests: Proxy DB Operations / proxy-db (key-generation, tests/proxy_unit_tests/test_key_generate_prisma.py, 30, 0) (push) Has been cancelled
Unit Tests: Proxy DB Operations / proxy-db (remaining, tests/proxy_unit_tests --ignore=tests/proxy_unit_tests/test_key_generate_prisma.py --ignore=tests/proxy_unit_tests/test_auth_checks.py --ignore=tests/proxy_unit_tests/test_user_api_key_auth.py, 30, 8) (push) Has been cancelled
Unit Tests: Security / security (push) Has been cancelled
Merge staging into feature to resolve merge conflict
2026-04-20 19:18:25 +00:00
Krrish Dholakia
f0efc5f670 test: cover _finalize_adaptive_router_if_configured
Router coverage check flagged this method as untested. Adds two cases:
- initializes AdaptiveRouter from model_list and is idempotent on re-entry
- no-op when no adaptive deployments are configured

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-20 07:43:53 -07:00
Sameer Kankute
57eae8d01c
Merge branch 'litellm_internal_staging' into litellm_staging_03_22_2026
Some checks failed
Unit Tests: Caching (Redis) / caching-redis (push) Has been cancelled
Unit Tests: Proxy DB Operations / proxy-db (auth-checks, tests/proxy_unit_tests/test_auth_checks.py tests/proxy_unit_tests/test_user_api_key_auth.py, 20, 8) (push) Has been cancelled
Unit Tests: Proxy DB Operations / proxy-db (key-generation, tests/proxy_unit_tests/test_key_generate_prisma.py, 30, 0) (push) Has been cancelled
Unit Tests: Proxy DB Operations / proxy-db (remaining, tests/proxy_unit_tests --ignore=tests/proxy_unit_tests/test_key_generate_prisma.py --ignore=tests/proxy_unit_tests/test_auth_checks.py --ignore=tests/proxy_unit_tests/test_user_api_key_auth.py, 30, 8) (push) Has been cancelled
Unit Tests: Security / security (push) Has been cancelled
2026-04-20 19:56:00 +05:30
mubashir1osmani
499f5d6d6b
prevent post call guardrail called twice 2026-04-20 09:13:22 -04:00
Sameer Kankute
7fc54ad460
fix(vertex_ai): omit system_instruction/tools/toolConfig when cachedContent set
Vertex generateContent returns INVALID_ARGUMENT if cachedContent is sent
with system_instruction, tools, or toolConfig; those belong on CachedContent.

Fixes #26014

Made-with: Cursor
2026-04-20 10:23:40 +05:30
Krrish Dholakia
dd4a1d2be2 feat: add adaptive routing to litellm
allow model routing to improve based on conversation signals

ensures router is picking best model for task
2026-04-18 16:35:17 -07:00
Ryan Crabbe
c8b7c1bafa
Merge remote-tracking branch 'origin/litellm_internal_staging' into litellm_feat-multi_threshold_budget_alerts 2026-04-18 15:26:02 -07:00
Ryan Crabbe
eb6fd98611
Merge remote-tracking branch 'origin/main' into litellm_feat-multi_threshold_budget_alerts 2026-04-18 14:54:26 -07:00
ishaan-berri
ecff06df65
Merge pull request #26032 from BerriAI/litellm_mcp_pkce_fix_v2
fix(mcp): restore PKCE-triggering 401 when no stored per-user token exists
2026-04-18 14:52:31 -07:00
yuneng-jiang
e69051916e
Merge pull request #25983 from BerriAI/litellm_yj_apr17
[Infra] Merge dev branch
2026-04-18 14:43:04 -07:00
Ishaan Jaffer
b7813aad41
fix(mcp): restore PKCE-triggering 401 when no stored per-user token exists
Per-user OAuth MCP requests now only skip pre-emptive 401 when a stored token is available, preserving token-reuse behavior while restoring fast PKCE kickoff for first-time or missing-token users.
2026-04-18 14:04:22 -07:00
shivam
dbf4f9637f
Merge remote-tracking branch 'upstream/litellm_internal_staging' into litellm_project_rate_limiting 2026-04-18 13:26:24 -07:00
Yuneng Jiang
f483f1e800
Merge remote-tracking branch 'origin/litellm_internal_staging' into litellm_yj_apr17 2026-04-18 13:19:16 -07:00
Ryan Crabbe
208d583a33
[Fix] handle metadata=null on service-account keys
Addresses Greptile P1: `metadata: null` on a key with a reserved field
was crashing inside prepare_metadata_fields because cast(dict, None) is
a runtime no-op, so the loop hit `reserved_field in None` and returned
500 instead of 400.

Extend the rejection condition to cover `casted_metadata is None`, so
attempts to clear an immutable field via `metadata: null` return 400
consistently with the overwrite path. Non-service-account keys still
fall through to the existing "clear all metadata" behavior.
2026-04-18 11:52:54 -07:00
Shivam Rawat
f870095f3f
Merge pull request #25991 from BerriAI/litellm_persist_default_router_end_budget
Litellm persist default router end budget.
2026-04-18 11:52:20 -07:00
ishaan-berri
d03c301c79
Merge pull request #25936 from BerriAI/litellm_health-check-reasoning-tokens
fix(proxy): prioritize reasoning health-check max token precedence
2026-04-18 11:35:04 -07:00
ishaan-berri
f476447875
Merge pull request #25846 from BerriAI/litellm_bedrock_cache_start_negative_cost
fix(bedrock): prevent negative streaming costs for start-only cache usage
2026-04-18 11:30:07 -07:00
Ryan Crabbe
01acbb8d3d
[Fix] reject explicit null when clearing reserved metadata field
Addresses Greptile review feedback:
- Clarify LiteLLM_Reserved_Metadata_Fields comment to describe both
  preserve-on-omit and reject-on-change behaviors.
- Treat explicit null as a change attempt so callers trying to clear
  service_account_id get a 400 instead of a silent no-op.
2026-04-18 11:06:22 -07:00
Yuneng Jiang
9c0b73e5f4
[Fix] should_create_missing_views returns False for reltuples=0 (falsy zero bug)
`should_create_missing_views()` had `and result[0]["reltuples"]` which is
falsy when reltuples=0. On a fresh empty PostgreSQL table, CREATE INDEX sets
reltuples=0, causing the guard to return False and skip view creation entirely.
Views like MonthlyGlobalSpendPerKey are never created, and the
/global/spend/logs endpoint returns 500.

Fix: change to `and result[0]["reltuples"] is not None` so reltuples=0
(empty table) and reltuples=-1 (unanalyzed table) both correctly return True.

Also harden test_vertex_ai.py to return None instead of crashing with
JSONDecodeError when the spend-logs endpoint returns a non-JSON 500 response,
and add unit tests covering all three reltuples branches (0, -1, positive).
2026-04-18 11:00:09 -07:00
ishaan-berri
d042b4418a
Merge pull request #25929 from BerriAI/litellm_pages_support_for_ocr
feat(ocr/azure-di): support Mistral-style pages param via analyze query string
2026-04-18 10:26:59 -07:00
Yuneng Jiang
ecf65f5d61
Merge remote-tracking branch 'origin/litellm_internal_staging' into litellm_yj_apr17 2026-04-18 09:16:59 -07:00
Ryan Crabbe
48fb19b4fd
fix: align test assertion with additive merge semantics
test_virtual_key_max_budget_alert_check_per_key_overrides_global asserted
override semantics but the implementation does additive merge. Renamed test
and updated assertion to match: per-key and global thresholds are unioned,
not replaced.
2026-04-17 23:46:40 -07:00
Ryan Crabbe
80d48a41e4
[Fix] preserve service_account_id in metadata on /key/update
/key/update and /user/update wholesale-replaced the metadata JSON column
whenever a caller passed a `metadata` field, silently dropping
service_account_id. The pre-call check in litellm_pre_call_utils.py then
stopped treating the key as a service account and bypassed
service_account_settings.enforced_params.

Add LiteLLM_Reserved_Metadata_Fields and have prepare_metadata_fields
preserve these keys from the existing row when the caller omits them.
Reject attempts to change an already-set value (400) since rebinding
service_account_id would break spend attribution.
2026-04-17 23:21:20 -07:00
Yuneng Jiang
e004876950
Merge remote-tracking branch 'origin/litellm_internal_staging' into litellm_/wonderful-bouman
# Conflicts:
#	tests/test_litellm/proxy/ui_crud_endpoints/test_proxy_setting_endpoints.py
2026-04-17 21:32:09 -07:00
shivam
e8c33409ad
test: add coverage for get_project_model_rpm/tpm_limit and check_complete_credentials
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-17 19:38:13 -07:00
Shivam Rawat
37765e679f
Merge branch 'litellm_internal_staging' into litellm_pages_support_for_ocr 2026-04-17 19:29:45 -07:00
shivam
a449fc11a6
Merge branch 'litellm_internal_staging' into litellm_project_rate_limiting 2026-04-17 19:10:06 -07:00
shivam
fad884e9a7
Merge branch 'litellm_internal_staging' into litellm_persist_default_router_end_budget 2026-04-17 19:06:32 -07:00
Yuneng Jiang
a282ac4170
[Fix] Remove unresolved merge conflict markers in bedrock test file
Fixes SyntaxError at pytest collection time caused by leftover
<<<<<<<, =======, >>>>>>> markers in test_bedrock_common_utils.py.
Keeps the assertion matching the model under test
(claude-haiku-4-5-20251001-v1:0).
2026-04-17 18:23:49 -07:00
shivam
6fd49f1da1
fix: enforce project-level model-specific rate limits in parallel_request_limiter_v3
Project-level model rpm/tpm limits stored in project_metadata were never
checked during rate limit enforcement — only model-level limits applied.

Adds _add_project_model_rate_limit_descriptor_from_metadata() to the v3
limiter (mirrors the existing team metadata path) and calls it in
async_pre_call_hook, creating a model_per_project descriptor keyed as
"{project_id}:{model}" with the project's configured limits.

Also extends get_model_rate_limit_from_metadata's Literal to accept
"project_metadata" and adds get_project_model_rpm/tpm_limit helpers.

Fixes: LIT-2317

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-17 18:17:24 -07:00
Ryan Crabbe
44eb2ea56e
fix: address Greptile review — empty recipients guard, type annotation, task pre-filter
- Guard empty recipients in _handle_multi_threshold_max_budget_alert:
  log warning and skip instead of falling through to old path error loop
- Widen max_budget_alert_emails type to Dict[str, Union[str, List[str]]]
  to match _parse_email_list runtime behavior (accepts comma-separated strings)
- Pre-filter asyncio.create_task with min threshold check to avoid
  unnecessary task allocation on every request when spend is below
  all configured thresholds
2026-04-17 17:54:16 -07:00
Krrish Dholakia
bb9955beca
[Fix] Budget reset job now resets implicitly-created end users with NULL budget_id
When litellm.max_end_user_budget_id is configured, implicitly-created end users
(via /chat/completions) have budget_id=NULL in the DB since the default budget
is only applied in-memory. The budget reset job filtered by budget_id, so these
users were never reset and eventually permanently blocked.

Fix: when the default budget is in the reset list, also query for and reset
end users with budget_id=NULL and spend > 0. This keeps the hot auth path
unchanged (no DB writes on every request).

Fixes #22019

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-17 17:49:33 -07:00
Ryan Crabbe
41a719a537
feat: add global fallback config, fix no-owner crash, improve email greeting
- Add `default_key_max_budget_alert_emails` litellm_settings config as
  global fallback for all virtual keys (per-key metadata takes priority)
- Fix crash when key has no user_id/user_email by passing recipient email
  to _get_email_params (same pattern as team soft budget path)
- Use owner email for greeting, falling back to key_alias or token
- Rename setting from default_max_budget_alert_emails to
  default_key_max_budget_alert_emails for clarity
2026-04-17 17:49:28 -07:00
Krrish Dholakia
89365628c9
[Fix] Persist default end-user budget_id to DB so budget reset job picks up implicitly created users
Previously, _apply_default_budget_to_end_user() only set the budget in-memory,
leaving budget_id NULL in the database. This caused the budget reset job to skip
these users since it filters by budget_id. Now the function also persists
budget_id via a Prisma update call (non-fatal on failure).

Fixes #22019

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-17 17:48:54 -07:00
Yuneng Jiang
11c3270cdc
Merge remote-tracking branch 'origin/litellm_internal_staging' into litellm_yj_apr17
# Conflicts:
#	litellm/__init__.py
2026-04-17 17:36:40 -07:00
yuneng-jiang
b9f5be8956
Merge pull request #25922 from BerriAI/litellm_a2a_agent_acl
[Fix] Agent endpoint and routing permission checks
2026-04-17 17:19:59 -07:00
Ryan Crabbe
779a9fab8e
feat: add configurable multi-threshold budget alerts for virtual keys
Users can set metadata.max_budget_alert_emails as a JSON map of threshold
percentages to email recipients on virtual keys. When configured, the email
handler loops over each threshold, checks per-threshold dedup cache, and
sends to the configured recipients (auto-including the key owner's email).

When no map is set, the existing single 80% threshold behavior is preserved
unchanged. Teams support is out of scope for this v0.
2026-04-17 17:12:35 -07:00