Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions src/mcprobe/agents/adk.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
7 changes: 7 additions & 0 deletions src/mcprobe/synthetic_user/user.py
Original file line number Diff line number Diff line change
Expand Up @@ -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))

Expand Down
36 changes: 36 additions & 0 deletions tests/unit/test_synthetic_user.py
Original file line number Diff line number Diff line change
Expand Up @@ -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()