From ae902052adca1d055dbdeb94e2487321d267ceb2 Mon Sep 17 00:00:00 2001 From: Alexander Kuzmik Date: Wed, 28 Jan 2026 16:55:08 +0100 Subject: [PATCH 1/3] Make _part_has_payload respect function response --- src/google/adk/models/lite_llm.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/google/adk/models/lite_llm.py b/src/google/adk/models/lite_llm.py index 79182d7b0a..651e7d9818 100644 --- a/src/google/adk/models/lite_llm.py +++ b/src/google/adk/models/lite_llm.py @@ -470,6 +470,8 @@ def _part_has_payload(part: types.Part) -> bool: return True if part.file_data and (part.file_data.file_uri or part.file_data.data): return True + if part.function_response: + return True return False From 04657c1d1c63ffe566f409135c3d3774875475e0 Mon Sep 17 00:00:00 2001 From: Alexander Kuzmik Date: Wed, 28 Jan 2026 17:42:05 +0100 Subject: [PATCH 2/3] Add new test --- tests/unittests/models/test_litellm.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/tests/unittests/models/test_litellm.py b/tests/unittests/models/test_litellm.py index 2ebbc5dfe8..b4bf69d949 100644 --- a/tests/unittests/models/test_litellm.py +++ b/tests/unittests/models/test_litellm.py @@ -1035,6 +1035,23 @@ async def test_generate_content_async_adds_fallback_user_message( 4, id="user content is not the last message scenario", ), + pytest.param( + LlmRequest( + contents=[ + types.Content( + role="user", + parts=[ + types.Part.from_function_response( + name="test_function", + response={"result": "test_result"}, + ) + ], + ), + ] + ), + 1, + id="user content with function_response has payload", + ), ] From 0fe6e39a49198718d1a69c9785c23024a87eb55e Mon Sep 17 00:00:00 2001 From: Alexander Kuzmik Date: Wed, 28 Jan 2026 17:57:26 +0100 Subject: [PATCH 3/3] update test --- tests/unittests/models/test_litellm.py | 58 ++++++++++++++++++-------- 1 file changed, 41 insertions(+), 17 deletions(-) diff --git a/tests/unittests/models/test_litellm.py b/tests/unittests/models/test_litellm.py index b4bf69d949..8c07ee7061 100644 --- a/tests/unittests/models/test_litellm.py +++ b/tests/unittests/models/test_litellm.py @@ -990,6 +990,47 @@ async def test_generate_content_async_adds_fallback_user_message( ) +@pytest.mark.asyncio +async def test_generate_content_async_no_fallback_for_function_response( + mock_acompletion, lite_llm_instance +): + """Tests that no fallback message is added for a user message with a function response.""" + llm_request = LlmRequest( + contents=[ + types.Content( + role="user", + parts=[ + types.Part.from_function_response( + name="test_function", + response={"result": "test_result"}, + ) + ], + ) + ] + ) + + # Run generate_content_async which calls _append_fallback_user_content_if_missing + async for _ in lite_llm_instance.generate_content_async(llm_request): + pass + + # Verify that the fallback message was NOT added to the llm_request + assert len(llm_request.contents) == 1 + assert len(llm_request.contents[0].parts) == 1 + assert llm_request.contents[0].parts[0].function_response is not None + + # Verify that the message sent to litellm does not contain the fallback text + mock_acompletion.assert_called_once() + _, kwargs = mock_acompletion.call_args + user_messages = [ + message for message in kwargs["messages"] if message["role"] == "user" + ] + assert not any( + message.get("content") + == "Handle the requests as specified in the System Instruction." + for message in user_messages + ) + + litellm_append_user_content_test_cases = [ pytest.param( LlmRequest( @@ -1035,23 +1076,6 @@ async def test_generate_content_async_adds_fallback_user_message( 4, id="user content is not the last message scenario", ), - pytest.param( - LlmRequest( - contents=[ - types.Content( - role="user", - parts=[ - types.Part.from_function_response( - name="test_function", - response={"result": "test_result"}, - ) - ], - ), - ] - ), - 1, - id="user content with function_response has payload", - ), ]