Skip to content

Commit e737f22

Browse files
GWealecopybara-github
authored andcommitted
fix: surface sub-agent RPC errors from AgentTool
When a sub-agent invoked through AgentTool fails mid-run (for example a RemoteA2aAgent whose RPC errors out), the failing event carries an error_message but no content. AgentTool.run_async only inspected event content, so it discarded the error and returned an empty string, hiding the failure from the calling agent and the model. Track the most recent error_message while draining the sub-agent's event stream and return it when there is no usable content, so callers see the actual failure instead of a silent empty result. Co-authored-by: George Weale <gweale@google.com> PiperOrigin-RevId: 952181505
1 parent 851654f commit e737f22

2 files changed

Lines changed: 60 additions & 1 deletion

File tree

src/google/adk/tools/agent_tool.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,7 @@ async def run_async(
286286
)
287287

288288
last_content = None
289+
last_error_message = None
289290
last_grounding_metadata = None
290291
async with Aclosing(
291292
runner.run_async(
@@ -296,6 +297,8 @@ async def run_async(
296297
# Forward state delta to parent session.
297298
if event.actions.state_delta:
298299
tool_context.state.update(event.actions.state_delta)
300+
if event.error_message:
301+
last_error_message = event.error_message
299302
if event.content:
300303
last_content = event.content
301304
last_grounding_metadata = event.grounding_metadata
@@ -305,9 +308,11 @@ async def run_async(
305308
await runner.close()
306309

307310
if last_content is None or last_content.parts is None:
308-
return ''
311+
return last_error_message or ''
309312
parts_text = (_part_to_text(p) for p in last_content.parts if not p.thought)
310313
merged_text = '\n'.join(t for t in parts_text if t)
314+
if not merged_text and last_error_message:
315+
return last_error_message
311316
output_schema = _get_output_schema(self.agent)
312317
if output_schema:
313318
tool_result = validate_schema(output_schema, merged_text)

tests/unittests/tools/test_agent_tool.py

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1148,6 +1148,60 @@ async def test_run_async_skips_thought_parts():
11481148
assert result == '42'
11491149

11501150

1151+
async def _run_agent_tool_with_events(events: list[Event]) -> Any:
1152+
"""Drives AgentTool with an inner agent that yields `events` in order."""
1153+
1154+
class _StaticAgent(BaseAgent):
1155+
1156+
async def _run_async_impl(self, ctx):
1157+
for event in events:
1158+
yield event
1159+
1160+
inner = _StaticAgent(name='inner_agent', description='static')
1161+
agent_tool = AgentTool(agent=inner)
1162+
1163+
session_service = InMemorySessionService()
1164+
session = await session_service.create_session(
1165+
app_name='test_app', user_id='test_user'
1166+
)
1167+
invocation_context = InvocationContext(
1168+
invocation_id='invocation_id',
1169+
agent=inner,
1170+
session=session,
1171+
session_service=session_service,
1172+
)
1173+
tool_context = ToolContext(invocation_context=invocation_context)
1174+
1175+
return await agent_tool.run_async(
1176+
args={'request': 'test request'}, tool_context=tool_context
1177+
)
1178+
1179+
1180+
@mark.asyncio
1181+
async def test_run_async_preserves_error_event_with_no_content():
1182+
"""An error-only event with no content surfaces its error_message."""
1183+
result = await _run_agent_tool_with_events([
1184+
Event(author='inner_agent', error_message='A2A request failed: 503'),
1185+
])
1186+
assert result == 'A2A request failed: 503'
1187+
1188+
1189+
@mark.asyncio
1190+
async def test_run_async_preserves_error_when_only_thought_parts():
1191+
"""When the final content is all thought parts, the error_message wins."""
1192+
result = await _run_agent_tool_with_events([
1193+
Event(
1194+
author='inner_agent',
1195+
content=types.Content(
1196+
role='model',
1197+
parts=[types.Part(text='thinking', thought=True)],
1198+
),
1199+
),
1200+
Event(author='inner_agent', error_message='A2A request failed: 503'),
1201+
])
1202+
assert result == 'A2A request failed: 503'
1203+
1204+
11511205
class TestAgentToolWithCompositeAgents:
11521206
"""Tests for AgentTool wrapping composite agents (SequentialAgent, etc.)."""
11531207

0 commit comments

Comments
 (0)