Commit graph

18927 commits

Author SHA1 Message Date
ryan-crabbe-berri
36eb9cdb35 test(proxy): drop the route-list membership test that the PATCH gate tests already cover 2026-09-16 15:56:27 -07:00
Yujong Lee
c635399f6e merge: origin/main into litellm_rust_bridge_declarative_route_catalog
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-16 22:54:51 +00:00
kerry
9885dc8962 test(e2e): add azure, bedrock converse and vertex wires to the cost suite
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-16 22:52:42 +00:00
ryan-crabbe-berri
c37d0a2e66 fix(proxy): read general_settings without a cast and test the /team/update gate by behavior only 2026-09-16 15:51:04 -07:00
kerry
4b70696afa fix(streaming): estimate interrupted Anthropic stream usage from reasoning_content
Interrupted Anthropic streams that die before message_delta were billed at
the message_start placeholder (any value above 1 was trusted) or at 0 when
the partial response was reasoning-only, because the token_counter fallback
only looked at visible text. Reset the placeholder whenever no finish_reason
or second usage event arrived, fold the already-counted reasoning tokens into
the fallback estimate, and drop the stale completion_tokens_details so cost
is computed from the recovered count

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-16 22:49:25 +00:00
Yujong Lee
9617312ab2 add PublicDispatch 2026-09-16 15:44:46 -07:00
ryan
dae16264c1 test(auth): cover over-budget user on zero-cost vs paid model in common_checks
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-16 15:42:15 -07:00
ryan
287bbaa6c1 fix(proxy): remove duplicate user budget hook that 429'd zero-cost models
_PROXY_MaxBudgetLimiter re-checked spend:user:{id} against user_max_budget in
async_pre_call_hook without the zero-cost model exemption that
_user_max_budget_check applies in auth, so free models were rejected with
"Max budget limit reached." once a user was over budget. Auth already owns
this check, so the hook is deleted rather than taught the exemption again

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-16 15:42:15 -07:00
ryan-crabbe-berri
6e2ae19670 fix(proxy): enforce org budget ceilings on /team/update
update_team loaded the org without its budget row, so the org max_budget,
tpm_limit and rpm_limit checks silently passed. It now loads the budget the
same way /team/new does
2026-09-16 15:38:30 -07:00
ryan-crabbe-berri
a44a58e91a feat(proxy): let team admins edit tpm_limit when a proxy admin enables it
tpm_limit is the first field in the team-admin allow-list registry. The team
settings tab gives a team admin a form with only the enabled fields and sends
only those on save, and UI Settings labels the checkbox the same way
2026-09-16 15:38:30 -07:00
ryan-crabbe-berri
d233043b05 test(proxy): expect team-admin budget changes to stop at the allow-list
max_budget is not a team-admin editable field yet, so the behavior suite now
pins the 403 in both directions instead of the old lower-is-allowed rule
2026-09-16 15:38:30 -07:00
ryan-crabbe-berri
66519da9b6 fix(proxy): report the caller's team edit access on /team/info
The dashboard gated the team settings form on a role it guessed from the
is_* props, the members list and the org list. The org list is premium
gated and empty while loading, so a team admin who is also an org admin
was told team admins cannot edit, although /team/update accepts them as
an org admin

/team/info now returns caller_edit_access, resolved by the same helper
/team/update uses, and TeamInfo keys the form and the toast off that
field. The org list is only read for the organization dropdown now, and
general_settings is read through one validated accessor in both handlers
2026-09-16 15:38:30 -07:00
ryan-crabbe-berri
50f890d02d fix(proxy): keep the team-admin field allow-list importable on python 3.10
assert_never landed in typing in 3.11, so importing it from typing broke the
3.10 import smoke job and the py310 typing gate. Take it from typing_extensions
like the rest of the proxy does.

Also drop /team/update from test_neighbouring_team_routes_stay_closed. The route
is self-managed now, so the coarse gate admits the caller and update_team decides,
which the sibling test in the same file already asserts.

Claude-Session: https://claude.ai/code/session_018PUCupsaarVLJy4iDFx256
2026-09-16 15:38:06 -07:00
ryan-crabbe-berri
ac47c95db9 fix(proxy): re-read UI settings on every config reload
The persisted UI settings were read once at startup, so a proxy admin
flipping a runtime flag through PATCH /update/ui_settings only changed the
pod that served the request. Every other pod kept serving the old value
until it restarted.

add_deployment, the reload the scheduler runs every 30s, now re-reads the
row and applies the runtime flags before it takes the model reconcile lock,
so a change made through one pod reaches the rest within one reload
interval. The startup hook and the two settings endpoints share that helper
instead of each repeating the flag copy.

Claude-Session: https://claude.ai/code/session_018PUCupsaarVLJy4iDFx256
2026-09-16 15:38:06 -07:00
ryan-crabbe-berri
9b77b5c2cb feat(proxy): let proxy admins choose which team fields team admins may edit
Team admins could never reach POST /team/update: the route gate answered
401 before the handler's team-admin branch ran. This moves /team/update
into the self-managed routes, resolves proxy admin, org admin or team
admin inside the handler, and filters team admins through a new
proxy-wide UI setting, team_admin_editable_team_fields. The setting is
an allow-list of team fields. Empty means team admins cannot edit team
settings and get a 403 pointing at the proxy admin, and changing a field
outside the list fails 403 naming that field. Only values that differ
from what is stored count, since the dashboard resends the whole form.

The registry of fields the setting accepts ships empty on purpose. Each
field lands in its own follow-up PR with its value diff and dashboard
wiring. The Admin UI gains a "Team admin editable fields" section under
Settings > UI and a toast on the team page while editing is disabled.

Refs LIT-5722

Claude-Session: https://claude.ai/code/session_01A6SkwJdfZUmkzfUkrEkqX8
2026-09-16 15:38:06 -07:00
yucheng
62b69294c1 test(utils): build the rewritten hook response without in-place mutation
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-16 22:34:52 +00:00
yucheng
f3e05d1d13 fix(otel): budget indexed messages from the tracer's own span limits and skip already-mapped error keys
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-16 22:34:02 +00:00
Yuneng Jiang
99545b5f26
Merge remote-tracking branch 'origin/main' into litellm_/buildkite-litellm-e2e-setup-ff714d 2026-09-16 15:15:22 -07:00
yucheng
934baa7441 fix(utils): swap converted stream iterator in place instead of rewrapping
Keeps the original CustomStreamWrapper so response headers and the
correlation-context cleanup in __del__ are untouched when a deployment
hook rewrites the converted response. Covers the early-return branches
for real provider streams and unmapped call types

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-16 22:14:58 +00:00
Yassin Kortam
a6e87526f8
Merge pull request #40843 from elifozdamar/litellm_fix_nonstream_parallel_slot_release
fix(proxy): release completed max-parallel slots promptly
2026-09-16 15:13:59 -07:00
mateo-berri
ea5887d4bb test: cover proxy_admin_viewer sessions in the model_group/info admin regression test 2026-09-16 15:10:48 -07:00
mateo-berri
167edf2769 fix(proxy): read the database user row only in the credential mint
The token exchange mint keeps reading the user row from the database, since JWT auth caches the user it creates before adding it to the JWT's team and a mint off that cached row refused the first exchange for a new user. Introspection and the refresh revalidation go back to the cache read, so a resource server calling /introspect per request pays no database read.
2026-09-16 15:10:03 -07:00
mateo-berri
d5570d04d9 fix(logging): keep a log extra only after inspecting every value it holds
The filter kept an extra as its original object whenever the plain and
scrubbed safe_dumps renderings matched, but safe_dumps skips what it cannot
render (non-string dict keys, anything past its depth limit, fields a repr
hides), so a secret in those places rode the untouched object past the
litellm_redacted stamp. The filter now walks JSON-native shapes itself
(strings, scalars, string-keyed dicts, lists and tuples) and keeps the
original only when every value it holds comes back unchanged from the
redactor; anything else is handed to safe_dumps and the record carries the
scrubbed JSON shape the formatter would have rendered
2026-09-16 15:07:22 -07:00
Yujong Lee
a84f68b6e3 refactor(rust_bridge): give chat completions, messages and responses the ocr dispatch shape
Each route now has litellm/rust_bridge/<route>/{entrypoints,callbacks}.py and a
public dispatch module (litellm/chat_completions/dispatch.py,
litellm/responses/dispatch.py, litellm/messages/dispatch.py) that binds the
public call to the legacy Python signature, builds a frozen request, and asks
the runtime to pick Rust or Python from the catalog. The legacy implementations
stay in litellm/main.py, litellm/responses/main.py and the anthropic messages
handler, and litellm/__init__.py re-exports the dispatch names over them the
same way it already does for ocr

The per-handler shims in rust_bridge/chat_completions/native.py and
rust_bridge/messages/native.py are removed along with their call sites in the
anthropic and bedrock chat handlers and the http handler. The exception
mapping that every callbacks module repeated moves to rust_bridge/failures.py
and the signature binding helpers to rust_bridge/public_call.py
2026-09-16 15:02:12 -07:00
Yuneng Jiang
76c0f8db1d
chore(e2e): report the key components behind a mount that never converges
Builds 232 and 233 held the Bedrock hit rate at 9% with the Claude Code
driver already sending byte-identical requests and headers, so something
between the proxy's ingress and the upstream still moves per build and
the flat key cannot say what.

Emit a digest per key component next to the counters: the test id, the
method, the URL, each keyed header, the whole body, and one digest per
top-level JSON body field. Values are digested, so no payload or
credential reaches the artifact. Diffing two builds' artifacts names the
field that moved.

Diagnostic, to be removed once it has answered.
2026-09-16 15:01:08 -07:00
yucheng
a5f85c2bdb fix(otel): fit per-index OpenInference messages to the span's remaining attribute budget
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-16 21:57:05 +00:00
yucheng
325a42ea75 fix(utils): run post-call deployment hook on converted chat streams
A pre-call deployment hook can turn a requested stream into a non-streaming provider call and the result is wrapped back into a fake stream. The async client wrapper treated that wrapper like a caller-requested stream and returned before async_post_call_success_deployment_hook, so SDK callers lost post-call deployment processing (including CustomGuardrail post_call enforcement) on converted streams. Run the hook on the complete ModelResponse behind the wrapper and rewrap a modified response so it reaches the emitted chunks.

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-16 21:49:47 +00:00
Yassin Kortam
f62f140f75
Merge pull request #41403 from BerriAI/litellm_key_total_spend
feat(proxy): expose lifetime total_spend on virtual keys
2026-09-16 14:49:02 -07:00
Yassin Kortam
2bfa10b6d9
Merge pull request #41311 from BerriAI/litellm_key_status_filter_deleted_lookup
feat(keys): filter /key/list by active, expired, revoked or deleted status and serve deleted keys from /key/info
2026-09-16 14:48:34 -07:00
Yassin Kortam
95abc9fb0b
Merge pull request #41330 from BerriAI/litellm_team_model_max_budget_v2
feat(team): team-level model_max_budget with key-level overrides
2026-09-16 14:48:29 -07:00
Yassin Kortam
314c0d71a5
Merge pull request #41327 from BerriAI/litellm_s3_log_prompts_only
feat(s3): add s3_log_prompts_only option to log prompts without responses
2026-09-16 14:48:18 -07:00
kerry
4b60682600 ci: auto-merge provider-info-sync PRs when CI, Greptile and Bugbot are clean
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-16 21:48:08 +00:00
shivam
8a41e10332 fix(anthropic-bridge): convert mid-conversation system turns to user turns on /v1/messages to chat completions
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-16 21:47:46 +00:00
yujonglee
cc99ad00dd
Merge pull request #41489 from BerriAI/litellm_ocr_fileio_core
refactor(ocr): move file preparation from the python bridge into litellm-core
2026-09-16 14:45:09 -07:00
mateo-berri
eaeeb3a9bc Merge remote-tracking branch 'origin/main' into litellm_dashscope_reasoning_effort 2026-09-16 14:41:08 -07:00
mateo-berri
da844e3dd2 Merge remote-tracking branch 'origin/main' into litellm_model_group_info_proxy_admin_all_models 2026-09-16 14:40:10 -07:00
ryan-crabbe-berri
4439631e05
Merge pull request #41379 from runjivu/fix/fallback-budget-check
fix!: re-check budget on router fallback targets
2026-09-16 14:39:56 -07:00
Yujong Lee
62c862796a cleanup 2026-09-16 14:38:59 -07:00
Yassin Kortam
cd08c65002
Merge pull request #41425 from BerriAI/litellm_streaming_buffer_release_on_scan
feat(guardrails): release buffered stream chunks after each passing scan
2026-09-16 14:37:56 -07:00
Yassin Kortam
16bbff6643
Merge pull request #41474 from BerriAI/litellm_router_tpm_rpm_count_before_headers_v2
fix(router): count TPM/RPM usage before building rate-limit headers
2026-09-16 14:37:04 -07:00
Yuneng Jiang
0de187e76c style(test): annotate the new locals as Final 2026-09-16 14:34:13 -07:00
Yuneng Jiang
515bf8c9d5 refactor(test): validate cost-map entries into a typed model
The selector read raw cost-map dicts as `Mapping[str, Any]`. It now validates
each together_ai entry into a frozen Pydantic model and takes the two
capabilities as keyword booleans, so nothing in the helper is coarsely typed
or stringly addressed.
2026-09-16 14:32:08 -07:00
Mateo Wang
6edb549dbd
Merge pull request #41112 from BerriAI/litellm_registry_audit_2026_09_14
fix(models): rolling registry audit: Gemini latest aliases, Nova cache pricing, OpenRouter/Together sync, Mistral GLM 5.3, Azure snapshots, Grok caching
2026-09-16 14:31:50 -07:00
Yuneng Jiang
ba6c9fa61d fix(test): drop the redundant sys.path.insert
CI runs these lanes as `python -m pytest` from the repo root, so the root is
already on sys.path and `tests._live_test_helpers` imports without help. The
insert only tripped the TQ003 test-quality budget.
2026-09-16 14:26:16 -07:00
mateo-berri
09f3a5160a test(azure_ai): assert the bare deployment name reaches the native Responses endpoint 2026-09-16 14:21:14 -07:00
Yuneng Jiang
b478131701 test(together_ai): select the live model from the cost map
`together_ai/openai/gpt-oss-20b` was hardcoded in two live tests and is no
longer served, so both failed on a vendor catalog change rather than on
anything litellm did.

Both call sites now resolve the cheapest non-deprecated together_ai chat
entry at runtime, filtered on the capabilities the tests actually exercise,
mirroring what tests/e2e/llm_translation/test_together_ai_e2e.py already
does. The selector lives in tests/_live_test_helpers.py so both lanes share
one implementation.
2026-09-16 14:20:49 -07:00
mateo-berri
04eae31769 fix(logging): keep secret-free log extras as their original objects
A non-string extra was scrubbed by a safe_dumps round trip, which handed
every user-attached handler a JSON-shaped copy even when nothing in it
was redacted. The record now keeps the original object whenever the plain
and the scrubbed renderings compare equal, so only an extra that carried
a secret comes back as its scrubbed shape
2026-09-16 14:17:48 -07:00
ryan-crabbe-berri
17844cf14b Merge remote-tracking branch 'origin/main' into pr41379 2026-09-16 14:17:23 -07:00
Yujong Lee
64cd6538a6 cleanup 2026-09-16 14:16:15 -07:00
kerry
35a5fc92bc Merge remote-tracking branch 'origin/main' into litellm_e2e_cost_calculation_scripted_provider 2026-09-16 21:15:34 +00:00