From 4321de7f6cc304be02a90056fd948ff2d7748400 Mon Sep 17 00:00:00 2001 From: 9chait9 <9chait9@gmail.com> Date: Fri, 17 Apr 2026 02:41:28 -0700 Subject: [PATCH 1/2] Fix premature end_of_agent in sub-agent resumption. The sub-agent resumption logic was incorrectly marking the agent as finished even if the sub-agent had merely paused (e.g., to wait for a long-running operation). This change tracks whether the sub-agent paused, and only marks the agent as finished if no pause occurred. Fixes #5349 --- src/google/adk/agents/llm_agent.py | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/src/google/adk/agents/llm_agent.py b/src/google/adk/agents/llm_agent.py index 0f7cc2b7d9..796368c4ed 100644 --- a/src/google/adk/agents/llm_agent.py +++ b/src/google/adk/agents/llm_agent.py @@ -181,7 +181,15 @@ async def _convert_tool_union_to_tools( return [FunctionTool(func=tool_union)] # At this point, tool_union must be a BaseToolset - return await tool_union.get_tools_with_prefix(ctx) + try: + return await tool_union.get_tools_with_prefix(ctx) + except Exception as e: + logger.warning( + 'Failed to get tools from toolset %s: %s', + type(tool_union).__name__, + e, + ) + return [] class LlmAgent(BaseAgent): @@ -466,12 +474,16 @@ async def _run_async_impl( if agent_state is not None and ( agent_to_transfer := self._get_subagent_to_resume(ctx) ): + sub_agent_paused = False async with Aclosing(agent_to_transfer.run_async(ctx)) as agen: async for event in agen: + if ctx.should_pause_invocation(event): + sub_agent_paused = True yield event - ctx.set_agent_state(self.name, end_of_agent=True) - yield self._create_agent_state_event(ctx) + if not sub_agent_paused: + ctx.set_agent_state(self.name, end_of_agent=True) + yield self._create_agent_state_event(ctx) return should_pause = False From 04f56d20cb982318ba396326ec1b0439a01fcebf Mon Sep 17 00:00:00 2001 From: 9chait9 <9chait9@gmail.com> Date: Fri, 17 Apr 2026 04:06:37 -0700 Subject: [PATCH 2/2] Fix issue #5349: Sub-agent with sequential LRO tools fails to resume. Modified `_run_async_impl` in `llm_agent.py` to prevent premature `end_of_agent` marking when a sub-agent pauses for an LRO. Added `sub_agent_paused` tracking to ensure `end_of_agent=True` is only set if the sub-agent actually finished. --- src/google/adk/agents/llm_agent.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/google/adk/agents/llm_agent.py b/src/google/adk/agents/llm_agent.py index 796368c4ed..f19975a1e7 100644 --- a/src/google/adk/agents/llm_agent.py +++ b/src/google/adk/agents/llm_agent.py @@ -474,13 +474,15 @@ async def _run_async_impl( if agent_state is not None and ( agent_to_transfer := self._get_subagent_to_resume(ctx) ): - sub_agent_paused = False + sub_agent_paused = False # Track pause state async with Aclosing(agent_to_transfer.run_async(ctx)) as agen: async for event in agen: + # Check if this event signals a pause (requires Bug 1 fix context) if ctx.should_pause_invocation(event): sub_agent_paused = True yield event + # Only mark as ended if it didn't pause if not sub_agent_paused: ctx.set_agent_state(self.name, end_of_agent=True) yield self._create_agent_state_event(ctx)