Commit graph

48008 commits

Author SHA1 Message Date
Mateo Wang
db7ca65b69
Merge pull request #40462 from BerriAI/litellm_fix_responses_stream_named_tool_choice
fix(responses): echo a named tool_choice in the Responses API shape on the chat-completions bridge
2026-09-09 18:48:32 -07:00
kerry-berri
a268c3d274
Merge pull request #40257 from BerriAI/litellm_playground_null_cost_crash
fix(ui): guard playground cost metric against null and NaN
2026-09-09 18:47:41 -07:00
Mateo Wang
aefa1040a0
Merge pull request #40249 from BerriAI/litellm_fix_responses_bridge_reasoning_effort
fix: keep reasoning_effort for mode: responses bridge deployments
2026-09-09 18:46:58 -07:00
mateo-berri
4adf99557f fix(responses): echo "auto" for a tool_choice the bridge cannot express instead of failing after the provider call 2026-09-09 18:27:12 -07:00
Kerry Lu
3aa9267df2 fix(ui): drop blank streamed costs instead of reading them as zero
Number("") and Number(" ") both return 0, which passed the finite check, so a
provider reporting an empty cost got a fabricated $0.000000 metric instead of
having the unusable value omitted.

Both ingestion sites carried the same inline parsing, so this pulls it into one
parseUsageCost helper that keeps finite numbers and non-blank numeric strings and
drops everything else, including booleans, arrays and breakdown objects.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YNw8WvkvCSeTcE5qvergu3
2026-09-09 18:19:52 -07:00
Mateo Wang
b22ca7ac6d
Merge pull request #40464 from BerriAI/litellm_internal_copy_35771
fix(azure): respect DEFAULT_MAX_RETRIES in initialize_azure_sdk_client (internal copy of #35771)
2026-09-09 18:19:08 -07:00
Mateo Wang
21ae29b759
Merge pull request #40284 from BerriAI/litellm_legacy_hook_streaming_pipeline_step
feat(guardrails): run legacy post-call hooks as streaming pipeline steps
2026-09-09 18:14:37 -07:00
Mateo Wang
53f3e70f02
Merge pull request #40461 from BerriAI/litellm_lit_7373_responses_custom_tool_call_guardrail
fix(guardrails): scan and rewrite Responses custom_tool_call output items
2026-09-09 18:13:00 -07:00
Mateo Wang
0e088337a2
Merge pull request #31884 from BerriAI/litellm_add-claude-sonnet-5-pricing
fix(pricing): rolling model registry update: Bedrock gpt-6-astra, gpt-image-2.5, Cohere rerank 4, Vertex Grok 4.3/4.6/4.20, Gemini 3.5 audio, OpenAI web search fee, xAI Imagine video, Lyria 3.5, Voyage, ChatGPT GPT-5.5/5.6, Bedrock Mantle, Scaleway dates
2026-09-09 18:11:37 -07:00
tin-berri
e34c4c8edc
fix(ui): scope shadow eval models to configured chat groups (#40488)
Co-authored-by: Claude Code <noreply@anthropic.com>
2026-09-09 18:09:28 -07:00
tin-berri
317b29e69d
feat(cli): add lite configure claude and lite unconfigure claude (#40319)
Persistently route Claude Code through a LiteLLM proxy with a long-lived virtual key or the stored lite login, turn on gateway model discovery so /model lists the proxy's models, optionally pick the model Claude Code starts on, and record what changed so unconfigure restores only the keys the user has not touched since. lite login --config-claude writes through the same receipt and is undoable too. The two settings merges (lite up / --config-claude and lite autoroute) collapse into one credential-aware merge
2026-09-09 18:02:23 -07:00
kerry-berri
b8d7f68aeb
Apply suggestion from @greptile-apps[bot]
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
2026-09-09 17:46:12 -07:00
joshua-berri
a8bb2f93b9
Merge pull request #40494 from BerriAI/litellm_fix_mcp_dotted_properties_5777
fix(ui): preserve dotted MCP tool argument names
2026-09-09 17:45:00 -07:00
tin-berri
6b721de3e5
fix(databricks): route Unity model services through AI Gateway (#40492)
Co-authored-by: Claude Code <noreply@anthropic.com>
2026-09-09 17:15:48 -07:00
Joshua Valluru
0b21b99ebd fix(ui): type MCP argument resolver results explicitly 2026-09-09 16:57:15 -07:00
Joshua Valluru
70c238dde0 fix(ui): preserve dotted MCP tool argument names 2026-09-09 16:54:43 -07:00
ryan-crabbe-berri
a650178ebe
Merge pull request #33703 from BerriAI/litellm_fix_jwt_key_mapping_cascade_delete
fix(jwt): cascade-delete JWT key mappings when their virtual key is deleted
2026-09-09 16:52:20 -07:00
tin-berri
2000642592
fix(router): resolve route candidate ids through the router's own resolver (#40491)
get_candidate_model_ids_for_route (added in #40280 for the encrypted-content affinity
check) reconstructed the candidate pool by unioning the model_name and team indexes with
pattern_router.route. That diverged from how the router actually resolves a route: it took
a union instead of the first matching path, and pattern_router.route only matches the
literal name, so a provider-qualified pattern (matched by get_deployments_by_pattern, which
retries the {provider}/{model} form) was missed and the default deployment was ignored.

For an affinity follow-up on a wildcard or team-public route, that mismatch could strip
encrypted reasoning on a same-group cooldown, or return a 503 on a real cross-path switch.

Delegate the non-model_name case to _try_early_resolve_deployments_for_model_not_in_names,
the same resolver _common_checks_available_deployment uses, so candidate membership follows
the router's real precedence. With include_team_models left off it stays read-only and does
not raise. Behavior for concrete model groups and routing groups is unchanged.


Claude-Session: https://claude.ai/code/session_01KAumQbhzk6jdWWHFLA8Jar

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-09-09 16:43:50 -07:00
ryan-crabbe-berri
969d152c4b fix(jwt): evict jwt_key_mapping cache when a virtual key is deleted
The FK cascade drops the LiteLLM_JWTKeyMapping row, but the cached
jwt_key_mapping:{claim}:{value} entry still resolved to the deleted token
hash, so every JWT call from that identity failed until
virtual_key_mapping_cache_ttl expired instead of auto-registering against a
recreated key. delete_verification_tokens now snapshots the mapping cache
keys before the delete and evicts them across replicas afterwards, the same
way /key/regenerate already does.

Claude-Session: https://claude.ai/code/session_011Tn3657NkV6ojLqewL64Kb
2026-09-09 16:40:25 -07:00
Mateo Wang
b7dad8b44e
Merge pull request #40294 from shotsan/fix/empty-choices-handling
fix(convert_dict_to_response): handle empty choices list without raising 500 APIError
2026-09-09 16:34:47 -07:00
mateo-berri
a68fe4e4d9 fix(responses): keep the client's usage shape when the logging copy cannot re-validate the response 2026-09-09 16:31:48 -07:00
mateo-berri
7563d94e65 test(responses): assert the streamed response.completed event echoes the named tool_choice 2026-09-09 16:29:55 -07:00
mateo-berri
a248ff2c6e fix(guardrails): fail open on Responses tool-call rewrites in another shape and keep item names
Guardrails that hand back tool_calls in their own shape (vendor JSON, user code output) raised a KeyError on the non-stream Responses write-back. Returned tool calls are now validated before comparison; a shape or count that does not line up leaves every tool-call item unchanged and logs a warning naming the guardrail. A tool call's name is written back only when the guardrail changed it, so a nameless custom_tool_call no longer picks up the custom_tool placeholder.
2026-09-09 16:14:50 -07:00
Mateo Wang
8b2983bd90
Merge pull request #40449 from BerriAI/litellm_databricks_reasoning_content
fix(databricks): keep top-level reasoning_content from OpenAI-compatible gateway models
2026-09-09 16:07:15 -07:00
mateo-berri
96e46ba8ff fix(responses): stamp streamed usage cost when the provider usage arrives as a dict
Perplexity's Responses payload fails ResponsesAPIResponse validation on
truncation "" and is kept as an unvalidated model, so its usage stays a
plain dict and _stamp_responses_usage_cost raised AttributeError on every
streamed completion once reasoning made the cost non-zero. Validate the
dict into ResponseAPIUsage before stamping, keeping a provider-reported
cost when it carries one.

Resolves LIT-7391
2026-09-09 16:06:55 -07:00
mateo-berri
fbc6fb56ae fix(bedrock): route gpt-6-astra reasoning_effort to reasoning.effort and mark Nova 2 tool_choice
The converse reasoning gate only matched openai.gpt-5, so gpt-6-astra fell through to
Anthropic's thinking block and Bedrock rejected the call with 400 Unknown parameter:
'thinking'. Match any openai.gpt-<digit> model at the three gate sites instead.

Nova 2 lite and pro accept forced tool_choice on Converse (verified live on
us.amazon.nova-2-lite-v1:0), so the nine Nova 2 registry keys now advertise
supports_tool_choice. The invoke dispatcher also forwards json_mode to Nova like it
already does for Anthropic and TwelveLabs.
2026-09-09 16:06:19 -07:00
mateo-berri
21e6c6e2f3 test(convert_dict_to_response): expect the type-naming error for a null choices value 2026-09-09 15:56:41 -07:00
yucheng-berri
fc161faa96
fix(langfuse): give each call in a session header its own trace instead of upserting one trace per session (#40177)
* fix(langfuse): give session-header calls their own trace id

A client that sends only a session header (x-litellm-session-id, a vendor
x-<name>-session-id such as Claude Code's X-Claude-Code-Session-Id, a bare
x-session-id, or the Codex session/thread/conversation family) has that value
stamped into both trace_id and session_id by the proxy. Langfuse upserts a
trace by id, so every turn of a session collapsed into one growing trace and
the Sessions view showed "Total traces: 1"

Detect that aliasing in the Langfuse callback from the request headers the
callback already receives, and use litellm_call_id as the trace id for those
calls. session_id still carries the header value, so the turns stay grouped
under one session. An explicit x-litellm-trace-id, langfuse_trace_id, or
langfuse_existing_trace_id keeps its trace id, including when the caller sets
it to the same value as the session id

Co-authored-by: jesus <jesus@berri.ai>

* test(langfuse): cover direct-SDK callers without proxy request headers

* fix(langfuse): preserve session trace provenance

---------

Co-authored-by: jesus <jesus@berri.ai>
2026-09-09 15:56:38 -07:00
tin-berri
eb45a088d3
fix(router): resolve team-scoped auto-routers by their public name (#40432)
A team-scoped auto-router is stored under an internal
model_name_{team_id}_{uuid} with the caller-facing name in
model_info.team_public_model_name, and the four pre-routing strategy
registries key on that internal name. A team key asks for the public name,
so the strategy lookup missed, the team early-resolve exit handed back the
marker deployment itself, and every call 400'd with "Unmapped LLM provider".

The strategy lookup now resolves the requested name through the same
team-first, then global, then admin-across-teams deployment resolution the
deployment path uses, and looks the registries up under the model_name of
whatever that resolves to. Both exits of _common_checks_available_deployment
drop strategy markers through one helper, so a marker-only resolution is
rejected as uncallable on every path. The request team id has one reader.

Resolves LIT-7363


Claude-Session: https://claude.ai/code/session_01NU97S7d2FUDDvTk59k53Wp

Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-09 15:53:05 -07:00
mateo-berri
5fdbb2a1c8 Merge remote-tracking branch 'origin/litellm_internal_staging' into litellm_legacy_hook_streaming_pipeline_step 2026-09-09 15:52:48 -07:00
mateo-berri
f5a410585a fix(responses): keep a custom tool_choice type in the bridged echo and type the new tests 2026-09-09 15:44:29 -07:00
devin-ai-integration[bot]
6e96885629
fix(proxy): accept non-string callback vars in default_team_settings (#40458)
* fix(proxy): accept non-string callback vars in default_team_settings

A YAML boolean such as turn_off_message_logging: true in a
default_team_settings block failed TeamCallbackMetadata's str-only
callback_vars validation and errored the request before any callback
ran. Stringify the value the same way AddTeamCallback does.

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

* test(proxy): drop docstring from default_team_settings bool regression test

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

* test(proxy): move default_team_settings bool regression test to mapped pre_call_utils suite

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

---------

Co-authored-by: yucheng <yucheng@berri.ai>
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-09 15:40:15 -07:00
ryan-crabbe-berri
eee239cd9e fix(jwt): cascade-delete JWT key mappings when their virtual key is deleted
LiteLLM_JWTKeyMapping_token_fkey was created ON DELETE RESTRICT, so deleting
a virtual key that a JWT mapping pointed at failed with a foreign key
violation on every deletion path (/key/delete, Admin UI, alias delete,
team and user cascades). Declaring onDelete: Cascade on the relation lets
the database clean the mapping up uniformly, so the next JWT call from that
identity re-registers against the newly created key.

Rebase of #33703 onto current staging.

Claude-Session: https://claude.ai/code/session_011Tn3657NkV6ojLqewL64Kb
2026-09-09 15:39:21 -07:00
mateo-berri
ae6893bc64 refactor(guardrails): narrow the Responses tool-call item mapping types 2026-09-09 15:38:55 -07:00
Mateo Wang
2b2e6cf283
Merge pull request #40271 from BerriAI/litellm_lit_7174_stream_tool_call_rewrites
feat(guardrails): deliver tool-call rewrites into buffered chat, Responses, and Messages streams
2026-09-09 15:36:13 -07:00
devin-ai-integration[bot]
264fc82dc1
fix(rate_limiter): attach v3 priority rate limit headers on /v1/messages (#37228)
Some checks are pending
LiteLLM Rust / rust-test (push) Waiting to run
Unit Tests: Documentation Validation / documentation (push) Waiting to run
Unit Tests: Proxy DB Operations / proxy-utils (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / assert-shard-coverage (push) Waiting to run
Unit Tests: Proxy DB Operations / auth-checks (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / budgets (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / custom-logging (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / db-and-spend (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / endpoints-and-responses (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / guardrails-hooks (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / jwt-and-keys (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / key-generation (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / logging-misc (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / proxy-runtime (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / proxy-server-core (push) Blocked by required conditions
Unit Tests / integrations (push) Waiting to run
Unit Tests / Vertex AI (push) Waiting to run
Unit Tests / misc (push) Waiting to run
Unit Tests / proxy-endpoints (push) Waiting to run
Unit Tests / proxy-extras (push) Waiting to run
Unit Tests / proxy-infra (push) Waiting to run
Unit Tests / proxy-server (push) Waiting to run
Unit Tests / responses-caching-types (push) Waiting to run
GitHub Actions Security Analysis / zizmor (push) Waiting to run
Unit Tests / caching-local (push) Waiting to run
Unit Tests / core-utils (push) Waiting to run
Unit Tests / enterprise-package (push) Waiting to run
Unit Tests / enterprise-routing (push) Waiting to run
Unit Tests / All Other Providers (push) Waiting to run
Unit Tests / proxy-auth (push) Waiting to run
* fix(rate_limiter): attach v3 priority rate limit headers on /v1/messages

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

* feat(playground): honor the Stream responses toggle for /v1/messages

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

* test(rate_limiter): drop explanatory docstrings from v3 dict response tests

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

---------

Co-authored-by: yucheng <yucheng@berri.ai>
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-09 15:14:10 -07:00
mateo-berri
cbeac27656 fix(convert_dict_to_response): name the non-list choices type in the converter error
When a provider returns choices as null, an object, a string or a number, the
converter said the response had no 'choices' even though the key was present in
the raw keys it listed. A shared message now keeps the old wording for a missing
key and names the offending type otherwise.

The cached-stream regression test also pins the chunk count so a leaked extra
chunk fails it.
2026-09-09 15:12:13 -07:00
devin-ai-integration[bot]
2488f84b02
fix(proxy): keep a body litellm_session_id in SpendLogs under missing_session_id omit (#40379)
* fix(proxy): keep a body litellm_session_id in SpendLogs under missing_session_id omit

Under general_settings.missing_session_id: omit, apply_missing_session_id_policy now
mirrors a client-supplied top-level litellm_session_id into metadata.session_id when the
client did not set one there, so SpendLogs.session_id and Langfuse agree with the session
callbacks already report through StandardLoggingPayload.session_id

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

* fix(proxy): keep client metadata.session_id ahead of body litellm_session_id on litellm_metadata routes

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

* test(proxy): drop docstrings from the missing_session_id omit regression tests

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

---------

Co-authored-by: yucheng <yucheng@berri.ai>
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-09 14:53:35 -07:00
mateo-berri
830ee2d39d fix(azure): default max_retries to DEFAULT_MAX_RETRIES with regression tests
initialize_azure_sdk_client now falls back to litellm.constants.DEFAULT_MAX_RETRIES
when litellm_params carries no max_retries, so off-router Azure clients (files,
batches, fine-tuning, assistants, audio) honor the env var like OpenAI clients do.
Router paths already default max_retries to 0 and are unchanged.

Regression tests cover the default, explicit 0/5/None values, and the env var
reaching the SDK client in a fresh interpreter.
2026-09-09 14:29:06 -07:00
Praveena
5e7cb89806 fix(azure): respect DEFAULT_MAX_RETRIES in initialize_azure_sdk_client
When litellm_params does not include max_retries (the common case for
deployments configured without explicit retry settings),
initialize_azure_sdk_client() previously passed None through the
'if max_retries is not None' guard, resulting in AsyncAzureOpenAI being
created without a max_retries argument. The OpenAI SDK then uses its
own hardcoded default of 2, ignoring the DEFAULT_MAX_RETRIES env var.

Fix: fall back to litellm.constants.DEFAULT_MAX_RETRIES when
litellm_params has no max_retries. This ensures the SDK client
respects the configured retry count.

Steps to reproduce:
  1. Set env var DEFAULT_MAX_RETRIES=0
  2. Configure a deployment without explicit max_retries in litellm_params
  3. Make a request that triggers a timeout
  4. Observe: SDK retries (x-stainless-retry-count=1) despite env var=0

Related: https://github.com/BerriAI/litellm/issues/5124
2026-09-09 14:24:14 -07:00
mateo-berri
cce1d2087b fix(responses): echo a named tool_choice in the Responses API shape on the chat-completions bridge
A streamed /v1/responses request with tool_choice {"type": "function", "name": ...}
that reaches a chat-completions-only deployment failed with HTTP 500 before the
first byte: the synthetic response.created and response.in_progress events copied
the chat-shaped tool_choice into ResponsesAPIResponse, whose ToolChoice type expects
the flat Responses API shape. The non-streamed path echoed "auto" regardless of the
request.

Both paths now normalize the request's tool_choice through the existing chat
transform and map it back to the Responses API vocabulary, validated by a
TypeAdapter(ToolChoice), so a named function is echoed as {"type": "function",
"name": ...} and a missing tool_choice is echoed as "auto".

Fixes #33689
2026-09-09 14:22:22 -07:00
mateo-berri
0a053d2c81 test(guardrails): cover streamed tool-call name rewrites on chat and Messages
Some checks failed
LiteLLM Rust / rust-lint (push) Has been cancelled
LiteLLM Rust / rust-test (push) Has been cancelled
Terraform Modules / fmt, validate, test (aws) (push) Has been cancelled
Terraform Modules / fmt, validate, test (gcp) (push) Has been cancelled
Skipping the name write-back in either handler left every test green; a
guardrail that renames a tool call now has a regression test on both the
chat chunk path and the Anthropic SSE path
2026-09-09 14:21:40 -07:00
Mateo Wang
9315f5dd5e
Merge pull request #40329 from BerriAI/litellm_hosted_vllm_image_edit
feat(hosted_vllm): add image edit support
2026-09-09 14:20:41 -07:00
mateo-berri
354365eeca test(proxy): give the pipeline-managed native hook audit test its chat completions route
Some checks failed
LiteLLM Rust / rust-lint (push) Has been cancelled
Terraform Modules / fmt, validate, test (aws) (push) Has been cancelled
LiteLLM Rust / rust-test (push) Has been cancelled
Terraform Modules / fmt, validate, test (gcp) (push) Has been cancelled
2026-09-09 14:15:01 -07:00
cursor[bot]
2c836f473c
test(ui): derive reasoning-effort assertion from the anthropic preset (#40456)
Preset #40341 pointed the Anthropic family REASONING tier at claude-fable-5-1,
but this test still hardcoded claude-opus-5, so the payload it saw no longer
matched. Rebase the assertion on ANTHROPIC_PRESET.complexity_router_config.tier_model_configs
so a preset refresh flows through instead of redding the suite on staging.

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Krrish Dholakia <krrish-berri-2@users.noreply.github.com>
2026-09-09 14:14:24 -07:00
Oliver Jensen
f2eacc3c36
Merge pull request #40116 from BerriAI/litellm_disable_env_credential_login
feat(auth): add disable_env_credential_login setting with admin ui warning
2026-09-09 23:08:26 +02:00
mateo-berri
29af8b7349 fix(streaming_handler): replay a cached completion with no choices as an empty stream
A stream cache hit on an entry stored with choices == [] indexed choices[0]
in the cached_response branch and failed with IndexError, so the streaming
converters' empty chunk had no working consumer. The branch now treats a
chunk without choices as empty and lets the wrapper close the stream with
its usual finish_reason stop chunk
2026-09-09 14:04:54 -07:00
mateo-berri
b89c32407f test(cost): assert gpt-4o-mini keeps chat web search off while the flat search fee still matches its alias
Some checks failed
LiteLLM Rust / rust-lint (push) Has been cancelled
LiteLLM Rust / rust-test (push) Has been cancelled
Terraform Modules / fmt, validate, test (aws) (push) Has been cancelled
Terraform Modules / fmt, validate, test (gcp) (push) Has been cancelled
2026-09-09 14:01:36 -07:00
Mateo Wang
11b31c19be
Merge pull request #40274 from BerriAI/litellm_post_call_pipeline_background_responses
feat(guardrails): run post_call policy pipelines on background Responses retrieval
2026-09-09 13:56:37 -07:00
mateo-berri
5bdf45726d fix(bedrock): honor the json_mode kwarg on invoke Nova structured output and keep gpt-4o-mini off chat web search 2026-09-09 13:52:08 -07:00