Skip to content

Commit c2ba5cb

Browse files
feat: Bump a2a-python version (#24)
Contains pkg update to latest https://github.com/a2aproject/a2a-python and all the required changes --------- Signed-off-by: Janos Sarusi-Kis <janossk@cisco.com>
1 parent 702baed commit c2ba5cb

10 files changed

Lines changed: 213 additions & 49 deletions

File tree

examples/echo_agent/client.py

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,10 @@
1010
from a2a.client import (
1111
A2ACardResolver,
1212
Client,
13-
create_text_message_object,
1413
minimal_agent_card,
1514
)
16-
from a2a.types.a2a_pb2 import AgentCard, SendMessageRequest
15+
from a2a.helpers import new_text_message
16+
from a2a.types.a2a_pb2 import AgentCard, Role, SendMessageRequest
1717
from a2a.utils.constants import (
1818
AGENT_CARD_WELL_KNOWN_PATH,
1919
)
@@ -160,25 +160,25 @@ async def send_message(
160160
client: Client,
161161
text: str,
162162
) -> str:
163-
message = create_text_message_object(content=text)
163+
message = new_text_message(text, role=Role.ROLE_USER)
164164
request = SendMessageRequest(message=message)
165165

166166
output = ""
167167
try:
168-
async for stream_response, task in client.send_message(request=request):
168+
async for stream_response in client.send_message(request=request):
169169
which = stream_response.WhichOneof("payload")
170170
if which == "message":
171171
for part in stream_response.message.parts:
172172
if part.WhichOneof("content") == "text":
173173
output += part.text
174174
elif which == "task":
175-
if task:
176-
logger.info(f"task ({task.id}) status: {task.status.state}")
177-
if task.artifacts:
178-
for artifact in task.artifacts:
179-
for part in artifact.parts:
180-
if part.WhichOneof("content") == "text":
181-
output += part.text
175+
task = stream_response.task
176+
logger.info(f"task ({task.id}) status: {task.status.state}")
177+
if task.artifacts:
178+
for artifact in task.artifacts:
179+
for part in artifact.parts:
180+
if part.WhichOneof("content") == "text":
181+
output += part.text
182182
elif which == "artifact_update":
183183
artifact = stream_response.artifact_update.artifact
184184
for part in artifact.parts:
@@ -198,7 +198,7 @@ async def send_message_multicast(
198198
client: MulticastClient,
199199
text: str,
200200
) -> None:
201-
message = create_text_message_object(content=text)
201+
message = new_text_message(text, role=Role.ROLE_USER)
202202
request = SendMessageRequest(message=message)
203203

204204
try:

examples/echo_agent/echo_agent_executor.py

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import logging
22

3+
from a2a.helpers import new_task_from_user_message
34
from a2a.server.agent_execution import AgentExecutor, RequestContext
45
from a2a.server.events import EventQueue
56
from a2a.server.tasks.task_updater import TaskUpdater
@@ -26,12 +27,18 @@ async def execute(
2627

2728
logging.debug(f"received message: {context.message}")
2829

30+
# The V2 request handler requires an initial Task to be enqueued
31+
# before any status/artifact update events are emitted.
32+
task = context.current_task
33+
if task is None:
34+
task = new_task_from_user_message(context.message)
35+
await event_queue.enqueue_event(task)
36+
2937
task_updater = TaskUpdater(
3038
event_queue=event_queue,
31-
task_id=context.message.task_id,
32-
context_id=context.message.context_id,
39+
task_id=task.id,
40+
context_id=task.context_id,
3341
)
34-
await task_updater.submit(message=context.message)
3542

3643
if context.message.parts[0].WhichOneof("content") != "text":
3744
raise Exception("only text parts are supported")

examples/echo_agent/server.py

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ async def main() -> None:
5252
default_request_handler = DefaultRequestHandler(
5353
agent_executor=agent_executor,
5454
task_store=task_store,
55+
agent_card=agent_card,
5556
)
5657

5758
match args.type:
@@ -91,14 +92,23 @@ async def main() -> None:
9192
await server.serve_async()
9293
case "starlette":
9394
import uvicorn
94-
from a2a.server.apps import A2AStarletteApplication
95+
from a2a.server.routes import (
96+
create_agent_card_routes,
97+
create_jsonrpc_routes,
98+
)
99+
from starlette.applications import Starlette
95100

96-
servicer = A2AStarletteApplication(
97-
agent_card=agent_card,
98-
http_handler=default_request_handler,
101+
routes = create_agent_card_routes(agent_card=agent_card)
102+
routes += create_jsonrpc_routes(
103+
request_handler=default_request_handler,
104+
rpc_url="/",
99105
)
106+
app = Starlette(routes=routes)
100107

101-
uvicorn.run(servicer.build(), host="0.0.0.0", port=9999)
108+
# main() already runs inside asyncio.run(), so use the awaitable
109+
# uvicorn Server API instead of the blocking uvicorn.run().
110+
config = uvicorn.Config(app, host="0.0.0.0", port=9999)
111+
await uvicorn.Server(config).serve()
102112
case _:
103113
raise ValueError(f"Invalid server type: {args.type}")
104114

examples/travel_planner_agent/agent_executor.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
from a2a.helpers import new_text_artifact
12
from a2a.server.agent_execution import AgentExecutor, RequestContext
23
from a2a.server.events import EventQueue
34
from a2a.types import (
@@ -6,7 +7,6 @@
67
TaskStatus,
78
TaskStatusUpdateEvent,
89
)
9-
from a2a.utils import new_text_artifact
1010
from typing_extensions import override
1111

1212
from examples.travel_planner_agent.agent import TravelPlannerAgent

examples/travel_planner_agent/client.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,10 @@
1414
from a2a.client import (
1515
Client,
1616
ClientFactory,
17-
create_text_message_object,
1817
minimal_agent_card,
1918
)
20-
from a2a.types.a2a_pb2 import SendMessageRequest
19+
from a2a.helpers import new_text_message
20+
from a2a.types.a2a_pb2 import Role, SendMessageRequest
2121

2222
from slima2a import setup_slim_client
2323
from slima2a.client_transport import (
@@ -43,19 +43,20 @@ async def interact_with_server(client: Client) -> None:
4343
print("bye!~")
4444
break
4545

46-
message = create_text_message_object(content=user_input)
46+
message = new_text_message(user_input, role=Role.ROLE_USER)
4747
request = SendMessageRequest(message=message)
4848

4949
output = ""
5050
try:
51-
async for stream_response, task in client.send_message(request=request):
51+
async for stream_response in client.send_message(request=request):
5252
which = stream_response.WhichOneof("payload")
5353
if which == "message":
5454
for part in stream_response.message.parts:
5555
if part.WhichOneof("content") == "text":
5656
output += part.text
5757
elif which == "task":
58-
if task and task.artifacts:
58+
task = stream_response.task
59+
if task.artifacts:
5960
for artifact in task.artifacts:
6061
for part in artifact.parts:
6162
if part.WhichOneof("content") == "text":

examples/travel_planner_agent/server.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ async def main() -> None:
4949
request_handler = DefaultRequestHandler(
5050
agent_executor=TravelPlannerAgentExecutor(),
5151
task_store=InMemoryTaskStore(),
52+
agent_card=agent_card,
5253
)
5354

5455
# Initialize and connect to SLIM

pyproject.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ description = "A2A protocol over slimrpc"
88
readme = "README.md"
99
requires-python = ">=3.10, <4.0"
1010
dependencies = [
11-
"a2a-sdk[telemetry,sqlite]==1.0.0-alpha.0",
11+
"a2a-sdk[telemetry,sqlite]==1.1.0",
1212
"slim-bindings>=1.4,<2",
1313
]
1414
classifiers = [
@@ -34,6 +34,7 @@ Changelog = "https://github.com/agntcy/slim/blob/main/data-plane/python/integrat
3434
linting = ["ruff>=0.12", "mypy>=1.17.0", "types-protobuf>=6.30.2.20250822"]
3535
testing = ["pytest>=8.3.4"]
3636
examples = [
37+
"a2a-sdk[http-server]",
3738
"langchain-core",
3839
"langchain-openai",
3940
"typing-extensions",

slima2a/client_transport.py

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -267,9 +267,8 @@ class MultiAgentClientFactory(ClientFactory):
267267
def __init__(
268268
self,
269269
config: ClientConfig,
270-
consumers: list | None = None,
271270
) -> None:
272-
super().__init__(config, consumers)
271+
super().__init__(config)
273272
self._config: ClientConfig = config
274273
self._multiagent_labels: set[str] = set()
275274
self.register("slimrpc", SRPCTransport.create, multiagent=True) # type: ignore[arg-type]
@@ -287,14 +286,13 @@ def register( # type: ignore[override]
287286
def create( # type: ignore[override]
288287
self,
289288
card: AgentCard | list[AgentCard],
290-
consumers: list | None = None,
291289
interceptors: list | None = None,
292290
) -> "Client | MulticastClient":
293291
if not isinstance(card, list):
294-
return super().create(card, consumers, interceptors)
292+
return super().create(card, interceptors)
295293

296294
if len(card) == 1:
297-
return super().create(card[0], consumers, interceptors)
295+
return super().create(card[0], interceptors)
298296

299297
protocol = self._find_common_multiagent_protocol(card)
300298
producer = self._registry[protocol]

slima2a/handler.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,11 @@
1313
get_requested_extensions,
1414
)
1515
from a2a.server.context import ServerCallContext
16-
from a2a.server.request_handlers.request_handler import RequestHandler
16+
from a2a.server.request_handlers.request_handler import RequestHandler, validate
1717
from a2a.types import a2a_pb2
1818
from a2a.types.a2a_pb2 import AgentCard
1919
from a2a.utils import proto_utils
2020
from a2a.utils.errors import A2AError, TaskNotFoundError
21-
from a2a.utils.helpers import validate, validate_async_generator
2221
from google.protobuf import empty_pb2
2322
from google.rpc import code_pb2
2423

@@ -132,7 +131,7 @@ async def SendMessage(
132131
await self.raise_error_response(e)
133132
return a2a_pb2.SendMessageResponse()
134133

135-
@validate_async_generator(
134+
@validate(
136135
lambda self: self.agent_card.capabilities.streaming,
137136
"Streaming is not supported by the agent",
138137
)
@@ -168,7 +167,7 @@ async def CancelTask(
168167
await self.raise_error_response(e)
169168
return a2a_pb2.Task()
170169

171-
@validate_async_generator(
170+
@validate(
172171
lambda self: self.agent_card.capabilities.streaming,
173172
"Streaming is not supported by the agent",
174173
)

0 commit comments

Comments
 (0)