diff --git a/src/google/adk/models/lite_llm.py b/src/google/adk/models/lite_llm.py index 7d13696c96..9f612f3ca6 100644 --- a/src/google/adk/models/lite_llm.py +++ b/src/google/adk/models/lite_llm.py @@ -912,7 +912,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 ace08ad997..addce21800 100644 --- a/tests/unittests/models/test_litellm.py +++ b/tests/unittests/models/test_litellm.py @@ -2127,6 +2127,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(