Commit graph

1076 commits

Author SHA1 Message Date
yujonglee
8fc0663198
fix(ci): pin setup-uv to v10.0.1 (#39111) 2026-09-03 20:44:24 -07:00
devin-ai-integration[bot]
aec083cdac
feat(proxy): per-worker admission control that rejects excess requests with 503 (#39352)
* feat(proxy): reject excess per-worker requests with 503

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

* refactor(proxy): drop redundant suppressions in admission middleware

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

* fix(proxy): exempt the /metrics/ redirect target from admission control

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

* ci: allowlist live Granian saturation benchmark

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

* fix(proxy): regenerate dashboard API types

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

* fix(proxy): normalize root_path for admission exemptions, validate settings, inject state

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

* test(proxy): cover prometheus metric factory, lifespan scope, and prefix lookalike paths

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

* fix(proxy): queue behind pending waiters, cache admission settings parsing, log invalid limits

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

* refactor(proxy): simplify invalid admission settings handling

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

---------

Co-authored-by: yassin <yassin@berri.ai>
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-03 18:19:04 -07:00
Mateo Wang
3a00e8020a
Merge pull request #39464 from BerriAI/litellm_containers_error_passthrough_pagination
fix(containers): pass upstream error status through and forward list pagination params
2026-09-03 14:36:44 -07:00
Mateo Wang
5e5cc54b28
Merge pull request #39496 from BerriAI/litellm_ui_build_check_image_boundary
ci(ui): run the UI build check through the image's ui-builder stage
2026-09-03 14:35:56 -07:00
Mateo Wang
c99149ac0f
Merge pull request #39493 from BerriAI/litellm_ci_rust_server_feature
ci(rust): build and test the ai-gateway server feature
2026-09-03 14:35:53 -07:00
yujonglee
2c30fe16b0
Merge pull request #38765 from BerriAI/litellm_ocr_sdk_parity_tests
test(harness): add OCR parity with migration strategy runners
2026-09-03 10:16:35 -07:00
mateo-berri
fbb799e240 ci: drop the ai-gateway image from the coverage allowlist now that a job builds it 2026-09-03 01:44:20 -07:00
mateo-berri
b55833b1f9 fix(ai-gateway): build the release image again and cover it in CI
The image had two independent breaks. The Dockerfile pinned rust 1.90 while
the repo pins 1.98 in rust-toolchain.toml and never copied it in, so the first
cargo call died on crates needing a newer rustc. The runtime stage then ran
pip install on the root pyproject, which builds with maturin against the
python-bridge crate, so metadata generation failed with no Cargo manifest and
no Rust toolchain in that stage.

Copy rust-toolchain.toml into the builder so every cargo call uses the pinned
channel, build the wheel in the builder stage where cargo and python3-dev
already live, and have the runtime stage install that artifact instead of
compiling anything. Add the ai-gateway image job to the rust workflow so a
broken build fails a PR instead of surfacing on a release.
2026-09-03 01:40:00 -07:00
mateo-berri
f986fc52f0 ci(rust): lint every gateway feature and keep one checks runbook
Clippy never links, so python-config's pyo3/auto-initialize needs no
libpython and the gateway clippy step can cover every feature at once.
The test step stays on --features server because cargo test does link
and this job installs no Python.

The check list existed in three places that had already drifted apart;
CLAUDE.md is now the only copy and the other two point at it.
2026-09-02 22:16:40 -07:00
mateo-berri
06e60e08d2 ci(ui): run the UI build check through the image's ui-builder stage
The build-ui check compiled the dashboard from a full checkout, so any
import reaching above ui/litellm-dashboard/ resolved there and only broke
inside the images, where the stage copies the dashboard tree alone.
Building the stage itself puts the check on the same file boundary the
shipped images use.
2026-09-02 22:09:55 -07:00
mateo-berri
cf958c0e6f ci(rust): build and test the ai-gateway server feature
litellm-ai-gateway's server feature is off by default and nothing in the workspace turns it on, so the workspace clippy and test steps never compiled src/auth, src/routes, src/state, src/realtime or the gateway binary. 43 tests ran instead of 57.

Adds the two steps CLAUDE.md already documents as the local gate, and fixes the three collapsible_if violations that had accumulated behind the flag.
2026-09-02 21:56:23 -07:00
mateo-berri
cd296814be Merge remote-tracking branch 'origin/litellm_internal_staging' into litellm_containers_error_passthrough_pagination 2026-09-02 21:26:40 -07:00
mateo-berri
425c8d37fc fix(containers): page upstream until a non-admin container list fills its limit
Forwarding limit to OpenAI made the ownership filter cut the page down after
the fact, so a key that owned an older container got an empty first page and
its cursor never moved. Non-admin lists now walk upstream pages of 100 until
they have enough owned containers (or five pages), trim to the requested
limit, and report first_id, last_id and has_more off what the caller keeps.

Also assigns tests/test_litellm/proxy/container_endpoints to a CI shard.
2026-09-02 21:26:34 -07:00
mateo-berri
85961201e7 Merge remote-tracking branch 'origin/litellm_internal_staging' into litellm_python_version_ci 2026-09-02 18:30:13 -07:00
devin-ai-integration[bot]
92edcb90db
fix: keep litellm importable on Python 3.10 and guard 3.11-only typing imports in CI (#39448)
* ci: guard against Python 3.10-incompatible typing imports

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

* ci: address Python 3.10 typing guard review

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

* fix(ci): honor version-guard direction and scan litellm-proxy-extras in py310 typing check

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

---------

Co-authored-by: yassin <yassin@berri.ai>
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-02 18:27:19 -07:00
mateo-berri
748075be4f Merge origin/litellm_internal_staging into litellm_python_version_ci 2026-09-02 18:21:48 -07:00
Yuneng Jiang
a3ee6b2566
ci(e2e): fail a pass whose every collected test was skipped 2026-09-02 17:50:35 -07:00
Yuneng Jiang
1af9c229fa
ci(e2e): leave the managed-files opt-in file to its own lane instead of failing on an empty collection 2026-09-02 17:29:56 -07:00
Yuneng Jiang
1c4e46f17e
ci(e2e): reload the stack config every 7s so the harness propagation budget holds, and only mask credential-named values 2026-09-02 17:15:36 -07:00
yujonglee
62e318de8e
fix(python-bridge): harden sync and async route boundaries (#39332) 2026-09-02 16:26:35 -07:00
yujonglee
198906495f
refactor(python-bridge): split routes and add shared function tracing (#39031)
* refactor(python-bridge): split non-streaming bridge modules

* refactor(python-bridge): bring shared function tracing into route layer

* feat(dev): list Python route functions and call sites

* feat(dev): list Rust route functions and call sites

* docs(dev): record OCR parity gaps across Python and Rust

* feat(dev): list executed SDK calls with runtime tracing

* feat(dev): report Python vs Rust SDK pipeline steps in one CLI

* feat(dev): side-by-side pipeline step report in compare CLI

* fix(dev): drop invalid Final annotations in compare cell loop

* feat(dev): blue python-only and yellow rust-only steps in compare CLI

* feat(dev): vertical layout with section spacing in compare CLI

* fix(dev): validate SDK trace stages across sync and async routes

* refactor(rust): align SDK route call structure with Python

* refactor(python-bridge): share sync and async route call wrappers

* refactor(dev): split compare CLI into fixtures, runtime, and report modules

* fix(ci): run SDK trace tests and satisfy test lint
2026-09-02 16:26:35 -07:00
Yuneng Jiang
c62643f0cf
ci(e2e): drop trailing newlines from fetched secret values before writing the env 2026-09-02 15:39:21 -07:00
Yuneng Jiang
743f94f82a
ci(e2e): fail when nothing collects and ignore lanes with their own checks in the smoke trigger 2026-09-02 14:59:15 -07:00
Yuneng Jiang
b348ed7f09
ci(e2e): only tail stack logs when the stack actually booted 2026-09-02 14:56:52 -07:00
Yuneng Jiang
4a646dd9a0
ci(e2e): run a PR's changed e2e tests three times behind a human-approved environment
Adds a required-check candidate that selects the tests/e2e test files a PR added or
modified, boots a stage-mirror stack on the runner (migrations, backend, two gateway
processes behind nginx, Postgres, Jaeger, TLS cluster Valkey), and runs those files
three times with retries off. The run job sits behind the e2e-changed GitHub
environment, so a reviewer approves each run before the OIDC token that reads the
provider keys from AWS Secrets Manager exists. Supersedes #34981
2026-09-02 14:53:40 -07:00
Yujong Lee
77d6aedf0a fix: address cross-version CI failures 2026-09-02 14:17:19 -07:00
Yujong Lee
8010f267e2 ci: keep Python compatibility coverage in unit workflow 2026-09-02 13:42:22 -07:00
Yujong Lee
0313dcea61 ci: test Python 3.10 through 3.14 compatibility 2026-09-02 13:38:28 -07:00
Yuneng Jiang
3d0223b661 ci: install the mongodb extra for the unit test shard that runs the provider
tests/test_litellm/llms/mongodb imports pymongo's exception classes to check the
error translation against the real hierarchy, and the shard that runs it
(tests/test_litellm/llms, per test-unit.yml) synced --extra google, proxy,
semantic-router and saml but not mongodb, so 24 of 109 tests would have errored
with ModuleNotFoundError on the first CI run. CircleCI hid this because it syncs
--all-groups --all-extras.

  uv export --frozen ... --extra saml                  -> no pymongo
  uv export --frozen ... --extra saml --extra mongodb  -> pymongo==4.17.0

Also close the two gaps a mutation run found in the suite: nothing asserted that
a short request timeout shortens server selection as well as connect, and the
existing code 13 case carried "not authorized", which the message markers match
too, so it could not tell whether the code was still being checked. 28 of 28
mutants now die.
2026-09-02 12:51:19 -07:00
Yujong Lee
90eadac409
test(build): keep wheel checks outside package 2026-09-02 12:16:25 -07:00
Yujong Lee
ce0c85ea69
refactor(rust): colocate native wheel contract checks 2026-09-02 12:16:25 -07:00
Yujong Lee
cbb8a1784d
chore(ci): extract setup-uv pin 2026-09-02 12:16:25 -07:00
Yujong Lee
38150dfc2c
fix(ci): pin workflow toolchain dependencies 2026-09-02 12:16:25 -07:00
Yujong Lee
ef9a207ed5
fix(ci): harden release wheel reporting 2026-09-02 12:16:25 -07:00
Yujong Lee
e6a317e079
fix(ci): enforce release wheel metadata contract 2026-09-02 12:16:25 -07:00
Yujong Lee
9dc9cd325c
fix(ci): isolate release wheel reporting permissions 2026-09-02 12:16:25 -07:00
Yujong Lee
2f362cfec2
fix(ci): preserve release wheel contract parity 2026-09-02 12:16:25 -07:00
Yujong Lee
25987cb961
test(build): validate release wheel contracts 2026-09-02 12:16:25 -07:00
mateo-berri
b0aafabdee ci(lint): gate top-level tests/e2e and litellm files in the diff-scoped lint steps
Without :(glob), git matches 'tests/e2e/**/*.py' with * crossing slashes, so the
pattern needs at least one directory below tests/e2e and a top-level file never
matches. PR #39209 added tests/e2e/test_junit_properties.py with three
basedpyright errors and the e2e step printed "No changed tests/e2e Python files;
skipping." The ruff format step's 'litellm/**/*.py' skipped litellm/main.py and
the other top-level modules the same way.

:(glob) makes /**/ match zero or more directories, so both gates now select
top-level and nested files alike. A regression test runs the workflow's own
pathspecs against a throwaway repo and locks that in for every diff-scoped gate.
2026-09-01 22:30:46 -07:00
devin-ai-integration[bot]
93219a9257
fix(docker): install bedrock-realtime extra in monolith proxy images (#39223)
The Dockerfile, docker/Dockerfile.non_root and docker/Dockerfile.database uv sync stages never passed --extra bedrock-realtime, so aws-sdk-bedrock-runtime was absent from the image venv and Bedrock Nova Sonic /v1/realtime sessions failed with 'Missing aws_sdk_bedrock_runtime'. gateway/Dockerfile already had the extra (PR #34426).

Adds a static check over every uv sync in the proxy Dockerfiles and an image-level import probe that the image-scan workflow runs against the built root, non-root and gateway images.

Co-authored-by: yassin <yassin@berri.ai>
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-01 17:51:55 -07:00
Kolade Fajimi
d1320404fe
fix(redis): coerce env var string types and fix param discovery through decorator wrappers (#30644)
* fix(redis): coerce env var string types and fix param discovery through decorator wrappers

inspect.getfullargspec doesn't work on redis.Redis/redis.RedisCluster because
their __init__ is wrapped by @deprecated_args, which replaces the explicit
signature with *args/**kwargs internally. getfullargspec returns an empty arg
list, so _get_redis_kwargs and _get_redis_cluster_kwargs silently dropped every
real constructor parameter not in their hand-picked include_args set --
cluster_error_retry_attempts and connection_error_retry_attempts among them, so
an operator's configured retry bound never reached the Redis Cluster client and
it fell back to redis-py's own default instead.

Rebased onto litellm_internal_staging, which had independently added
_init_arg_names (MRO-walking, inspect.unwrap-based) for the same class of bug
in _get_redis_url_kwargs. Reused that pattern (as _unwrapped_init_args, without
the MRO walk: redis.Redis/RedisCluster declare every real parameter directly on
their own __init__, and MRO-walking breaks the tests here that mock the class
with autospec=True, since inspect.getmro needs a real __mro__) rather than
introducing a second, differently-shaped fix for the same problem.
_get_redis_cluster_kwargs now also honors its own client argument instead of
ignoring it, so the async cluster client's own extra constructor kwargs
(cluster_error_retry_attempts, connection_error_retry_attempts,
decode_responses, ...) are no longer filtered out by introspecting the sync
class regardless of which client is actually built.

Also fixes environment variables and Helm --set values always arriving as
strings: redis-py 8.x changed health_check_interval's arithmetic to require a
real number, so a stringified value raised TypeError on every Redis operation
instead of connecting. _coerce_redis_kwargs_types coerces to each parameter's
declared type at the end of _get_redis_client_logic, with an explicit type
table for max_connections/socket_timeout/socket_connect_timeout since redis-py
8.x changed the timeout defaults from None to int 5, which would otherwise
make a fractional value fail int() and get dropped.

Co-authored-by: mangabits <1457532+mangabits@users.noreply.github.com>

* ci: verify redis-py client version compatibility across a version matrix

* test(redis): assert an async-only cluster kwarg every matrix version declares

connection_error_retry_attempts is on the async cluster constructor in redis-py
5.x only; 6.0 removed it in favor of retry. The 6.4.0, 7.4.1 and 8.0.1 legs were
failing on that missing parameter name rather than on the behavior under test,
while the allow-list itself was doing the right thing on all four versions.

decode_responses is async-cluster-only on every version the matrix covers, so it
stands in for the same property: the sync cluster class takes it through **kwargs
and never names it in its signature. Reverting _get_redis_cluster_kwargs to ignore
its client argument still fails both tests on 5.3.1 and 8.0.1.

test_async_cluster_passes_async_only_kwargs now builds the real async cluster
client and reads connection_kwargs off it, so it no longer needs a patched class
factory; the constructor does no I/O. The retry-attempts test keeps its patch,
since redis-py >= 6 stores no cluster_error_retry_attempts attribute on the built
client and the constructor call is the only place the forwarded value shows up.

The _get_redis_cluster_kwargs docstring cited the same two parameters as its
examples of async-only kwargs, which is what made the test look reasonable;
cluster_error_retry_attempts is on both classes and connection_error_retry_attempts
is gone from 6.0 on, so it now names decode_responses instead.

* test(redis): drop internal patches from the kwarg coercion tests

The test-quality gate flagged the new patch() calls on litellm internals these
tests added. Three of them faked litellm._redis.inspect.signature with a MagicMock
to hand _coerce_redis_kwargs_types a synthetic parameter; that function already
takes a client argument, so they pass stub functions instead, matching the
_redis_signature_8x idiom the file uses elsewhere. The fourth patched
_redis_kwargs_from_environment to {} to prove _get_redis_client_logic raises
without a host or url, which clearing the real env keys through
_get_redis_env_kwarg_mapping does without pinning the test to that call.

Both files now sit one TQ008 below the merge base rather than six above it.

* fix(redis): keep the sync client construction inside the basedpyright budget

_get_redis_client_logic now returns dict[str, object] rather than an untyped
dict, which is the honest type for operator-supplied config, but it turns the
33 reportUnknownArgumentType errors at redis.Redis(**redis_kwargs) into 33
reportArgumentType errors plus one reportCallIssue, both over their budget.
No static type fits: redis-py's constructor declares 40-odd differently typed
parameters and the values arrive from config and env, so the allow-list and
coercion above are derived from that same signature and redis-py validates each
value itself at runtime.

The two suppressions name their exact rule and carry that reason. The file ends
up 42 basedpyright errors below the merge base, with reportArgumentType and
reportCallIssue back at the base counts of 3 and 0.

* fix(redis): coerce cluster-only and None-default bool kwargs

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

---------

Co-authored-by: mangabits <1457532+mangabits@users.noreply.github.com>
Co-authored-by: yassin <yassin@berri.ai>
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-08-31 20:51:31 -07:00
Yujong Lee
9b774d3dcf
fix(ci): isolate editable Cargo cache namespace 2026-08-31 17:25:28 -07:00
Yujong Lee
849269d52d
build(rust): configure native extension profiles 2026-08-31 17:25:28 -07:00
mateo-berri
044e6c28bd fix(price-sync): skip Friendli rows without valid token prices so priced entries never get wiped 2026-08-31 16:05:43 -07:00
Mateo Wang
d60e77ae8c
Merge pull request #38819 from BerriAI/litellm_fix_gemini_tts_response_format
fix(speech): stop forwarding response_format as a chat param for Gemini TTS
2026-08-31 15:56:18 -07:00
mateo-berri
c7d5949690 Merge branch 'litellm_internal_staging' of https://github.com/BerriAI/litellm into feat/friendli-model-metadata-sync
# Conflicts:
#	litellm/model_prices_and_context_window_backup.json
#	model_prices_and_context_window.json
2026-08-31 15:23:30 -07:00
mateo-berri
077cdb5fb9 fix(scripts): replace synced Friendli entries wholesale and seed the backup cost map 2026-08-31 13:56:54 -07:00
mateo-berri
81f9ad322b fix(scripts): keep the weekly price sync alive past unrepresentable rows
Vercel now lists video and embedding models without token pricing or token
limits, and the first of them KeyError'd the whole weekly run before any
provider was synced. Those rows are skipped, and a failed catalog fetch for
any provider now yields an empty transform instead of a crash.
2026-08-31 13:39:52 -07:00
mateo-berri
b4a9ddb924 fix(friendli): emit declared reasoning-effort levels and harden weekly sync
The transform now declares reasoning_effort_levels straight from the catalog's
effort options instead of mapping them onto per-level support flags, which
mis-advertised efforts these models do not take. max_tokens mirrors
max_completion_tokens rather than context_length, supports_prompt_caching is
derived from cache-read pricing, video input is read from input_modalities, and
a failed Friendli fetch no longer breaks the weekly sync run. The committed
friendliai entries are regenerated from the live catalog: stale gemma-4 token
caps refreshed, the delisted K-EXAONE-236B-A23B entry dropped, and GLM-5.3 /
GLM-5.3-Flash picked up with current billed pricing.
2026-08-31 13:34:48 -07:00
siyoon
b346dd414b fix(scripts): use PEP 604 union syntax for Optional[str]
Ruff UP045 flags Optional[str] as legacy typing; the repo lint baseline
expects the modern str | None form for new/changed annotations.
2026-08-30 14:52:35 +09:00