diff --git a/src/google/adk/models/lite_llm.py b/src/google/adk/models/lite_llm.py index 3a6c36624d..a26163cb30 100644 --- a/src/google/adk/models/lite_llm.py +++ b/src/google/adk/models/lite_llm.py @@ -925,7 +925,9 @@ async def _content_to_message_param( ): reasoning_texts.append(_decode_inline_text_data(part.inline_data.data)) - reasoning_content = _NEW_LINE.join(text for text in reasoning_texts if text) + # Preserve reasoning deltas exactly as received. Injecting separators + # between fragments can corrupt provider-streamed thinking text. + reasoning_content = "".join(text for text in reasoning_texts if text) return ChatCompletionAssistantMessage( role=role, content=final_content, diff --git a/tests/unittests/models/test_litellm.py b/tests/unittests/models/test_litellm.py index c195076349..1d871e7a14 100644 --- a/tests/unittests/models/test_litellm.py +++ b/tests/unittests/models/test_litellm.py @@ -2153,6 +2153,38 @@ async def test_content_to_message_param_assistant_thought_and_content_message(): assert message["reasoning_content"] == "internal reasoning" +@pytest.mark.asyncio +async def test_content_to_message_param_preserves_chunked_reasoning_deltas(): + thought_part_1 = types.Part.from_text(text="Hel") + thought_part_1.thought = True + thought_part_2 = types.Part.from_text(text="lo") + thought_part_2.thought = True + content = types.Content( + role="assistant", parts=[thought_part_1, thought_part_2] + ) + + message = await _content_to_message_param(content) + + assert message["role"] == "assistant" + assert message["content"] is None + assert message["reasoning_content"] == "Hello" + + +@pytest.mark.asyncio +async def test_content_to_message_param_preserves_reasoning_newlines(): + thought_part_1 = types.Part.from_text(text="line 1\n") + thought_part_1.thought = True + thought_part_2 = types.Part.from_text(text="line 2") + thought_part_2.thought = True + content = types.Content( + role="assistant", parts=[thought_part_1, thought_part_2] + ) + + message = await _content_to_message_param(content) + + assert message["reasoning_content"] == "line 1\nline 2" + + @pytest.mark.asyncio async def test_content_to_message_param_function_call(): content = types.Content(