Skip to content

feat(decisions): backport #45474, #45811, #45734, #46594, and #46596 to rc/1.106.0 - #46628

Merged
mateo-berri merged 5 commits into
rc/1.106.0from
litellm_backport_45474_45811_45734_46594_46596_rc_1_106_0
Oct 15, 2026
Merged

mateo-berri merged 5 commits into
rc/1.106.0from
litellm_backport_45474_45811_45734_46594_46596_rc_1_106_0

Conversation

@devin-ai-integration

@devin-ai-integration devin-ai-integration Bot commented Oct 15, 2026 •

Copy link
Copy Markdown
Contributor

TLDR

Backport of #45474, #45811, #45734, #46594, and #46596 to rc/1.106.0, so the next rc on this line ships the same change as main

Problem this solves:

How it solves it:

  • Cherry-picks each PR's squash commit from main, original author kept, one commit per PR

User Flow

#45474

Before: a deployment set to model_info.mode: decisions fails its health check

  1. The admin adds typesafe/jev-latest to config.yaml with model_info: {mode: decisions}
  2. GET https://litellm-domain/health?model=that-model returns Mode decisions not supported

After: decisions and evaluation behave the same

  1. The admin adds typesafe/jev-latest with model_info: {mode: decisions}
  2. GET https://litellm-domain/health?model=that-model probes it with the Decisions call and reports it healthy
  3. Deployments with no model_info.mode still report "mode": "evaluation" in /model_group/info, same as today

#45811

Before: a developer judging call recordings through Clef-omni gets answers that never heard the audio

  1. They send POST https://litellm-domain/v1/systemone with "model": "clef-omni", a state, a questions map, and "audio": ["data:audio/wav;base64,..."]
  2. The response is 200 with answers, but usage.input_tokens counts only the text, because the clip never reached Cloudflare
  3. The same clips on POST https://litellm-domain/v1/decisions (OpenAI shape, input plus a questions list) are dropped the same way
  4. Clips sent to a model that cannot take them (clef, clef-flash, an OpenAI decider) also come back 200 with the clips ignored
  5. GET https://litellm-domain/model/info shows no supports_audio_input or supports_video_input for clef-omni

After: the same request judges the audio, and a model that cannot take clips says so

  1. They send the same POST https://litellm-domain/v1/systemone with "audio": [...] and optionally "videos": [...], each clip a data URL or {"content_type": ..., "base64": ...}
  2. The response is 200, the answers reflect what is in the clip, and usage.input_tokens now counts the media
  3. The same body on POST https://litellm-domain/v1/decisions, and on the unversioned /systemone and /decisions routes, reaches Cloudflare with the clips intact
  4. Clips sent to a model that cannot take them return 400 naming audio and videos and the drop_params hint, or, when the deployment or the proxy sets drop_params: true, are dropped (malformed or not) and the text-only request goes out with a 200
  5. A clip that is not audio or video, a data URL whose media type carries parameters, or more than 4 audio or 2 video clips return 400 naming the problem; "audio": null or "videos": null is treated as no clips
  6. GET https://litellm-domain/model/info shows "supports_audio_input": true, "supports_video_input": true on clef-omni and neither flag on clef-flash

#45734

Before: a developer asking clef about a photo through the gateway gets a 400 on /v1/decisions, and on /v1/systemone the photo is silently left out

  1. The admin adds a cloudflare/clef (or cloudflare/clef-flash) model and gives the developer a key
  2. The developer sends POST https://litellm-domain/v1/decisions with an input_text part, an input_image part holding a PNG data URL, and a predicate question
  3. The gateway answers 400 "input_image content parts are not supported because System One providers accept text input only", and Cloudflare is never called
  4. They send the same photo to POST https://litellm-domain/v1/systemone in a top-level images list next to state and questions
  5. That returns 200, but clef answered from the text alone because the photo never reached Cloudflare

After: both requests reach clef with the photo, so its answers are about the image

  1. The admin adds a cloudflare/clef (or cloudflare/clef-flash) model and gives the developer a key
  2. The developer sends POST https://litellm-domain/v1/decisions with an input_text part, an input_image part holding a PNG data URL, and a predicate question
  3. The gateway answers 200 with a probability for the predicate, and Cloudflare got the photo in its images field
  4. They send the same photo to POST https://litellm-domain/v1/systemone in a top-level images list, as a data URL, a {content_type, base64} object, or an https URL the gateway downloads first
  5. That returns 200 with an answer about the photo, and the same request to a text-only decision model answers 400 naming images and drop_params

#46596

Before: a developer on Jev 1.14 cannot send an image, a box question, or long context through the proxy

  1. They send POST https://litellm-domain/v1/systemone to jev-1.14.0 with an image in assets and the images header
  2. A box question gets 400 "Input tag 'box' ... does not match any of the expected tags", on /v1/decisions too
  3. Without the box question they get 200, but the image never reached Jev, so "is there a red square" on a red square scores 0.23
  4. A 240k-token state with the long-context header still gets 400 max_tokens_exceeded

After: the same requests reach Jev 1.14 with the image, the box question, and the header

  1. They send the same POST https://litellm-domain/v1/systemone with the image in assets and the images header
  2. The box comes back as {"type": "box", "box": {"top": 0.11, "bottom": 0.52, "left": 0.49, "right": 0.82}, "confidence": 0.94}, and /v1/decisions with an input_image part works too
  3. The yes/no question now scores 0.99
  4. The long state with the header returns 200, and an image without the header or a box to jev-1.13.0 gets 400, or a drop with drop_params

Backport checklist

  • feat(decisions): accept decisions as a model mode alongside evaluation #45474 feat(decisions): accept decisions as a model mode alongside evaluation (#45474), cherry-picked from 4c532a5, same change as on main
  • feat(decisions): support Clef-omni audio and video #45811 feat(decisions): support Clef-omni audio and video (#45811), cherry-picked from a86ad9e, adapted to the line in tests/unit/decisions/test_main.py
  • feat(decisions)!: send images to Cloudflare Clef through its images field #45734 feat(decisions)!: send images to Cloudflare Clef through its images field (#45734), cherry-picked from 2f3ccbe, same change as on main
  • fix(cost): price typesafe/jev-1.14.0 #46594 fix(cost): price typesafe/jev-1.14.0 (#46594), cherry-picked from 9d72bae, same change as on main
  • feat(typesafe): support Jev 1.14 images, box questions, and long-context headers #46596 feat(typesafe): support Jev 1.14 images, box questions, and long-context headers (#46596), cherry-picked from 3fec507, adapted to the line in litellm/proxy/_lazy_openapi_snapshot.json, tests/integration/_support/timing.py, tests/unit/decisions/test_main.py
  • No version bump (rc line)
  • Importer scan: no name the picks dropped is still imported on the line
  • Picked tests: 3166 passed on the line in tests/unit/decisions/test_main.py, tests/unit/litellm_core_utils/test_health_check_helpers.py, tests/unit/litellm_core_utils/test_image_handling.py, tests/unit/llms/base_llm/decisions/test_base_decisions_transformation.py, tests/unit/llms/bedrock/chat/chat_completions/test_bedrock_chat_completions_transformation.py, tests/unit/llms/openai/decisions/test_openai_decisions_transformation.py, tests/unit/proxy/decisions_endpoints/test_endpoints.py, tests/unit/proxy/health_endpoints/test_health_endpoints.py, tests/unit/proxy/pass_through_endpoints/llm_provider_handlers/test_typesafe_passthrough_logging_handler.py, tests/unit/proxy/pass_through_endpoints/test_llm_pass_through_endpoints.py, tests/unit/proxy/test_litellm_pre_call_utils.py, tests/unit/systemone/test_main.py, tests/unit/test_model_prices_schema.py, tests/unit/test_typesafe_model_metadata.py, tests/unit/test_utils.py, tests/unit/types/test_types_utils.py, tests/unit/test_constants.py, tests/unit/llms/custom_httpx/test_llm_http_handler.py, tests/unit/test_main.py, tests/unit/proxy/pass_through_endpoints/test_llm_passthrough_endpoints.py, collected but not run here: tests/integration/management/test_model_health_check.py, tests/integration/providers/test_cloudflare_clef_images_chaos.py, tests/integration/providers/test_cloudflare_clef_images_wire.py, tests/integration/providers/test_cloudflare_clef_omni_media_chaos.py, tests/integration/providers/test_cloudflare_clef_omni_media_wire.py, tests/integration/providers/test_decisions_openai_format_wire.py, not run here: ui/litellm-dashboard/src/components/provider_info_helpers.test.tsx, ui/litellm-dashboard/src/lib/decisionModels.test.ts, the picks change litellm-rust/, and this tool runs no cargo tests
  • gauntlet-mini and the grype sweep were skipped on this line for speed on Mateo's call, the e2e leg on Kerry's

Pre-Submission checklist

Please complete all items before asking a LiteLLM maintainer to review your PR

  • I have added meaningful tests
  • The handful of test files covering my change pass locally
  • My PR passes all required CI/CD checks (e.g., lint, schema.d.ts sync check, etc.)
  • My PR's scope is as isolated as possible; it only solves 1 specific problem
  • Every automated review on my PR's latest commit has finished, and I have addressed or replied to each of its findings before requesting a maintainer review

Screenshots / Proof of Fix

Live proof ran on main at the source tip of #46596 (ee9e86a), a 2-worker proxy on port 4046 with a real TypeSafe key from the Shared vault, before the merge, plus SDK legs at 3fec507

  1. POST /v1/systemone, jev-1.14.0, TypeSafe-Danger-Zone-Images: true, 512x512 PNG asset plus a box question answered 200 with a box answer (confidence 0.85)
  2. The same request without the header answered 400 (TypeSafe experimental-feature error for images, LiteLLM unsupported-parameter error for the box)
  3. jev-1.13.0 with a box question answered 400 without drop_params and 200 with a refusal slot under drop_params
  4. POST /typesafe/v1/systemone with the header answered 200 with the box answer, without it 400, so the pass-through forwards only TypeSafe-Danger-Zone-*
  5. POST /v1/decisions with an input_image part (standard and URL-safe base64) and a box question answered 200 (predicate 0.97, box 0.85 and 0.89)

On this line the picked unit tests (3166) pass against the line's own venv, and the e2e leg was skipped on Kerry's call since the change is self-contained

Type

🆕 New Feature

Caveats (if any)

Only on this line

Copied from #45474

Low

  • A config that sets model_info.mode: decisions and then runs on a proxy older than this PR still fails /health with Mode decisions not supported. Only configs that opt in can hit this
  • The new decisions rows will return Mode decisions not supported from /health on proxies older than this PR. Real /v1/decisions and /v1/systemone calls to them still work, since mode only picks the health probe
  • Lens (BerriAI/lens) matches mode == "evaluation" exactly, so it needs its own change before it lists decisions models. Its bundled cost map snapshot also parses with a pinned litellm-model-catalog, so refreshing that snapshot after decisions rows land needs the pin bumped past this PR
  • The Add Model form still writes evaluation, so a model added through the UI keeps working if the proxy is rolled back
  • The auto-router's dependency role: "evaluation" is a different concept and is unchanged

Copied from #45811

Medium

Low

  • audio and videos on /v1/decisions are a LiteLLM extension, not an OpenAI field
  • Cloudflare's decoded-byte, duration, and combined-size limits are not pre-checked, so an oversize clip surfaces as Cloudflare's own error
  • A data URL whose media type carries parameters, or one that is uppercase, line-wrapped, or missing ;base64, is refused with the pattern message rather than a hint to use the object form, which takes parameters
  • Whether a model takes clips now comes from the cost map, so a proxy on an older remote map (or a custom local map without the flags) refuses clips on Clef-omni until its map carries them
  • A text-only Decisions request now reads the two media flags from the cost map as well (up to four lookups, each caught for an unmapped custom model), on top of the pricing lookup it already made
  • supports_video_input now shows in get_model_info and GET /model/info for every cost-map entry that carries it, next to supports_audio_input, which was already surfaced
  • A misspelled clip key (audios, video) passes as an unknown key instead of a 400, the same as any unknown key on a Decisions body today
  • A deployment that opts into the media flags through model_info on a map without the Clef-omni rows has to use the canonical cloudflare/@cf/cloudflare/clef-omni name, since the gate reads that key: on the short cloudflare/clef-omni alias the flags show in GET /model/info but clips still answer the 400
  • Base64 clips land in spend logs when request logging is on and reach custom callbacks in the raw request body, the same as base64 input_image today
  • The docs page for Clef-omni media goes to the docs repo as a follow-up

Copied from #45734

Medium

  • Callers on released versions that send images to text-only decision models go from 200 to 400
    • The same 400 hits images next to input on any model, and router fallbacks to text-only deployments. drop_params brings back the 200 with the images dropped, and the title carries !
  • OpenAI decision models now receive and bill System One images
    • This is a declared product change. Luna input tokens go from 120 to 125 per call with one small image
  • Text next to an image in an input_image message no longer sits next to it on Cloudflare
    • Cloudflare's images field has no positions, so a label such as "screen 2:" goes in the state and its image in images. OpenAI keeps the parts in place

Low

  • Mixed Cloudflare and OpenAI model groups answer some image requests differently per deployment
    • Only Cloudflare checks the 4 image, 4 MiB, 8 MiB and image type limits, so the router's pick decides whether the same request passes
  • Remote images are downloaded in full before the size check
    • The shared image downloader holds up to 50 MB per image before the 400, the same as chat completions on main
  • Raw request logs carry the downloaded image bytes, not the caller's URL
    • Logging callbacks and spend logs keep the URL in input. Opt-in raw request logging and OTEL raw request spans record the wire body, the same as chat completions after it inlines an image
  • The caller's timeout bounds each image download, not the whole request
    • Sync calls download images one after another, as chat completions does on main, so 4 slow images can take up to 5 times the timeout. httpx also applies it per read, so a host that keeps sending bytes slowly is not cut off at the timeout
  • Image URL query keys without = are dropped on download
    • This comes from the shared HTTP handler on main, not from this PR
  • The docs still say Cloudflare decision models take no images
  • The gpt-6-luna billing control cell is red on main and on this PR

Copied from #46596

Low

  • The Admin UI playground has no form for assets or box questions, a separate UI change
  • Docs for these options go in a separate litellm-docs PR

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

Note

High Risk
Large, behavior-changing Decisions surface (multimodal payloads, stricter 400s vs silent drops, remote image downloads, and opt-in danger-zone headers) on a critical proxy routing path.

Overview
Backports several main-line Decisions changes onto the rc line: decisions as a first-class model mode (with evaluation still treated the same for health checks), plus a large expansion of what Decisions/System One requests can carry and how providers accept them.

The Decisions call path now validates and transforms images (input_image / images), assets, audio, and videos, with provider capability checks and drop_params stripping (or 400 / UnsupportedParamsError when dropping would leave no input or questions). Box question/answer types are wired through IR, OpenAI, System One, proxy OpenAPI, and TypeSafe. Cloudflare Clef gets image limits, remote URL inlining, and an images payload; Clef-omni gets audio/video on System One and OpenAI-shaped routes. TypeSafe Jev 1.14 uses typesafe-danger-zone-* headers (including proxy pass-through) to enable assets and box questions, converting OpenAI message images into referenced assets.

Supporting updates include supports_video_input / supports_box_questions, image URL fetch timeouts, separate logged vs wire bodies when images are inlined, model-catalog Decisions mode, and cost-map entries for clef-omni and jev-1.14.0.

Reviewed by Cursor Bugbot for commit f3904e2. Bugbot is set up for automated code reviews on this repo. Configure here.

devin-ai-integration Bot and others added 5 commits October 15, 2026 06:21
#45474)

* refactor(decisions): rename the evaluation model mode to decisions

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

* refactor(decisions): canonicalize the health check mode without rebinding

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

* refactor(decisions): replace canonical_model_mode with is_decisions_model_mode

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

* fix(decisions): preserve evaluation mode compatibility

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

* chore: drop the rebuilt dashboard bundle from this PR

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

* style(dashboard): format decision mode helper

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

---------

Backport of #45474 to rc/1.106.0
Cherry-picked from 4c532a5 (main)

Co-authored-by: kerry <kerry@berri.ai>
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
* feat(decisions): support Clef-omni audio and video

* fix(decisions): accept Clef-omni media types with parameters and cover the proxy routes

The clip patterns now mirror Cloudflare's input schema, so a data URL or
content_type carrying parameters like audio/webm;codecs=opus is accepted.
The four proxy routes get media tests of their own, the backup cost map
is synced with the new Clef-omni rows, and the docs page moves to the
docs repo as a follow-up.

* fix(decisions): refuse parameterized media-type data URLs and refresh the OpenAPI snapshot

Cloudflare answers 422 to a data URL whose media type carries parameters even though its schema only requires the data:audio/ prefix, so LiteLLM now refuses those with a 400 before the call. The object form keeps passing parameters through, which Cloudflare accepts. The lazy OpenAPI snapshot and the dashboard API types are regenerated for the new audio and videos fields

* fix(decisions): gate media by cost-map flags, treat null clips as none, drop unsupported clips before validation

* fix(decisions): keep the SDK's positional order and gate media flags on evaluation-mode models

* fix(decisions): gate media on both decisions model modes and move the audit cells onto the harness helpers

* test(decisions): cover the Fireworks System One router in the media refusal cells

---------

Backport of #45811 to rc/1.106.0
Cherry-picked from a86ad9e (main)

Co-authored-by: moyai-devin-berriai[bot] <336287033+moyai-devin-berriai[bot]@users.noreply.github.com>
Co-authored-by: mateo-berri <277851410+mateo-berri@users.noreply.github.com>
…ield (#45734)

* feat(decisions): send images to Cloudflare Clef

OpenAI-format input_image parts and the System One images field now reach Cloudflare clef and clef-flash in its images field, with remote URLs downloaded and inlined first. Providers that cannot take images drop them under drop_params and answer 400 otherwise.

* fix(decisions): follow drop_params for images and use the call timeout for image downloads

* fix(decisions): drop a malformed images entry on its own under drop_params

* fix(decisions): refuse images next to input whatever drop_params says

* fix(decisions): bound clef image fetches, honor drop_params for images, and log caller URLs

Refuse more than 4 images for Cloudflare clef before any download, keep the
caller's timeout as one deadline across image fetch retries, accept images
next to input under drop_params, validate image strings and objects, and pass
the caller's image URLs (not inlined bytes) to logging callbacks.

* fix(decisions): check input_image URLs and clef image sizes

* fix(decisions): accept data URL media type parameters and check clef image types

* fix(decisions): count clef images after dropping unsupported types and flag clef vision

---------

Backport of #45734 to rc/1.106.0
Cherry-picked from 2f3ccbe (main)

Co-authored-by: mateo-berri <277851410+mateo-berri@users.noreply.github.com>
* fix(cost): price typesafe/jev-1.14.0

TypeSafe released jev-1.14.0 on 2026-10-14 at the same price as jev-1.13.0
($0.042 per 1M input tokens, output free; https://docs.typesafe.ai/models).
Without an entry, calls through the TypeSafe pass-through log a cost of 0:
TypeSafePassthroughLoggingHandler prices from litellm.model_cost["typesafe/<model>"],
and a deployment's model_info price is registered under its model id only.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(cost): add max_input_tokens to the typesafe jev rows

---------

Backport of #46594 to rc/1.106.0
Cherry-picked from 9d72bae (main)

Co-authored-by: Mike Hyams <241361536+hyamie@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: devin-ai-integration[bot] <158243242+devin-ai-integration[bot]@users.noreply.github.com>
…ext headers (#46596)

* feat(typesafe): support Jev 1.14 images, box questions, and long-context headers

* fix(cost): drop the typesafe/jev-1.14.0 entry main already prices

* fix(typesafe): send images only with the images header and box questions only to models that answer them

TypeSafe takes assets and input_image parts only when the request carries
TypeSafe-Danger-Zone-Images: true, so without it they follow drop_params like
any other provider that cannot take images. Box support now comes from a
supports_box_questions cost-map flag set on jev-1.14.0 and jev-preview, so
jev-1.13.0 and jev-latest refuse or drop a box question before the call. A
malformed provider_specific_header answers 400 instead of 500.

* fix(typesafe): allow null box confidence and validate asset references and base64

* fix(typesafe): gate box questions on the images header, drop unreadable assets under drop_params, forward opt-in headers on the pass-through

---------

Backport of #46596 to rc/1.106.0
Cherry-picked from 3fec507 (main)

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

greptile-apps Bot commented Oct 15, 2026

Copy link
Copy Markdown
Contributor

Automatic reviews are disabled for this repository.

@CLAassistant

CLAassistant commented Oct 15, 2026 •

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 4 committers have signed the CLA.

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

@mateo-berri

Copy link
Copy Markdown
Contributor

@litereview code-review

@mateo-berri

Copy link
Copy Markdown
Contributor

bugbot run

@litereview

litereview Bot commented Oct 15, 2026

Copy link
Copy Markdown

✅ code-review

5/5 · Ready for human review

Scope: full · Full PR review.

Completed · Some checks not run.

No correctness findings.

The title needs a breaking-change marker. This backport includes #45734 (feat(decisions)!:), which changes images sent to a text-only decision model from a silent drop with 200 to a 400 unless drop_params is set. The PR body explains the impact and the drop_params migration, but the title feat(decisions): ... has no !. Use feat(decisions)!: so rc/1.106.0 release notes flag it.

Checks and execution details
  • Passed · Real testing evidence (required): Scope applies. The PR changes translation code in litellm/llms/{base_llm,openai,typesafe,cloudflare}/decisions/transformation.py and litellm/litellm_core_utils/prompt_templates/image_handling.py. It adds images, assets, audio, videos, box questions and answers, and TypeSafe danger-zone headers.

Evidence:

  • Manual E2E proof on the source PRs.

  • Same code on main and this backport. I compared the backport against raw.githubusercontent.com/BerriAI/litellm/3fec5075fa. The backport and main have byte-identical typesafe, openai and cloudflare decisions transformations, plus image_handling.py, types/decisions.py, decisions/main.py, systemone/main.py and decisions_endpoints/endpoints.py. The only differences in base_llm/decisions/transformation.py and decisions/call.py are main-only resolve_connection refactors that the release-candidate line lacks.

  • Proxy-level wire tests. New tests in tests/integration/providers/ assert outbound bodies through a scripted upstream.

  • Results. The head commit's GitHub status is buildkite/e2e-tests: success, and the unit-test check passed.

  • Passed · Picked unit tests (local) (optional): uv sync --frozen --all-extras --group dev, then uv run pytest -n 8 across these paths:

  • tests/unit/decisions/test_main.py

  • tests/unit/systemone/test_main.py

  • tests/unit/llms/base_llm/decisions

  • tests/unit/llms/openai/decisions

  • tests/unit/litellm_core_utils/test_image_handling.py

  • tests/unit/litellm_core_utils/test_health_check_helpers.py

  • tests/unit/proxy/decisions_endpoints

  • tests/unit/test_model_prices_schema.py

  • tests/unit/test_typesafe_model_metadata.py

  • tests/unit/types/test_types_utils.py

  • tests/unit/proxy/test_litellm_pre_call_utils.py

Result: 1006 passed.

  • Passed · Backport fidelity vs upstream squash commits (optional): I downloaded upstream commit diffs 4c532a5, a86ad9e, 2f3ccbe, 9d72bae and 3fec507 and compared the changed product files against main at 3fec507. Every difference traces to unrelated main-only work. Examples: resolve_connection, AGENTIC_LOOP_KWARG_NAMES, and callback-registration refactors in litellm/utils.py. The decisions/evaluation health handler path (is_decisions_model_mode) matches main.
  • Not run · Integration wire/chaos tests (local) (optional): Not run locally. These tests need the CircleCI harness (proxy, Postgres, Redis and scripted upstream). The head commit shows buildkite/e2e-tests: success.
  • Not run · Rust model-catalog tests (optional): I did not run cargo test for litellm-rust/crates/model-catalog. The rust-test check was still in progress when I queried GitHub.

View review · Reviewed f3904e2e65b7

@cursor cursor Bot left a comment

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.

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit f3904e2. Configure here.


def ir_to_openai_request(model: str, request: DecisionsIRRequest) -> Mapping[str, object] | UnsupportedDecisionsRequest:
if request.audio or request.videos:
return UnsupportedDecisionsRequest(reason="audio/video input is not supported by this Decisions provider")

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.

OpenAI parser drops box answers

Low Severity

The OpenAI decisions response parser never matches a box question to a box answer, so a valid box result is turned into a refusal. Request conversion and outbound formatting already handle box questions, and the response adapter already accepts OpenAIBoxAnswer, but inbound _ir_answer has no box case. Any OpenAI-format provider that returns a box answer will look like it refused the question.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit f3904e2. Configure here.

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.

Real but pre-existing, this file is byte-identical to main after #46596. Fixing on main first so it rides the next rc, not this pick

@mateo-berri mateo-berri left a comment

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.

LGTM

@mateo-berri
mateo-berri merged commit 6468f7f into rc/1.106.0 Oct 15, 2026
10 checks passed
@mateo-berri
mateo-berri deleted the litellm_backport_45474_45811_45734_46594_46596_rc_1_106_0 branch October 15, 2026 06:58
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