Commit Graph
37515 Commits
Author SHA1 Message Date
yuneng-jiangandGitHub bb46d36bab Merge pull request #26182 from BerriAI/litellm_budget_spend_counter_alignment
[Fix] Align user and org budget spend checks with atomic counter pattern
2026-04-21 11:46:25 -07:00
Yuneng Jiang c2b7c4bfcd fix: skip personal budget check in MaxBudgetLimiter for team-key requests 2026-04-21 10:38:08 -07:00
Yuneng Jiang 7656e26331 fix: align user and org spend checks with atomic counter pattern
Brings user personal budget and organization budget enforcement
in line with the existing key and team patterns, which already
read spend from the atomic cross-pod Redis counter.
2026-04-21 10:21:29 -07:00
yuneng-jiangandGitHub 1702b513ef Merge pull request #26142 from BerriAI/litellm_mcp_broker_endpoint_auth
[Fix] MCP broker OAuth endpoint access controls
2026-04-20 17:46:58 -07:00
Yuneng Jiang b6de470ce9 fix: add access control to register endpoint to match authorize and token 2026-04-20 17:00:34 -07:00
Yuneng Jiang 99f007f51d refactor: consolidate redirect_uri scheme check into shared handler 2026-04-20 16:59:54 -07:00
Yuneng Jiang 9deefc0f76 fix: align MCP broker endpoint access controls with existing auth patterns 2026-04-20 16:52:59 -07:00
yuneng-jiangandGitHub ba820160ab Merge pull request #26141 from BerriAI/litellm_/relaxed-moser-92f086
[Fix] CI - auth_ui_unit_tests: use Postgres sidecar instead of shared DB
2026-04-20 16:32:29 -07:00
ryan-crabbe-berriandGitHub 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 DholakiaGitHubyuneng-jiangClaude Opus 4greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>Ryan Crabbenhyy244
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
Yuneng Jiang bb62099323 [Fix] CI - auth_ui_unit_tests: use Postgres sidecar instead of shared DB
Run auth_ui_unit_tests against a per-job cimg/postgres:16.0 sidecar
with DATABASE_URL pointing at localhost:5432, matching the pattern
used by e2e_ui_testing. Seed the schema via 'litellm --skip_server_startup
--use_prisma_db_push' so each run starts on a clean DB with the current
schema.prisma.
2026-04-20 16:22:10 -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
yuneng-jiangandGitHub 7979044c76 Merge pull request #26140 from BerriAI/litellm_fix_black_formatting
[Fix] Apply black formatting to fix CI lint failures
2026-04-20 16:01:17 -07:00
Yuneng Jiang 505f6e0522 [Fix] Apply black formatting to fix CI lint failures 2026-04-20 15:53:12 -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
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
4f823cedac Add supported providers to prompt caching doc (#26124)
* Add supported providers to prompt caching doc

* Move Z.ai / GLM to cache_control marker list

* Mark xAI models as supporting prompt caching

* Narrow xAI prompt caching flag to models with documented cache pricing

* Add prompt caching flag to grok-4, grok-4-0709, grok-4-latest

---------

Co-authored-by: Michael Riad Zaky <michaelr@Michaels-MacBook-Air.local>
2026-04-20 15:25:21 -07:00
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
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
ryan-crabbe-berriandGitHub ea12bae9a3 Merge pull request #25901 from BerriAI/litellm_feat-add-reload-flag-proxy
feat(proxy): add --reload flag for uvicorn hot reload (dev only)
2026-04-20 08:48:21 -07:00
yuneng-jiangandGitHub 26fcbc93e5 Merge pull request #26044 from BerriAI/litellm_internal_staging
[Infra] Promote staging to main
v1.83.10-nightly
2026-04-18 19:33:24 -07:00
ishaan-berriandGitHub 2f22a1293e bump litellm-proxy-extras to 0.4.67 (#26043)
* bump litellm-proxy-extras version to 0.4.67

* bump litellm-proxy-extras pin to 0.4.67 in litellm pyproject

* regenerate uv.lock for litellm-proxy-extras 0.4.67

* bump litellm-enterprise version to 0.1.38

* bump litellm-enterprise pin to 0.1.38 in litellm pyproject

* regenerate uv.lock for litellm-enterprise 0.1.38
2026-04-18 19:03:56 -07:00
yuneng-jiangandGitHub 9e77e25107 Merge pull request #26038 from BerriAI/yj_bump_apr18
bump: version 1.83.9 → 1.83.10
2026-04-18 18:54:11 -07:00
Yuneng Jiang 49ba6b8160 add uv lock 2026-04-18 18:43:09 -07:00
yuneng-jiangandGitHub e16bd158c3 Merge pull request #26033 from BerriAI/yj_ui_build_apr18
[Infra] Build UI
2026-04-18 18:37:01 -07:00
Yuneng Jiang 4d63a1367e bump: version 1.83.9 → 1.83.10 2026-04-18 18:31:24 -07:00
Yuneng Jiang 0278d73cd9 Merge remote-tracking branch 'origin/litellm_internal_staging' into yj_ui_build_apr18 2026-04-18 16:48:19 -07:00
Yuneng Jiang aab3ef8988 chore: update Next.js build artifacts (2026-04-18 23:46 UTC, node v22.16.0) 2026-04-18 16:46:25 -07:00
Yuneng Jiang ba24e4a1b3 remove next env 2026-04-18 16:45:32 -07:00
Ryan Crabbe 9bea02c291 Merge remote-tracking branch 'origin/litellm_internal_staging' into litellm_feat-add-reload-flag-proxy 2026-04-18 16:31:34 -07:00
ryan-crabbe-berriandGitHub 67bf18dfe0 Merge pull request #25989 from BerriAI/litellm_feat-multi_threshold_budget_alerts
feat: configurable multi-threshold budget alerts for virtual keys
2026-04-18 16:21:29 -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-berriandGitHub 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 de790fd273 chore: update Next.js build artifacts (2026-04-18 21:49 UTC, node v22.16.0) 2026-04-18 14:49:27 -07:00
shin-berriandGitHub 85b1b93661 Merge pull request #26022 from BerriAI/litellm_/reverent-kirch-7cf0a6
[Infra] Bump proxy dependencies and raise minimum Python to 3.10
2026-04-18 14:44:24 -07:00
yuneng-jiangandGitHub e69051916e Merge pull request #25983 from BerriAI/litellm_yj_apr17
[Infra] Merge dev branch
2026-04-18 14:43:04 -07:00
yuneng-jiangandGitHub 63313bcd77 Merge pull request #25994 from BerriAI/litellm_project_rate_limiting
fix: enforce project-level model-specific rate limits in parallel_req…
2026-04-18 14:31:08 -07:00
Ryan Crabbe 0a4b02fe76 fix: tighten recipient_emails guard to reject empty list
send_max_budget_alert_email previously guarded with `is not None`, which
accepts `[]` and then crashes on `recipient_emails[0]` inside
_get_email_params. The current caller (_handle_multi_threshold_max_budget_alert)
already filters empty lists upstream, but the public method signature makes
no such guarantee — a future caller passing [] would hit IndexError.

Switch to truthiness so both None and [] fall through to the single-recipient
path.
2026-04-18 14:07:18 -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
Ryan Crabbe 029d9bcfc7 refactor: inline _parse_email_list in auth_checks to drop enterprise dep
The lazy import from litellm_enterprise inside _normalize_alert_emails
coupled the core proxy auth path to an optional package. Core should not
depend on enterprise, even lazily — it hides the dependency from static
analysis and inverts the intended layering.

Duplicate the 7-line parser locally. It's pure and unlikely to drift; the
enterprise copy stays where it is for its own callers.
2026-04-18 13:51:00 -07:00
Ryan Crabbe 8b86a3b041 fix: normalize alert-email configs at merge boundary
_merge_budget_alert_email_configs previously called list() directly on each
threshold's value, which raised TypeError on null YAML values and silently
split bare strings into single characters. Both are reachable from user-
supplied global config and per-key metadata, so the crash could fire on
every authenticated request once the metadata was in place.

Route both inputs through a _normalize_alert_emails helper that delegates
to the existing _parse_email_list parser (lazy-imported, matching the
enterprise import pattern used elsewhere in proxy/). The merge body keeps
its tight Dict[str, List[str]] contract.
2026-04-18 13:48:48 -07:00
Ryan Crabbe 09a524a351 fix: narrow CallInfo.max_budget_alert_emails to Dict[str, List[str]]
The Union[str, List[str]] value type was speculative — _merge_budget_alert_email_configs
always returns List[str] values, and no caller produces bare strings. Narrowing to
match the runtime guarantee resolves a mypy invariance error at auth_checks.py:3021
without adding casts or Mapping covariance.
2026-04-18 13:39:33 -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
Yuneng Jiang ec590f938b Merge remote-tracking branch 'origin/litellm_internal_staging' into litellm_/reverent-kirch-7cf0a6 2026-04-18 13:18:45 -07:00
yuneng-jiangandGitHub 643e941b64 Merge pull request #26026 from BerriAI/litellm_fixPrometheusHelpersPackageCollision
[Fix] Resolve prometheus_helpers file/package shadow breaking /global/spend/logs
2026-04-18 13:18:04 -07:00
Yuneng Jiang cfdf893226 [Fix] Merge prometheus_helpers.py into prometheus_helpers/__init__.py to resolve file/package collision
A previous refactor added `litellm/integrations/prometheus_helpers.py` as a
sibling to the existing `litellm/integrations/prometheus_helpers/` directory
(which contains `prometheus_api.py` and has no `__init__.py`). The file
shadowed the namespace-package directory, so any deferred
`from litellm.integrations.prometheus_helpers.prometheus_api import ...`
raised `ModuleNotFoundError: 'litellm.integrations.prometheus_helpers' is
not a package` at request time.

Two runtime call sites hit that path:
- /global/spend/logs (spend_management_endpoints.py) returned plain-text 500
  "Internal Server Error" for every call, breaking the Admin UI Usage tab
  and programmatic consumers.
- SlackAlerting.send_fallback_stats_from_prometheus silently failed inside
  its own try/except.

Fix: move prometheus_helpers.py content into prometheus_helpers/__init__.py
and delete the stray .py. The directory becomes a regular package, so both
the package-root import (from ...prometheus_helpers import X) and the
submodule import (from ...prometheus_helpers.prometheus_api import X)
resolve correctly. No call sites change.
2026-04-18 13:04:32 -07:00
yuneng-jiangandGitHub 8e00f61026 Merge pull request #26023 from BerriAI/litellm_/eloquent-feistel-b346ec
[Fix] UI - Keys: strip empty premium fields from key update payload
2026-04-18 13:01:38 -07:00