From 7e904172d11e752750bfe4f450b70b32bf1abcdf Mon Sep 17 00:00:00 2001 From: Richard Kiene Date: Sun, 25 Jan 2026 11:15:52 -0700 Subject: [PATCH 1/2] Fix empty agent response in ADK agent when tools are used Capture text from all events with text content, not just events marked as final response. When ADK agent uses tools, the response text may come in events that are not marked as final, causing empty response strings. --- src/mcprobe/agents/adk.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/mcprobe/agents/adk.py b/src/mcprobe/agents/adk.py index b4da9d4..f3ac55e 100644 --- a/src/mcprobe/agents/adk.py +++ b/src/mcprobe/agents/adk.py @@ -134,8 +134,9 @@ async def send_message(self, message: str) -> AgentResponse: self._process_function_responses(responses, pending_calls) ) - # Get final response text - if event.is_final_response() and event.content and event.content.parts: + # Capture text from any event with text content + # (not just final response - text may come in earlier events when tools are used) + if event.content and event.content.parts: for part in event.content.parts: if hasattr(part, "text") and part.text: response_text += part.text From 8d47e1e2ff178b284a59d01b072e9105cdbbc3f1 Mon Sep 17 00:00:00 2001 From: Richard Kiene Date: Sun, 25 Jan 2026 12:23:20 -0700 Subject: [PATCH 2/2] Handle empty agent responses in synthetic user When the agent returns an empty response, have the synthetic user ask for clarification instead of passing empty content to the LLM which would confuse it and cause it to return empty, triggering the fallback "Thanks" message that masks the bug. --- src/mcprobe/synthetic_user/user.py | 7 ++++++ tests/unit/test_synthetic_user.py | 36 ++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+) diff --git a/src/mcprobe/synthetic_user/user.py b/src/mcprobe/synthetic_user/user.py index 2985d18..08452ce 100644 --- a/src/mcprobe/synthetic_user/user.py +++ b/src/mcprobe/synthetic_user/user.py @@ -62,6 +62,13 @@ async def respond(self, assistant_message: str) -> UserResponse: Raises: OrchestrationError: If the LLM call fails. """ + # Handle empty agent responses - ask for clarification instead of confusing the LLM + if not assistant_message.strip(): + response = "I didn't receive a response. Could you try again?" + self._conversation_history.append(Message(role="assistant", content=assistant_message)) + self._conversation_history.append(Message(role="user", content=response)) + return UserResponse(message=response, tokens_used=0) + # Add assistant message to history self._conversation_history.append(Message(role="assistant", content=assistant_message)) diff --git a/tests/unit/test_synthetic_user.py b/tests/unit/test_synthetic_user.py index f12124f..4d5d728 100644 --- a/tests/unit/test_synthetic_user.py +++ b/tests/unit/test_synthetic_user.py @@ -129,3 +129,39 @@ async def test_tokens_default_to_zero_on_missing_usage( response = await user.respond("Hello") assert response.tokens_used == 0 + + @pytest.mark.asyncio + async def test_empty_agent_response_asks_for_retry( + self, + mock_provider: LLMProvider, + user_config: SyntheticUserConfig, + ) -> None: + """Test that empty agent responses result in clarification request.""" + user = SyntheticUserLLM(mock_provider, user_config) + + # Agent sends empty response + response = await user.respond("") + + # Synthetic user asks for retry instead of calling LLM + assert response.message == "I didn't receive a response. Could you try again?" + assert response.tokens_used == 0 + + # LLM should NOT have been called + mock_provider.generate.assert_not_called() + + @pytest.mark.asyncio + async def test_whitespace_only_agent_response_asks_for_retry( + self, + mock_provider: LLMProvider, + user_config: SyntheticUserConfig, + ) -> None: + """Test that whitespace-only agent responses result in clarification request.""" + user = SyntheticUserLLM(mock_provider, user_config) + + # Agent sends whitespace-only response + response = await user.respond(" \n\t ") + + # Synthetic user asks for retry + assert response.message == "I didn't receive a response. Could you try again?" + assert response.tokens_used == 0 + mock_provider.generate.assert_not_called()