fix(agents): await cancelled tasks in _merge_agent_run_pre_3_11 to prevent aclose() RuntimeError#5416
Open
Koushik-Salammagari wants to merge 7 commits intogoogle:mainfrom
Conversation
…in thread pool When RunConfig.tool_thread_pool_config is enabled, _call_tool_in_thread_pool used None as a sentinel to distinguish "FunctionTool ran in thread pool" from "non-FunctionTool sync tool, needs async fallback". Because None is also a valid return value from any FunctionTool whose underlying function has no explicit return statement (implicit None), the sentinel check failed and execution fell through to tool.run_async(), invoking the function a second time silently. Replace the None sentinel with a dedicated _SYNC_TOOL_RESULT_UNSET object so that a legitimate None result from a FunctionTool is correctly returned on the first execution, without triggering the async fallback path. Fixes google#5284
…ases
Per reviewer feedback: collapse the two near-identical None tests into a
single @pytest.mark.parametrize test, and add falsy-but-not-None cases
(0, '', {}, False) to prove the sentinel is identity-based and does not
mishandle any falsy return value from a FunctionTool.
…event aclose() RuntimeError On Python 3.10, ParallelAgent uses _merge_agent_run_pre_3_11 instead of asyncio.TaskGroup. When a sub-agent raises, the finally block cancelled all tasks but did not await them. This left the internal process_an_agent coroutines still executing their own finally blocks (which hold references to the sub-agent async generators) when _run_async_impl subsequently called aclose() on those generators, raising: RuntimeError: aclose(): asynchronous generator is already running Fix: add asyncio.gather(*tasks, return_exceptions=True) after cancellation so that all tasks — and their generator cleanup — complete before the caller can invoke aclose(). Fixes google#5297
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Link to Issue or Description of Change
Fixes #5297
Description
On Python 3.10,
ParallelAgentuses_merge_agent_run_pre_3_11instead ofasyncio.TaskGroup. When a sub-agent raises an exception, thefinallyblockcancelled all internal tasks with
task.cancel()but did not await them.This left the
process_an_agentcoroutines still executing their ownfinallyblocks — which hold references to the sub-agent async generators — when
_run_async_implsubsequently calledaclose()on those generators, raising:This secondary error masked the original sub-agent exception (e.g., a
Pydantic validation failure from a structured-output agent).
Fix: add
await asyncio.gather(*tasks, return_exceptions=True)aftercancellation so all tasks — including their generator cleanup — complete fully
before the caller can invoke
aclose()on the generators.Changes
src/google/adk/agents/parallel_agent.py: one line added to_merge_agent_run_pre_3_11finally blocktests/unittests/agents/test_parallel_agent.py: regression test that directly exercises_merge_agent_run_pre_3_11with a slow generator + failing generator, then callsaclose()— without the fix this raisesRuntimeErrorTesting Plan
test_merge_agent_run_pre_3_11_no_aclose_error_on_failureadded totests/unittests/agents/test_parallel_agent.py