Skip to content

fix(sap): normalize list-shaped reasoning_content into a string#34613

Open
devin-ai-integration[bot] wants to merge 1 commit into
litellm_internal_stagingfrom
litellm_sap_reasoning_content_list
Open

fix(sap): normalize list-shaped reasoning_content into a string#34613
devin-ai-integration[bot] wants to merge 1 commit into
litellm_internal_stagingfrom
litellm_sap_reasoning_content_list

Conversation

@devin-ai-integration

Copy link
Copy Markdown
Contributor

TLDR

Problem this solves:

  • sap/gemini-3.5-flash completions fail with a Pydantic error
  • SAP returns reasoning_content as a list of blocks
  • LiteLLM's Message.reasoning_content only accepts a string

How it solves it:

  • Normalize reasoning_content lists before validating the response
  • Join the block texts into the string field
  • Keep the blocks (with signatures) in thinking_blocks
  • Apply the same normalization to streaming chunks

Relevant issues

Fixes #34612

Linear ticket

Pre-Submission checklist

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

  • I have added meaningful tests
  • 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
  • I have received a Greptile Confidence Score of at least 4/5 before requesting a maintainer review (Greptile reviews automatically once the PR is opened; only comment @greptileai to re-request a review after pushing changes)

Delays in PR merge?

If you're seeing a delay in your PR being merged, ping the LiteLLM Team on Slack (#pr-review).

Screenshots / Proof of Fix

I don't have SAP AI Core / Generative AI Hub credentials on hand, so I couldn't run a live sap/gemini-3.5-flash call against a local proxy; the reproduction and the fix are covered by unit tests that fail on the parent commit and pass on this branch. Happy to capture live curl output if someone can share a service key, or the reporter can validate with:

curl -sS http://localhost:4000/v1/chat/completions \
  -H "Authorization: Bearer sk-1234" -H "Content-Type: application/json" \
  -d '{"model": "sap/gemini-3.5-flash", "messages": [{"role": "user", "content": "Hi!"}]}'

Before the fix that returns litellm.APIConnectionError: 1 validation error for ModelResponse reasoning_content Input should be a valid string [input_value=[{'content': '', 'signature': '...'}]]; after it, a normal completion with reasoning_content as a string

Type

🐛 Bug Fix

Changes

GenAIHubOrchestrationConfig.transform_response fed the raw SAP payload straight into ModelResponse.model_validate. Gemini models on SAP put the model's chain of thought in reasoning_content as a list of blocks, e.g. [{"content": "...", "signature": "..."}], which blows up against the OpenAI-compatible schema where the field is a string

normalize_reasoning_content (in litellm/llms/sap/chat/handler.py, so both the non-streaming transform and the stream parser can use it) rewrites each choice's message/delta:

{"reasoning_content": [{"content": "thinking...", "signature": "sig"}]}
->
{
    "reasoning_content": "thinking...",
    "thinking_blocks": [{"type": "thinking", "thinking": "thinking...", "signature": "sig"}],
}

Empty blocks (the shape in the issue, where SAP sends content: "" with just a signature) collapse to None rather than an empty string, string values pass through untouched, and an existing thinking_blocks on the payload wins over the derived one

Link to Devin session: https://app.devin.ai/sessions/3782d36dd4e24d4ea7a6f4a70d62646f

@devin-ai-integration

Copy link
Copy Markdown
Contributor Author

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR. Add '(aside)' to your comment to have me ignore it.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment, CI, and merge conflict monitoring

@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 sign our Contributor License Agreement before we can accept your contribution.
You have signed the CLA already but the status is still pending? Let us recheck it.

@greptile-apps

greptile-apps Bot commented Jul 25, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR normalizes SAP list-shaped reasoning content before shared response validation.

  • Converts reasoning blocks into concatenated reasoning_content text while retaining structured blocks and signatures in thinking_blocks.
  • Applies the normalization to both non-streaming responses and all supported streaming chunk shapes.
  • Adds focused unit coverage for populated, empty, pre-normalized string, and streaming reasoning content.

Confidence Score: 5/5

The PR appears safe to merge, with the SAP-specific normalization confined to list-shaped reasoning content and covered across synchronous and streaming paths.

Existing string values pass through unchanged, list values are converted before schema validation, structured signatures are retained, and the changed response paths have focused regression coverage.

Important Files Changed

Filename Overview
litellm/llms/sap/chat/handler.py Adds a localized response-normalization helper and consistently invokes it before validating SAP streaming chunks.
litellm/llms/sap/chat/transformation.py Normalizes SAP final-result reasoning content before constructing the shared ModelResponse.
tests/test_litellm/llms/sap/chat/test_sap_transformation.py Adds mock-based regression tests covering list, empty, string, and streaming reasoning-content forms.

Reviews (1): Last reviewed commit: "fix(sap): normalize list-shaped reasonin..." | Re-trigger Greptile

@codecov

codecov Bot commented Jul 25, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 85.71429% with 3 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
litellm/llms/sap/chat/handler.py 85.00% 3 Missing ⚠️

📢 Thoughts on this report? Let us know!

@codspeed-hq

codspeed-hq Bot commented Jul 25, 2026

Copy link
Copy Markdown
Contributor

Merging this PR will not alter performance

✅ 31 untouched benchmarks


Comparing litellm_sap_reasoning_content_list (e0961ec) with litellm_internal_staging (b9b27c2)

Open in CodSpeed

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]: LiteLLM SAP provider fails to parse gemini-3.5-flash responses due to reasoning_content type mismatch

1 participant