Skip to content

chore(staging): roll oss_staging_04_25_2026 into internal staging (output_config fix + 4 upstream sync fixes) - #26530

Merged
mateo-berri merged 11 commits into
litellm_internal_stagingfrom
litellm_oss_staging_04_25_2026
May 2, 2026
Merged

chore(staging): roll oss_staging_04_25_2026 into internal staging (output_config fix + 4 upstream sync fixes)#26530
mateo-berri merged 11 commits into
litellm_internal_stagingfrom
litellm_oss_staging_04_25_2026

Conversation

@mateo-berri

@mateo-berri mateo-berri commented Apr 25, 2026

Copy link
Copy Markdown
Contributor

Summary

Merge litellm-oss-staging-04-25-2026 into litellm_internal_staging. Headline change is the output_config passthrough fix (PR #26439); four unrelated upstream OSS staging fixes ride along in the same merge.

Headline change: output_config passthrough (PR #26439)

fix(adapters,vertex): pass output_config through to backends that accept it

Closes #23380. Supersedes #23475/#23396/#23706/#22727.

Two silent-drop bugs:

  • Vertex AI Claude (both chat-completion and Messages paths) was unconditionally stripping output_config, hiding Anthropic Structured Outputs from callers who explicitly requested them.
  • /v1/messages/chat/completions adapter was re-merging the raw Anthropic-shaped output_config key into completion kwargs after translation already mapped its meaningful parts to response_format / reasoning_effort, causing 400 "Extra inputs are not permitted" on non-Anthropic backends (Azure, Fireworks, Bedrock Nova).

Fix introduces:

  • Shared leaf-module helper sanitize_vertex_anthropic_output_params (in output_params_utils.py) that strips Vertex-unsupported keys (effort) while preserving format. Lives in its own module to avoid a CodeQL-flagged cyclic import through the parent transformation module.
  • ANTHROPIC_ONLY_REQUEST_KEYS named constant gating the adapter re-merge so output_config doesn't leak past the translator.
  • Adapter translator extension: _translate_output_format_to_openai now reads both top-level output_format and output_config.format with explicit precedence rules.
  • Side fix: extra_kwargs or {}extra_kwargs if extra_kwargs is not None else {} so callers passing an explicit empty dict don't get a default substituted.

Full design notes, Greptile feedback table, and reproduction steps live on PR #26439.

Sync-pulled OSS staging fixes (no design changes here, just rolling forward)

Commit Change Origin PR
98a9005c76 arize._set_usage_outputs handles raw OpenAI Pydantic CompletionUsage (previously assumed dict shape) #26506
f63a6f1b26 Proxy honors LITELLM_LOG=INFO by setting verbose_logger level (was previously a no-op above WARNING) #26401
334aedf2d4 UI Add-Model dropdown shows zai (Z.AI / Zhipu AI) provider #26419 (re-fix of #25482)
e2d0fd9eac Remove duplicate MAX_SIZE_PER_ITEM_IN_MEMORY_CACHE_IN_KB definition (kept the 1024-default one) + Cloudflare Workers AI response_text key fallback for newer Nemotron models #26385

These are individual upstream PRs that already passed their own review; this merge just rolls them into internal staging alongside the output_config fix.

Heads-up for reviewers

  • Greptile P0 on MAX_SIZE_PER_ITEM_IN_MEMORY_CACHE_IN_KB is a false alarm. The e2d0fd9eac commit removed only one of two duplicate definitions; the surviving definition is at litellm/constants.py:85 with default 1024. from litellm.constants import MAX_SIZE_PER_ITEM_IN_MEMORY_CACHE_IN_KB and from litellm.caching.in_memory_cache import InMemoryCache both import cleanly. Verified locally.
  • Greptile P1 on Vertex output_format is legitimate and worth confirming. PR fix(adapters,vertex): pass output_config through to backends that accept it (closes #23380, supersedes #23475/#23396/#23706/#22727) #26439 reverses an assertion in test_vertex_ai_claude_sonnet_4_5_structured_output_fix from "stripped" to "forwarded," based on the claim that Vertex AI now accepts output_format alongside tools/tool_choice. Issue [Bug]: Structured output with claude-sonnet 4.5 VertexAI endpoint #18625 is the only data point and was negative. If Vertex still 400s on the combined payload, the sanitizer needs to be extended to also strip output_format (the helper docstring says it does — the code currently doesn't). Recommend confirming against a live Vertex Claude endpoint before this merges further.

Test plan

dkindlund and others added 7 commits April 24, 2026 11:48
…ept it

Resolves the silent strip of Anthropic Structured Outputs across the
Vertex AI Claude transformation paths and the Anthropic-adapter
re-merge. Consolidates and supersedes four stalled community PRs
addressing overlapping aspects of the same root bug:

- #23475 (Vertex AI Claude blanket-strip removal)
- #23396 (Vertex AI Claude conditional passthrough)
- #23706 (Anthropic adapter exclude output_config from non-Anthropic
  backends)
- #22727 (Anthropic adapter strip output_config for non-Anthropic
  backends)

Closes / addresses: #23380 (Vertex AI Claude output_config drop),
related: #26423, #25079, #24549, #25971, #25957, #26163, #24856.

What was broken
---------------
* Vertex AI Claude paths called ``data.pop("output_config")`` and
  ``data.pop("output_format")`` unconditionally even when Vertex
  accepted those fields. Callers asking for Structured Outputs got a
  200 with prose and never knew the schema constraints had been
  silently dropped (often masked for months by permissive fallback
  parsers).
* The ``/v1/messages`` -> ``/chat/completions`` adapter
  (``LiteLLMMessagesToCompletionTransformationHandler``) re-merged the
  raw Anthropic-shaped ``output_config`` into ``completion_kwargs``
  AFTER the translator already mapped its meaningful parts to
  ``response_format`` / ``reasoning_effort``. Non-Anthropic backends
  (Azure OpenAI, Fireworks, Bedrock Nova, etc.) then 400'd with
  "Extra inputs are not permitted".

Approach
--------
Vertex AI Claude (chat-completion + experimental_pass_through paths):
  Replace the unconditional pop with a sanitizer
  ``_sanitize_vertex_anthropic_output_params`` that strips only the
  Vertex-unsupported keys (today: ``effort``) from ``output_config``
  while forwarding ``format`` and the legacy top-level
  ``output_format``. Defensive: non-dict ``output_config`` values are
  dropped to avoid sending malformed payloads downstream.
  Greptile P1 from PR #23396 addressed: when ``output_config`` carries
  both ``format`` and ``effort``, the prior conditional pass-through
  forwarded ``effort`` and reproduced the 400. The new helper filters
  per-key.

Anthropic ``/v1/messages`` adapter:
  Add ``output_config`` to a named module-level constant
  ``ANTHROPIC_ONLY_REQUEST_KEYS`` and wire it into ``excluded_keys`` so
  the post-translation re-merge skips re-adding the raw key. This
  fixes the 400 on non-Anthropic backends and avoids the conflicting
  duplicate (``response_format`` + raw ``output_config``) on
  Anthropic-family backends.
  Greptile P2 from PR #23706 addressed: the constant gives reviewers
  one grep target instead of an inline literal that silently grows.
  Greptile P2 from PR #22727 addressed: ``extra_kwargs or {}`` is
  replaced with explicit ``is None`` checks so empty-dict callers no
  longer skip the fallback path.

Tests
-----
* tests/test_litellm/llms/vertex_ai/vertex_ai_partner_models/anthropic/
  test_vertex_ai_partner_models_anthropic_transformation.py:
  - 5 new/updated cases plus a direct unit test for
    ``_sanitize_vertex_anthropic_output_params``.
  - Updated ``test_vertex_ai_claude_sonnet_4_5_structured_output_fix``
    so its mock-injected ``output_format`` is asserted to FLOW THROUGH
    (the original test asserted the now-buggy strip behavior).
* tests/test_litellm/llms/anthropic/experimental_pass_through/
  adapters/test_handler_output_config_passthrough.py (new):
  - Constant export sanity, output_config strip with ``effort`` only,
    output_config strip with ``format`` only, regression guard that
    unrelated extras still flow, explicit-empty-dict path, and the
    ``extra_kwargs=None`` no-crash path.

Test-quality fixes incorporated from Greptile review on the
superseded PRs:
* No ``inspect.getsource`` source-text assertions (PR #24114 / #23475).
* ``sys.path`` insertion is anchored to ``__file__`` (PR #23706).
* Assertion messages are positional, not tuple (PR #24114-class bug).
* No ``or {}`` masking explicit empty dicts in helper signatures
  (PR #22727).

Verified locally: 26/26 pass with this commit. The new tests
fail (or fail to import) on ``main`` without it.

Out of scope
------------
* The ``max_tokens`` capping logic from PR #22727 — independent
  concern, deserves its own PR with a focused test plan.
* Architectural rework of the ``excluded_keys`` mechanism (Greptile
  P2 on PR #23706 noted point-fix growth). The named constant gives
  maintainers a clear place to extend; a registry-based approach
  would be a follow-up.

Co-Authored-By: netbrah <netbrah>
Co-Authored-By: s-zx <s-zx>
Co-Authored-By: invoicepulse <invoicepulse>
Co-Authored-By: cfdude <cfdude>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Three concerns raised by bot reviewers, all addressed:

1. CodeQL cyclic-import warning
   ``experimental_pass_through/transformation.py`` imported from the
   parent ``..transformation`` module, which CodeQL flagged as a
   potential cycle. Extracted the helper into a new leaf module
   ``vertex_ai_partner_models/anthropic/output_params_utils.py`` that
   has no heavy imports of its own. Both transformation files now
   import from it cleanly. Renamed the helper from the underscore-
   prefixed ``_sanitize_vertex_anthropic_output_params`` to the
   public ``sanitize_vertex_anthropic_output_params`` since it is now
   shared across modules.

2. Greptile P2: redundant ``None`` guard on ``extra_kwargs``
   ``handler.py`` had two ``extra_kwargs = extra_kwargs if ... else {}``
   coercions; the second was a no-op because line 220 already
   coerced. Removed the second one and added a NOTE comment so future
   readers understand ``extra_kwargs`` is guaranteed non-None at the
   point of use.

3. Greptile P2: misleading "already translated" docstring
   The docstring claimed the translator above mapped
   ``output_config.format`` to ``response_format``, but Greptile
   correctly traced the code and found that only the legacy top-level
   ``output_format`` was being translated — ``output_config.format``
   was being silently dropped on the adapter path. Two-part fix:

   a. Code: extended ``_translate_output_format_to_openai`` to accept
      both shapes (top-level ``output_format`` AND
      ``output_config.format`` sub-key). Top-level still takes
      precedence when both are supplied. This means callers using the
      newer Anthropic Structured Outputs API now have their schema
      properly forwarded to non-Anthropic backends as
      ``response_format``.

   b. Tests: rewrote the misleading docstring to describe what
      actually happens, plus added two new tests:
      * ``test_output_format_top_level_still_translates`` —
        regression guard for the legacy path
      * ``test_output_format_takes_precedence_over_output_config_format``
        — documents the precedence rule explicitly

Tests: 28/28 pass (was 26/26 before; +2 for the new translation
behavior + precedence). All run in ~0.5s, no real network calls.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…#26385)

- Remove duplicate MAX_SIZE_PER_ITEM_IN_MEMORY_CACHE_IN_KB definition
  (kept the one with default 1024, removed the one with default 512)
- Add fallback from 'response' to 'response_text' key in Cloudflare
  Workers AI transformation for newer Nemotron models

Co-authored-by: yuneng-jiang <yuneng@berri.ai>
Co-authored-by: Jah-yee <110645028+Jah-yee@users.noreply.github.com>
…opdown (#25482) (#26419)

The Z.AI (Zhipu AI) provider was missing from the Add-Model dropdown in
the admin UI, even though the rest of the stack already supports it:

- /public/providers returns 'zai' in the provider list
- provider_endpoints_support.json includes a full 'zai' entry with
  endpoints and a docs URL (https://docs.litellm.ai/docs/providers/zai)
- Backend routing works for zai/* models (e.g. zai/glm-4.5, zai/glm-5)
- There are many zai/* entries in model_prices_and_context_window.json

The dropdown is driven by the hard-coded Providers enum and provider_map
in provider_info_helpers.tsx, which did not include 'zai', so users
could not select Z.AI when adding a model through the UI.

This PR:

- Adds Providers.ZAI ('Z.AI (Zhipu AI)') to the enum.
- Maps it to 'zai' in provider_map so the UI round-trips the existing
  backend provider key.
- Wires a reasonable placeholder 'zai/glm-4.5' in getPlaceholder, since
  glm-4.5 is an established zai/* model in the pricing catalog.
- Adds two regression tests in provider_info_helpers.test.tsx:
    1. getProviderLogoAndName('zai') resolves to Providers.ZAI.
    2. getPlaceholder(Providers.ZAI) returns 'zai/glm-4.5'.

No logo asset is added in this PR; getProviderLogoAndName already
gracefully returns an empty logo string for providers missing from
providerLogoMap, matching the existing pattern for several other
providers. A follow-up can add a dedicated logo.

Fixes #25482

Co-authored-by: yuneng-jiang <yuneng@berri.ai>
Fixes #26396.

The `LITELLM_LOG=INFO` branch in proxy_server only set
`verbose_router_logger` and `verbose_proxy_logger`. The third logger
`verbose_logger` (used by e.g. `token_based_routing.py`) inherited the
Python root default (WARNING) and its INFO-level messages were
silently filtered — inconsistent with the neighbouring DEBUG branch
which configures all three and with the `debug=True` / `detailed_debug`
paths above.

Include `verbose_logger` in the INFO branch as well so all three
loggers behave the same.

Co-authored-by: yuneng-jiang <yuneng@berri.ai>
Co-authored-by: Yufeng He <40085740+universeplayer@users.noreply.github.com>
…Usage (#26506)

* [Feat] Day-0 support for GPT-5.5 and GPT-5.5 Pro (#26449)

* feat(openai): day-0 support for GPT-5.5 and GPT-5.5 Pro

Add pricing + capability entries for the new GPT-5.5 family launched by
OpenAI on 2026-04-24:

- gpt-5.5 / gpt-5.5-2026-04-23 (chat): $5/$30/$0.50 per 1M
  input/output/cached input
- gpt-5.5-pro / gpt-5.5-pro-2026-04-23 (responses-only): $60/$360/$6
  per 1M input/output/cached input

Other fees (long-context >272k, flex, batches, priority, cache
discounts) follow the same ratios as GPT-5.4, with context window
retained at 1.05M input / 128K output.

No transformation / classifier code changes are required:
OpenAIGPT5Config.is_model_gpt_5_4_plus_model() already matches 5.5+ via
numeric version parsing, and model registration is driven from the
JSON. The existing responses-API bridge for tools + reasoning_effort
(litellm/main.py:970) already covers gpt-5.5-pro.

Tests:
- GPT5_MODELS regression list now covers gpt-5.5-pro and dated variants
- New test_generic_cost_per_token_gpt55_pro cost-calc test
- Updated test_generic_cost_per_token_gpt55 for long-context fields

* fix(openai): mirror reasoning_effort flags onto gpt-5.5 dated variants

gpt-5.5-2026-04-23 and gpt-5.5-pro-2026-04-23 were missing the
supports_none_reasoning_effort, supports_xhigh_reasoning_effort, and
supports_minimal_reasoning_effort flags that their non-dated
counterparts define. Reasoning-effort routing in OpenAIGPT5Config is
fully capability-driven from these JSON flags — since an absent flag
is treated as False for opt-in levels (xhigh), users pinning to a
dated snapshot would silently lose xhigh support and diverge from the
base alias on logprobs + flexible temperature handling.

Copy the flags onto both dated variants so every dated snapshot
inherits the base model's reasoning-effort capability profile.

Adds a parametrized regression test that asserts
supports_{none,minimal,xhigh}_reasoning_effort parity between each
dated variant and its non-dated counterpart, preventing future drift
when new snapshots are added.

* [Feat] Add azure/gpt-5.5 + azure/gpt-5.5-pro entries (+ dated variants) (#26361)

* feat(azure): add azure/gpt-5.5 + azure/gpt-5.5-pro entries (+ dated variants)

Azure variants of OpenAI's GPT-5.5 family. Microsoft has not yet
shipped GPT-5.5 on Azure OpenAI (latest GA on the Foundry models page
is GPT-5.4 as of 2026-04-24), but adding the entries day-0 mirrors the
established precedent for azure/gpt-5.4* (which were in the cost map
before the Azure rollout) so cost tracking and capability flags work
the moment customers deploy.

Schema follows the existing azure/gpt-5.4* shape:
- Same base/long-context pricing as openai/gpt-5.5*: $5/$30 chat,
  $60/$360 pro per 1M, with priority tier 2x base
- Azure variants drop the flex/batches keys (Azure has no flex tier)
  but keep priority pricing, matching gpt-5.4* precedent
- mode=chat for the thinking model, mode=responses for pro

reasoning_effort capability flags mirror the OpenAI variants exactly
since Azure proxies the same API contract: minimal rejection on both
chat and pro, low/none rejection on pro. Once #26456 (which sets
supports_low_reasoning_effort + minimal=false on openai/gpt-5.5*)
lands, OpenAI and Azure flag profiles align.

Tests pin entry presence + pricing for all four Azure variants and
verify the live-API-derived reasoning_effort flags.

* test: register supports_low_reasoning_effort in cost-map JSON schema

azure/gpt-5.5-pro and azure/gpt-5.5-pro-2026-04-23 added in this branch
carry supports_low_reasoning_effort=false. The strict
'additionalProperties: false' schema in
test_aaamodel_prices_and_context_window_json_is_valid rejected the new
key. Register it alongside the other supports_*_reasoning_effort
entries.

Note: the runtime side of this flag (code that reads it) lands in
#26456. Until that PR merges the flag is inert for both Azure and
OpenAI pro entries, but having the schema accept it lets cost-map
tests pass on either merge order.

* fix(arize/langfuse_otel): handle Pydantic usage objects without `.get`

`_set_usage_outputs` called `usage.get(...)` and
`usage.get('output_tokens_details', {}).get('reasoning_tokens')`. These
crash with `AttributeError: 'CompletionUsage' object has no attribute
'get'` when `usage` (or the nested token-details object) is a raw OpenAI
Pydantic model rather than a dict / litellm `Usage` wrapper. Reproduces
on the langfuse_otel + arize Responses API logging paths.

Fixes #13672.

Changes:
- Add `_safe_get(obj, key, default)` that prefers dict-style `.get` when
  available and otherwise falls back to `getattr`. Works uniformly for
  dicts, litellm's `Usage`, and plain Pydantic models like
  `openai.types.completion_usage.CompletionUsage` /
  `CompletionTokensDetails` / `OutputTokensDetails`.
- Use `_safe_get` for total / completion / prompt / output tokens.
- Look for reasoning tokens in `completion_tokens_details` (Chat
  Completions API) before falling back to `output_tokens_details`
  (Responses API). Previously reasoning tokens from the Chat Completions
  API were silently dropped.

Tests:
- `test_set_usage_outputs_pydantic_completion_usage` — covers the chat
  completions path with raw `CompletionUsage` + `CompletionTokensDetails`.
- `test_set_usage_outputs_pydantic_response_api_usage` — covers the
  Responses API path with a Pydantic usage object lacking `.get`.

Both tests fail on main before this commit and pass after.

---------

Co-authored-by: yuneng-jiang <yuneng@berri.ai>
Co-authored-by: Mateo Wang <277851410+mateo-berri@users.noreply.github.com>
Co-authored-by: alvinttang <alvin@pm.me>
Co-authored-by: Krrish Dholakia <krrish+github@berri.ai>
…h-consolidated

fix(adapters,vertex): pass output_config through to backends that accept it (closes #23380, supersedes #23475/#23396/#23706/#22727)
@CLAassistant

CLAassistant commented Apr 25, 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.
6 out of 7 committers have signed the CLA.

✅ Jah-yee
✅ MackDing
✅ dkindlund
✅ alvinttang
✅ mateo-berri
✅ he-yufeng
❌ cursoragent
You have signed the CLA already but the status is still pending? Let us recheck it.

@veria-ai

veria-ai Bot commented Apr 25, 2026

Copy link
Copy Markdown
Contributor

Anthropic adapter output_config passthrough fix and upstream sync

This PR fixes parameter translation between Anthropic's output_config/output_format and OpenAI-format response_format for non-Anthropic backends, adds a safe attribute accessor for Pydantic models in the Arize integration, supports a new Cloudflare response key, and adds the Z.AI provider to the UI. The changes are confined to provider translation layers and telemetry utilities — no authentication, authorization, or input validation boundaries are affected. The parameter sanitization logic correctly filters to an allowlist of known-supported keys rather than forwarding arbitrary user input to downstream providers.


Status: 0 open
Risk: 1/10

@mateo-berri mateo-berri changed the title Litellm oss staging 04 25 2026 fix(adapters,vertex): pass Anthropic output_config through to backends that accept it Apr 25, 2026
@greptile-apps

greptile-apps Bot commented Apr 25, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This merge rolls the output_config passthrough fix (PR #26439) and four upstream OSS staging patches into internal staging. The headline change replaces unconditional output_format/output_config drops on Vertex AI Claude with a targeted sanitizer that forwards format while stripping effort, and prevents output_config from leaking past the /v1/messages/chat/completions adapter into non-Anthropic backends.

  • P1 (Cloudflare streaming): The response_text fallback key added in transform_response for Nemotron models was not applied to CloudflareChatResponseIterator.chunk_parser, so streaming requests to those models will silently return empty content.

Confidence Score: 4/5

Safe to merge with one P1 streaming gap in the Cloudflare path and the acknowledged unconfirmed Vertex output_format parity assumption.

One confirmed P1: the Cloudflare response_text streaming gap produces silent empty content for Nemotron models in streaming mode. The Vertex output_format+tools parity concern is already tracked in the previous review thread. All other changes are well-tested and correct.

litellm/llms/cloudflare/chat/transformation.py (streaming path not updated); litellm/llms/vertex_ai/vertex_ai_partner_models/anthropic/transformation.py (Vertex parity assumption).

Important Files Changed

Filename Overview
litellm/llms/cloudflare/chat/transformation.py Adds response_text fallback for non-streaming responses but leaves the streaming chunk_parser unchanged, producing empty content for Nemotron models in streaming mode.
litellm/llms/anthropic/experimental_pass_through/adapters/handler.py Adds ANTHROPIC_ONLY_REQUEST_KEYS constant and gates the post-translation extra-kwargs re-merge with it, correctly preventing output_config leakage to non-Anthropic backends.
litellm/llms/anthropic/experimental_pass_through/adapters/transformation.py Extends _translate_output_format_to_openai to read output_config.format as a fallback when top-level output_format is absent; clean precedence logic.
litellm/llms/vertex_ai/vertex_ai_partner_models/anthropic/output_params_utils.py New leaf-module helper sanitize_vertex_anthropic_output_params that strips effort from output_config while preserving format, avoiding the CodeQL cyclic-import flagged by the original design.
litellm/llms/vertex_ai/vertex_ai_partner_models/anthropic/transformation.py Replaces unconditional output_format/output_config drops with sanitize_vertex_anthropic_output_params; behavior depends on Vertex AI accepting output_format alongside tools/tool_choice, which is unconfirmed per PR description.
litellm/llms/vertex_ai/vertex_ai_partner_models/anthropic/experimental_pass_through/transformation.py Same sanitization applied to the Messages pass-through path; same unconfirmed Vertex parity assumption applies.
litellm/integrations/arize/_utils.py Introduces _safe_get to handle both dict-like and Pydantic-model usage objects; also adds completion_tokens_details branch for Chat Completions API reasoning tokens.
litellm/constants.py Removes the duplicate MAX_SIZE_PER_ITEM_IN_MEMORY_CACHE_IN_KB definition (512-default); the surviving definition at line 85 (1024-default) is the authoritative one imported by in_memory_cache.py.
litellm/proxy/proxy_server.py Adds verbose_logger.setLevel(logging.INFO) so LITELLM_LOG=INFO now propagates to the package-level logger, not just the proxy/router loggers.
ui/litellm-dashboard/src/components/provider_info_helpers.tsx Adds ZAI provider entry to the Providers enum, provider_map, and getPlaceholder; straightforward addition with test coverage.
tests/test_litellm/llms/vertex_ai/vertex_ai_partner_models/anthropic/test_vertex_ai_partner_models_anthropic_transformation.py Existing regression test inverted to assert output_format IS forwarded; new tests added for sanitizer helper and mixed format+effort cases. Correctness depends on unconfirmed Vertex AI parity.
tests/test_litellm/llms/anthropic/experimental_pass_through/adapters/test_handler_output_config_passthrough.py New test file covering output_config strip, ANTHROPIC_ONLY_REQUEST_KEYS export, precedence rules, and empty extra_kwargs edge case; all mock-based, no real network calls.
tests/test_litellm/integrations/arize/test_arize_utils.py Adds two regression tests for Pydantic usage objects (CompletionUsage and a plain Responses API shape); mock-only, good coverage for the _safe_get fix.

Comments Outside Diff (1)

  1. litellm/llms/cloudflare/chat/transformation.py, line 202 (link)

    P1 Streaming path doesn't handle response_text fallback

    The non-streaming transform_response now falls back to result.get("response_text") for newer Nemotron models, but CloudflareChatResponseIterator.chunk_parser (line 202, used in the streaming path) still only reads chunk["response"]. For streaming requests to Nemotron models, this will silently produce empty content since the chunk never enters the if "response" in chunk branch.

Reviews (3): Last reviewed commit: "Merge remote-tracking branch 'origin/lit..." | Re-trigger Greptile

Comment on lines +300 to 310
# output_format is now forwarded to Vertex (Vertex parity has shifted —
# it accepts the field and uses it to enforce the JSON schema). The
# prior behavior silently stripped it, hiding Structured Outputs from
# callers who explicitly requested them.
assert "output_format" in final_data
assert final_data["output_format"]["type"] == "json_schema"
assert (
"output_format" not in final_data
), "output_format should be removed for VertexAI"
assert "model" not in final_data, "model should be removed for VertexAI"
"model" not in final_data
), "model is still stripped (Vertex routes by URL)"
assert "tools" in final_data, "tools should still be present"
assert "tool_choice" in final_data, "tool_choice should still be present"

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.

P1 output_format re-introduced alongside tools/tool_choice on Vertex

The original test_vertex_ai_claude_sonnet_4_5_structured_output_fix was a regression guard for issue #18625, where output_format caused 400 "Extra inputs are not permitted" on Vertex AI Claude. The fix stripped output_format and used tool-based structured output exclusively.

This PR reverses that: output_format is now asserted to be present (assert "output_format" in final_data) while tools and tool_choice are also still present in the same payload. Sending all three simultaneously to Vertex Cloud Claude may reproduce the original 400 error unless Vertex has explicitly documented that output_format is now accepted alongside tool-based structured outputs. The PR comment says "Vertex parity has shifted" but there is no linked changelog or API documentation confirming that Vertex now tolerates output_format when tools are also present.

@mateo-berri mateo-berri mentioned this pull request Apr 25, 2026
7 tasks
Comment thread litellm/constants.py
Comment on lines 409 to 412
AUDIO_SPEECH_CHUNK_SIZE = int(
os.getenv("AUDIO_SPEECH_CHUNK_SIZE", 8192)
) # chunk_size for audio speech streaming. Balance between latency and memory usage
MAX_SIZE_PER_ITEM_IN_MEMORY_CACHE_IN_KB = int(
os.getenv("MAX_SIZE_PER_ITEM_IN_MEMORY_CACHE_IN_KB", 512)
)
DEFAULT_MAX_TOKENS_FOR_TRITON = int(os.getenv("DEFAULT_MAX_TOKENS_FOR_TRITON", 2000))

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.

P0 ImportError: MAX_SIZE_PER_ITEM_IN_MEMORY_CACHE_IN_KB removed but still imported downstream

This PR deletes MAX_SIZE_PER_ITEM_IN_MEMORY_CACHE_IN_KB from constants.py, but litellm/caching/in_memory_cache.py still does from litellm.constants import MAX_SIZE_PER_ITEM_IN_MEMORY_CACHE_IN_KB and uses it in both the constructor fallback and the check_value_size fast-path:

# in_memory_cache.py line 22
from litellm.constants import MAX_SIZE_PER_ITEM_IN_MEMORY_CACHE_IN_KB   # ImportError at startup
...
self.max_size_per_item = max_size_per_item or MAX_SIZE_PER_ITEM_IN_MEMORY_CACHE_IN_KB
...
< self.max_size_per_item * MAX_SIZE_PER_ITEM_IN_MEMORY_CACHE_IN_KB

Any process that imports litellm.caching (which includes the entire proxy stack) will fail with ImportError: cannot import name 'MAX_SIZE_PER_ITEM_IN_MEMORY_CACHE_IN_KB' from 'litellm.constants'. This constant appears unrelated to the output_config fix and its removal looks accidental.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

this is a duplicate definition, safe to remove

@codecov

codecov Bot commented Apr 25, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 90.00000% with 4 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
litellm/integrations/arize/_utils.py 85.71% 2 Missing ⚠️
litellm/llms/cloudflare/chat/transformation.py 0.00% 2 Missing ⚠️

📢 Thoughts on this report? Let us know!

@mateo-berri mateo-berri changed the title fix(adapters,vertex): pass Anthropic output_config through to backends that accept it chore(staging): roll oss-staging-04-25-2026 into internal staging (output_config fix + 4 upstream sync fixes) Apr 26, 2026
@mateo-berri mateo-berri changed the title chore(staging): roll oss-staging-04-25-2026 into internal staging (output_config fix + 4 upstream sync fixes) chore(staging): roll oss_staging_04_25_2026 into internal staging (output_config fix + 4 upstream sync fixes) Apr 26, 2026
@mateo-berri
mateo-berri requested a review from Sameerlite April 26, 2026 02:03

@Sameerlite Sameerlite 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.

.

Comment thread litellm/constants.py
Comment thread litellm/proxy/proxy_server.py
…itellm_oss_staging_04_25_2026

# Conflicts:
#	litellm/model_prices_and_context_window_backup.json
#	model_prices_and_context_window.json

Co-authored-by: Mateo Wang <mateo-berri@users.noreply.github.com>
@mateo-berri
mateo-berri requested a review from Sameerlite April 30, 2026 19:38
@Sameerlite

Copy link
Copy Markdown
Contributor

@greptile-apps

@Sameerlite

Copy link
Copy Markdown
Contributor

P1 Streaming path doesn't handle response_text fallback
The non-streaming transform_response now falls back to result.get("response_text") for newer Nemotron models, but CloudflareChatResponseIterator.chunk_parser (line 202, used in the streaming path) still only reads chunk["response"]. For streaming requests to Nemotron models, this will silently produce empty content since the chunk never enters the if "response" in chunk branch.

@mateo-berri is this comment valid?

Newer Cloudflare Workers AI models (e.g. Nemotron) emit 'response_text'
instead of 'response' on streamed chunks. The non-streaming path was
already updated to fall back to 'response_text' (#26385), but the
streaming chunk parser still only read 'response', which caused
streaming requests against those models to silently produce empty
content.

Mirror the non-streaming fallback in CloudflareChatResponseIterator.chunk_parser
and add a streaming test for the response_text shape.

Co-authored-by: Mateo Wang <mateo-berri@users.noreply.github.com>
@mateo-berri

Copy link
Copy Markdown
Contributor Author

@mateo-berri is this comment valid?

good call out; fixed. Please re-review

…itellm_oss_staging_04_25_2026

Co-authored-by: Mateo Wang <mateo-berri@users.noreply.github.com>

@Sameerlite Sameerlite 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, thanks!

@mateo-berri
mateo-berri enabled auto-merge May 2, 2026 06:10
@mateo-berri
mateo-berri merged commit cfa058c into litellm_internal_staging May 2, 2026
96 of 101 checks passed
@mateo-berri
mateo-berri deleted the litellm_oss_staging_04_25_2026 branch May 2, 2026 06:11
fzowl pushed a commit to fzowl/litellm that referenced this pull request Jun 24, 2026
…25_2026

chore(staging): roll oss_staging_04_25_2026 into internal staging (output_config fix + 4 upstream sync fixes)
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.

[Bug]: Dropped output_config parameter in Messages API prevents schema and effort constraints from being reflected in VertexAI Claude model responses

9 participants