Commit graph

48834 commits

Author SHA1 Message Date
Yuneng Jiang
323f51269d
fix(vector_stores): return 400 when a MongoDB TLS file cannot be read
tlsCAFile and tlsCertificateKeyFile are how a self-managed deployment presents a
private CA, so they are the options on-prem operators actually set. pymongo opens
those files itself during TLS setup and lets OSError out, which is neither a
PyMongoError nor a ValueError, so it missed every branch of the translator and
litellm.exception_type turned it into a 500 with a traceback in the body. A
mistyped path, or one that exists on the host but not inside the container, is a
routine mistake and has to read as a 400 naming the file.

Matched on the exception carrying a filename so a socket-level OSError still falls
through to the branches that handle it. Verified against a self-managed mongod with
a missing CA file, a CA path that is a directory, and a missing client certificate.
2026-09-04 13:59:07 -07:00
Yuneng Jiang
9e0659212a
test(e2e): repair two suites broken by intentional behaviour changes
Both of these are e2e assumptions that PRs #31731 and #39532 invalidated, not
product regressions. They have been red in litellm-e2e builds 119-123.

Wildcard readiness probe (6 errors in test_model_access_group_e2e.py)

#31731 made _get_wildcard_models drop a wildcard route from /v1/models
unconditionally; before it, a wildcard with a matching router deployment stayed
in the list and only the no-router / no-deployment fallbacks removed it. The
shared readiness helper polls /v1/models for an exact id match, so registering
openai/gpt-5.4* now times out at model_servable_timeout every run and every
test in the class errors in setup.

return_wildcard_routes=True still re-adds the route, so the poll asks for it.
The flag is a no-op for a concrete model name -- it only ever adds wildcard
entries -- so it is set unconditionally rather than sniffing the name.

Semantic auto-router spend assertion

#39532 bills the routing embedding to the caller's key on purpose, so the key's
spend logs now legitimately carry an openai/text-embedding-3-small row and
_assert_served_only_by rejects it.

Widening the allowlist would have weakened the assertion this test exists for --
that the request reached the target deployment. Instead the embedding row is
split off and asserted separately, which turns the break into coverage for
#39532. The poll gains a predicate so it waits for the embedding row rather than
racing whichever row is written first.
2026-09-04 13:48:42 -07:00
Mateo Wang
300d335255
Merge pull request #39361 from BerriAI/litellm_fix_mantle_host_re_anchor
fix(bedrock_mantle): anchor MANTLE_HOST_RE so custom Mantle hosts are honored
2026-09-04 13:40:02 -07:00
Yuneng Jiang
50fb35e17e
fix(vector_stores): make MongoDB errors actionable on self-managed deployments
mongod serves $vectorSearch identically whether mongot runs under Atlas or beside
a self-managed deployment, so the provider already worked against on-prem. The
guidance did not: a refused connection told the operator to check their project's
IP access list and whether the cluster was paused, neither of which exists outside
Atlas, and the index errors claimed an "Atlas Vector Search index" they do not have.
Every message now names a remedy for both, keeping the Atlas-specific hint labelled
as such.

Also diagnoses unescaped credentials, which self-managed deployments hit more often
because the password is usually generated. pymongo reports those three different
ways and none of them mentions the password: '@', ':' and '%' raise an RFC 3986
complaint, '/' is read as the database separator and surfaces as Bad database name,
and an unescaped ':' looks like a bad port and comes back as a plain ValueError.
All three now point at the credentials. The ValueError branch's comment claimed it
fired on an unescaped '/', which pymongo actually reports as InvalidURI; corrected
to the port parse it really catches.

Verified against a self-managed mongod 8.0 with mongot, reached over plain
mongodb:// with no SRV and no TLS: 13 cases with live OpenAI embeddings, and 4
credential cases against an auth-enabled instance whose password holds % @ / and :.
list_search_indexes returns the same queryable and status fields there as on Atlas,
so the index-readiness check needed no change.
2026-09-04 13:39:54 -07:00
tin-berri
8beca1d58d
fix(auto-router): route 1M complex tier to GPT Sol (#39797)
* feat(ui): add 1M context auto-router preset

* feat(ui): use heuristic v2 for 1M preset

* fix(ui): keep 1M preset test within lint budget

* fix(auto-router): route 1M complex tier to GPT Sol

* test(auto-router): update 1M complex tier expectation
2026-09-04 13:33:06 -07:00
ryan-crabbe-berri
189bd857f4
Merge pull request #39794 from BerriAI/litellm_v2_org_update_public
feat(organization): expose PATCH /v2/organization/{organization_id} in the OpenAPI schema
2026-09-04 13:32:52 -07:00
ryan-crabbe-berri
38a1b44993
Merge pull request #39793 from BerriAI/litellm_v2_org_update_validation
fix(organization): reject negative limits and unparseable budget_duration on PATCH /v2/organization
2026-09-04 13:32:07 -07:00
ryan-crabbe-berri
a502c728ac
Merge pull request #39670 from BerriAI/litellm_fix_org_update_null_budget_limits
fix(organization): clear org budget limits when PATCH /organization/update sends null
2026-09-04 13:31:56 -07:00
Mateo Wang
338a37d8cd
Merge pull request #39632 from BerriAI/litellm_lit6874_fireworks_perplexity_off_peak_pricing
fix(cost): honor off_peak_pricing in the fireworks_ai and perplexity cost calculators
2026-09-04 13:20:52 -07:00
Mateo Wang
44b1cc7b0f
Merge pull request #39589 from BerriAI/litellm_fix_v1_messages_midstream_timeout_failure_logging
fix(proxy): log mid-stream /v1/messages failures as failures with partial usage
2026-09-04 13:20:30 -07:00
mateo-berri
f9a5f676a8 docs(claude): have runs embed their own QA screenshots on visual changes 2026-09-04 13:16:39 -07:00
moe-berri
6234399f9e fix(router): keep circuit-open fallbacks out of session pins
An open classifier circuit routed through the ordinary heuristic or
classifier_fallback path, and both causes are pin-worthy, so a session
whose turn landed on the cooldown fallback held that model for the whole
session_affinity TTL and never reclassified after the breaker closed.

The circuit-open signal now blocks the pin, and _classifier_failure_outcome
tags its outcomes through one helper instead of reassigning a Final.
2026-09-04 13:16:34 -07:00
ryan-crabbe-berri
7a717740dd test(organization): assert rejected values write nothing to the DB 2026-09-04 13:11:31 -07:00
mateo
50d6b26a86 fix(registry): mark baseten GLM-5.3 as vision-capable per Baseten vision docs
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-04 20:10:58 +00:00
ryan-crabbe-berri
0eb2363074 test(organization): assert route publicity through the production OpenAPI generator 2026-09-04 13:10:37 -07:00
ryan-crabbe-berri
3e4a884b25 feat(organization): expose PATCH /v2/organization/{organization_id} in the OpenAPI schema 2026-09-04 13:03:18 -07:00
ryan-crabbe-berri
976ff0a785 fix(organization): 422 on negative limits and unparseable budget_duration in v2 update 2026-09-04 12:58:33 -07:00
mateo
f5157a63eb test: allow 128k and 256k tiered cache fields in registry schema test
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-04 19:56:30 +00:00
ryan-crabbe-berri
d71fe43c1a
Merge pull request #39682 from BerriAI/litellm_lit_4738_per_user_usage_pagination
fix(ui): paginate per-user usage with the shared server-side DataTable footer
2026-09-04 12:53:12 -07:00
ryan-crabbe-berri
3bdc5ecd0e refactor(ui): drop the per-user usage page clamp now handled by the shared DataTable
The shared DataTable clamps a server-mode page index whenever rowCount no
longer reaches it (#39776), including the empty-dataset case this table's
own clamp skipped because it required total_pages > 0. Remove the local
clamp and cover the empty case through the component so the wiring into
the shared behavior is what the tests prove
2026-09-04 12:47:37 -07:00
ryan
7fde31fe08 fix(ui): fall back to the last page when per-user usage shrinks under the current page
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-04 12:45:26 -07:00
ryan
fd42bddee6 fix(ui): reset per-user usage page in the same render as the tag filter change
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-04 12:45:26 -07:00
ryan
11f272e08b fix(ui): paginate per-user usage with the shared server-side DataTable footer
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-04 12:45:26 -07:00
devin-ai-integration[bot]
205a5e9d6c
feat(mcp): use x-mcp-<access_group>-* headers as default upstream credentials for group members (#39717)
Co-authored-by: yassin <yassin@berri.ai>
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-04 12:45:24 -07:00
ryan-crabbe-berri
62087c5d5f
Merge pull request #39776 from BerriAI/litellm_datatable_server_page_clamp
fix(ui): clamp server-paginated DataTable page index when rowCount shrinks
2026-09-04 12:43:38 -07:00
mateo-berri
8debf8294c fix(batches): resolve a legacy row's org from the key's organization_id and keep the Batch label on grouped rows 2026-09-04 12:42:39 -07:00
yuneng-jiang
4ad4db22f1
Merge pull request #39773 from BerriAI/litellm_/pr-39770-test-failure-c4aacd
test(caching): drive the redis stall burst off the clock, not asyncio.wait_for
2026-09-04 12:33:01 -07:00
yuneng-jiang
150182d76a
Merge pull request #39772 from BerriAI/litellm_ci_remove_pytest_x_flag
ci: report every failing test in a job instead of stopping at the first
2026-09-04 12:32:50 -07:00
mateo
1f0611a8b9 fix(registry): drop Together MiniMax M2.7 and revert Qwen2.5 7B Turbo pricing, both non-serverless
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-04 19:25:10 +00:00
mateo
7b96a11e5f feat(registry): add OpenRouter catalog gaps, Fireworks DeepSeek V4 Flash Vision, Together MiniMax M2.7 and Qwen2.5 7B Turbo pricing
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-04 19:19:08 +00:00
moe-berri
9f3aa8f36e
Merge pull request #39701 from BerriAI/litellm_classifier_circuit_breaker
feat(router): add classifier circuit breaker
2026-09-04 12:10:11 -07:00
mateo
93abc3a0cd Merge remote-tracking branch 'origin/litellm_internal_staging' into litellm_registry_audit_2026_09_02 2026-09-04 19:02:44 +00:00
devin-ai-integration[bot]
dd01abc439
feat(team): report per-user spend within a team for JWT traffic (#39771)
* feat(team): report per-user spend within a team for JWT traffic

Add GET /team/spend/by_user, which groups raw spend logs by (team_id, user)
so JWT/SSO requests with no virtual key are attributed to the user inside
each selected team. Team admins see every member, plain members see only
their own row. The Team Usage page gets a Spend Per User Within Team card
with CSV export backed by the same endpoint.

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

* test(team): cover /team/spend/by_user in behavior suite, tf audit allowlist and EntityUsage unit test

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

* refactor(team): drop explanatory docstrings from /team/spend/by_user and regen schema.d.ts

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-04 12:00:47 -07:00
mateo-berri
7e51fbc819 Merge remote-tracking branch 'origin/litellm_internal_staging' into litellm_batch_ui_logs
# Conflicts:
#	tests/proxy_unit_tests/test_check_batch_cost.py
2026-09-04 12:00:14 -07:00
Yuneng Jiang
2042364fc2
fix(proxy): strip every TypedDict qualifier before numeric form-field detection
_numeric_form_type only peeled a single ReadOnly layer, so a field still
wrapped in Required/NotRequired was read as non-numeric and dropped from the
mapping. Which qualifiers survive get_type_hints varies by interpreter version
and by include_extras, so on Python 3.10 NotRequired[ReadOnly[int]] reached the
check intact and the field was silently skipped, which is what turns the mapped
test red on the 3.10 leg only.

Peel Required/NotRequired/ReadOnly/Annotated in any order and nesting instead.
The one production caller feeds a schema with no qualifiers, so the resulting
mapping is unchanged on every interpreter in the matrix, but a field written the
house-convention way stops being dropped.
2026-09-04 11:50:28 -07:00
ryan-crabbe-berri
d05d2a6f05 fix(ui): clamp server-paginated DataTable page index when rowCount shrinks
Server-mode tables kept whatever page index the user was on after the
server's total dropped below it, for example after deleting the last
rows of the final page or when a refetch came back empty. The footer
then read "Page 2 of 1" and "Showing 26-25 of 25" with Previous and
First enabled over an empty body, and every one of the 13 server-mode
consumers was exposed since none of them clamped

The shared DataTable now snaps the controlled page index to the last
valid page as soon as a non-loading rowCount no longer reaches it, so
the fix applies to every consumer without per-table clamps. Loading
responses are ignored so a pending fetch never bounces the user to
page 1
2026-09-04 11:33:26 -07:00
ryan-crabbe-berri
caa1ab0e60 fix(guardrails): store an unpriced Bedrock counter as unknown, not free
A counter missing from the cost map entry was priced at 0.0 per unit, so
the rollup recorded it as known-free usage. It now stamps None for that
counter and the rollup writes NULL, while the per-request guardrail_cost
that feeds spend and budgets still sums only the known prices.

Claude-Session: https://claude.ai/code/session_01EX13mWex6RaBo9PYnkAtFW
2026-09-04 11:27:57 -07:00
ryan-crabbe-berri
4f3b02360e test(organization): type the legacy update helper's request body precisely 2026-09-04 11:21:37 -07:00
Yuneng Jiang
7d3b03d006
test(caching): drive the redis stall burst off the clock, not asyncio.wait_for
test_event_loop_stall_timeout_burst_keeps_breaker_closed built its timeout
burst by wrapping a healthy fake call in asyncio.wait_for. Before 3.12,
wait_for returns the inner result when the inner future also completed while
the loop was blocked, so no call timed out, the burst never materialised, and
the test's own liveness guard failed with 0 >= 3.

The fake now checks its own client deadline against the clock, the way a client
library does, so the stall produces a real redis TimeoutError burst on every
interpreter. The breaker itself is unchanged: its duration gate is plain
time.time() bookkeeping and never depended on the version.
2026-09-04 11:09:01 -07:00
Yuneng Jiang
4bd3cd9e06
ci: report every failing test in a job instead of stopping at the first
Drops `-x` from all 24 pytest invocations in .circleci/config.yml. With
`-x`, a job stops at its first failure, so a second broken test in the
same suite stays invisible until the first is fixed and CI is re-run.
That turns one round trip into N when a job has several broken tests.

This is exactly what happened in #39770: fixing
test_missing_model_parameter_curl in
tests/store_model_in_db_tests/test_openai_error_handling.py immediately
unmasked test_chat_completion_bad_model_with_spend_logs in the same
file, which had been failing for a long time without ever being
reported.

Only `-x` is removed; -v/-vv/-s/-n/--reruns and every other flag are
untouched.
2026-09-04 11:05:58 -07:00
yuneng-jiang
f74bc9427b
Merge pull request #39770 from BerriAI/litellm_/chronic-test-failures-e0994f
test: repair four chronically failing CI tests
2026-09-04 11:01:52 -07:00
Mateo Wang
04a198e3e3
Merge pull request #39568 from BerriAI/litellm_fix-batch-spend-key-double-hash-bcae
fix(spend-tracking): keep batch spend keys joinable after v1.99 provenance gate
2026-09-04 10:47:34 -07:00
Yuneng Jiang
a5a78670d0
test: address review notes on the chronic-test repairs
Drop the two new docstrings, annotate the new locals Final, and replace the
mutable call recorder with a rebuild stub that fails the test if it is ever
reached.
2026-09-04 10:18:15 -07:00
Yuneng Jiang
dbf8fe0f4e
test: repair four chronically failing CI tests
test_no_linear_scans_in_router: #39468 added config_deployments() and
heuristic_v2_router_limit_violation(), which both scan the whole model_list
from admin-only paths (model add/upsert), so add them to the allowlist. The
allowlist becomes a mapping so each exemption carries its reason as data.

test_missing_model_parameter_curl: a request with no model is rejected by the
proxy when nothing can serve it and by the router when a wildcard or default
deployment exists, and by the upstream provider when a wildcard forwards it,
so the message text is not a stable contract. Assert the contract that holds
in every case: HTTP 400 with a non-empty error message.

test_model_group_info_e2e: /model_group/info resolves wildcards, so it can
never return "anthropic/*" verbatim. cc3f9cd65b rewrote the assertion to
expect the raw pattern after claude-3-5-haiku-20241022 left the price map,
which made it unsatisfiable. Assert the expansion instead.

test_should_derive_ocr_mapping_status_from_live_tests: the audit needs a
native bridge built with the trace-parity feature, which CI never builds, so
skip with the harness's own diagnostic instead of erroring. Extract that
check out of ensure_trace_bridge as trace_bridge_error so a pytest run
reports the state without kicking off a maturin rebuild.
2026-09-04 10:10:47 -07:00
Krrish Dholakia
dad1b13225 style(fireworks_ai): format capability fallback
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-04 17:07:59 +00:00
Krrish Dholakia
2f1da035ae fix(fireworks_ai): keep generic capability fallback for reasoning and tool_choice
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-04 17:06:01 +00:00
mateo-berri
bef3585d82 feat(pricing): add GovCloud rows for every live but unpriced Bedrock model
Every model bedrock list-foundation-models and list-inference-profiles
report as live in us-gov-west-1 or us-gov-east-1 now has a priced row:
Claude Fable 5.1 (profile plus in-region), Nemotron Nano 9B (profile plus
in-region), Grok 4.6 (profile plus Mantle in both regions), the us-gov.
Claude 3 Haiku profile in the east, Nova Lite, Micro and the Nova 2
multimodal embeddings in the west, and the Gemma 4 and gpt-oss Mantle
SKUs the GovCloud offer files price. Offer-file rates are used where AWS
publishes them; Claude rows carry the 1.2x GovCloud premium.
2026-09-04 10:03:43 -07:00
mateo-berri
8b3faa6ed8 fix(proxy): keep /health inside the caller's team for unrestricted non-admin keys 2026-09-04 09:53:53 -07:00
mateo-berri
69a45e81cc fix(proxy): refuse /health targets outside the caller's scope instead of probing the rest 2026-09-04 09:40:00 -07:00
mateo
e7c29351e8 chore: ratchet lint budgets after merging litellm_internal_staging
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-04 16:35:26 +00:00