Commit graph

44654 commits

Author SHA1 Message Date
Mateo Wang
296ebc1103
Merge pull request #38252 from BerriAI/litellm_pr_template_caveat_severity
docs(pr-template): split Caveats bullets into severity tiers and call for plain engineering language
2026-08-25 15:04:37 -07:00
Yassin Kortam
6c0c91c5ad
fix(team): serialize member_add, member_delete, and delete under the team's advisory lock (#37969)
* fix(proxy): make /team/member_delete's four cleanups atomic

The team roster update, the user.teams update, the team membership
delete, and the team-scoped verification token delete ran as four
sequential writes with no transaction around them, so a failure
between any two left the removal half applied. Thread a single
prisma transaction through all four writes, following the same
tx.<table> pattern /team/member_add and /team/member_update already
use, so either all four land or none do.

* fix(team): serialize member_add, member_delete, and delete under the team's advisory lock

/team/member_add validated a team exists and then wrote the user's teams array and
a membership row without holding anything across that gap, so a /team/delete could
commit its reference sweeps in between and leave a member pointing at a team id that
no longer exists. The write path already re-read members_with_roles under a row lock
before this change, but SELECT ... FOR UPDATE can deadlock with the access-group
endpoints, which lock an access group and then a team.

member_add now takes pg_advisory_xact_lock(hashtext(team_id)) before re-reading the
team and only writes if it is still there, so a delete that already committed is
visible before any write happens. delete_team takes the same lock around its own
row delete and reference sweep, so the two requests can never interleave: whichever
acquires the lock first runs to completion before the other's read can proceed.

Dropping the row lock from member_add's read also dropped the incidental protection
it gave against a concurrent member_delete, which still wrote from the snapshot it
validated against, unlocked, and could silently overwrite whatever member_add had
just committed. member_delete now takes the same advisory lock and re-reads the
roster under it before computing its own write, so it can never resurrect a member
by overwriting from stale data.

Resolves LIT-5544

* fix(team): run member writes on the advisory lock's transaction

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

* fix(team): keep member writes on the lock holder's connection after merge

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

* fix(team): keep the transactional member create an upsert on user_id

The transaction path was creating the email-identified user row outright, where the
regular client path upserts on user_id. Share one upsert helper between both member
paths so the create stays idempotent on the lock holder's connection.

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

* fix(team): read member_delete's user and key rows on the lock-holding transaction

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

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-08-25 21:55:11 +00:00
Mateo Wang
9962f4fba8
Merge pull request #38251 from BerriAI/litellm_fix_tool_result_document_drop
fix(anthropic): translate tool_result document blocks in the /v1/messages bridge
2026-08-25 14:54:01 -07:00
Mateo Wang
a40157c55d
chore: make it more concise 2026-08-25 14:53:24 -07:00
Mateo Wang
d61ccd0f58
chore: make it more clear 2026-08-25 14:51:53 -07:00
Mateo Wang
99c1b33fd3
chore: humanize the CLAUDE.md 2026-08-25 14:50:14 -07:00
Deepanshu Lulla
75c4565dde
fix(cerebras): add max_retries and extra_headers to get_supported_openai_params (#36601)
Co-authored-by: Deepanshu <deepanshu.lulla@alpha-sense.com>
2026-08-25 14:10:56 -07:00
Mateo Wang
d8d384eada
Merge pull request #38230 from BerriAI/litellm_together_models_backfill
feat(models): add missing Together AI serverless models to the cost map
2026-08-25 14:02:58 -07:00
ryan-crabbe-berri
02cba40bb6
Merge pull request #37756 from BerriAI/litellm_jwt_team_allowed_routes_wildcard
fix(auth): support wildcard prefixes in jwt team_allowed_routes
2026-08-25 13:49:31 -07:00
Yassin Kortam
c70b911122
fix(router): support mid-stream fallback for anthropic_messages route type (#38153)
anthropic_messages goes through _ageneric_api_call_with_fallbacks rather
than _acompletion, so its returned streaming iterator was never wrapped
by the chat-completions fallback handler. A retriable SSE event: error
frame (overloaded_error, internal_server_error) from a native
Anthropic/Bedrock passthrough passed through to the client unchanged,
and a MidStreamFallbackError raised by the completion-bridge path's
CustomStreamWrapper propagated unhandled.

Add _aanthropic_messages_streaming_iterator, mirroring
_acompletion_streaming_iterator: it detects a retriable SSE error event
via the new parse_anthropic_error_event helper, raises
MidStreamFallbackError once real generated content (a content_block_delta
frame) has not yet reached the caller, and re-enters the Router's
fallback chain. A MidStreamFallbackError raised directly by the source
iterator (the completion-bridge path) is gated the same way via its own
is_pre_first_chunk flag. The raised MidStreamFallbackError carries a
status-coded original_exception built from the parsed error type, so
status_code/cooldown logic sees the real 429/500/503/etc. instead of a
hardcoded 503.

Lifecycle/bookkeeping frames (message_start, content_block_start, ping,
...) never disqualify a fallback attempt by themselves, since Anthropic
routinely sends message_start before an overload error - but they are
buffered rather than forwarded immediately, since forwarding one and
then appending a fallback attempt's own message_start would produce two
overlapping message lifecycles on one SSE stream. Buffered frames flush,
in order, once real content arrives or the stream ends without error.
Once real content has streamed, or the error is a non-retriable 4xx, the
chunk (or exception) is forwarded as-is rather than starting a second
lifecycle. Content and error coalesced into a single physical read are
handled the same way: once the client has genuinely received the content
(bundled in that same forwarded chunk), no fallback is attempted. A
`ping` keepalive is dropped outright before any real content arrives
(it recurs indefinitely on a slow-starting connection and carries
nothing worth buffering), and the pre-content lifecycle buffer is capped
at MAX_BUFFERED_PRE_CONTENT_ANTHROPIC_CHUNKS, forcing an early commit to
the primary stream so a hostile or pathological upstream can't grow it
without bound. is_anthropic_ping_chunk only matches a chunk whose every
event: line is event: ping, so a ping coalesced with real content or a
retriable error into one physical transport chunk is never dropped.

The fallback request kwargs also deep-copy nested litellm_metadata/metadata
(matching the Responses API path) so the primary attempt's
deployment-specific fields never leak into the fallback request, and the
fallback deployment's own provider headers are merged onto the wrapper's
_hidden_params so they still reach the client/logging pipeline. A
fallback that resolves to a non-streaming response (e.g. an agentic
tool-use interception loop) is synthesized into a real Anthropic SSE
event sequence via the new anthropic_messages_response_as_sse_events
helper, instead of yielding a raw dict into the byte stream - including
a trailing signature_delta for a thinking block, and a message_start
whose stop_reason/stop_sequence/output_tokens stay null/zero the way a
real stream's does instead of leaking the completed response's final
state.

Resolves #24004
2026-08-25 13:40:46 -07:00
devin-ai-integration[bot]
c96245d7bf
fix(scim): preserve existing team memberships when POST /Users adoption carries no groups (#38166)
Co-authored-by: yassin <yassin@berri.ai>
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-08-25 13:39:34 -07:00
devin-ai-integration[bot]
6d0cc1423e
fix(scim): return user_id as Group members[].value on transformed group responses (#38161)
* fix(scim): return user_id as Group members[].value on transformed group responses

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

* style: format scim transformation tests per ruff

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

* test: drop redundant assertion comment

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

* chore: retrigger ci

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-08-25 13:37:45 -07:00
ryan-crabbe-berri
b1f903743c Merge remote-tracking branch 'origin/litellm_internal_staging' into litellm_jwt_team_allowed_routes_wildcard 2026-08-25 13:33:29 -07:00
ryan-crabbe-berri
e5adf7d926
Merge pull request #37493 from BerriAI/devin_ai_lit5815_guardrail_tag_mode_ui
fix(ui): render tag-based guardrail mode instead of crashing the guardrails page
2026-08-25 13:24:19 -07:00
Yassin Kortam
104fe73113
fix(dashboard): don't show a stale provider prompt-cache chip on a response-cache hit (#37951)
* fix(dashboard): don't show a stale provider prompt-cache chip on a response-cache hit

The playground's non-streaming chat completion and responses paths replayed a cache hit's original usage payload verbatim, so ResponseMetrics kept rendering the provider's prompt-cache-write/read chips using token counts from the original request. Detect the hit via the x-litellm-cache-key response header and render a Response Cache indicator instead.

* fix(dashboard): expose x-litellm-cache-key through CORS for the playground cache-hit indicator
2026-08-25 13:07:09 -07:00
Yassin Kortam
27ca05a707
fix(ui): read reasoning tokens from Responses API output_tokens_details (#37952) 2026-08-25 13:01:51 -07:00
Mateo Wang
ece03ceafe
Merge pull request #38248 from BerriAI/litellm_together_chat_config
fix(together_ai): route chat completions through a dedicated TogetherAIChatConfig
2026-08-25 12:55:31 -07:00
mateo-berri
8829b3269f docs(pr-template): group caveats under severity subheadings and promote Final Attestation 2026-08-25 12:52:54 -07:00
devin-ai-integration[bot]
0458accaa0
perf(auth): drop guaranteed-miss internal-cache Redis read from team object lookup (#38073)
Co-authored-by: yassin <yassin@berri.ai>
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-08-25 12:47:37 -07:00
devin-ai-integration[bot]
896e2598da
fix(caching): keep upstream RedisCluster on redis-py with per-connection recovery (#38171)
Co-authored-by: yassin <yassin@berri.ai>
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-08-25 12:45:23 -07:00
devin-ai-integration[bot]
e25ce85dbc
fix(proxy): stop expected 4xx responses from saturating worker CPU on failure logging (#38102)
* fix(proxy): stop expected 4xx responses from saturating worker CPU on failure logging

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

* fix(proxy): keep threaded sync failure handler so CustomLogger sync callbacks still run

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

* chore: remove redundant comments per review

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-08-25 12:44:16 -07:00
Mateo Wang
c6082c5255
Merge pull request #37897 from BerriAI/litellm_reasoning_effort_capability_v2
feat(router): per-group supported reasoning efforts with the max level
2026-08-25 12:41:21 -07:00
ryan-crabbe-berri
3db6c5ab18
Merge pull request #37770 from BerriAI/litellm_fix_model_router_spend_log_model
fix(proxy): store the actual selected model in spend logs for Azure Model Router
2026-08-25 12:35:35 -07:00
mateo-berri
d749b186de docs(pr-template): make intent the severe-vs-high discriminator 2026-08-25 12:34:31 -07:00
mateo-berri
2bd2c1393c docs(pr-template): split Caveats bullets into severity tiers and call for plain engineering language 2026-08-25 12:31:43 -07:00
mateo-berri
17845b4fb0 fix(anthropic): translate tool_result document blocks in the /v1/messages bridge 2026-08-25 12:20:51 -07:00
mateo-berri
5b2d1874b0 Merge remote-tracking branch 'origin/litellm_internal_staging' into litellm_reasoning_effort_capability_v2
# Conflicts:
#	tests/test_litellm/test_router.py
2026-08-25 12:07:05 -07:00
Mateo Wang
a9f42f0ccf
Merge pull request #38227 from BerriAI/litellm_mantle_codex_input_items
fix(bedrock_mantle): normalize Codex input item types Mantle rejects
2026-08-25 12:04:13 -07:00
mateo-berri
32ebfba5ed refactor(together_ai): build the trimmed supported-params list without mutating the inherited list 2026-08-25 12:03:51 -07:00
mateo-berri
636ae5d3c7 Merge remote-tracking branch 'origin/litellm_internal_staging' into litellm_mantle_codex_input_items 2026-08-25 11:56:13 -07:00
Mateo Wang
c543461297
Merge pull request #38225 from BerriAI/litellm_fix_bedrock_mantle_gpt5_context_window
fix(model_prices): raise bedrock_mantle gpt-5.6 max_input_tokens to Mantle's enforced 1050000
2026-08-25 11:51:19 -07:00
Mateo Wang
76e1105f74
Merge pull request #38235 from BerriAI/litellm_router_api_base_resolution
fix(router): resolve provider from api_base in deployment validation and acompletion
2026-08-25 11:51:15 -07:00
Mateo Wang
18108ecc24
Merge pull request #38231 from BerriAI/litellm_fix_bedrock_mantle_passthrough_invoke
fix(bedrock_mantle): register a Bedrock runtime passthrough config so /bedrock/model/<deployment>/invoke works
2026-08-25 11:51:03 -07:00
mateo-berri
62ec3b6116 fix(together_ai): route chat completions through a dedicated TogetherAIChatConfig 2026-08-25 11:44:06 -07:00
milan
6cd1fcdcf0 test: drop unneeded proxy_server patches and ratchet lint budgets
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-08-25 18:37:26 +00:00
milan
77f22be207 style: apply ruff format to common_utils
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-08-25 18:27:19 +00:00
milan
559588a473 fix(azure_ai): remove new LIT002 violations to satisfy type-discipline budget
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-08-25 18:23:09 +00:00
Mateo Wang
41aa1caff1
Merge pull request #38233 from BerriAI/litellm_together_api_host
fix(together_ai): default endpoints to api.together.ai instead of api.together.xyz
2026-08-25 11:17:17 -07:00
milan
dacb1473bc chore: merge remote branch and resolve test conflicts
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-08-25 18:00:19 +00:00
milan
7a4567b6b3 chore: merge branch updates and resolve test conflicts
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-08-25 17:59:30 +00:00
Yassin Kortam
5470c1bccb
fix(ui): forward OAuth issuer/authorization/token/registration URLs from the MCP server edit form (#38154)
The edit form's Authorize & Fetch Token button built its temporary OAuth
session payload without issuer, authorization_url, token_url, or
registration_url, unlike the create form's equivalent payload builder. The
backend's temporary-session endpoint builds its ephemeral server purely from
that payload, so any admin-configured OAuth endpoints on an existing server
were silently dropped, endpoint discovery fell back to (and failed against)
the plain server url, and Authorize & Fetch Token 400'd with "authorization
url is not configured" even though the saved server had those fields filled
in. Add the four missing fields to the edit form's temporary payload builder,
mirroring the create form.
2026-08-25 10:59:26 -07:00
mateo-berri
e8bdbcd1cf fix(bedrock_mantle): parse converse passthrough bodies with the converse shape config for logging 2026-08-25 10:56:55 -07:00
ryan-crabbe-berri
c04b5dba32 Merge remote-tracking branch 'origin/litellm_internal_staging' into litellm_fix_model_router_spend_log_model
# Conflicts:
#	tests/test_litellm/litellm_core_utils/test_litellm_logging.py
#	tests/test_litellm/llms/azure_ai/chat/test_azure_ai_transformation.py
2026-08-25 10:55:53 -07:00
milan
65c0521b01 Merge remote-tracking branch 'origin/litellm_internal_staging' into litellm_fix_model_router_spend_log_model 2026-08-25 17:54:45 +00:00
ryan-crabbe-berri
c3bcb6f64f
test(mcp): drain the logging worker after each test so queued callbacks cannot leak into the next test (#38228)
LoggingWorker now carries still-queued coroutines onto the next event loop (12a34a10d8). Under xdist,
a success-logging coroutine queued by test_acompletion_mcp_respects_manual_approval ran nine seconds
later inside test_mcp_tool_call_hook on the same worker, resolved litellm.callbacks at run time and
overwrote that test's captured payload with a gpt-4o-mini completion (assert 1.35e-05 == 1.42).

Run clear_queue() in the suite's autouse teardown so every coroutine a test enqueues finishes before the
next test registers its callbacks, and add a subprocess regression test that runs the real conftest
against a stopped worker with work still queued.
2026-08-25 10:50:35 -07:00
ryan-crabbe-berri
0ea6f5e159 fix(azure_ai): stamp the model router's selected model instead of matching on the model name
The model Azure Model Router served was recovered by checking whether the text
"model_router" or "model-router" appeared in a model string. Spend logs applied that
check to the litellm model path, where the route prefix guarantees a match, but the
proxy applied it to the client's model group alias, which carries no prefix. A model
group named anything else therefore lost the selected model in both the response and
the spend row.

AzureModelRouterConfig now stamps the served model onto _hidden_params, and the spend
log payload and the proxy's response restamping read that stamp. The name heuristic
survives as a fallback for callers with no response in hand, routed through
get_azure_ai_route so it lives in one place.
2026-08-25 10:50:11 -07:00
Mateo Wang
751976db8b
Merge pull request #38229 from BerriAI/litellm_vertex_ai_interactions
feat(vertex_ai): add native Vertex AI Interactions API support
2026-08-25 10:50:02 -07:00
mateo-berri
5e6b6c6281 fix(together_ai): let an explicit api_key beat the Together env key on api_base match 2026-08-25 10:39:10 -07:00
mateo-berri
367a6e5dc5 test(router): pin the guard that keeps a junk-typed operator effort value out of model group info 2026-08-25 10:37:48 -07:00
mateo-berri
0bd4d323da fix(router): resolve provider from api_base in deployment validation and acompletion
Router._add_deployment called get_llm_provider without the deployment's api_base, so a config entry with a bare model plus a known OpenAI-compatible endpoint failed startup validation with LLM Provider NOT provided and the proxy returned 400 no healthy deployments for that model group. acompletion had the same gap at request time: it forwarded only base_url into its get_llm_provider call, dropping the api_base kwarg the router passes. Both now forward api_base so endpoint matching resolves the provider the same way sync completion already does
2026-08-25 10:33:40 -07:00