From 8a595978632e1bd87fbf53bad06d72a1d4703226 Mon Sep 17 00:00:00 2001 From: Huang Huang Date: Mon, 20 Oct 2025 13:53:50 +0800 Subject: [PATCH] fix(kagent-adk/cli/test): fix "asyncio.exceptions.CancelledError" ## before ``` $ uv run cli.py test --task 'who are you' --filepath config.json INFO:root:Starting KAgent INFO:kagent.adk._a2a: >>> User Query: who are you xxx INFO:kagent.adk._a2a: [Event] {xxxx} ERROR:asyncio:unhandled exception during asyncio.run() shutdown task: ()> exception=RuntimeError('Attempted to exit cancel scope in a different task than it was entered in')> Traceback (most recent call last): File "/xxx/kagent/python/.venv/lib/python3.13/site-packages/anyio/_backends/_asyncio.py", line 776, in __aexit__ raise exc_val File "/xxx/kagent/python/.venv/lib/python3.13/site-packages/mcp/client/streamable_http.py", line 498, in streamablehttp_client yield ( ...<3 lines>... ) asyncio.exceptions.CancelledError During handling of the above exception, another exception occurred: Traceback (most recent call last): File "/xxx/kagent/python/.venv/lib/python3.13/site-packages/mcp/client/streamable_http.py", line 474, in streamablehttp_client async with anyio.create_task_group() as tg: ~~~~~~~~~~~~~~~~~~~~~~~^^ File "/xxx/kagent/python/.venv/lib/python3.13/site-packages/anyio/_backends/_asyncio.py", line 778, in __aexit__ if self.cancel_scope.__exit__(type(exc), exc, exc.__traceback__): ~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/xxx/kagent/python/.venv/lib/python3.13/site-packages/anyio/_backends/_asyncio.py", line 457, in __exit__ raise RuntimeError( ...<2 lines>... ) RuntimeError: Attempted to exit cancel scope in a different task than it was entered in ``` ## After ``` $ uv run cli.py test --task 'who are you' --filepath config.json INFO:root:Starting KAgent INFO:kagent.adk._a2a: >>> User Query: who are you xxx INFO:kagent.adk._a2a: [Event] {xxx} INFO:google_adk.google.adk.runners:Closing toolset: MCPToolset INFO:google_adk.google.adk.runners:Successfully closed toolset: MCPToolset ``` Signed-off-by: Huang Huang --- .../kagent-adk/src/kagent/adk/_a2a.py | 31 ++++++++++++------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/python/packages/kagent-adk/src/kagent/adk/_a2a.py b/python/packages/kagent-adk/src/kagent/adk/_a2a.py index def2ff1cc..04e17682b 100644 --- a/python/packages/kagent-adk/src/kagent/adk/_a2a.py +++ b/python/packages/kagent-adk/src/kagent/adk/_a2a.py @@ -123,14 +123,23 @@ async def test(self, task: str): content = types.Content(role="user", parts=[types.Part(text=task)]) # Key Concept: run_async executes the agent logic and yields Events. # We iterate through events to find the final answer. - async for event in runner.run_async( - user_id=USER_ID, - session_id=SESSION_ID, - new_message=content, - ): - # You can uncomment the line below to see *all* events during execution - # print(f" [Event] Author: {event.author}, Type: {type(event).__name__}, Final: {event.is_final_response()}, Content: {event.content}") - - # Key Concept: is_final_response() marks the concluding message for the turn. - jsn = event.model_dump_json() - logger.info(f" [Event] {jsn}") + try: + async for event in runner.run_async( + user_id=USER_ID, + session_id=SESSION_ID, + new_message=content, + ): + # You can uncomment the line below to see *all* events during execution + # print(f" [Event] Author: {event.author}, Type: {type(event).__name__}, Final: {event.is_final_response()}, Content: {event.content}") + + # Key Concept: is_final_response() marks the concluding message for the turn. + jsn = event.model_dump_json() + logger.info(f" [Event] {jsn}") + finally: + # Ensure proper cleanup of any async resources + try: + # Close any open connections or resources + if hasattr(runner, 'close'): + await runner.close() + except Exception as cleanup_error: + logger.warning(f"Error during cleanup: {cleanup_error}")