Commit graph

46335 commits

Author SHA1 Message Date
Mateo Wang
1bb9b175e2
Merge pull request #39369 from BerriAI/litellm_langfuse_root_observation_io
fix(otel): stamp Langfuse root observation input and output from the request task
2026-09-02 14:29:09 -07:00
Yassin Kortam
8e65265bb4
fix(agents): redact secret litellm_params fields from all /v1/agents responses (#39389)
* fix(agents): redact secret litellm_params fields from all /v1/agents responses

Secret-bearing litellm_params fields (aws_secret_access_key, api_key, and
similar) are now write-only: list, get, create, update, and patch
responses always replace them with a fixed marker, regardless of caller
role. Editing an agent no longer requires resending a real credential --
an update that omits a sensitive field, or echoes the marker back,
preserves the stored value; a real value still rotates it.

* fix(agents): redact secrets nested inside dicts/lists in litellm_params too

Greptile found that a secret nested one level down under a
non-sensitively-named key, or inside a list of per-provider configs, was
neither redacted on read nor restored symmetrically on write (the marker
string could get persisted as the real value). Recurse into lists on the
read side, and mirror that recursion on the write side so restoration
isn't limited to top-level keys. Also fixes a regression the redact
rewrite introduced (a plain string leaf like a model name was being
misinterpreted as a JSON blob and redacted), and suppresses 3 new
test-quality-gate findings on an established repo-wide mocking pattern
this PR's new tests also use.

* fix(agents): guard list-position credential restore against misassignment

Two more real gaps Greptile/veria found in the recursive redact/restore
mechanism, verified directly against the exact reported shape
(litellm_params.model_list, each entry carrying its own nested
litellm_params.api_key/aws_secret_access_key) before fixing:

- Positional restoration inside a list could attach one entry's stored
  credential to a different entry if the list were reordered or resized
  between GET and PUT/PATCH. Restoration by index now only fires when the
  incoming and existing entries match on every non-secret field; otherwise
  the caller's own value is used (never a guessed cross-entry secret).
- A subtree collapsed to the flat REDACTED_BY_LITELM marker by the
  read-side recursion depth cap couldn't be recovered on write (the marker
  string itself would get persisted). Restore now recognizes that shape and
  recovers the whole existing subtree.

Both covered by regression tests mirroring the exact model_list shape
reported, mutation-verified.

* fix(agents): simplify list-entry credential restore to positional matching

The content-match guard from the previous commit fixed one Greptile
finding (cross-entry misassignment on reorder) but introduced a worse one:
it also rejected restoration whenever an entry's own non-secret fields
changed, which is the common case (rename a model_list entry while
leaving its own secret masked) -- silently dropping the stored credential
on an ordinary edit.

There is no stable per-element identity in a plain dict[str, object]
schema, so no rule can satisfy both 'restore whenever the entry itself
only had its secret masked' and 'never restore across a reorder' at once.
Positional correspondence is what every other part of this restore (and
the endpoints' full-replace-on-PUT semantics) already assumes, so drop
the content-match gate and rely on it here too: this fixes the common
case correctly and accepts cross-entry misassignment on a simultaneous
reorder-plus-masked-echo as a known, narrow, documented limitation (not a
leak between different agents or tenants, since it only reshuffles one
agent's own stored values). Tests updated to pin the accepted trade-off
explicitly rather than asserting it away, and to cover the previously
broken ordinary-edit case.
2026-09-02 14:28:44 -07:00
Yassin Kortam
25991fe78a
feat(auth): enforce configurable password policy and SSO-only login (#39381)
Adds a configurable password-strength policy (default: min 12 chars,
upper/lower/number/special, all individually toggleable, floored at 8
so a misconfigured minimum cannot disable the length check, and
unicode-aware so an accented letter cannot satisfy the special-
character requirement) enforced on every path that sets a local
user's password: /user/update, /user/bulk_update, and the invitation
onboarding claim flow.

Adds general_settings.disable_password_login_when_sso_enabled, which
rejects username/password login on /login, /v2/login and /v3/login
(including the UI_USERNAME/UI_PASSWORD admin fallback) once ANY
configured SSO provider is FULLY ready: every companion secret/
endpoint an OAuth provider needs, checked independently per provider
so a stray leftover client id for an unused provider can't mask a
different, fully configured one; and for SAML, the optional
python3-saml runtime being importable, checked without letting a
fully-missing package's ModuleNotFoundError take down password login
itself. SSO becomes the enforced boundary for interactive UI access
without an incomplete, mixed, or half-installed SSO setup locking
every admin out or breaking login outright. Master-key API access is
untouched, and unsetting the setting plus a restart restores password
login as the documented recovery path.
2026-09-02 14:28:13 -07:00
Yassin Kortam
646f3404a5
fix(security): restrict and validate file uploads at /v1/files and /upload/logo (#39379)
* fix(security): restrict and validate file uploads at /v1/files and /upload/logo

Extends fast-fail upload validation to every purpose at POST /v1/files,
not just purpose=batch: a configurable max_file_size_mb size cap and a
blocked_file_extensions denylist, plus rejection of filenames carrying a
directory-traversal component before anything is read, stored, or
forwarded to a provider.

Also fixes two concrete gaps found while auditing every upload surface:
the Azure Blob Storage backend derived a blob path's extension with
filename.split(".")[-1], which does not parse path structure and let a
crafted filename embed a directory traversal sequence into the stored
blob path; and POST /upload/logo (the admin UI logo upload) had no
role check at all, so any authenticated API key, not just a proxy
admin, could write a file to the server's disk.

* fix(lint): drop cast()/mutation from settings coercion, sync blocked_file_extensions on reload

Replaces the TypeAdapter+cast() reads of max_file_size_mb and
blocked_file_extensions with small isinstance-based validators, since the
codebase's cast() budget (LIT006) had no headroom left. Also adds the
blocked_file_extensions reload block that was missing from
_update_general_settings: it was registered as an editable setting but
never re-synced into runtime state, so a value set through the DB-backed
settings editor would silently never take effect (Greptile finding).

* fix(security): declare max_file_size_mb and blocked_file_extensions on ConfigGeneralSettings

The DB-backed general-settings update endpoints validate every field
through ConfigGeneralSettings.model_fields before persisting it, so
without these declarations an operator could never actually set either
setting through that path even though both were registered for the
Admin UI's settings editor and reloaded on config refresh (Greptile
finding). blocked_file_extensions is typed as a tuple, not a list, to
stay out of the immutable-collections lint budget; the stored JSON
value is unaffected since the raw request payload, not the validated
model, is what gets persisted.

* chore: regenerate schema.d.ts for the new ConfigGeneralSettings fields

* fix(security): normalize configured blocked_file_extensions casing

check_blocked_extension lowercased the uploaded filename's extension
before comparing but compared it against blocked_extensions verbatim,
so an admin-configured blocked_file_extensions: ['.EXE'] would never
match an uploaded payload.exe (Greptile finding). Normalizes the
configured values the same way at comparison time, and adds the
missing case (mismatched-case config, lowercase upload) as a
regression test, mutation-checked against the unfixed comparison.

* fix(security): restore caller-owned stream position after size inspection

_file_size_bytes unconditionally seeked back to 0 after measuring a
BinaryIO's length, discarding wherever the caller had actually
positioned it (Greptile finding). Saves and restores the original
position instead. Rewrites the existing test that had encoded the
old "always resets to 0" behavior as its expectation, and adds a
sibling case for the under-cap path; both are mutation-checked
against the unfixed always-reset-to-0 behavior.
2026-09-02 14:27:46 -07:00
Mateo Wang
719b67114d
Merge pull request #36811 from BerriAI/litellm_realtime_router_session_model
fix(router): resolve realtime session model to routed deployment
2026-09-02 14:16:00 -07:00
tin-berri
2ade3e16a9
feat(ui): update OpenAI preset model tiers (#39396) 2026-09-02 13:45:16 -07:00
mateo-berri
ec1fba5dc7 chore: merge litellm_internal_staging into litellm_realtime_router_session_model
Carries a mutable-ok suppression on the router session rewrite for the
tightened LIT002 budget, since the realtime callees deep-copy and
JSON-dump the session, and captures the realtime session kwargs through
an async mock in the router tests instead of an untyped dict.
2026-09-02 13:42:30 -07:00
Yassin Kortam
711430216e
fix(ui): preserve full AgentCore runtime ARN in agent edit form (#39382)
parseDynamicAgentForForm recovered a credential field's value from a
stored model string by splitting both the model_template and the model
on "/" and matching by array index. That breaks for any placeholder
value that itself contains "/", such as a Bedrock AgentCore runtime ARN
resource path (runtime/<runtime-id>), silently dropping everything
after the first slash when populating the edit form. Saving without
touching the field then persisted the truncated ARN.

Replace the index-matching split with a non-mutating template parse
(split on the placeholder pattern, escape and rejoin the literal
segments into a regex) so a placeholder captures everything it needs
regardless of embedded slashes. Also add a lightweight ARN-shape
validator for the AgentCore runtime ARN field, guarded against a
malformed pattern string, so a truncated value is rejected client-side
before it reaches the backend.

Resolves LIT-6737
2026-09-02 13:33:14 -07:00
yujonglee
d8bb7451bf
Merge pull request #39331 from BerriAI/litellm_rust_error_type
refactor(rust): standardize the core Error type
2026-09-02 13:17:19 -07:00
mateo-berri
5da9b7ef90 fix(otel): stamp the Langfuse root observation from the post-guardrail request and response 2026-09-02 13:12:05 -07:00
Mateo Wang
afb4d76b67
Merge pull request #39220 from BerriAI/litellm_containers_route_model_list_creds
fix(proxy): route container create and list through model_list deployments
2026-09-02 13:04:04 -07:00
Mateo Wang
d2fe8af276
Merge pull request #39365 from BerriAI/litellm_fix_v2_resolver_migrate_deploy_timeout
fix(proxy-extras): give prisma migrate deploy its own timeout budget
2026-09-02 12:48:54 -07:00
devin-ai-integration[bot]
987ab76921
fix(proxy): share per-model budget counters across replicas through the spend counter cache (#39375)
* fix(proxy): share per-model budget counters across replicas through the spend counter cache

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

* test(proxy): keep the shared fake Redis store immutable

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-02 12:40:59 -07:00
devin-ai-integration[bot]
cde9d94c36
feat(agentcore-a2a): derive runtime session id from A2A message.contextId (#39371)
Native AgentCore A2A always sent either a fresh generated runtime session id
or the single configured runtimeSessionId, so related turns lost context and
unrelated callers shared one AgentCore microVM. The runtime session id is now
params.message.contextId scoped to the calling key hash, then runtimeSessionId,
then generated, and is length-validated (33-256) before the header is signed.
Invalid ids surface as JSON-RPC -32602 / HTTP 400 instead of a 500.

Co-authored-by: yassin <yassin@berri.ai>
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-02 12:40:24 -07:00
mateo-berri
034ff58558 test(otel): assert Langfuse logger behavior instead of its class 2026-09-02 12:36:32 -07:00
mateo-berri
3af19cbf61 test(proxy-extras): use the modern optional annotation in the deploy budget test 2026-09-02 12:36:29 -07:00
Yujong Lee
518a2a70f1
refactor(rust): standardize the core Error type 2026-09-02 12:16:27 -07:00
Yujong Lee
9de4e84feb
refactor(rust): extract domain-neutral Python interop 2026-09-02 12:16:26 -07:00
Yujong Lee
90eadac409
test(build): keep wheel checks outside package 2026-09-02 12:16:25 -07:00
Yujong Lee
814204e21f
fix(rust): satisfy native wheel verifier lint 2026-09-02 12:16:25 -07:00
Yujong Lee
ce0c85ea69
refactor(rust): colocate native wheel contract checks 2026-09-02 12:16:25 -07:00
Yujong Lee
cbb8a1784d
chore(ci): extract setup-uv pin 2026-09-02 12:16:25 -07:00
Yujong Lee
38150dfc2c
fix(ci): pin workflow toolchain dependencies 2026-09-02 12:16:25 -07:00
Yujong Lee
ef9a207ed5
fix(ci): harden release wheel reporting 2026-09-02 12:16:25 -07:00
Yujong Lee
e6a317e079
fix(ci): enforce release wheel metadata contract 2026-09-02 12:16:25 -07:00
Yujong Lee
9dc9cd325c
fix(ci): isolate release wheel reporting permissions 2026-09-02 12:16:25 -07:00
Yujong Lee
2f362cfec2
fix(ci): preserve release wheel contract parity 2026-09-02 12:16:25 -07:00
Yujong Lee
25987cb961
test(build): validate release wheel contracts 2026-09-02 12:16:25 -07:00
mateo-berri
c83b4a1d19 fix(proxy-extras): honor a raised command timeout for migrate deploy and name the right knob on db push timeouts 2026-09-02 12:10:54 -07:00
Devin AI
4a09c35d94 Merge remote-tracking branch 'origin/litellm_internal_staging' into litellm_containers_route_model_list_creds 2026-09-02 19:10:45 +00:00
Ali Ahmed
a677242d6f
fix(headroom): stop re-compressing retrieved CCR content in client tool loops (#38591)
When the headroom_retrieve tool is exposed to a client that runs its own
tool-execution loop (the LiteLLM MCP gateway path), the client executes the
retrieve call and sends the recovered original content back as a tool result
on the next turn. The guardrail then compressed that row again, and because
CCR is content-addressed it collapsed back to the exact same hash it was just
retrieved from. The model never saw the expansion and the agent looped.

Hold tool-result rows that carry headroom_retrieve output back from the
compression service, the same way the live turn and trailing tool exchange are
already protected, so the expansion survives. Retrieve calls are matched by the
direct headroom_retrieve name and the mcp__<server>__headroom_retrieve gateway
name. Because a long gateway name is truncated past 64 chars in the
OpenAI-translated view the guardrail scans, the pairing also falls back to the
tool-call id read from the request's own untranslated messages, which is never
truncated.

Fixes #38558
2026-09-02 12:07:13 -07:00
Mateo Wang
2f0f0685c0
Merge pull request #39188 from BerriAI/litellm_bump_tornado_658
fix(deps): raise the tornado and pypdf floors for six new advisories
2026-09-02 12:00:06 -07:00
mateo-berri
cc2cbb36f3 fix(otel): stamp Langfuse root observation input and output from the request task 2026-09-02 11:57:45 -07:00
Mateo Wang
ba2e5d2d8e
Merge pull request #39341 from BerriAI/litellm_azure_deepseek_v4_flash_0731
fix(models): key Azure DeepSeek V4 Flash 0731 by its Foundry catalog id
2026-09-02 11:52:22 -07:00
mateo-berri
f38a1ec129 Merge branch 'litellm_internal_staging' of https://github.com/BerriAI/litellm into litellm_azure_deepseek_v4_flash_0731
# Conflicts:
#	litellm/model_prices_and_context_window_backup.json
#	model_prices_and_context_window.json
2026-09-02 11:43:22 -07:00
Mateo Wang
b600f02fc2
Merge pull request #34788 from BerriAI/litellm_fix_s3_vectors_search
fix(vector_stores): s3 vectors search router bypass + rag query config drop + ui error swallow
2026-09-02 11:35:56 -07:00
Mateo Wang
a43228ef72
Merge pull request #39249 from BerriAI/litellm_router_settings_reject_unknown_keys
fix: apply optional_pre_call_checks and reject unsupported router settings on /config/update
2026-09-02 11:23:22 -07:00
mateo-berri
f7b37e4e6e Merge remote-tracking branch 'origin/litellm_internal_staging' into litellm_bump_tornado_658 2026-09-02 11:19:59 -07:00
Mateo Wang
4049a075bd
Merge pull request #39170 from BerriAI/litellm_registry_audit_2026_09_01
fix(models): registry audit 2026-09-01: openai realtime and long-context tiers, mistral aliases, voyage, xai, fireworks, together, scaleway, azure ai, govcloud, azure gov, cloudflare whisper, deprecation dates
2026-09-02 11:02:43 -07:00
mateo-berri
e0be9a35e6 fix(deps): raise the pypdf floor to 6.16.1 for three new advisories
GHSA-jp53-mhqp-8xcg (fixed in 6.16.0), GHSA-23w6-3w8w-8484 and
GHSA-763m-79hh-57f2 (fixed in 6.16.1) flag pypdf 6.15.0 in uv.lock and
keep osv-scan red alongside the tornado advisories. The proxy-runtime
extra now requires pypdf>=6.16.1 and the lock resolves 6.16.2.
2026-09-02 11:02:43 -07:00
mateo-berri
a9d3a0746c fix(models): price Azure DeepSeek V4 Flash 0731 from its own meters under the catalog id 2026-09-02 10:59:11 -07:00
devin-ai-integration[bot]
ffc0a8e428
fix: run access group key sync UPDATEs on the writer, not the read replica (#39128)
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-02 10:51:17 -07:00
mateo-berri
47804d0f1a Merge remote-tracking branch 'origin/litellm_internal_staging' into litellm_bump_tornado_658 2026-09-02 10:51:08 -07:00
mateo-berri
0c53961445 fix(proxy-extras): give prisma migrate deploy its own timeout budget 2026-09-02 10:44:51 -07:00
mateo-berri
7a35c34303 fix(models): add the us-gov. geo inference profile keys for Claude Sonnet 5 and Opus 4.8 2026-09-02 10:30:14 -07:00
Mateo Wang
2ffe6a1dc8
Merge pull request #39160 from BerriAI/litellm_gemini_thinking_content
fix(gemini): return enabled thinking content by default
2026-09-02 10:22:28 -07:00
Yassin Kortam
de80e3afe4
fix(helm): scale the classic chart's HPA out at the documented 60 percent CPU (#35975)
* fix(helm): scale the classic chart's HPA out at the documented 60 percent CPU

The litellm-helm chart shipped targetCPUUtilizationPercentage: 80, which is
unexamined helm create scaffold rather than a chosen number. It arrived packaged
with the stock minReplicas: 1, maxReplicas: 100, a commented-out
targetMemoryUtilizationPercentage: 80, and the boilerplate "such as Minikube"
comment, the same provenance as the 128Mi resource example this file just
corrected.

60 is the documented recommendation. The mechanism behind it is scale-up lag:
the chart's own startupProbe is failureThreshold: 30 times periodSeconds: 10, so
a replica can take up to 300 seconds to become ready, and a pod added at 80
percent utilization arrives minutes after saturation.

The memory target stays commented out on purpose. The prisma query engine's
resident memory is a high-water mark that ratchets to the pod's worst-ever write
and is never returned, so a memory-target HPA reads the largest write a pod ever
did rather than what it is doing now, and replicas ratchet up without scaling
back in.

hpa_tests.yaml carried its second suite after a YAML document separator, and
helm-unittest loads only the first document per file, so that suite never ran;
an assertion planted in it still passed. Fold it into the one live suite and add
coverage pinning the rendered CPU target, the absence of a memory metric by
default, and that overrides still take effect.

Bump the chart to 1.1.2, since rendered output changes for anyone running with
autoscaling enabled.

* fix(helm): bump litellm-helm to 1.1.3 after rebase onto 1.1.2

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-09-02 10:19:03 -07:00
Mateo Wang
6ed2cdd428
Merge pull request #39238 from BerriAI/litellm_anthropic_models_display_name
feat(proxy): configurable display_name for the Anthropic-shaped /v1/models listing
2026-09-02 10:18:43 -07:00
Mateo Wang
921c1d1248
Merge pull request #39246 from BerriAI/litellm_fix_e2e_junit_properties_types
test(e2e): read JUnit properties off the real collected pytest Item
2026-09-02 10:18:18 -07:00
Mateo Wang
1710d977bf
Merge pull request #39176 from BerriAI/litellm_rerank_provider_error_body
fix(rerank): map provider errors with the resolved provider on sync and async paths
2026-09-02 10:18:11 -07:00