Commit Graph
37524 Commits
Author SHA1 Message Date
Yuneng Jiang 5b007add62 [Docs] Fix docstring inaccuracies in run_migration.py
- _find_destructive_statements: add DROP INDEX to the docstring (the
  regex already detects it; only the docstring lagged).
- create_migration: correct the base_branch default documented in the
  docstring from "main" to "litellm_internal_staging".
2026-04-21 12:07:19 -07:00
Yuneng Jiang b39f210a6c [Infra] Add freshness and destructive guards to migration workflow
Generating a migration from a stale branch could silently emit DROP
COLUMN for columns the stale branch did not know about, and the
script would write that SQL to a new migration file with no warning.

Adds two guards to ci_cd/run_migration.py:

- Branch freshness check: fetches origin/<base-branch> and exits 3 if
  HEAD is behind. Default base is litellm_internal_staging. New
  flags: --base-branch, --skip-freshness-check.
- Destructive guard: refuses (exit 2) if the generated diff contains
  DROP COLUMN / DROP TABLE / DROP INDEX, unless --allow-destructive
  is passed.

Refusal banners include guidance and an explicit callout instructing
AI agents not to auto-bypass the flags. Also treats Prisma's
"-- This is an empty migration." output as a no-op rather than
writing an empty file.

Updates litellm-proxy-extras/migration_runbook.md with the new
workflow, flag documentation, and agent warnings.
2026-04-21 12:00:23 -07:00
shin-berriandGitHub 7cc22dbe19 Merge pull request #26047 from BerriAI/litellm_ui-api-double-prefix-a8a3
[Fix] CI: e2e_ui_testing tests stale bundle on Ubuntu (cp -r merge semantics)
2026-04-21 10:42:32 -07:00
Yuneng Jiang 0f5d503169 fix(ci): make e2e_ui_testing actually test the freshly built UI bundle
The Build UI from source step used:

    cp -r out/ ../../litellm/proxy/_experimental/out/

GNU cp (CircleCI's Ubuntu image, coreutils 8.32) interprets this as
copy the source directory as a CHILD of the destination when the
destination already exists — so the command silently created
litellm/proxy/_experimental/out/out/ instead of replacing the served
bundle at litellm/proxy/_experimental/out/*.

The proxy continued serving whatever bundle was checked in, so every
e2e_ui_testing run between this job's introduction (d09d98a70a,
2026-04-08) and the bundle-rebuild commit (de790fd273, 2026-04-18) was
effectively testing a STALE bundle — not the fresh build. That is why
the double-prefix regression (NEXT_PUBLIC_BASE_URL="ui/" combined with
networking.tsx reading the env var) was never caught in CI even though
the source contained the trigger the whole time: the bundle the proxy
served never picked up the source change.

Replace cp -r with rm + mv so the destination is cleanly swapped.

Verified end-to-end on an Ubuntu 22.04 / GNU coreutils 8.32 container:
- Before fix: fresh build has 9 "ui/" literals in chunks; after cp,
  _experimental/out/*  still has 0 (stale); _experimental/out/out/ is a
  nested dir the proxy does not serve.
- After fix: _experimental/out/*  has 9 "ui/" literals — the proxy now
  serves the freshly built (broken, in this repro) bundle, so
  globalSetup fails at login and every spec is blocked. Removing the
  bug from .env.production and rebuilding brings the count back to 0
  and the suite passes.

No spec changes, no fixtures, no new infrastructure. The existing
Playwright suite already catches this class of regression via the
login flow in globalSetup; it just needs the CI to actually hand it
the freshly built bundle.
2026-04-20 22:09:54 -07:00
yuneng-jiangandGitHub b9bedc8153 Merge pull request #26055 from BerriAI/litellm_non-root-dockerfile-optimization-31b6
[Infra] Streamline Dockerfile.non_root build time
2026-04-20 17:35:51 -07:00
Yuneng Jiang 0ecc89c355 Merge branch 'litellm_internal_staging' into litellm_non-root-dockerfile-optimization-31b6 2026-04-20 16:42:32 -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
Yuneng Jiang 353e406229 [Refactor] remove orphaned _experimental/out build artifacts
The previous revert left three files under
_experimental/out/_next/static/8Gn6tA2K4jsPxzCCMwObH/ still staged
(git checkout origin/main -- only restores files present in main, it
does not delete files that exist only on the PR branch). Remove them
so the PR no longer touches _experimental/out/ at all.
2026-04-20 15:45:31 -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
Yuneng Jiang 3bae051113 [Refactor] revert _experimental/out regeneration; leave to release runbook
The UI rebuild bundled into this PR is not needed for the Dockerfile
change — the image simply copies whatever _experimental/out/ is in the
tree. Regenerating here conflicts with the release-time refresh policy
and adds ~100 files of review noise / merge-conflict risk for any
concurrent UI PR.
2026-04-20 15:43:47 -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
Yuneng Jiang 995bff0dec [Fix] Dockerfile.non_root: drop prisma --version sanity call
prisma --version invokes the Schema Engine, which has no binary for the
Wolfi base image (only debian). In the baseline this was silenced by a
trailing || true wrapping the whole prisma chain; removing that wrapper
uncovered the failure on arm64 builds. The main Dockerfile does not
call prisma --version at all, so drop it here to match — prisma generate
is sufficient to validate the toolchain.
2026-04-20 13:51:53 -07:00
Yuneng Jiang db49885102 [Refactor] Dockerfile.non_root: drop UI drift guard approach
Revert the .dockerignore ui/ exclusion and remove the UI Drift Guard
workflow. _experimental/out/ refresh is already handled by the release
runbook; the global .dockerignore change also broke Dockerfile.custom_ui
(explicit COPY ./ui/litellm-dashboard) and the enterprise-colors inline
rebuild path in Dockerfile, Dockerfile.database, and Dockerfile.dev.

Dockerfile.non_root itself is unchanged functionally — still stages the
UI from the checked-in _experimental/out/. Only the companion workflow
and global dockerignore exclusion are dropped.
2026-04-20 13:47:18 -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
Cursor Agentandyuneng-jiang 4c8cbaf0a2 [Refactor] Dockerfile.non_root: drop dead lines and shrink build context
Five small, individually-verified cleanups collected into one commit:

- Drop 'prisma migrate diff --from-empty ... > /dev/null 2>&1 || true'
  from the builder. Stdout/stderr/exit-status all discarded; nothing
  reads the output. Dead line.
- Drop 'mkdir -p /app/.cache/npm' from the same RUN. npm is gone.
- Drop the runtime's redundant 'sed -i' + 'chmod +x' on the entrypoint
  scripts. The builder already does the same three lines, and the
  runtime copies /app from the builder via COPY --from=builder, so
  the normalized files (and exec bits, which buildkit preserves) are
  already in place.
- Drop NPM_CONFIG_CACHE and NPM_CONFIG_PREFER_OFFLINE from the runtime
  ENV — nothing reads them after Task 2.2 removed npm.
- Drop '/.npm' and '/tmp/.npm' from the runtime's mkdir + chown. These
  directories only existed as npm's writable dirs for the non-root
  user; npm is gone.

.dockerignore: add 'ui/'. After Task 2.1 the non_root image sources
its UI bytes from litellm/proxy/_experimental/out/, so the whole
ui/litellm-dashboard/ source tree is dead weight when the blanket
'COPY . .' pulls it into /app. Verified (with ripgrep) that no Python
code under litellm/ opens any file under ui/. All string references to
'ui/...' are URL paths, not filesystem paths.

Final image size: 6.57GB baseline -> 1.96GB. API parity and UI visual
regression match baseline across all 12 API scenarios and 10 UI
routes. Trivy HIGH/CRITICAL: 6 -> 2, no new CVEs introduced.

Co-authored-by: yuneng-jiang <yuneng-berri@users.noreply.github.com>
2026-04-19 06:50:50 +00:00
Cursor Agentandyuneng-jiang e24c02f478 [Infra] Dockerfile.non_root: add BuildKit uv cache mount
Mount /app/.cache/uv as a BuildKit type=cache on both 'uv sync' steps.
The cache persists across builds on the same builder (and, when used
with type=gha in CI, across CI runs) so repeat builds don't re-download
every wheel.

Side-effect: because the cache lives outside the image layer, the
~742MB of downloaded wheel archives that were previously baked into
/app/.cache/uv drop out of the final image. Compressed image size
goes from ~5.0GB to ~3.7GB, and the 'USER nobody' prisma-generate
layer is 1.7GB vs 2.4GB.

Warm-build timing: a uv-sync-invalidating edit now takes ~1m30s vs
~2m39s without the cache mount, on this dev VM.

API parity and UI visual regression continue to match baseline.
Trivy HIGH/CRITICAL: 6 at baseline -> 2 now, no new CVEs.

Co-authored-by: yuneng-jiang <yuneng-berri@users.noreply.github.com>
2026-04-19 06:35:39 +00:00
Cursor Agentandyuneng-jiang ca52e346b0 [Infra] Dockerfile.non_root: slim C toolchain in builder stage
After Task 2.1 removed the in-image Next.js build, the builder stage no
longer needs a full C/C++ + Clang toolchain. Keep gcc + python3-dev
(required to compile ml-dtypes 0.4.1 from source — no wheel published
for Python 3.13 yet). Drop everything else.

Removed from apk: clang, llvm, lld, linux-headers, build-base,
openssl-dev, npm. Removed NVM_DIR env and /root/.nvm from PATH
(no nvm-based Node install anymore).

Kept: python3, python3-dev, gcc, bash, coreutils, curl, openssl,
libsndfile, nodejs. gcc (15.2) serves both C and C++; the separate
g++ package doesn't exist in Wolfi.

Image size unchanged (builder stage doesn't end up in the runtime);
cold builds slightly slower due to ml-dtypes source compile, but that
will be recovered in the next task via a BuildKit uv cache mount.
API parity and UI visual regression both match baseline, Trivy
HIGH/CRITICAL CVE count unchanged from opt-2 (4 CVEs, none new).

Co-authored-by: yuneng-jiang <yuneng-berri@users.noreply.github.com>
2026-04-19 05:59:31 +00:00
Cursor Agentandyuneng-jiang 78485f5a32 [Infra] Dockerfile.non_root: remove unused npm from runtime stage
npm was installed in the runtime only to globally install vulnerability
patched versions of tar/glob/brace-expansion/minimatch/diff and to
in-place rewrite npm's own bundled package.json. Both were to silence
CVE scanners against modules that ship with npm itself.

Since we no longer run npm anywhere in the runtime (Prisma uses the
node binary directly for migrate deploy and generate), we can just
skip installing npm in the first place. This eliminates both the
~25-line CVE-patch shuffle AND the underlying CVE surface.

Kept: nodejs (needed by prisma-python's CLI and migrate deploy).
Removed: npm apk package, all 'npm install -g', all find+sed patching,
the redundant 'apk upgrade --no-cache nodejs' (already covered by the
preceding 'apk upgrade').

Image: 4.97GB (opt-1) -> 4.97GB (opt-2); the real win is that two
CVEs (CVE-2026-33671 and GHSA-q4gf-8mx6-v5v3) drop off the Trivy
HIGH/CRITICAL list. No new CVEs introduced. API parity and UI
visual regression both match baseline.

Co-authored-by: yuneng-jiang <yuneng-berri@users.noreply.github.com>
2026-04-19 05:11:06 +00:00
Cursor Agentandyuneng-jiang 004c6b1b3e [Infra] Dockerfile.non_root: stage pre-built UI from _experimental/out
The checked-in Next.js static export at litellm/proxy/_experimental/out/
is kept fresh by the UI Drift Guard CI workflow. Stage it directly
instead of re-running npm ci + npm run build inside the image.

This removes: nvm install, node 20.20.2 install, npm ci (801 pkgs),
next build, and the resulting intermediate node_modules/out tree.

Build time: ~6m25s -> ~2m (fuse-overlayfs DinD); image 6.57GB -> 5.0GB.
Behavior parity verified: API endpoints, UI screenshots (all 10 routes
pixel-perfect), and Trivy HIGH/CRITICAL CVE count (6 -> 5, one npm
GHSA removed) all match or improve over baseline.

Co-authored-by: yuneng-jiang <yuneng-berri@users.noreply.github.com>
2026-04-19 04:21:46 +00:00
Cursor Agentandyuneng-jiang 65a60dbe35 [Infra] CI: add UI drift guard + regenerate _experimental/out
Adds a CI job that rebuilds the admin UI from source and fails if the
committed static export at litellm/proxy/_experimental/out/ has drifted
from what npm run build produces. This prevents silently shipping stale
UI bytes and is a prerequisite for the non_root Dockerfile streamlining
work, which will stage the UI from _experimental/out/ directly instead
of rebuilding it inside the image.

Also regenerates litellm/proxy/_experimental/out/ to match a fresh
npm run build (Node 20.20.2) — the committed tree had drifted from
source prior to this commit.

Co-authored-by: yuneng-jiang <yuneng-berri@users.noreply.github.com>
2026-04-19 04:03:10 +00: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