Commit graph

45353 commits

Author SHA1 Message Date
ryan-crabbe-berri
6975b8ea4b fix(utils): make prompt_token_calculator count claude models again
The claude branch called the anthropic SDK's `Anthropic().count_tokens`, which the
SDK removed, so every claude call raised AttributeError. Counting now goes through
litellm's own token_counter, which handles anthropic models offline and drops the
SDK dependency entirely.

Hiding that was a swallowed error: `except Exception: Exception("Anthropic import
failed please run `pip install anthropic`")` built the exception without raising
it, so an environment missing the SDK fell through to the unguarded
`from anthropic import ...` on the next line and got a bare ModuleNotFoundError
instead of the install hint.

That was the codebase's last PLW0133, so the rule graduates from the ratcheted
budget into ruff.toml where it hard-fails, and editors get the diagnostic inline.
2026-08-24 12:19:03 -07:00
mateo-berri
7f0c1c7665 chore(videos): mark multi-branch video-create response as rebind-ok
The file-less multipart branch added a third mutually-exclusive request-shape
branch, so response can no longer be Final. Suppress the type-discipline gate
the way the codebase does for other multi-branch locals.
2026-08-24 12:11:59 -07:00
mateo-berri
e7c2ede159 fix(vertex-passthrough): never forward proxy auth headers to Google
On the credential-less Vertex passthrough branch, drop every header that
can only carry LiteLLM caller auth (x-litellm-api-key, api-key, x-api-key)
by name, since Google never consumes them, and strip the virtual key by
value from Authorization / x-goog-api-key, which may instead hold a genuine
bring-your-own Google credential. This closes the residual leak where a
distinct caller secret in api-key or x-api-key still reached upstream.
2026-08-24 12:08:43 -07:00
ryan-crabbe-berri
5ed83942dc chore(codeowners): unown ui container plumbing entirely
The Dockerfile and nginx.conf are deploy infra, so nobody on the dashboard side needs to gate them. Drop the remaining owner instead of making one person the sole required approver.
2026-08-24 12:04:17 -07:00
Mateo Wang
f818a48ae5
Merge pull request #36513 from Souravrajvi0/bugfix/video-edits-form-body-36487-8fc4
fix(proxy): parse form-encoded video edit/extension bodies after auth
2026-08-24 12:03:10 -07:00
mateo-berri
088a700933 test(passthrough): cover virtual key echoed in api-key and x-api-key
Adds a regression asserting the value-based strip also drops the caller's
virtual key when it is duplicated into the api-key and x-api-key headers,
while a genuine bring-your-own Google credential still forwards.
2026-08-24 12:00:21 -07:00
ryan-crabbe-berri
79d0d7a48e chore(codeowners): drop ryan-crabbe-berri from ui infra and generated files
The /ui/ rule sweeps in the container plumbing (Dockerfile, nginx.conf) and the checked-in tsbuildinfo, none of which are dashboard code. Exempt them so review requests land on the people who actually own that surface.
2026-08-24 11:59:12 -07:00
mateo-berri
458a63935f test(health): guard that test_connection authorizes on post-merge probe params
Add an endpoint-level regression test asserting can_user_make_model_call
receives the litellm_params after health_check_params are merged in, so the
merge-before-auth ordering cannot silently regress and let a request smuggle
a field past authorization.
2026-08-24 11:58:33 -07:00
mateo-berri
b00afc03a5 Merge origin/litellm_internal_staging into litellm_fix_36493_image_video_routes 2026-08-24 11:58:22 -07:00
mateo-berri
4ddf1e5c6d test: guard the restore padding against a long escaped-quote run before a definition 2026-08-24 11:57:45 -07:00
devin-ai-integration[bot]
a1134755ca
fix(ui): boot the UI image as an arbitrary uid by anchoring nginx writes under /tmp (#37982)
* fix(ui): boot the UI image as an arbitrary uid by anchoring nginx writes under /tmp

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

* test(ui): type the arbitrary-uid image test fixture

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-24 11:57:36 -07:00
Mateo Wang
33c51e84b0
Merge pull request #35415 from BerriAI/litellm_azure_ai_entra_auth
feat(azure_ai): support entra id / oauth auth on every azure ai foundry route
2026-08-24 11:54:48 -07:00
mateo-berri
51ab4c7486 test(videos): lock AzureVideoConfig inherited file-less multipart behavior
AzureVideoConfig subclasses OpenAIVideoConfig and so inherits the new
use_multipart_form_data() -> True. Azure's /openai/v1/videos surface is
OpenAI-SDK-compatible, so the JSON->multipart flip is intentional; assert it
through the real handler so the inherited behavior can't silently regress.
2026-08-24 11:54:29 -07:00
mateo-berri
671a454baa Merge remote-tracking branch 'origin/litellm_internal_staging' into litellm_bing_grounding_search_provider 2026-08-24 11:53:45 -07:00
mateo-berri
0322107414 fix(images): flatten nested image-edit params to SDK multipart form
The openai/azure/compat image-edit funnel merged non_default_params and
extra_body straight into the multipart body, so a nested value (e.g.
extra_body={"metadata": {...}}) reached the httpx encoder and 500'd with
"Invalid type for value. Expected primitive type". Route the funnel through
a shared flattener that serializes nested values as OpenAI-SDK bracket fields
(key[subkey], lists as key[], bools lowercased, None/empty dropped), matching
the wire format of the rest of this fix.
2026-08-24 11:51:28 -07:00
mateo-berri
4bc097733f fix(passthrough): strip virtual key from all headers on credential-less Vertex forward
The credential-less Vertex passthrough dropped the caller's LiteLLM
virtual key only from Authorization by exact match. A caller who sent
the same key in x-goog-api-key (which doubles as a real Google
credential) had it accepted as a credential and forwarded upstream.

Drop the virtual key by value across every forwarded header, normalizing
any Bearer prefix, so no header name carries it to Google.
2026-08-24 11:51:23 -07:00
mateo-berri
25b379f3c7 test: register supports_legacy_thinking in model-prices schema
Regenerate model_prices_and_context_window.schema.json and add the flag to
the inline validator schema in test_utils.py so the new cost-map key passes
validate-model-prices-json and the JSON-valid test.
2026-08-24 11:47:21 -07:00
mateo-berri
e43b496000 fix: undouble single-quoted payloads before reading them for routine calls
Call detection restored a single-quoted DO or EXECUTE payload through
without_comments while its `''` escapes were still doubled. The first quote of
a pair opened an empty string and closed it on the second, leaving a `--` or
`/*` from a nested string bare, so it blanked the real call after it and the
routine read as uncalled: its rewrite body then went unscanned at boot. Undouble
each single-quoted payload before restoring it, and pad it back to the span it
fills so the later offsets still land. Dollar-quoted bodies do not escape quotes
and are left as they were.
2026-08-24 11:45:04 -07:00
Darien Kindlund
b36f34813a
fix(anthropic): reconcile enum with declared type in output_format schema (#37882)
* fix(anthropic): reconcile enum with declared type in output_format schema

Anthropic cross-validates `enum` against `type` in structured outputs: every
enum value must match a single declared type. A union `type` array, or an enum
value whose JSON type differs from a scalar `type`, is rejected with
"Invalid schema: Enum value 'low' does not match declared type '['string','null']'"

filter_anthropic_output_schema had no enum/type reconciliation, so both keys
reached Anthropic untouched. Drop the conflicting `type` -- `enum` is the
tighter constraint, and an enum with no `type` is accepted

The drop is conditional: `type` is only removed when it is a union array, or
when some enum value does not match the scalar type. A matching enum plus
scalar `type` is left exactly as-is, so existing behaviour is unchanged

Pydantic emits the failing shape for Optional[SomeEnum], so this affects any
caller with a nullable enum field on the native output_format path. vertex_ai
is unaffected because it is forced onto the permissive tool-use path

Fixes #37881

* refactor(anthropic): make enum/type reconciliation immutable and precisely typed

Address review: the predicate registry was a mutable `dict[str, Any]`, and the
reconciliation removed `type` by mutating the built result with `pop`

- registry is now `Final[Mapping[str, Callable[[Any], bool]]]` wrapped in
  `MappingProxyType`, so predicate signatures are statically checked and the
  table cannot be mutated
- the conflict decision moves into a pure helper evaluated once against the
  input schema, and the conflicting `type` key is skipped at build time in the
  existing loop instead of being popped afterwards, so nothing is mutated

Behaviour is unchanged; all 27 tests in the schema-filter suite still pass
2026-08-24 11:43:47 -07:00
mateo-berri
b117190b0b chore(pricing): regenerate model prices schema for new video cost tier fields 2026-08-24 11:43:40 -07:00
Mateo Wang
a626170c89
Merge pull request #36806 from BerriAI/litellm_bedrock_converse_no_trailing_empty_chunk
fix(bedrock): stop emitting an empty assistant delta after the finish_reason chunk
2026-08-24 11:37:04 -07:00
mateo-berri
37f8b9600a Merge origin/litellm_internal_staging into litellm_azure_ai_entra_auth
Bring the Entra ID / OAuth auth work for Azure AI Foundry routes up to date
with staging and fix the lint-budget regressions the merge surfaced:

- widen get_azure_ai_auth_headers return type to Mapping[str, str] (LIT001)
- build the azure_ai image_generation request headers into a new Final local
  instead of rebinding the Final headers dict (reportGeneralTypeIssues)
- order HuggingFace rerank validate_environment params to match BaseRerankConfig
  so litellm_params lines up positionally (reportIncompatibleMethodOverride)
- add a match= to the credential-error test and document the handler-boundary
  patches the auth wiring tests rely on
2026-08-24 11:33:18 -07:00
mateo-berri
a7cd2cd439 Merge branch 'litellm_internal_staging' into litellm_fix_46_thinking_budget 2026-08-24 11:31:10 -07:00
mateo-berri
531aafdf75 Merge remote-tracking branch 'origin/litellm_internal_staging' into litellm_health_test_connection_health_check_params
# Conflicts:
#	tests/test_litellm/proxy/test_health_check_max_tokens.py
2026-08-24 11:30:04 -07:00
mateo-berri
603d3358d6 Merge origin/litellm_internal_staging into bugfix/video-edits-form-body-36487-8fc4
Pulls in the detect-changes CI action and the test-unit job timeout bump, which clears the red lint and code-quality checks on this PR

The merged, tightened lint budgets flag this PR's own code, so this merge also makes video_reference_to_id a pure function instead of a helper that mutates its input dict, and rewrites the form-body regression test to call the video_edit and video_extension handlers directly rather than patching an internal class method. Adds pure-logic unit tests for video_reference_to_id
2026-08-24 11:26:03 -07:00
mateo-berri
bf4069a80c fix(proxy): authorize health test-connection on final probe params
Move _update_litellm_params_for_health_check before can_user_make_model_call
so health_check_params cannot retarget the probe after the auth check. Type
the Pegasus test helper signature and drop the redundant test narrative.
2026-08-24 11:24:21 -07:00
mateo-berri
6407a66375 fix(runwayml): route every generation endpoint and fix video cost tracking
Six defects in the RunwayML video provider:

- transform_video_create_request hardcoded /image_to_video, so text-to-video 400'd and video-to-video was unreachable; the endpoint is now selected from the inputs present (promptVideo/videoUri, promptImage, or text only)
- get_error_class raised instead of returning, turning a provider 4xx into a proxy 500 APIConnectionError; it now returns a RunwayMLError
- VideoObject.progress was typed int while Runway sends a 0..1 float, 500'ing status polls while RUNNING; it is now scaled to a 0..100 percent
- custom per-deployment pricing stored under litellm_metadata was ignored for video; the deployment model_info lookup now checks both metadata keys
- stale cost-map entries (gen3a_turbo, gen4_aleph) were removed and current models added, with output_cost_per_second_480p/_4k tier keys plumbed through the model-info and router types
- video cost now falls back to Runway's estimatedCost from the create response when no custom pricing is configured, and custom pricing always wins over it

Fixes #36483
2026-08-24 11:23:03 -07:00
mateo-berri
e6eb6a4a4d fix(passthrough): stop leaking the caller's virtual key on credential-less Vertex passthrough
When no Vertex credential is configured (no default_vertex_config, no matching
use_in_pass_through deployment, no vector-store credential), the Vertex passthrough
took the bring-your-own-credentials branch and forwarded the entire incoming header
set upstream to Google. That set included whichever header carried the caller's
LiteLLM virtual key: x-litellm-api-key, or Authorization when get_litellm_virtual_key
read the key from there. The proxy's own secret was sent to a third-party provider.

The credential-less branch now drops x-litellm-api-key and the Authorization value
that equals the virtual key, keeping a genuine bring-your-own Google credential
(an OAuth token in Authorization, or x-goog-api-key) so real BYO passthrough still
works. When neither survives, the request fails with a clean 401 telling the operator
no credential is configured, instead of forwarding the virtual key.

Regression coverage in the mapped test path asserts the 401-and-never-forwarded
behavior for both leak vectors and that a real Google credential still passes through
with the virtual key stripped.
2026-08-24 11:21:26 -07:00
Mateo Wang
9bcc00b1f1
Merge pull request #33310 from BerriAI/litellm_google_interactions_cost
fix(interactions): track cost and spend for Google Interactions API requests
2026-08-24 11:18:58 -07:00
mateo-berri
d23069e907 fix(passthrough): attribute spend and release budget reservation on router-model /vllm and /azure routes
The /vllm and /azure router-model passthrough branches called
llm_router.allm_passthrough_route directly with no request metadata,
so the cost callback saw no user_api_key and no
user_api_key_budget_reservation. Spend for a budgeted virtual key hit
neither the key's spend nor the spend logs, and the reservation minted
at auth into the shared Redis counter was never released, drifting the
counter up until the key falsely tripped BudgetExceededError.

Thread the authenticated key's attribution metadata into both calls via
the same builder add_litellm_data_to_request uses, so the cost callback
attributes spend and reconciles the reservation. Regression tests cover
both branches.
2026-08-24 11:16:57 -07:00
Mateo Wang
10b42a84e6
Merge pull request #37917 from BerriAI/litellm_a2a_protocol_binding_casing
fix(a2a): normalize agent card protocolBinding casing before transport match
2026-08-24 11:14:01 -07:00
mateo-berri
fef5f41985 fix(anthropic): keep legacy thinking budget_tokens on Claude 4.6 models 2026-08-24 11:12:54 -07:00
mateo-berri
dd2e1cf7a8 fix: read a single-quoted DO body for routine calls, not only dollar-quoted ones 2026-08-24 11:08:59 -07:00
mateo-berri
03a676995a feat(search): add Grounding with Bing Search (bing_grounding) as a search provider 2026-08-24 11:08:24 -07:00
mateo-berri
3337a0a01f fix: match OpenAI SDK wire format on image/video routes (#36493)
POST /v1/videos without an input_reference file now goes out as
multipart/form-data the way the OpenAI SDK always sends it, instead of a
JSON body that OpenAI-compatible backends (SGLang Diffusion, vLLM-Omni)
reject; gemini, vertex, and runwayml keep their JSON bodies

/v1/images/edits on the openai/azure/openai-compatible path now forwards
unknown provider params (e.g. seed) and honors extra_body, matching
/v1/images/generations, and aimage_edit forwards
extra_headers/extra_query/extra_body instead of dropping them

Generic pass-through no longer downgrades a file-less multipart form to
application/x-www-form-urlencoded
2026-08-24 11:08:21 -07:00
mateo-berri
d0dd24ed6d fix(health): apply model_info.health_check_params to health check probes 2026-08-24 11:01:34 -07:00
mateo-berri
b9e5eec28c test(e2e): pin require_managed_files enforcement behind a marker-gated stack phase 2026-08-24 10:59:13 -07:00
Felipe Rodrigues Gare Carnielli
6a0e7fe10f fix(tencent): route thinking through extra_body in chat completions
Tencent chat completions route through the OpenAI SDK's
chat.completions.create(), which raises TypeError on unknown kwargs -
so a top-level 'thinking' optional param crashed every reasoning
request with a 500 before any HTTP call was made.

Nest the resolved thinking object in extra_body instead: the SDK merges
extra_body into the top-level JSON payload, so TokenHub still receives
the documented thinking field (type/budget_tokens) in the request body.

Also align the param mapping with TokenHub's documented behavior:
- reasoning_effort="none" now maps to thinking={"type": "disabled"}
  instead of being dropped (deepseek-v4-* default to thinking enabled,
  so dropping it never actually disabled thinking)
- MiniMax models only accept thinking.type "adaptive"/"disabled",
  so "enabled" is coerced to "adaptive" instead of returning a 400

Refs: https://www.tencentcloud.com/document/product/1300/82345
2026-08-24 14:58:13 -03:00
Mateo Wang
ddf4c8e58b
Merge pull request #37953 from BerriAI/litellm_fix_24985_thinking_roundtrip
fix(anthropic): round-trip thinking blocks to OpenAI backends on /v1/messages
2026-08-24 10:57:23 -07:00
mateo-berri
fe567bd846 fix(a2a): speak the 0.3 dialect to servers with mis-cased protocol bindings 2026-08-24 10:51:14 -07:00
mateo-berri
91b2a9c360 fix(proxy): keep video reference normalization within lint budgets 2026-08-24 10:40:44 -07:00
mateo-berri
e0511e9384 Merge branch 'litellm_internal_staging' into litellm_bedrock_converse_no_trailing_empty_chunk
Resolves the test-file conflict by keeping both sides, extends the
finish-reason gate to trace-bearing metadata events so guardrail trace
chunks keep their pre-regression delta shape, parametrizes the
regression test over tool-call, mixed, and reasoning streams, and
repairs the one ant-design icon usage the lucide-react migration left
behind in skill_detail.tsx (semantic conflict on the base branch)
2026-08-24 10:37:32 -07:00
mateo-berri
ed8480a821 Merge remote-tracking branch 'origin/litellm_internal_staging' into litellm_lit5458_rerank_sigv4_bearer_fix
Some checks failed
Terraform Provider / gofmt, vet, build, test (push) Waiting to run
Terraform Provider / Provider endpoints vs proxy OpenAPI schema (push) Waiting to run
Terraform Modules / fmt, validate, test (aws) (push) Has been cancelled
LiteLLM Rust / rustfmt, clippy, test (push) Has been cancelled
2026-08-24 10:37:13 -07:00
Mateo Wang
3122600e21
Merge pull request #37975 from BerriAI/litellm_databricks_cache_token_pricing
fix(databricks): bill cached tokens at cache rates and add missing Claude pricing
2026-08-24 10:36:19 -07:00
Mateo Wang
28b433a007
Merge pull request #37966 from BerriAI/litellm_1787426863_strategy_router_health_check
fix(proxy): skip health checks for strategy routers
2026-08-24 10:26:09 -07:00
mateo-berri
20a82cad8a fix: read a wrapped group before VALUES can end the search, and blank comments in restored bodies 2026-08-24 10:23:17 -07:00
ryan-crabbe-berri
4913b2a3ca
Merge pull request #33514 from ozolam/litellm_fix_skills_marketplace_commands_v2
fix(UI): correct skill install command and marketplace setup UX
2026-08-24 10:17:25 -07:00
yuneng-jiang
3fb1009f81
fix(ui): make playground chat bubbles theme-aware (#37978)
The playground message bubble painted its fill, border and avatar circle from
inline hex values, so in dark mode both bubbles stayed near-white while the text
inherited the dark foreground: the message body was unreadable. The MCP-events
placeholder bubble in ChatUI carried the same three fills.

They move onto the tokens the rest of the sweep already uses, so the assistant
surface is bg-card over border-border and the user surface is the info tint at
the same weight the other selected-state surfaces take. Light mode keeps the
same colour family it had.

The regression test asserts the token classes and that no inline style survives
on either surface, which is the exact shape the bug took.
2026-08-24 10:13:24 -07:00
yuneng-jiang
7113685a76
fix(ui): repoint the key detail URL to the rotated hash after regenerating (#37968)
Regenerating a key from the key info page left the ?key= query param on the
old hash, so dismissing the dialog or reloading landed on a key that no longer
exists and the page rendered "Key not found".

Two defects had to line up. POST /key/{key}/regenerate returns the rotated
hash in token_id and leaves token null, but RegenerateKeyModal read
response.token || response.key_id, neither of which the endpoint populates, so
it always reported the old hash back to its parent. And KeyInfoView's
onKeyDataUpdate prop had no caller anywhere in the tree: VirtualKeysTable owns
the ?key= param and mounts the view but never passed it, so even a correct
hash went nowhere.

VirtualKeysTable now handles the update by pointing ?key= at the rotated hash
and refetching. KeyInfoView holds that callback until the regenerate dialog is
dismissed rather than firing it on the API response, because swapping the
selected key mid-dialog unmounts the view and tears down the one-time
plaintext key before the user can copy it.
2026-08-24 10:12:55 -07:00
yuneng-jiang
5b1c142c6e
fix(ui): render team and org tpm/rpm limits of 0 as 0 instead of Unlimited (#37916)
* fix(ui): render team and org tpm/rpm limits of 0 as 0 instead of Unlimited

A tpm_limit or rpm_limit of 0 is a hard block on the backend (every request 429s) and only null means unlimited, but the team and organization views rendered both as "Unlimited" (and a team-member limit of 0 as "No Limit") because every display site used a falsy || fallback. The team member edit dialog also seeded its form with `tpm_limit || null`, so opening Edit Member on a member stored with 0 and clicking Save sent null to /team/member_update and silently turned the hard block into unlimited

Every limit display site in TeamInfo, organization_view, the organizations list cell and the team members table now uses a nullish check, and both member form seeding paths keep 0 for max_budget_in_team, tpm_limit and rpm_limit. Regression tests cover each site and the existing memberFormValues test that asserted 0 -> null is flipped to assert 0 survives

Resolves LIT-5760

* test(ui): assert a stored 0 member limit survives an untouched save

The EditMembership integration test named the old 0 -> null collapse as the expected payload, so the related-tests CI job went red once the form kept 0. It now asserts 0 survives and only the empty budget_duration collapses to null. The TeamMemberTab fixture is built with a map instead of mutating the nested membership
2026-08-24 10:12:52 -07:00