From d78eae682f9519c5b7eccf2ab4b58d31ca0a3af9 Mon Sep 17 00:00:00 2001 From: Phil Stephens Date: Thu, 22 May 2025 00:57:36 +0000 Subject: [PATCH 1/6] feat: Update to support python 3.12 - add case statement to use the asyncio.Queue.shutdown method for 3.13+ - add special handling to allow for similar semantics as asyncio.Queue.shutdown for 3.12 Tested on multiple samples in the a2a repo and some examples in this repo --- pyproject.toml | 4 ++++ src/a2a/server/events/event_consumer.py | 6 ++++++ 2 files changed, 10 insertions(+) diff --git a/pyproject.toml b/pyproject.toml index 9bb3814a..a01a9014 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -22,10 +22,14 @@ classifiers = [ "Intended Audience :: Developers", "Programming Language :: Python", "Programming Language :: Python :: 3", +<<<<<<< HEAD "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", +======= + "Programming Language :: Python :: 3.12", +>>>>>>> 8ec734c (feat: Update to support python 3.12) "Operating System :: OS Independent", "Topic :: Software Development :: Libraries :: Python Modules", "License :: OSI Approved :: Apache Software License", diff --git a/src/a2a/server/events/event_consumer.py b/src/a2a/server/events/event_consumer.py index 6fc91856..89ba90d2 100644 --- a/src/a2a/server/events/event_consumer.py +++ b/src/a2a/server/events/event_consumer.py @@ -15,6 +15,12 @@ from a2a.utils.errors import ServerError from a2a.utils.telemetry import SpanKind, trace_class +# This is an alias to the execption for closed queue +QueueClosed = asyncio.QueueEmpty + +# When using python 3.13 or higher, the closed queue signal is QueueShutdown +if sys.version_info >= (3, 13): + QueueClosed = asyncio.QueueShutDown # This is an alias to the exception for closed queue QueueClosed = asyncio.QueueEmpty From 3649a7e137765595fb0147f8285d98f035148a5a Mon Sep 17 00:00:00 2001 From: Phil Stephens Date: Thu, 22 May 2025 15:08:38 +0000 Subject: [PATCH 2/6] Change to 3.10 and provided detailed description about event queue usage --- pyproject.toml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index a01a9014..9bb3814a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -22,14 +22,10 @@ classifiers = [ "Intended Audience :: Developers", "Programming Language :: Python", "Programming Language :: Python :: 3", -<<<<<<< HEAD "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", -======= - "Programming Language :: Python :: 3.12", ->>>>>>> 8ec734c (feat: Update to support python 3.12) "Operating System :: OS Independent", "Topic :: Software Development :: Libraries :: Python Modules", "License :: OSI Approved :: Apache Software License", From 00e03d5b47711318381261017cc1ef8793d22ce1 Mon Sep 17 00:00:00 2001 From: Phil Stephens Date: Thu, 22 May 2025 18:12:21 +0000 Subject: [PATCH 3/6] Update birthday agent example with adk 1.0 --- .../google_adk/birthday_planner/adk_agent_executor.py | 11 ++++++----- examples/google_adk/birthday_planner/pyproject.toml | 4 ++-- examples/google_adk/calendar_agent/__main__.py | 5 +++-- examples/google_adk/calendar_agent/adk_agent.py | 8 ++++---- .../google_adk/calendar_agent/adk_agent_executor.py | 11 ++++++----- examples/google_adk/calendar_agent/pyproject.toml | 4 ++-- 6 files changed, 23 insertions(+), 20 deletions(-) diff --git a/examples/google_adk/birthday_planner/adk_agent_executor.py b/examples/google_adk/birthday_planner/adk_agent_executor.py index 7b4c396f..c5966a9d 100644 --- a/examples/google_adk/birthday_planner/adk_agent_executor.py +++ b/examples/google_adk/birthday_planner/adk_agent_executor.py @@ -156,9 +156,10 @@ async def _process_request( session_id: str, task_updater: TaskUpdater, ) -> AsyncIterable[TaskStatus | Artifact]: - session_id = self._upsert_session( + session = await self._upsert_session( session_id, - ).id + ) + session_id = session.id async for event in self._run_agent( session_id, new_message, task_updater ): @@ -243,10 +244,10 @@ async def cancel(self, context: RequestContext, event_queue: EventQueue): # Ideally: kill any ongoing tasks. raise ServerError(error=UnsupportedOperationError()) - def _upsert_session(self, session_id: str): - return self.runner.session_service.get_session( + async def _upsert_session(self, session_id: str): + return await self.runner.session_service.get_session( app_name=self.runner.app_name, user_id='self', session_id=session_id - ) or self.runner.session_service.create_session( + ) or await self.runner.session_service.create_session( app_name=self.runner.app_name, user_id='self', session_id=session_id ) diff --git a/examples/google_adk/birthday_planner/pyproject.toml b/examples/google_adk/birthday_planner/pyproject.toml index 24eaff37..81f71729 100644 --- a/examples/google_adk/birthday_planner/pyproject.toml +++ b/examples/google_adk/birthday_planner/pyproject.toml @@ -3,14 +3,14 @@ name = "adk-a2a-client-example" version = "0.1.0" description = "Birthday planner agent example" readme = "README.md" -requires-python = ">=3.10" +requires-python = ">=3.12" dependencies = [ "a2a-sdk", "click>=8.1.8", "dotenv>=0.9.9", "httpx>=0.28.1", "google-genai>=1.9.0", - "google-adk>=0.0.3", + "google-adk>=1.0.0", "pydantic>=2.11.4", "python-dotenv>=1.1.0", ] diff --git a/examples/google_adk/calendar_agent/__main__.py b/examples/google_adk/calendar_agent/__main__.py index 448e7ba5..f577bf2a 100644 --- a/examples/google_adk/calendar_agent/__main__.py +++ b/examples/google_adk/calendar_agent/__main__.py @@ -1,3 +1,4 @@ +import asyncio import logging import os @@ -66,10 +67,10 @@ def main(host: str, port: int): skills=[skill], ) - adk_agent = create_agent( + adk_agent = asyncio.run(create_agent( client_id=os.getenv('GOOGLE_CLIENT_ID'), client_secret=os.getenv('GOOGLE_CLIENT_SECRET'), - ) + )) runner = Runner( app_name=agent_card.name, agent=adk_agent, diff --git a/examples/google_adk/calendar_agent/adk_agent.py b/examples/google_adk/calendar_agent/adk_agent.py index 90da3f1f..e9f06a6f 100644 --- a/examples/google_adk/calendar_agent/adk_agent.py +++ b/examples/google_adk/calendar_agent/adk_agent.py @@ -1,12 +1,12 @@ import datetime from google.adk.agents import LlmAgent # type: ignore[import-untyped] -from google.adk.tools.google_api_tool import calendar_tool_set # type: ignore[import-untyped] +from google.adk.tools.google_api_tool import CalendarToolset # type: ignore[import-untyped] -def create_agent(client_id, client_secret) -> LlmAgent: +async def create_agent(client_id, client_secret) -> LlmAgent: """Constructs the ADK agent.""" - calendar_tool_set.configure_auth(client_id, client_secret) + toolset = CalendarToolset(client_id=client_id, client_secret=client_secret) return LlmAgent( model='gemini-2.0-flash-001', name='calendar_agent', @@ -23,5 +23,5 @@ def create_agent(client_id, client_secret) -> LlmAgent: Today is {datetime.datetime.now()}. """, - tools=calendar_tool_set.get_tools(), + tools=await toolset.get_tools(), ) diff --git a/examples/google_adk/calendar_agent/adk_agent_executor.py b/examples/google_adk/calendar_agent/adk_agent_executor.py index b52d74ad..f6a57ee9 100644 --- a/examples/google_adk/calendar_agent/adk_agent_executor.py +++ b/examples/google_adk/calendar_agent/adk_agent_executor.py @@ -65,9 +65,10 @@ async def _process_request( session_id: str, task_updater: TaskUpdater, ) -> None: - session_id = self._upsert_session( + session = await self._upsert_session( session_id, - ).id + ) + session_id = session.id auth_details = None async for event in self._run_agent(session_id, new_message): # This agent is expected to do one of two things: @@ -229,10 +230,10 @@ async def cancel(self, context: RequestContext, event_queue: EventQueue): async def on_auth_callback(self, state: str, uri: str): self._awaiting_auth[state].set_result(uri) - def _upsert_session(self, session_id: str): - return self.runner.session_service.get_session( + async def _upsert_session(self, session_id: str): + return await self.runner.session_service.get_session( app_name=self.runner.app_name, user_id='self', session_id=session_id - ) or self.runner.session_service.create_session( + ) or await self.runner.session_service.create_session( app_name=self.runner.app_name, user_id='self', session_id=session_id ) diff --git a/examples/google_adk/calendar_agent/pyproject.toml b/examples/google_adk/calendar_agent/pyproject.toml index c2e53ee0..0fdfe484 100644 --- a/examples/google_adk/calendar_agent/pyproject.toml +++ b/examples/google_adk/calendar_agent/pyproject.toml @@ -3,14 +3,14 @@ name = "adk-auth-example" version = "0.1.0" description = "Calendar agent example" readme = "README.md" -requires-python = ">=3.10" +requires-python = ">=3.12" dependencies = [ "a2a-sdk", "click>=8.1.8", "dotenv>=0.9.9", "httpx>=0.28.1", "google-genai>=1.9.0", - "google-adk>=0.0.3", + "google-adk>=1.0.0", "pydantic>=2.11.4", "python-dotenv>=1.1.0", "uvicorn>=0.34.2", From 081e6952b6b61d8ff4167b8c329da916855f0553 Mon Sep 17 00:00:00 2001 From: Phil Stephens Date: Thu, 22 May 2025 18:33:16 +0000 Subject: [PATCH 4/6] Fix field name for auth_config -> authConfig in calendar agent --- examples/google_adk/calendar_agent/adk_agent_executor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/google_adk/calendar_agent/adk_agent_executor.py b/examples/google_adk/calendar_agent/adk_agent_executor.py index f6a57ee9..5fb78aad 100644 --- a/examples/google_adk/calendar_agent/adk_agent_executor.py +++ b/examples/google_adk/calendar_agent/adk_agent_executor.py @@ -318,7 +318,7 @@ def get_auth_config( ) -> AuthConfig: """Extracts the AuthConfig object from the arguments of the auth request function call.""" if not auth_request_function_call.args or not ( - auth_config := auth_request_function_call.args.get('auth_config') + auth_config := auth_request_function_call.args.get('authConfig') ): raise ValueError( f'Cannot get auth config from function call: {auth_request_function_call}' From 3e170fae6b859009d661c34d0e12e21d27e557ed Mon Sep 17 00:00:00 2001 From: pstephengoogle Date: Thu, 22 May 2025 12:36:54 -0600 Subject: [PATCH 5/6] Update event_consumer.py --- src/a2a/server/events/event_consumer.py | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/a2a/server/events/event_consumer.py b/src/a2a/server/events/event_consumer.py index 89ba90d2..5296ec3f 100644 --- a/src/a2a/server/events/event_consumer.py +++ b/src/a2a/server/events/event_consumer.py @@ -15,13 +15,6 @@ from a2a.utils.errors import ServerError from a2a.utils.telemetry import SpanKind, trace_class -# This is an alias to the execption for closed queue -QueueClosed = asyncio.QueueEmpty - -# When using python 3.13 or higher, the closed queue signal is QueueShutdown -if sys.version_info >= (3, 13): - QueueClosed = asyncio.QueueShutDown - # This is an alias to the exception for closed queue QueueClosed = asyncio.QueueEmpty From eff23399b454c582ed75e2d14a213c46d1b93616 Mon Sep 17 00:00:00 2001 From: pstephengoogle Date: Thu, 22 May 2025 12:37:11 -0600 Subject: [PATCH 6/6] Update event_consumer.py --- src/a2a/server/events/event_consumer.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/a2a/server/events/event_consumer.py b/src/a2a/server/events/event_consumer.py index 5296ec3f..6fc91856 100644 --- a/src/a2a/server/events/event_consumer.py +++ b/src/a2a/server/events/event_consumer.py @@ -15,6 +15,7 @@ from a2a.utils.errors import ServerError from a2a.utils.telemetry import SpanKind, trace_class + # This is an alias to the exception for closed queue QueueClosed = asyncio.QueueEmpty