Skip to content

chore(release): backport #33244, #33592, #33554, #33853 to stable/1.92.x and cut 1.92.1 - #33892

Merged
yuneng-berri merged 8 commits into
stable/1.92.xfrom
litellm_backport_1_92_x_bp-192x-0718
Jul 19, 2026
Merged

chore(release): backport #33244, #33592, #33554, #33853 to stable/1.92.x and cut 1.92.1#33892
yuneng-berri merged 8 commits into
stable/1.92.xfrom
litellm_backport_1_92_x_bp-192x-0718

Conversation

@yuneng-berri

@yuneng-berri yuneng-berri commented Jul 19, 2026

Copy link
Copy Markdown
Contributor

Relevant issues

Backports four staging fixes onto stable/1.92.x and cuts 1.92.1 (v1.92.0 is already published on DockerHub and GHCR, so the tip version must move). Two of the picks repair the shipped Docker images: #33592 restores the /app/litellm-proxy-extras source dir that downstream migration jobs point prisma migrate deploy at (without it those jobs exit green while never migrating), and #33853 bakes the prisma CLI and engines at /opt/prisma so fresh-database migrations work for any runtime uid, offline, including readOnlyRootFilesystem deployments (the failure modes behind #33650 and #24554). #33244 drops a pinned temperature when adaptive thinking is downgraded for pre-4.6 Anthropic models on the /v1/messages passthrough, so clients like Claude Code stop receiving 400s. #33554 adds skip_unscannable_attachments to the Model Armor guardrail and removes the per-request attachment count cap

The original set also carried #33721 and #33864 (the /v1/models token-limit rework). Deep verification found the listing regressed on this branch for deployments carrying a malformed configured token limit, through the registered cost-map path (details in the PR comments), so that pair was dropped and returns in a later patch once the upstream hardening lands. The live replay on the rebuilt branch confirms the listing behaves exactly as 1.92.0 does today

On top of the picks: routine dependency maintenance (lock-only bumps of mcp to 1.28.1 and soupsieve to 2.8.4; each lock regeneration moved exactly the target package and nothing else), then the version bump and lock refresh

Linear ticket

What is included

Cherry-picks in staging merge order, each with a -x footer pointing at its staging squash commit:

Then four tool-generated commits: chore(deps): bump mcp to 1.28.1, chore(deps): bump soupsieve to 2.8.4 (both confined to uv.lock), bump: version 1.92.0 -> 1.92.1 (pyproject only), and chore: refresh uv.lock for 1.92.1 (moves only litellm's own entry)

Adaptation notes (one pick is not byte-identical to its staging commit)

Known noise on this line

Pre-existing on the untouched stable/1.92.x tip, unrelated to the picks, so reviewers can discount them in CI:

  • tests/test_litellm/proxy/test_proxy_utils.py::test_get_custom_url fails at the baseline (before any pick) and identically after
  • The full mirrored suite has 2 pre-existing collection errors from test-module basename collisions (tests/test_litellm/proxy/client/test_models.py, tests/test_litellm/realtime_api/test_main.py)

Pre-Submission checklist

  • I have added meaningful tests (each pick carries its own tests; all pass on this line)
  • My PR passes all CI/CD checks (e.g., lint, format, unit tests)
  • My PR's scope is as isolated as possible; it only solves 1 specific problem (one patch release for this line)

Screenshots / Proof of Fix

Targeted test set (the five test files the original picks touch, run on this line): baseline on the untouched tip was 269 passed, 1 failed (the known-noise failure above); on the final branch it is 280 passed and the same single pre-existing failure. Zero new failures; every test the remaining picks add passes on this line. ruff check and ruff format --check are clean on every touched module

Live proxy on this branch (config includes a deployment with model_info: {max_input_tokens: "128,000"} to pin the listing contract):

GET /v1/models                       -> HTTP 200; malformed deployment listed with limits omitted,
                                        identical to the 1.92.0 baseline capture
POST /v1/chat/completions (real call) -> HTTP 200

Reproducer replay for #33244 (claude-sonnet-4-5, thinking enabled, temperature: 0, real Anthropic call). Before the pick, on the untouched tip:

HTTP 400
"`temperature` may only be set to 1 when thinking is enabled. ..."

After the pick, same request:

HTTP 200, stop_reason end_turn, thinking block present

Docker picks, verified by building both changed images from this branch and running them (throwaway local tags, removed after):

docker build -f Dockerfile .                  -> OK (includes #33853's baked-layout build asserts)
docker build -f docker/Dockerfile.database .  -> OK
main image:  /app/litellm-proxy-extras/litellm_proxy_extras/schema.prisma present, 131 migration dirs   (#33592)
main image:  /opt/prisma CLI executable as uid 12345 with HOME overridden                               (#33853)
database image, fresh Postgres, internal-only network, --user 12345:12345, HOME=/tmp:
  "Using custom Prisma CLI at /opt/prisma/binaries/node_modules/.bin/prisma"
  130 migrations applied, liveliness in ~25s, POST /team/new created a team against the fresh DB        (#33853)

Dependency maintenance evidence: uv lock --upgrade-package moved exactly mcp 1.26.0 -> 1.28.1 and soupsieve 2.8.3 -> 2.8.4 (nothing else), and the synced environment resolves both at their targets

Remaining deep verification (adversarial behavioral gauntlet and the full-suite regression delta against a pristine baseline) is in progress; this body will be updated with the results

Type

🐛 Bug Fix
🚄 Infrastructure

Changes

Four cherry-picks onto stable/1.92.x (listed above), two lock-only dependency maintenance commits, and the 1.92.0 -> 1.92.1 version bump with its lock refresh

QA runbook

  1. Check out this branch and run uv sync --frozen --all-groups --all-extras
  2. uv run pytest tests/test_litellm/proxy/guardrails/guardrail_hooks/test_model_armor.py tests/test_litellm/llms/anthropic/experimental_pass_through/messages/test_anthropic_messages_effort.py -q; expect all green
  3. Start a proxy with an Anthropic pre-4.6 model (e.g. claude-sonnet-4-5) and POST /v1/messages with {"model": "claude-sonnet-4-5", "max_tokens": 1100, "thinking": {"type": "enabled", "budget_tokens": 1024}, "temperature": 0, ...}: expect 200 (it 400s before this PR)
  4. docker build -f Dockerfile -t litellm-192x-qa:main . then docker run --rm --user 12345:12345 -e HOME=/tmp --entrypoint sh litellm-192x-qa:main -c 'ls /app/litellm-proxy-extras/litellm_proxy_extras/schema.prisma && test -x /opt/prisma/binaries/node_modules/.bin/prisma && echo OK'

Final Attestation

  • The tests check the right things, including the edge cases, and regressions in the respective real-world customer use-cases are not possible after this PR

devin-ai-integration Bot and others added 3 commits July 18, 2026 16:55
…ading adaptive thinking for pre-4.6 models (#33244)

* fix(anthropic/passthrough): drop temperature and cap thinking budget when downgrading adaptive thinking for pre-4.6 models

* test(anthropic/passthrough): use sufficient max_tokens for reasoning_effort thinking mapping

* fix(anthropic/passthrough): drop incompatible temperature when downgrading adaptive thinking for pre-4.6 models

Narrow the fix to the temperature reconciliation; the reasoning_effort
budget cap is reverted because the live translation grid relies on
budget_tokens >= max_tokens to reject unsupported effort tiers
(xhigh/max) on budget-mode models, so capping turned those 400s into
200s.

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
(cherry picked from commit 71dffc1)
#33592)

* fix(docker): restore litellm-proxy-extras source dir in runtime images

#30243 narrowed the runtime stage to an allowlist COPY, which dropped
/app/litellm-proxy-extras from the published images. Downstream
migration jobs point prisma migrate deploy at that path; with the
schema gone (or a schema with no adjacent migrations dir, where prisma
exits 0 without applying anything) those jobs went green while never
migrating the database. Restore the folder in all three runtime stages
and assert in image-scan that the schema and a non-empty migrations dir
ship at the source path

* chore(ci): drop image-scan migration-assets assertion

(cherry picked from commit 111d447)
…attachments and remove the attachment count cap (#33554)

* fix(model_armor): add skip_unscannable_attachments to allow reference-only attachments through

* fix(model_armor): wire skip_unscannable_attachments through guardrail config

* fix(model_armor): make max_file_attachments configurable and scan overflow instead of dropping

* fix(model_armor): remove the per-request attachment count cap and scan all attachments

---------

Co-authored-by: yucheng <yucheng@berri.ai>
(cherry picked from commit 0d7b0f7)
@yuneng-berri
yuneng-berri requested a review from a team July 19, 2026 00:03
@CLAassistant

Copy link
Copy Markdown

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you all sign our Contributor License Agreement before we can accept your contribution.
1 out of 2 committers have signed the CLA.

✅ yuneng-berri
❌ devin-ai-integration[bot]
You have signed the CLA already but the status is still pending? Let us recheck it.

@yuneng-berri
yuneng-berri marked this pull request as draft July 19, 2026 00:07
@yuneng-berri

Copy link
Copy Markdown
Contributor Author

Converting to draft: the deep-verification pass found that GET /v1/models returns 500 on this branch when a configured deployment carries a malformed token limit, for example model_info: {max_input_tokens: "128,000"}. The router registers deployment model_info into the cost map at startup, so the malformed string comes back through litellm.get_model_info and hits the bare int() coercion introduced in the picked #33721 (create_model_info_response); #33864 hardened the router-deployment lookup branch but not this cost-map branch. Before the picks the listing tolerated the same config, so this is a regression the backport would ship

The same coercion exists on litellm_internal_staging (litellm/proxy/utils.py:6133), so the fix belongs upstream first: treat malformed cost-map values as absent, mirroring what #33864 did for configured deployment limits. Once that lands on staging it gets cherry-picked here and this PR leaves draft

metadata["_model_armor_status"] = "blocked"
raise self._unscannable_block_error(reason)

if len(attachments) > MAX_FILE_ATTACHMENTS_PER_REQUEST:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Medium: Unbounded guardrail request amplification

An authenticated user can include hundreds of small inline attachments in one request and cause a separate Model Armor API call for each attachment. The proxy accounts for this as one client request, so removing this bound permits guardrail quota exhaustion and prolonged worker occupancy; retain a configurable per-request cap or enforce an equivalent fan-out budget before scanning.

@veria-ai

veria-ai Bot commented Jul 19, 2026

Copy link
Copy Markdown
Contributor

PR overview

This PR backports several changes to the stable/1.92.x branch and prepares the 1.92.1 release. The affected proxy guardrail code includes Model Armor handling for scanning request content and inline attachments.

There is one open security concern in the Model Armor guardrail path. An authenticated user can submit many small inline attachments in a single request, causing unbounded downstream Model Armor scan calls while the proxy accounts for it as only one client request. This creates a practical quota-exhaustion and worker-occupancy risk until a per-request cap or equivalent fan-out budget is enforced.

Open issues (1)

Fixed/addressed: 0 · PR risk: 6/10

@greptile-apps

greptile-apps Bot commented Jul 19, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This is a backport release (v1.92.1) cherry-picking four targeted fixes from staging onto stable/1.92.x, plus routine lock-only dependency bumps for mcp and soupsieve.

Confidence Score: 5/5

All four cherry-picks are narrowly scoped bug fixes with matching tests; no new logic paths affect the auth layer, DB, or routing hot path.

The temperature-drop logic is correctly placed after all thinking-translation steps, handles all model variants (adaptive pass-through, legacy enabled, Opus 4.5 effort), and is covered by six unit tests with no network calls. The Prisma baking adds build-time assertions that would catch a broken image before it ships. The skip_unscannable_attachments change introduces a secure-by-default opt-in flag with proper kwarg plumbing and full test coverage. No pre-existing guards were removed without replacement, and no auth, DB, or routing paths were touched.

No files require special attention.

Important Files Changed

Filename Overview
litellm/llms/anthropic/experimental_pass_through/messages/transformation.py Adds _drop_incompatible_temperature_for_thinking staticmethod that removes non-1 temperature values when non-adaptive models have extended thinking enabled, fixing Anthropic 400 errors for clients like Claude Code that pin temperature.
litellm/proxy/guardrails/guardrail_hooks/model_armor/model_armor.py Removes the MAX_FILE_ATTACHMENTS_PER_REQUEST=10 cap and introduces skip_unscannable_attachments opt-in param that lets reference-only attachments pass through without blocking, while API errors still respect fail_on_error.
litellm/proxy/guardrails/guardrail_hooks/model_armor/file_scanning.py Removes the MAX_FILE_ATTACHMENTS_PER_REQUEST constant; all other scanning logic unchanged.
litellm/proxy/guardrails/guardrail_hooks/model_armor/init.py Forwards skip_unscannable_attachments from LitellmParams to ModelArmorGuardrail constructor; straightforward plumbing change.
litellm/types/guardrails.py Adds skip_unscannable_attachments: Optional[bool] field to BaseLitellmParams with a secure default of False.
Dockerfile Bakes Prisma CLI and engines under /opt/prisma with fixed env vars, adds build-time assertions, and restores the litellm-proxy-extras copy; drops the brittle /root/.cache copy approach.
docker/Dockerfile.database Same Prisma baking and litellm-proxy-extras fix as the main Dockerfile, applied to the database-focused image.
docker/Dockerfile.non_root Adds the missing litellm-proxy-extras copy to the non-root image; Prisma setup remains via its existing /app/.cache path.
tests/test_litellm/llms/anthropic/experimental_pass_through/messages/test_anthropic_messages_effort.py Adds six new pure-transform unit tests covering temperature-drop scenarios: haiku downgrade, temperature=1 preservation, non-reasoning model passthrough, adaptive model passthrough, opus-4-5 effort, and reasoning_effort alias.
tests/test_litellm/proxy/guardrails/guardrail_hooks/test_model_armor.py Replaces the attachment-count-cap test with a no-cap test; adds six new tests covering skip_unscannable_attachments behavior for file_id, gs:// URIs, API error passthrough, config forwarding, and default value.
pyproject.toml Version bump 1.92.0 -> 1.92.1.

Reviews (2): Last reviewed commit: "chore: refresh uv.lock for 1.92.1" | Re-trigger Greptile

Comment thread litellm/router.py Outdated
Comment on lines +8328 to +8344
deployment = self.get_deployment_by_model_group_name(model_group_name=model_name)
if deployment is None:
return (None, None)

def _as_int(value: object) -> "int | None":
if value is None or isinstance(value, bool):
return None
try:
return int(value)
except (TypeError, ValueError):
return None

model_info = deployment.model_info
return (
_as_int(model_info.get("max_input_tokens")),
_as_int(model_info.get("max_output_tokens")),
)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Multi-deployment model groups expose only the first deployment's limits

get_deployment_by_model_group_name always returns indices[0], so when a model group has two deployments with different model_info.max_input_tokens values, /v1/models will silently report whichever deployment happens to be first in the list. For example, if one deployment is a 128k context replica and another is an 8k replica under the same group name, clients that rely on the reported limit for sizing requests could receive a limit that is too large for the deployment they're actually routed to. A comment or docstring clarifying that this returns the first deployment's limits (not the minimum or representative value across the group) would prevent operators from being surprised by this.

…migrations work for any uid offline (#33853)

* fix(docker): bake prisma CLI and engines at a fixed path so fresh-DB migrations work for any uid offline

The runtime image shipped the prisma CLI and engines under /root/.cache, the
default HOME-derived prisma-python cache location. Any deployment whose
runtime HOME is not /root (kubernetes runAsUser, docker --user, HOME
overrides) missed that cache on a fresh database, fell back to a nodeenv
Node download that crashes on Wolfi (libatomic.so.1), and started the proxy
with zero tables while every DB-backed endpoint returned 500

The bake now lives at /opt/prisma, a path no HOME resolution or cache
volume mount can shadow. The builder records the engine paths there at
generate time, and the runtime stage pins PRISMA_BINARY_CACHE_DIR,
PRISMA_CLI_PATH, PRISMA_CLI_QUERY_ENGINE_TYPE=binary and
PRISMA_OFFLINE_MODE so both litellm-proxy-extras and prisma-python resolve
the baked CLI and engines directly. prisma migrate deploy on a fresh
database now needs no npm and no network access for any runtime uid,
including readOnlyRootFilesystem deployments

Verified against live containers: fresh and existing databases as root,
uid 12345, HOME overridden, on an internal-only docker network, and with
a read-only root filesystem all migrate and serve /team/new successfully

Fixes #33650, #24554

* chore(docker): fail the image build if the baked prisma CLI layout drifts

Asserts the baked CLI shim is executable and its entrypoint exists in the
runtime stage after the COPY and chmod, so a layout change in a future
prisma-python release breaks the image build loudly instead of silently
degrading the migration path at container startup

(cherry picked from commit 567ebcb)
@yuneng-berri
yuneng-berri force-pushed the litellm_backport_1_92_x_bp-192x-0718 branch from df77de0 to e7d3f93 Compare July 19, 2026 01:17
@yuneng-berri yuneng-berri changed the title chore(release): backport #33244, #33592, #33554, #33721, #33853, #33864 to stable/1.92.x and cut 1.92.1 chore(release): backport #33244, #33592, #33554, #33853 to stable/1.92.x and cut 1.92.1 Jul 19, 2026
@yuneng-berri

Copy link
Copy Markdown
Contributor Author

Dropped #33721 and #33864 from this backport and rebased the branch: the deep-verification replay showed GET /v1/models failing on a malformed configured token limit through the registered cost-map path (previous comment has the mechanics). The pair returns in a later 1.92.x patch once the upstream hardening lands on staging; the pending 1.93.0 cut needs that hardening regardless

The four remaining picks do not touch that code path. On the rebuilt branch the live replay shows /v1/models back to the exact 1.92.0 baseline behavior (200, malformed deployment listed with limits omitted) and the #33244 reproducer still fixed (400 on the untouched tip, 200 after the pick). Marking ready for review; the body carries the full evidence, with the gauntlet and full-suite delta results to follow in a body update

@yuneng-berri
yuneng-berri marked this pull request as ready for review July 19, 2026 01:18
@yuneng-berri
yuneng-berri merged commit 96baca0 into stable/1.92.x Jul 19, 2026
6 checks passed
@yuneng-berri
yuneng-berri deleted the litellm_backport_1_92_x_bp-192x-0718 branch July 19, 2026 03:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants