Skip to content

Commit 3d2e0f0

Browse files
authored
Merge branch 'main' into docs/add-new-example-mcp-without-llm-framework
2 parents 717c0d4 + 536e4a1 commit 3d2e0f0

File tree

16 files changed

+240
-82
lines changed

16 files changed

+240
-82
lines changed

examples/google_adk/birthday_planner/adk_agent_executor.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -156,9 +156,10 @@ async def _process_request(
156156
session_id: str,
157157
task_updater: TaskUpdater,
158158
) -> AsyncIterable[TaskStatus | Artifact]:
159-
session_id = self._upsert_session(
159+
session = await self._upsert_session(
160160
session_id,
161-
).id
161+
)
162+
session_id = session.id
162163
async for event in self._run_agent(
163164
session_id, new_message, task_updater
164165
):
@@ -243,10 +244,10 @@ async def cancel(self, context: RequestContext, event_queue: EventQueue):
243244
# Ideally: kill any ongoing tasks.
244245
raise ServerError(error=UnsupportedOperationError())
245246

246-
def _upsert_session(self, session_id: str):
247-
return self.runner.session_service.get_session(
247+
async def _upsert_session(self, session_id: str):
248+
return await self.runner.session_service.get_session(
248249
app_name=self.runner.app_name, user_id='self', session_id=session_id
249-
) or self.runner.session_service.create_session(
250+
) or await self.runner.session_service.create_session(
250251
app_name=self.runner.app_name, user_id='self', session_id=session_id
251252
)
252253

examples/google_adk/birthday_planner/pyproject.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,14 @@ name = "adk-a2a-client-example"
33
version = "0.1.0"
44
description = "Birthday planner agent example"
55
readme = "README.md"
6-
requires-python = ">=3.10"
6+
requires-python = ">=3.12"
77
dependencies = [
88
"a2a-sdk",
99
"click>=8.1.8",
1010
"dotenv>=0.9.9",
1111
"httpx>=0.28.1",
1212
"google-genai>=1.9.0",
13-
"google-adk>=0.0.3",
13+
"google-adk>=1.0.0",
1414
"pydantic>=2.11.4",
1515
"python-dotenv>=1.1.0",
1616
]

examples/google_adk/calendar_agent/__main__.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import asyncio
12
import logging
23
import os
34

@@ -66,10 +67,10 @@ def main(host: str, port: int):
6667
skills=[skill],
6768
)
6869

69-
adk_agent = create_agent(
70+
adk_agent = asyncio.run(create_agent(
7071
client_id=os.getenv('GOOGLE_CLIENT_ID'),
7172
client_secret=os.getenv('GOOGLE_CLIENT_SECRET'),
72-
)
73+
))
7374
runner = Runner(
7475
app_name=agent_card.name,
7576
agent=adk_agent,

examples/google_adk/calendar_agent/adk_agent.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
import datetime
22

33
from google.adk.agents import LlmAgent # type: ignore[import-untyped]
4-
from google.adk.tools.google_api_tool import calendar_tool_set # type: ignore[import-untyped]
4+
from google.adk.tools.google_api_tool import CalendarToolset # type: ignore[import-untyped]
55

66

7-
def create_agent(client_id, client_secret) -> LlmAgent:
7+
async def create_agent(client_id, client_secret) -> LlmAgent:
88
"""Constructs the ADK agent."""
9-
calendar_tool_set.configure_auth(client_id, client_secret)
9+
toolset = CalendarToolset(client_id=client_id, client_secret=client_secret)
1010
return LlmAgent(
1111
model='gemini-2.0-flash-001',
1212
name='calendar_agent',
@@ -23,5 +23,5 @@ def create_agent(client_id, client_secret) -> LlmAgent:
2323
2424
Today is {datetime.datetime.now()}.
2525
""",
26-
tools=calendar_tool_set.get_tools(),
26+
tools=await toolset.get_tools(),
2727
)

examples/google_adk/calendar_agent/adk_agent_executor.py

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -65,9 +65,10 @@ async def _process_request(
6565
session_id: str,
6666
task_updater: TaskUpdater,
6767
) -> None:
68-
session_id = self._upsert_session(
68+
session = await self._upsert_session(
6969
session_id,
70-
).id
70+
)
71+
session_id = session.id
7172
auth_details = None
7273
async for event in self._run_agent(session_id, new_message):
7374
# This agent is expected to do one of two things:
@@ -229,10 +230,10 @@ async def cancel(self, context: RequestContext, event_queue: EventQueue):
229230
async def on_auth_callback(self, state: str, uri: str):
230231
self._awaiting_auth[state].set_result(uri)
231232

232-
def _upsert_session(self, session_id: str):
233-
return self.runner.session_service.get_session(
233+
async def _upsert_session(self, session_id: str):
234+
return await self.runner.session_service.get_session(
234235
app_name=self.runner.app_name, user_id='self', session_id=session_id
235-
) or self.runner.session_service.create_session(
236+
) or await self.runner.session_service.create_session(
236237
app_name=self.runner.app_name, user_id='self', session_id=session_id
237238
)
238239

@@ -317,7 +318,7 @@ def get_auth_config(
317318
) -> AuthConfig:
318319
"""Extracts the AuthConfig object from the arguments of the auth request function call."""
319320
if not auth_request_function_call.args or not (
320-
auth_config := auth_request_function_call.args.get('auth_config')
321+
auth_config := auth_request_function_call.args.get('authConfig')
321322
):
322323
raise ValueError(
323324
f'Cannot get auth config from function call: {auth_request_function_call}'

examples/google_adk/calendar_agent/pyproject.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,14 @@ name = "adk-auth-example"
33
version = "0.1.0"
44
description = "Calendar agent example"
55
readme = "README.md"
6-
requires-python = ">=3.10"
6+
requires-python = ">=3.12"
77
dependencies = [
88
"a2a-sdk",
99
"click>=8.1.8",
1010
"dotenv>=0.9.9",
1111
"httpx>=0.28.1",
1212
"google-genai>=1.9.0",
13-
"google-adk>=0.0.3",
13+
"google-adk>=1.0.0",
1414
"pydantic>=2.11.4",
1515
"python-dotenv>=1.1.0",
1616
"uvicorn>=0.34.2",

src/a2a/server/agent_execution/context.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import uuid
22

3+
from a2a.server.context import ServerCallContext
34
from a2a.types import (
45
InvalidParamsError,
56
Message,
@@ -26,6 +27,7 @@ def __init__(
2627
context_id: str | None = None,
2728
task: Task | None = None,
2829
related_tasks: list[Task] | None = None,
30+
call_context: ServerCallContext | None = None,
2931
):
3032
"""Initializes the RequestContext.
3133
@@ -43,6 +45,7 @@ def __init__(
4345
self._context_id = context_id
4446
self._current_task = task
4547
self._related_tasks = related_tasks
48+
self._call_context = call_context
4649
# If the task id and context id were provided, make sure they
4750
# match the request. Otherwise, create them
4851
if self._params:
@@ -125,6 +128,11 @@ def configuration(self) -> MessageSendConfiguration | None:
125128
return None
126129
return self._params.configuration
127130

131+
@property
132+
def call_context(self) -> ServerCallContext | None:
133+
"""The server call context associated with this request."""
134+
return self._call_context
135+
128136
def _check_or_generate_task_id(self) -> None:
129137
"""Ensures a task ID is present, generating one if necessary."""
130138
if not self._params:

src/a2a/server/agent_execution/request_context_builder.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
from abc import ABC, abstractmethod
22

33
from a2a.server.agent_execution import RequestContext
4+
from a2a.server.context import ServerCallContext
45
from a2a.types import MessageSendParams, Task
56

67

@@ -14,5 +15,6 @@ async def build(
1415
task_id: str | None = None,
1516
context_id: str | None = None,
1617
task: Task | None = None,
18+
context: ServerCallContext | None = None,
1719
) -> RequestContext:
1820
pass

src/a2a/server/agent_execution/simple_request_context_builder.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import asyncio
22

33
from a2a.server.agent_execution import RequestContext, RequestContextBuilder
4+
from a2a.server.context import ServerCallContext
45
from a2a.server.tasks import TaskStore
56
from a2a.types import MessageSendParams, Task
67

@@ -22,6 +23,7 @@ async def build(
2223
task_id: str | None = None,
2324
context_id: str | None = None,
2425
task: Task | None = None,
26+
context: ServerCallContext | None = None,
2527
) -> RequestContext:
2628
related_tasks: list[Task] | None = None
2729

@@ -45,4 +47,5 @@ async def build(
4547
context_id=context_id,
4648
task=task,
4749
related_tasks=related_tasks,
50+
call_context=context,
4851
)

src/a2a/server/apps/starlette_app.py

Lines changed: 55 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import logging
33
import traceback
44

5+
from abc import ABC, abstractmethod
56
from collections.abc import AsyncGenerator
67
from typing import Any
78

@@ -12,9 +13,9 @@
1213
from starlette.responses import JSONResponse, Response
1314
from starlette.routing import Route
1415

15-
from a2a.server.request_handlers.request_handler import RequestHandler
16+
from a2a.server.context import ServerCallContext
1617
from a2a.server.request_handlers.jsonrpc_handler import JSONRPCHandler
17-
18+
from a2a.server.request_handlers.request_handler import RequestHandler
1819
from a2a.types import (
1920
A2AError,
2021
A2ARequest,
@@ -41,6 +42,14 @@
4142
logger = logging.getLogger(__name__)
4243

4344

45+
class CallContextBuilder(ABC):
46+
"""A class for building ServerCallContexts using the Starlette Request."""
47+
48+
@abstractmethod
49+
def build(self, request: Request) -> ServerCallContext:
50+
"""Builds a ServerCallContext from a Starlette Request."""
51+
52+
4453
class A2AStarletteApplication:
4554
"""A Starlette application implementing the A2A protocol server endpoints.
4655
@@ -49,18 +58,27 @@ class A2AStarletteApplication:
4958
(SSE).
5059
"""
5160

52-
def __init__(self, agent_card: AgentCard, http_handler: RequestHandler):
61+
def __init__(
62+
self,
63+
agent_card: AgentCard,
64+
http_handler: RequestHandler,
65+
context_builder: CallContextBuilder | None = None,
66+
):
5367
"""Initializes the A2AStarletteApplication.
5468
5569
Args:
5670
agent_card: The AgentCard describing the agent's capabilities.
5771
http_handler: The handler instance responsible for processing A2A
5872
requests via http.
73+
context_builder: The CallContextBuilder used to construct the
74+
ServerCallContext passed to the http_handler. If None, no
75+
ServerCallContext is passed.
5976
"""
6077
self.agent_card = agent_card
6178
self.handler = JSONRPCHandler(
6279
agent_card=agent_card, request_handler=http_handler
6380
)
81+
self._context_builder = context_builder
6482

6583
def _generate_error_response(
6684
self, request_id: str | int | None, error: JSONRPCError | A2AError
@@ -122,6 +140,11 @@ async def _handle_requests(self, request: Request) -> Response:
122140
try:
123141
body = await request.json()
124142
a2a_request = A2ARequest.model_validate(body)
143+
call_context = (
144+
self._context_builder.build(request)
145+
if self._context_builder
146+
else None
147+
)
125148

126149
request_id = a2a_request.root.id
127150
request_obj = a2a_request.root
@@ -131,11 +154,11 @@ async def _handle_requests(self, request: Request) -> Response:
131154
TaskResubscriptionRequest | SendStreamingMessageRequest,
132155
):
133156
return await self._process_streaming_request(
134-
request_id, a2a_request
157+
request_id, a2a_request, call_context
135158
)
136159

137160
return await self._process_non_streaming_request(
138-
request_id, a2a_request
161+
request_id, a2a_request, call_context
139162
)
140163
except MethodNotImplementedError:
141164
traceback.print_exc()
@@ -161,7 +184,10 @@ async def _handle_requests(self, request: Request) -> Response:
161184
)
162185

163186
async def _process_streaming_request(
164-
self, request_id: str | int | None, a2a_request: A2ARequest
187+
self,
188+
request_id: str | int | None,
189+
a2a_request: A2ARequest,
190+
context: ServerCallContext,
165191
) -> Response:
166192
"""Processes streaming requests (message/stream or tasks/resubscribe).
167193
@@ -178,14 +204,21 @@ async def _process_streaming_request(
178204
request_obj,
179205
SendStreamingMessageRequest,
180206
):
181-
handler_result = self.handler.on_message_send_stream(request_obj)
207+
handler_result = self.handler.on_message_send_stream(
208+
request_obj, context
209+
)
182210
elif isinstance(request_obj, TaskResubscriptionRequest):
183-
handler_result = self.handler.on_resubscribe_to_task(request_obj)
211+
handler_result = self.handler.on_resubscribe_to_task(
212+
request_obj, context
213+
)
184214

185215
return self._create_response(handler_result)
186216

187217
async def _process_non_streaming_request(
188-
self, request_id: str | int | None, a2a_request: A2ARequest
218+
self,
219+
request_id: str | int | None,
220+
a2a_request: A2ARequest,
221+
context: ServerCallContext,
189222
) -> Response:
190223
"""Processes non-streaming requests (message/send, tasks/get, tasks/cancel, tasks/pushNotificationConfig/*).
191224
@@ -200,18 +233,26 @@ async def _process_non_streaming_request(
200233
handler_result: Any = None
201234
match request_obj:
202235
case SendMessageRequest():
203-
handler_result = await self.handler.on_message_send(request_obj)
236+
handler_result = await self.handler.on_message_send(
237+
request_obj, context
238+
)
204239
case CancelTaskRequest():
205-
handler_result = await self.handler.on_cancel_task(request_obj)
240+
handler_result = await self.handler.on_cancel_task(
241+
request_obj, context
242+
)
206243
case GetTaskRequest():
207-
handler_result = await self.handler.on_get_task(request_obj)
244+
handler_result = await self.handler.on_get_task(
245+
request_obj, context
246+
)
208247
case SetTaskPushNotificationConfigRequest():
209248
handler_result = await self.handler.set_push_notification(
210-
request_obj
249+
request_obj,
250+
context,
211251
)
212252
case GetTaskPushNotificationConfigRequest():
213253
handler_result = await self.handler.get_push_notification(
214-
request_obj
254+
request_obj,
255+
context,
215256
)
216257
case _:
217258
logger.error(

0 commit comments

Comments
 (0)