Commit graph

39525 commits

Author SHA1 Message Date
yuneng-jiang
9c135abbf0
Merge pull request #30680 from BerriAI/litellm_backport_1_88_x_bp-30543-30542-30274-0617
chore(release): backport #30543, #30542 to stable/1.88.x and cut 1.88.3
2026-06-17 12:44:42 -07:00
Yuneng Jiang
7678078be2
chore: refresh uv.lock for 1.88.3 2026-06-17 12:22:23 -07:00
Yuneng Jiang
072d757b54
bump: version 1.88.2 → 1.88.3 2026-06-17 12:21:47 -07:00
Yassin Kortam
a68db8b5bb
fix(guardrails): stop re-initializing DB guardrails on every poll (#30542)
* fix(guardrails): stop re-initializing DB guardrails on every poll

InMemoryGuardrailHandler._has_guardrail_params_changed compared the
in-memory LitellmParams against the raw dict loaded from the DB. The
in-memory side carries every field default and coerces enums via
model_dump(), while the DB side only holds the keys originally stored,
so the two shapes never compared equal and the guardrail was rebuilt on
every poll cycle.

Each rebuild created a fresh instance, but delete_in_memory_guardrail
only removed the old callback from litellm.callbacks. Request handling
promotes guardrail callbacks into the success/failure/async lists, so
the previous instance stayed referenced there and instances accumulated.

Normalize both sides through LitellmParams(...).model_dump() before
diffing, and purge the callback from every callback list on delete.

* refactor(guardrails): narrow params-normalization fallback to ValidationError

The comparison normalizer caught a bare Exception and silently fell back
to the raw dict, which hid the cause and quietly degraded the affected
guardrail back to re-initializing on every poll. Catch only the
ValidationError that LitellmParams construction can raise, log a warning
so the offending row is diagnosable, and let any other error surface
instead of being swallowed.

* refactor(callbacks): add remove_callback_from_all_lists helper to manager

Move the knowledge of which callback lists a callback can be promoted
into out of the guardrail registry and into LoggingCallbackManager, where
the rest of the callback-list bookkeeping already lives. delete_in_memory_guardrail
now delegates to the new helper instead of iterating the lists itself.

(cherry picked from commit 9fa74ad8b4)
2026-06-17 11:25:36 -07:00
Yassin Kortam
05efbc6454
fix(guardrails): run pre_call hook once for model-level guardrails (#30543)
* fix(guardrails): run pre_call hook once for model-level guardrails

A CustomGuardrail attached to a deployment via litellm_params.guardrails
gets its async_pre_call_hook invoked twice per request: once by the proxy
pre-call loop and again by async_pre_call_deployment_hook after the router
spreads the model-level guardrails into the top-level request kwargs.

Record in request metadata that the proxy pre-call loop already ran a given
guardrail, and have the deployment hook skip it when the marker is present.
Direct-SDK usage never runs the proxy loop, so the deployment hook stays the
sole invocation there and still fires exactly once.

The marker key is stripped from untrusted caller metadata so a request body
cannot suppress a model-only guardrail by pre-seeding it.

* fix(guardrails): mark pre_call dedup on the post-hook request data

Record the exactly-once marker after async_pre_call_hook runs, on the data
object that flows downstream, rather than before it. A guardrail whose hook
returns a brand-new request dict (instead of mutating or spreading the one it
received) would otherwise discard the marker, letting the deployment hook
re-run the guardrail a second time.

(cherry picked from commit 4faeabc254)
2026-06-17 11:25:28 -07:00
yuneng-jiang
a0d05ba257
Merge pull request #30408 from BerriAI/litellm_backport_1_88_x_0613
chore(release): backport DB-resilience, passthrough, model-info, budget, and deps fixes to stable/1.88.x
2026-06-13 19:29:53 -07:00
Sameer Kankute
80f0c38e60
fix(proxy): populate access_via_team_ids on /v1/model/info (#30274)
* fix(proxy): populate access_via_team_ids on /v1/model/info

Team metadata enrichment previously only ran on /v2/model/info with
include_team_models=true, leaving /v1/model/info without
access_via_team_ids for project model-picker flows.

Co-authored-by: Cursor <cursoragent@cursor.com>

* docs(dashboard): sync OpenAPI schema for /v1/model/info query params

Add include_team_models and teamId to the generated schema for /model/info
and /v1/model/info after the proxy endpoint gained team-access filtering.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(proxy): always return direct_access on /v1/model/info

Set direct_access to true or false on every enriched model so clients
can filter without treating a missing field as ambiguous.

Co-authored-by: Cursor <cursoragent@cursor.com>

* perf(proxy): fail fast when teamId is set without a connected DB on /v1/model/info

Raise the db_not_connected error before building, enriching, and translating the model list instead of after, so a teamId query against a proxy with no database no longer wastes the full enrichment pipeline.

* fix(proxy): fail fast when include_team_models is set without a database

include_team_models=True relies on _populate_team_access_on_models to set
direct_access/access_via_team_ids, which only runs when a database is connected.
Without one, _filter_models_to_user_accessible discarded every model and the
endpoint returned an empty list with HTTP 200. Mirror the teamId guard so the
request fails fast with a clear db_not_connected error before any model-list work.

* fix(proxy): populate direct_access on single-model /model/info lookup

The /v1/model/info list path populates model_info.direct_access (and
access_via_team_ids) when a database is connected, but the
litellm_model_id single-model lookup returned early without it. This
made the two endpoints disagree, breaking the parity assertion in
test_get_specific_model. Run the same population on the single-model
path so both responses match.

* fix(proxy): apply no-DB fast-fail before litellm_model_id branch

The teamId/include_team_models no-DB guard sat after the litellm_model_id
early return, so ?litellm_model_id=X&teamId=Y with no DB returned 200 with
unpopulated access fields instead of the 500 raised on every other path.
Move the guard ahead of the branch so the fast-fail is uniform.

* fix(proxy): apply teamId/include_team_models filters on single-model lookup

The litellm_model_id early-return branch in model_info_v1 populated the
team access fields but returned before the teamId and include_team_models
filters ran, so a single-model lookup surfaced the deployment regardless
of team access when the DB was connected. Run both filters on the
single-model list before returning so the documented query params behave
the same with and without litellm_model_id.

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: mateo-berri <277851410+mateo-berri@users.noreply.github.com>

Adaptation: the generated ui schema.d.ts hunk is dropped (absent on this line,
regenerated at UI build, no Python dependency). proxy_server.py and the test apply
verbatim once the model_info_v1 BYOK pipeline is present from #29731 and #30025.

(cherry picked from commit 7d1f68e72a)
2026-06-13 18:00:16 -07:00
Sameer Kankute
b083ebef7d
fix(proxy): align /v1/model/info with router deployments (#30025)
* fix(proxy): align /v1/model/info with router deployments

Return router model_list entries (including team-scoped models) with team
access metadata instead of wildcard-expanded names from get_complete_model_list.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(proxy): gate v1 team filter and honor key allowlists

Only apply get_all_team_and_direct_access_models for admin or user-bound
keys, then intersect with key/team model restrictions to avoid empty lists
for service tokens and metadata leaks for restricted keys.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(proxy): skip v1 team filter when user row is missing

Require a DB-backed user before applying team-access filtering on
/v1/model/info, and skip the trailing filter in get_all_team_and_direct_access_models
when user context cannot be resolved.

Co-authored-by: Cursor <cursoragent@cursor.com>

* Revert "fix(proxy): skip v1 team filter when user row is missing"

This reverts commit 74e1fbd77a.

* fix(proxy): restore legacy v1 model access filtering

Keep /v1/model/info on key/team allowlists instead of DB team-membership
filtering, while still listing router deployments for team-scoped models.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(proxy): drop A2A agent entries from public /v1/model/info list

* fix(proxy): scope team BYOK rows on /v1/model/info to caller's teams

Listing the full router model_list let any authenticated key without
explicit model restrictions enumerate other teams' BYOK deployments
(public name, team_id, api_base) via /v1/model/info. Reuse the existing
_get_caller_byok_team_scope check so non-admin callers only see global
deployments plus their own team's BYOK rows; admins keep the full view.

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: mateo-berri <277851410+mateo-berri@users.noreply.github.com>
(cherry picked from commit 6068bb7781)
2026-06-13 17:59:54 -07:00
yuneng-jiang
91b2013644
fix(proxy): stop team BYOK model name corruption on model edit (#29731)
* fix(proxy): stop team model name corruption on edit (#28382) (#29001)

Team-scoped ("Team-BYOK") models store an internal routing key
model_name_{team_id}_{uuid} in the model_name column and the user-facing
name in model_info.team_public_model_name. The internal name leaked into
/v1, /v2, and /model/info responses; the dashboard bound its edit form to
it, so any non-rename save (e.g. a TPM tweak) PATCHed the internal name
back. The update path then treated it as a rename, overwriting
team_public_model_name and rewriting the team's models[] ACL with the
mangled string -- breaking team key calls with team_model_access_denied.

Two-layer fix:

- Read path (root cause): add _translate_model_name_for_response and apply
  it in model_info_v2 and _get_proxy_model_info so /v1, /v2, and
  /model/info surface the public name for team-scoped rows. The DB column
  and router index keep the internal name as the routing key; this is a
  presentation-layer swap on a shallow copy (never mutates input).

- Write path (defense in depth): harden _get_public_model_name so a value
  matching the internal shape, or a no-op against the current DB column,
  is never treated as a rename -- for both the top-level model_name and an
  explicit model_info.team_public_model_name.

Tests: regression for the reported scenario, full branch coverage of
_get_public_model_name, two internal-shape guard cases, an end-to-end
PATCH through _update_team_model_in_db (asserts the team ACL is untouched),
and four response-translation cases. 60 passed (model management),
181 passed (proxy server).

* fix(ui): key Agent Builder agent selection on model_info.id (#29729)

* fix(ui): key Agent Builder agent selection on model_info.id

Once team-scoped BYOK models can share a public name (the backend now
returns the public name on /model/info instead of the internal routing
key), selecting agents by model_name collides. Key selection, create,
update and delete on the stable model_info.id instead, falling back to
model_name only for config-defined agents that have no id.

* fix(ui): add name-match fallback to post-create agent selection

If the just-created agent's id is not yet present in the re-fetched
list, try matching by name before falling back to the first agent.
Addresses greptile review on #29729.

---------

Co-authored-by: tushar8408 <32977767+tushar8408@users.noreply.github.com>
(cherry picked from commit 56aa55b991)
2026-06-13 17:59:31 -07:00
yuneng-jiang
c86bf9b4d9
chore(deps): bump vitest, brace-expansion, pypdf and tornado (#30220)
* chore(deps): bump aiohttp to 3.14.1 and vitest to 3.2.6

Lockfile-only bump for aiohttp (3.13.5 -> 3.14.1, within the existing
pyproject constraint) and dashboard devDependency bumps for vitest,
@vitest/coverage-v8, @vitest/ui (3.2.4 -> 3.2.6) plus transitive
brace-expansion (5.0.5 -> 5.0.6). Clears the currently published
advisories flagged by osv.dev against uv.lock and the dashboard
lockfile. Verified: 154 custom_httpx unit tests and all 3943 dashboard
vitest tests pass; live proxy completion and streaming calls succeed on
the bumped venv

* chore(deps): raise aiohttp floor to 3.14.0

The lockfile bump alone only protects environments built from uv.lock.
Raising the pyproject floor extends the same minimum to package
consumers installing litellm from PyPI, and prevents a future lockfile
regeneration from resolving below 3.14.0

* Revert "chore(deps): raise aiohttp floor to 3.14.0"

This reverts commit d6c1c9dc0c.

* revert(deps): roll back aiohttp to 3.13.5

vcrpy is incompatible with aiohttp >= 3.14 (the aiohttp_stubs module
imports a symbol removed in 3.14) and the upstream fix is merged but
unreleased, so every cassette-based test suite fails on 3.14. Hold
aiohttp at 3.13.5 until a vcrpy release ships; the vitest and
brace-expansion bumps stay

* chore(deps): bump pypdf to 6.13.1 and tornado to 6.5.7

Lockfile-only bumps clearing the advisories published for both since
this branch was opened

* chore(deps): add regression guards for the bumped versions

Raise the pypdf floor to 6.12.0 (direct dependency, applies to package
consumers too) and add uv constraint-dependencies for the transitive
pins: tornado >= 6.5.6, and aiohttp held in [3.13.5, 3.14) so a lockfile
regeneration can neither fall back below the current version nor move
onto 3.14 while vcrpy is incompatible. Constraints live in [tool.uv]
and only affect this repo's resolution, not published metadata.
Verified: uv lock -P with each out-of-range version fails to resolve;
in-range resolutions unchanged (pypdf 6.13.1, tornado 6.5.7,
aiohttp 3.13.5)

Backport handling (stable/1.88.x): the manifest hunks (pyproject pypdf floor 6.10.2->6.12.0
plus the [tool.uv] tornado/aiohttp constraints, and the package.json vitest 3.2.4->3.2.6 bumps)
are taken as-is; the staging lockfiles are not. uv.lock and package-lock.json are regenerated on
this line so the closure stays minimal: uv.lock moves only pypdf 6.10.2->6.13.2 and tornado
6.5.5->6.5.7 (aiohttp held at 3.13.5 by the new constraint), and package-lock.json moves vitest
and @vitest to 3.2.6. brace-expansion reached 5.0.6 transitively on staging but resolves to 5.0.5
on this line's tree, so a brace-expansion 5.0.6 override is added to clear the same advisory. No
version bump: 1.88.2 is bumped but unreleased, so these ride the pending 1.88.2.

(cherry picked from commit d96ab467f1)
2026-06-13 17:04:02 -07:00
yuneng-jiang
44ff751e54
fix(proxy): return deprecated-key lookup result directly in get_data combined view (#30327)
The grace-period branch assigned the recursive get_data result (a
finished LiteLLM_VerificationTokenView) back into the variable that the
combined-view dict normalization then subscripts, raising TypeError on
every request made with a rotated key inside its grace window; auth
surfaced that as a 401. Return the recursive result directly instead.

Regression test drives the full get_data flow: old hash misses the view,
deprecated table resolves to the active token, and the call must return
the view object

(cherry picked from commit 5047eaf7f0)
2026-06-13 16:58:19 -07:00
Sameer Kankute
f59192b87a
fix(passthrough): skip [DONE] sentinels and non-JSON SSE frames in Anthropic streaming logging
Targeted subset of staging commit cfcdf8714a (#30202): only the
anthropic_passthrough_logging_handler.py hardening hunks and their four
tests are taken; the rest of that staging batch is intentionally excluded.

Backport adaptation (stable/1.88.x): the new TestBuildCompleteStreamingResponseRobustness
class is unioned with this line's existing test_parity_*/test_collapse_* tests, which
the 1.84.x base of this commit did not have. Source handler applies verbatim.

(cherry picked from commit cfcdf8714a)
(cherry picked from commit 973c7eb8d6)
2026-06-13 16:55:51 -07:00
Yassin Kortam
82a971a730
fix(passthrough): resolve costing model when body model is unknown (#30160)
Adaptation: in the test file, #30160's six own tests (cost-calculation model
resolution + extract_model) are taken; the trailing
test_passthrough_logging_sets_response_cost_with_server_tool_use_dict, which is
diff context present at the PR's base but not on this line, is dropped. Source
handler applies verbatim.

(cherry picked from commit 1828a7c6f0)
2026-06-13 16:54:10 -07:00
Yassin Kortam
c58c59e6b3
fix(proxy): return 5xx on DB infra errors during auth; reserve 401 for genuine auth failures (#29986)
Adaptation: this line's auth_exception_handler.py does not import
seed_request_identity. The OTEL request-identity feature has its call site in
user_api_key_auth.py here; the second call site staging added in the exception
handler is not on this line. The picked tests mock
auth_exception_handler.seed_request_identity to keep the failure path off OTEL,
so those four patch entries (three in test_auth_exception_handler.py, one in
the test_user_api_key_auth.py builder helper) are removed because the symbol is
absent and the handler never calls it here. The 503/401 behavioral assertions
are unchanged and pass. Separately, the one-line context hunk that reformats an
assert inside test_auto_register_passes_validated_org_context_to_generated_key
is dropped; that test is not present on this line. Source files apply verbatim.

(cherry picked from commit da9d64b4de)
2026-06-13 16:50:56 -07:00
Yassin Kortam
f8c22cdd8a
feat(proxy): add option to disable server-side prepared statements for DB lookups (#29984)
Adaptation: the generated ui/litellm-dashboard/src/lib/http/schema.d.ts hunk
is dropped; that file is absent on this line and is regenerated at UI build,
with no Python dependency. Source changes apply verbatim.

(cherry picked from commit dff25fef44)
2026-06-13 16:43:35 -07:00
Yassin Kortam
c4a7b27e91
fix(proxy): recover from cached-plan errors by reconnecting the Prisma client (#29983)
(cherry picked from commit 3bd3951e37)
2026-06-13 16:42:41 -07:00
yuneng-jiang
dac0f13ad9
test(proxy/utils): pin PrismaClient get_data behavior (subset of #29488)
Scaffolding dependency for the #29983 and #30327 regression tests, which
modify test_prisma_client_get_data.py. Only conftest.py and
test_prisma_client_get_data.py are taken from #29488; the other twelve test
files in that PR pin behavior unrelated to this backport and are dropped.
test_prisma_client_get_data.py and conftest.py are self-contained (no imports
from the dropped siblings) and pass on this line.

(cherry picked from commit 457f65eff9)
2026-06-13 16:42:18 -07:00
Armaan Sandhu
6a8e568f8a
feat(proxy): add disable_budget_reservation general setting (#27639) (#29493)
* feat(proxy): add disable_budget_reservation general setting (#27639)

* feat(proxy): register disable_budget_reservation in ConfigGeneralSettings (#27639)

* docs(proxy): document disable_budget_reservation concurrency tradeoff (#27639)

* ci: re-trigger flaky docker build (prisma generate ECONNRESET)

* fix(proxy): warn and document budget enforcement tradeoff when disable_budget_reservation is set (#27639)

Provenance: #29493 merged into litellm_oss_staging_080626, which was promoted
to litellm_internal_staging by the aggregator squash 32c88ca74f (#29932). There
is no discrete #29493 commit on internal_staging; this pick is the original PR
squash 1032dd75, content-verified identical to the disable_budget_reservation
hunks that 32c88ca74f introduced on internal_staging.

(cherry picked from commit 1032dd751f)
2026-06-13 16:36:09 -07:00
Mateo Wang
28baa9814f
Merge pull request #30144 from BerriAI/litellm_fable5_stable_1_88_x
chore(release): backport Fable 5, batch-file auth, CrowdStrike AIDR, Mantle Responses SigV4, and NetApp streaming-cost fix to stable/1.88.x and cut 1.88.2
2026-06-10 22:00:35 -07:00
mateo-berri
f116cda536
chore: refresh uv.lock for 1.88.2 2026-06-11 04:32:52 +00:00
mateo-berri
ba196a493d
bump: version 1.88.1 → 1.88.2 2026-06-11 04:32:48 +00:00
ishaan-berri
24b9655cd4
fix: completion_cost AttributeError on streaming Anthropic web_search responses (#26153) (#27346)
Cherry-picked from staging squash 4a3860df1f.

stable/1.88.x predates the Usage.__init__ server_tool_use dict->ServerToolUse
coercion that staging carries (it landed via the squashed OSS sync #29932 /
32c88ca74f, not as a standalone commit). The calculate_usage
Usage(**returned_usage.model_dump()) round-trip on this line re-serializes
server_tool_use to a plain dict, so without that coercion the rebuilt usage
holds a dict and the regression test asserting a ServerToolUse type fails.
Restored the coercion in litellm/types/utils.py to satisfy the prerequisite --
it matches #27346's own first commit (coerce server_tool_use dict to
ServerToolUse in Usage.__init__), which was dropped from the squash only because
staging already carried it.
2026-06-11 04:32:33 +00:00
Kent
ce5604413b
feat(bedrock_mantle): add SigV4/IAM auth to Responses API route (#29788)
Applied as the squash diff of PR #29788 (head 9800b2f17c), which landed
upstream inside the litellm_oss_staging_080626 sync (32c88ca74f, #29932)
and has no standalone commit to cherry-pick.
2026-06-11 03:09:30 +00:00
Kent
655e531846
feat(bedrock_mantle): route Responses API to native OpenAI endpoint (#29490)
Backport prerequisite for #29788. Applied as the squash diff of PR #29490,
which landed upstream inside the litellm_oss_staging_040626 sync
(cb041966bf, #29671) and has no standalone commit to cherry-pick.
2026-06-11 03:09:29 +00:00
yuneng-jiang
c3edd95666
fix(guardrails): read CrowdStrike AIDR identity from both metadata bags (#29991)
Capture user_id and extra_info from metadata or litellm_metadata. The single-bag read dropped identity whenever a request carried a present litellm_metadata field (null or a user-supplied dict), since /chat/completions routes the authenticated identity into metadata while the guardrail read litellm_metadata first

(cherry picked from commit 1bbaf1c39d)
2026-06-11 03:09:14 +00:00
Kenan Yildirim
2723601f1e
feat(guardrails): capture user and model metadata in CrowdStrike AIDR
(cherry picked from commit 6fc715c5bd)
2026-06-11 03:09:03 +00:00
Sameer Kankute
beb460b79d
fix(proxy): authorize batch files using upload target_model_names (LIT-3593) (#30009)
* fix(proxy): authorize batch files using upload target_model_names (LIT-3593)

After replace_model_in_jsonl, body.model is a stripped provider id. Reverse-mapping it via resolve_model_name_from_model_id is first-match on model_list and caused false 403s when multiple deployments share the same stripped name. Use target_model_names from the unified file id instead.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(proxy): restore resolve_model_name_from_model_id for JSONL fallback path (LIT-3593)

Restores the reverse-lookup for the JSONL body.model fallback path so that
legacy/pre-target_model_names managed files still map stripped provider IDs
back to proxy aliases before auth. Also cleans up redundant `or None`.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Revert "fix(proxy): restore resolve_model_name_from_model_id for JSONL fallback path (LIT-3593)"

This reverts commit 30d2e96f77.

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
(cherry picked from commit 2cd7e87485)
2026-06-11 03:08:42 +00:00
Mateo Wang
a2ab173a5f
Add Claude Fable 5 across Anthropic, Bedrock, Vertex AI, and Azure AI (#30064)
* Add Claude Fable 5 across Anthropic, Bedrock, Vertex AI, and Azure AI

Adds cost map entries for claude-fable-5 ($10/$50 per MTok, 1M context,
128K output, adaptive thinking only) on the Anthropic API, Bedrock
converse (base, global, and us/eu geo inference profiles at the 10%
regional premium), Vertex AI, and Azure AI (Microsoft Foundry, which
serves Fable 5 with the full 1M context window unlike Opus 4.8).

Registers anthropic.claude-fable-5 in BEDROCK_CONVERSE_MODELS, lists the
model in the setup wizard, and extends the reasoning effort e2e grid.
The Bedrock, Vertex, and Azure grid cells carry fail_reason markers
until the CI accounts are provisioned: Bedrock needs the provider data
sharing opt-in Fable 5 requires, and the Foundry resource needs a
claude-fable-5 deployment.

The first-party entry carries provider_specific_entry {us: 1.1} for the
inference_geo premium and deliberately no fast multiplier since Fable 5
has no fast mode.

https://claude.ai/code/session_01MZarYYT3aS7DxaNjoax6Gm

* Drop removed sampling params for Claude 4.7+ when drop_params is set

Fable 5, Opus 4.7, and Opus 4.8 removed sampling params: the API rejects
top_p, top_k, and any temperature other than 1 with a 400. LiteLLM was
forwarding them even with drop_params enabled because the Anthropic and
Bedrock converse transformations passed temperature/top_p through
unconditionally.

Mirror the GPT-5/o-series handling: temperature=1 still passes through,
other values and any top_p are dropped when drop_params is set, and
without drop_params a clean client-side UnsupportedParamsError tells the
caller how to opt in, instead of surfacing the raw provider error.

https://claude.ai/code/session_01MZarYYT3aS7DxaNjoax6Gm

* Drive sampling param gating from the cost map and cover top_k

Greptile review follow-ups on the sampling param fix: the restriction for
Fable 5 / Opus 4.7 / 4.8 is now declared as supports_sampling_params: false
on every affected cost map entry (perplexity excluded; that route is
OpenAI-compatible and maps sampling params upstream) and read back through
a tri-state map lookup, keeping the name check only as a fallback for
provider-routed ids whose hosted map entries predate the flag, the same
layering supports_adaptive_thinking uses. top_k bypasses map_openai_params
as a provider-specific kwarg, so it is gated at the shared
AnthropicConfig.transform_request boundary (direct, Bedrock invoke, Vertex,
Azure) and in the Bedrock converse _handle_top_k_value path, with
drop_params threaded through the converse transform helpers.

Also updates the reasoning effort grid cell count assertion for the four
Fable 5 rows added on this branch (29 x 11 cells).

https://claude.ai/code/session_01MZarYYT3aS7DxaNjoax6Gm

* Declare supports_sampling_params in the cost map schema

The model map validation schema uses additionalProperties: false, so the
new flag must be declared for the 28 entries that carry it; this was the
one failing job (misc / Run tests) on the previous commit.

https://claude.ai/code/session_01MZarYYT3aS7DxaNjoax6Gm

* fix(bedrock): gate top_k=0 on converse to match Anthropic boundary

Truthiness check let top_k=0 silently disappear on models that removed
sampling params, while AnthropicConfig.transform_request treats 0 as
present and raises UnsupportedParamsError (or drops when drop_params is
set). Switch to 'is not None' so converse, direct Anthropic, invoke,
Vertex, and Azure all behave the same for top_k=0.

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
2026-06-10 18:10:21 +00:00
yuneng-jiang
9c117a58be
Merge pull request #29989 from BerriAI/litellm_bump_version_1_88_1
chore(release): bump version to 1.88.1
2026-06-08 17:23:56 -07:00
Yuneng Jiang
b577372246
chore(release): bump version to 1.88.1
Bump the litellm version from 1.88.0 to 1.88.1 for the stable/1.88.x patch
that carries the pyjwt and ws dependency bumps. Updates the project and
commitizen versions in pyproject.toml and the editable litellm entry in
uv.lock.
2026-06-08 16:55:18 -07:00
yuneng-jiang
f685f2f34e
Merge pull request #29987 from BerriAI/litellm_deps_pyjwt_ws_backport_1_88_x
build(deps): bump pyjwt to 2.13.0 and ws override to 8.20.1 (1.88.x)
2026-06-08 16:49:38 -07:00
Yuneng Jiang
aa2deee363
build(deps): bump pyjwt to 2.13.0 and ws override to 8.20.1
Backport of #29982 to stable/1.88.x. Raises the PyJWT floor in pyproject
(>=2.13.0,<3.0) and re-resolves uv.lock to 2.13.0; bumps the ws transitive
override in the dashboard from 8.19.0 to 8.20.1 and regenerates package-lock,
with jsdom and openai deduping onto the single 8.20.1 copy.

Routine dependency maintenance to keep pinned versions current.
2026-06-08 16:44:53 -07:00
Sameer Kankute
bde16ff5b7
test(proxy): patch utils.get_server_root_path in passthrough auth tests
After removing get_server_root_path from pass_through_endpoints, route
and JWT tests must mock litellm.proxy.utils where normalization reads it.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-04 18:45:10 -07:00
Sameer Kankute
3d00874438
fix(proxy): match passthrough registry routes bare-to-bare with SERVER_ROOT_PATH
After #28547, get_request_route strips the deployment prefix while registry
lookup still re-inflated stored paths via SERVER_ROOT_PATH, causing 404s
under paths like /llmproxy/ml. Compare normalized bare routes in both
is_registered_pass_through_route and get_registered_pass_through_route.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-04 18:44:58 -07:00
Mateo Wang
67428bdb1c
Merge pull request #29639 from BerriAI/litellm_ghsa_q775_defaults_rc188
fix(key_generate): harden GHSA-q775 session-token exemption against default_key_generate_params (1.88 rc)
2026-06-03 19:27:27 -07:00
mateo-berri
c5d214cf81
fix(key_generate): harden GHSA-q775 session-token exemption against default_key_generate_params
Capture _requested_team_id before the default_key_generate_params loop runs and
key the UI/CLI session-token budget-ceiling exemption off it, instead of the
post-defaults data.team_id. On an install that sets
default_key_generate_params.team_id, a session token requesting a personal key
(no explicit team_id) would otherwise have data.team_id auto-filled, flipping
is_ui_session_team_key on and bypassing the delegated-authority ceiling -- the
exact escalation GHSA-q775 closed. Mirrors the existing pre-defaults capture of
_requested_max_budget. Adds a regression test.

https://claude.ai/code/session_01RT583b1khYC3wjLrQ5hT5h
(cherry picked from commit efeb101ec6)
2026-06-04 01:18:15 +00:00
Mateo Wang
c2a0a6a2ee
Merge pull request #29637 from BerriAI/litellm_cherrypick_1_88_0_rc3
chore(release): patch v1.88.0-rc.1 with #29612 (session-token budget-ceiling exemption)
2026-06-03 17:16:33 -07:00
yuneng-jiang
26e9689c73
fix(key_generate): exempt UI/CLI session tokens from the budget ceiling for team keys (#29612)
Non-admin users creating a team key through the UI were rejected with
"max_budget cannot exceed the caller's own max_budget (0.25)". The request is
authenticated by a UI/CLI session token whose max_budget is the per-session chat
spend cap (max_ui_session_budget, default $0.25), and the delegated-authority
budget ceiling (GHSA-q775-qw9r-2r4g) treated that cap as a delegation limit.

Skip the ceiling only when a session token creates a team key (data.team_id set);
that key's spend is bounded by the team budget at request time. Personal keys and
every other non-admin caller keep the ceiling, so a session token cannot mint an
arbitrary-budget personal key.

(cherry picked from commit 97ba7e1a30)
2026-06-04 00:06:34 +00:00
Mateo Wang
0aea62bf50
Merge pull request #29632 from BerriAI/litellm_cherrypick_1_88_0_rc2
chore(release): patch v1.88.0-rc.1 with four staged fixes
2026-06-03 16:25:44 -07:00
Mateo Wang
ed04563db5
fix: passthrough endpoints duplicate logs (#29598)
* fix duplicate cost callbacks for anthropic streaming pass-through

Two bugs caused _PROXY_track_cost_callback to see stream=True +
complete_streaming_response=None on every streaming pass-through request,
making the dedup guard in dispatch_success_handlers permanently inactive:

1. pass_through_endpoints.py created the Logging object with stream=False
   for all requests. _is_assembled_stream_success short-circuits on
   self.stream is not True, so has_dispatched_final_stream_success was
   never set and any second dispatch went through unchecked.
   Fix: set logging_obj.stream = True after stream detection.

2. _create_anthropic_response_logging_payload set complete_streaming_response
   inside the try block after litellm.completion_cost(), so a pricing error
   caused an early return without setting it on model_call_details.
   Fix: set complete_streaming_response before the try block.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix stream

* add stream to logging obj

* test(pass_through): give mock logging object a real model_call_details dict

The anthropic passthrough logging payload now records the assembled
response on model_call_details before cost calculation, which requires
model_call_details to support item assignment. In production it is always
a dict; the existing unit test stubbed the logging object with a bare Mock
whose attribute is not subscriptable, so the new assignment raised
TypeError. Use a real dict to match the production logging object.

* test(pass_through): cover streaming logging-obj stream flag

The streaming branch of pass_through_request that marks the logging object
as streaming (logging_obj.stream and model_call_details["stream"]) had no
unit coverage, so the patch coverage gate flagged it. Add a regression test
that drives a streaming pass-through request through pass_through_request and
asserts the logging object is flagged as a stream before dispatch.

* test(pass_through): cover SSE-response stream flag fallback branch

The auto-detected streaming branch of pass_through_request (when a request
that was not flagged as streaming returns a text/event-stream response) sets
logging_obj.stream and model_call_details["stream"] but had no unit coverage,
so the codecov patch gate failed at 60%. Drive a non-streaming pass-through
request whose upstream response is SSE through pass_through_request and assert
the logging object is flagged as a stream before dispatch.

* fix(pass_through): gate complete_streaming_response on stream flag

perform_redaction only scrubs complete_streaming_response when
model_call_details["stream"] is True. Setting it unconditionally for
non-streaming Anthropic pass-through responses left the assembled
response unredacted in model_call_details, which is handed to logging
callbacks as kwargs when message logging is disabled. Only record it for
actual streaming responses so redaction always applies.

---------

Co-authored-by: mubashir1osmani <mubashir.osmani777@gmail.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
(cherry picked from commit 2bbdbfa5c3)
2026-06-03 22:54:06 +00:00
Mateo Wang
2110b41a16
fix(vertex): strip output_config.effort for Vertex Claude models that reject it (Haiku 4.5) (#29585)
* fix(vertex): strip output_config.effort for models that reject it

Haiku 4.5 on Vertex AI does not support output_config.effort and 400s with
"output_config.effort: Extra inputs are not permitted". PR #27074 emptied
VERTEX_UNSUPPORTED_OUTPUT_CONFIG_KEYS so effort would forward for Opus/Sonnet
4.6+, but that made the strip unconditional across every Vertex Anthropic
model, including ones that don't support it. Claude Code injects effort into
its default Messages payload, so `claude --model claude-haiku-4.5` started
failing.

Make the sanitizer model-aware: drop output_config.effort for models that
don't advertise output_config support (or any reasoning effort level) while
forwarding it for those that do. The fix covers both the chat-completion and
Messages pass-through transformation paths since they share the helper.

* chore(vertex): log at debug when dropping unsupported output_config.effort

Operators pointing an unregistered Vertex Claude alias that does support
effort would otherwise see it stripped with no signal. Debug level keeps it
out of normal logs since Claude Code sends effort on every request.

(cherry picked from commit cc55662e5f)
2026-06-03 22:54:06 +00:00
milan-berri
8373712086
fix(key_generate): allow team members to create keys on org-scoped teams (#29310)
* fix(key_generate): allow team members to create keys on org-scoped teams

When a virtual key is created for a team, enterprise logic inherits the
team's organization_id onto the key (add_team_organization_id). Since the
VERIA-55 org-IDOR fix, /key/generate then required the caller to be an
explicit LiteLLM_OrganizationMembership member of that org, returning
403 "Caller is not a member of organization_id=<uuid>". Admins normally
only add users to teams (not orgs), so self-serve key creation regressed
for any user on an org-scoped team (regression since v1.84.0-rc.1).

Skip the org-membership check when organization_id was inherited from the
key's team (organization_id == team_table.organization_id). Team-level
authorization already gates this path, so team membership is sufficient.
The membership check still runs when a caller assigns an organization_id
that did not come from the key's team, preserving the IDOR protection.

Adds regression tests covering both the team-inherited (allowed) and
foreign-org (still blocked) cases.

Co-authored-by: Cursor <cursoragent@cursor.com>

* test(key_generate): cover mismatched team org IDOR path on generate

Add test_generate_key_foreign_org_with_mismatched_team_still_enforces_membership
for the case where a team is present but request organization_id differs from
team_table.organization_id. Enterprise inheritance is no-op'd in the test so
the guard is exercised directly; membership validation must still run.

Addresses Greptile review on #29310.

Co-authored-by: Cursor <cursoragent@cursor.com>

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
(cherry picked from commit b11833c737)
2026-06-03 22:54:06 +00:00
Shivam Rawat
521ddc3b18
fix(proxy): resolve managed video model ids for auth (#29545)
* fix(proxy): resolve managed video model ids for auth

Co-authored-by: Cursor <cursoragent@cursor.com>

* test(proxy): cover character_id router model resolution

Co-authored-by: Cursor <cursoragent@cursor.com>

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
(cherry picked from commit d45e9e4d56)
2026-06-03 22:54:06 +00:00
yuneng-jiang
5be0797d24
Merge pull request #29372 from BerriAI/litellm_internal_staging
Some checks failed
CodeQL / Analyze (actions) (push) Has been cancelled
CodeQL / Analyze (javascript-typescript) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
CodSpeed Benchmarks / benchmarks (push) Has been cancelled
Helm unit test / unit-test (push) Has been cancelled
Scorecard supply-chain security / Scorecard analysis (push) Has been cancelled
Unit Tests: Proxy DB Operations / assert-shard-coverage (push) Has been cancelled
Unit Tests: Security / security (push) Has been cancelled
GitHub Actions Security Analysis / zizmor (push) Has been cancelled
Unit Tests: Proxy DB Operations / auth-checks (push) Has been cancelled
Unit Tests: Proxy DB Operations / budgets (push) Has been cancelled
Unit Tests: Proxy DB Operations / custom-logging (push) Has been cancelled
Unit Tests: Proxy DB Operations / db-and-spend (push) Has been cancelled
Unit Tests: Proxy DB Operations / endpoints-and-responses (push) Has been cancelled
Unit Tests: Proxy DB Operations / guardrails-hooks (push) Has been cancelled
Unit Tests: Proxy DB Operations / jwt-and-keys (push) Has been cancelled
Unit Tests: Proxy DB Operations / key-generation (push) Has been cancelled
Unit Tests: Proxy DB Operations / logging-misc (push) Has been cancelled
Unit Tests: Proxy DB Operations / proxy-runtime (push) Has been cancelled
Unit Tests: Proxy DB Operations / proxy-server-core (push) Has been cancelled
Unit Tests: Proxy DB Operations / schema-migration (push) Has been cancelled
Unit Tests: Proxy DB Operations / proxy-utils (push) Has been cancelled
chore(ci): promote internal staging to main
2026-05-30 20:56:58 -07:00
yuneng-jiang
28c0d8579b
chore(deps): bump deps (#29373)
Some checks failed
Unit Tests: Proxy DB Operations / assert-shard-coverage (push) Has been cancelled
Unit Tests: Security / security (push) Has been cancelled
Unit Tests: Proxy DB Operations / auth-checks (push) Has been cancelled
Unit Tests: Proxy DB Operations / budgets (push) Has been cancelled
Unit Tests: Proxy DB Operations / custom-logging (push) Has been cancelled
Unit Tests: Proxy DB Operations / db-and-spend (push) Has been cancelled
Unit Tests: Proxy DB Operations / endpoints-and-responses (push) Has been cancelled
Unit Tests: Proxy DB Operations / guardrails-hooks (push) Has been cancelled
Unit Tests: Proxy DB Operations / jwt-and-keys (push) Has been cancelled
Unit Tests: Proxy DB Operations / key-generation (push) Has been cancelled
Unit Tests: Proxy DB Operations / logging-misc (push) Has been cancelled
Unit Tests: Proxy DB Operations / proxy-runtime (push) Has been cancelled
Unit Tests: Proxy DB Operations / proxy-server-core (push) Has been cancelled
Unit Tests: Proxy DB Operations / schema-migration (push) Has been cancelled
Unit Tests: Proxy DB Operations / proxy-utils (push) Has been cancelled
* bump: version 0.1.41 → 0.1.42

* uv lock
2026-05-30 20:41:23 -07:00
yuneng-jiang
54ed5a4eb5
fix(e2e): tolerate trailing slash in SERVER_ROOT_PATH login redirect (#29369)
The Next.js admin UI is exported with trailingSlash: true, so the proxy
serves /ui/login at /ui/login/index.html and 308s /ui/login → /ui/login/.
The waitForURL predicate used endsWith("/ui/login"), which never matched
the canonicalized URL and timed out after 15s.

This was masked until the build artifacts were regenerated against the
AuthContext fix: the prior bundles still hit the racy redirect path that
fired before proxyBaseUrl was populated, producing /ui/login (no prefix,
no proxy round-trip, no trailing slash) which fortuitously satisfied the
predicate. The first PR to ship the corrected bundle exposed the
assertion bug.

Switch the predicate to includes("/ui/login"); the prefix assertion below
still validates the SERVER_ROOT_PATH preservation that is the actual
contract under test.
2026-05-30 20:00:33 -07:00
michelligabriele
80cf50dedb
fix(v3 limiter): cap no-max_tokens TPM floor at smallest configured limit (#28805) 2026-05-30 19:36:04 -07:00
yuneng-jiang
8b16b61114
chore: update Next.js build artifacts (2026-05-31 02:04 UTC, node v20.20.2) (#29366) 2026-05-30 19:25:42 -07:00
michelligabriele
117136cccc
fix(openai-moderation): wire streaming flags through to unified dispatcher (#27324) 2026-05-30 19:22:25 -07:00
yuneng-jiang
f0ebfb2a1b
fix(ui): break logout redirect loop across origins (#29360)
When the user has visited both the dev UI (e.g. localhost:3000) and the
proxy UI (e.g. localhost:4000) in the same tab, logging out from the dev
origin produced an infinite logout/login redirect.

The proxy-side LoginPage's "is the user still authenticated?" check
was reading getCookie("token"), which falls back to sessionStorage when
document.cookie has no token. The cross-origin clearTokenCookies() call
from the dev origin can clear cookies on the shared hostname, but cannot
reach sessionStorage on the proxy origin (sessionStorage is per-origin),
so the fallback returned a stale token and LoginPage interpreted the
user as logged in, redirecting back to the dev origin. Dev origin then
saw no cookie and redirected to LoginPage, repeating ~20x per second.

This change introduces getCookieFromDocument(), a cookie-only read with
no sessionStorage fallback, and uses it in LoginPage's already-logged-in
check. The HttpOnly-reverse-proxy defense from PR #23532 is unaffected:
storeLoginToken still writes both the JS cookie at /ui and the
sessionStorage backup, and getCookie still falls back for callers that
want the full read path.
2026-05-30 19:02:29 -07:00