Skip to content

fix: preserve reasoning content signature from LiteLLM thinking models#1789

Open
giulio-leone wants to merge 1 commit intostrands-agents:mainfrom
giulio-leone:fix/litellm-thought-signature
Open

fix: preserve reasoning content signature from LiteLLM thinking models#1789
giulio-leone wants to merge 1 commit intostrands-agents:mainfrom
giulio-leone:fix/litellm-thought-signature

Conversation

@giulio-leone
Copy link

Problem

When streaming responses from thinking models (e.g., Gemini) via LiteLLM, the reasoning content signature is silently dropped. The LiteLLM adapter's _process_choice_content only emits reasoning text from delta.reasoning_content but never captures the signature from delta.thinking.signature.

The event loop in streaming.py already correctly handles reasoningContent.signature deltas (lines 240-248, 314-315), but the LiteLLM model provider never emits them.

Root Cause

LiteLLM provides reasoning signatures via a separate thinking attribute on stream deltas (delta.thinking.signature), distinct from delta.reasoning_content (which only contains the text). The LiteLLM model provider's _process_choice_content method only processed reasoning_content text, never checking for the thinking.signature attribute.

Fix

Added a check in _process_choice_content() for the thinking.signature attribute on each streaming delta. When a valid string signature is found, a contentBlockDelta with reasoningContent.signature is emitted so the event loop can accumulate and store it in the final content block.

An isinstance(sig, str) guard prevents false positives from unittest.mock.Mock objects that auto-create attributes.

Testing

  • Added test_stream_preserves_thinking_signature that simulates a 3-chunk streaming response with reasoning text and signature
  • All 42 existing tests pass with 0 errors/0 warnings

Fixes #1764

When streaming responses from thinking models (e.g., Gemini) via LiteLLM,
the reasoning content signature was silently dropped. The LiteLLM adapter's
_process_choice_content only emitted reasoning text from
delta.reasoning_content but never captured the signature from
delta.thinking.signature.

This patch adds a check for the thinking.signature attribute on each
streaming delta and emits a contentBlockDelta with
reasoningContent.signature so the event loop can accumulate and store
the signature in the final content block.

An isinstance(sig, str) guard prevents unittest.mock.Mock objects from
triggering false positives during testing.

Fixes strands-agents#1764

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@giulio-leone
Copy link
Author

All CI checks pass. Ready for review.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG] missing thought signature preservation for thinking models with LiteLLM Model Provider

1 participant