Skip to content

Commit 3716b35

Browse files
authored
Merge pull request #649 from esnible/upgrade-a2a-dep
chore: Upgrade a2a-sdk dependencies
2 parents bac1b4a + 87be0d5 commit 3716b35

18 files changed

Lines changed: 468 additions & 190 deletions

File tree

a2a/claude_agent/pyproject.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ readme = "README.md"
66
license = { text = "Apache" }
77
requires-python = ">=3.11"
88
dependencies = [
9-
# http-server extra pulls in the Starlette/SSE stack that A2AStarletteApplication needs.
10-
"a2a-sdk[http-server]==0.3.26",
9+
# http-server extra pulls in the Starlette/SSE stack the route factories need.
10+
"a2a-sdk[http-server]>=1.1.0,<2",
1111
"pydantic-settings>=2.14.1",
1212
"uvicorn>=0.30",
1313
"starlette>=0.49.1", # Indirect; prevents CVE-2025-62727

a2a/claude_agent/src/claude_agent/agent.py

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,15 @@
44
from textwrap import dedent
55

66
import uvicorn
7+
from starlette.applications import Starlette
78

9+
from a2a.helpers import new_task_from_user_message
810
from a2a.server.agent_execution import AgentExecutor, RequestContext
9-
from a2a.server.apps import A2AStarletteApplication
1011
from a2a.server.events.event_queue import EventQueue
1112
from a2a.server.request_handlers import DefaultRequestHandler
13+
from a2a.server.routes import create_agent_card_routes, create_jsonrpc_routes
1214
from a2a.server.tasks import InMemoryTaskStore, TaskUpdater
13-
from a2a.types import AgentCapabilities, AgentCard, AgentSkill
14-
from a2a.utils import new_task
15+
from a2a.types import AgentCapabilities, AgentCard, AgentInterface, AgentSkill
1516
from claude_agent.configuration import Configuration
1617
from claude_agent.events import StreamTranslator
1718
from claude_agent.runner import run_turn
@@ -46,7 +47,12 @@ def get_agent_card(host: str, port: int) -> AgentCard:
4647
- **prompt** (string) – the instruction or question for Claude.
4748
"""
4849
),
49-
url=os.getenv("AGENT_ENDPOINT", f"http://{host}:{port}").rstrip("/") + "/",
50+
supported_interfaces=[
51+
AgentInterface(
52+
url=os.getenv("AGENT_ENDPOINT", f"http://{host}:{port}").rstrip("/") + "/",
53+
protocol_binding="JSONRPC",
54+
)
55+
],
5056
version="1.0.0",
5157
default_input_modes=["text"],
5258
default_output_modes=["text"],
@@ -71,7 +77,7 @@ def __init__(
7177
async def execute(self, context: RequestContext, event_queue: EventQueue) -> None:
7278
task = context.current_task
7379
if not task:
74-
task = new_task(context.message) # type: ignore
80+
task = new_task_from_user_message(context.message) # type: ignore
7581
await event_queue.enqueue_event(task)
7682
task_updater = TaskUpdater(event_queue, task.id, task.context_id)
7783
translator = StreamTranslator(task_updater)
@@ -118,11 +124,16 @@ def run() -> None:
118124
request_handler = DefaultRequestHandler(
119125
agent_executor=ClaudeAgentExecutor(config, registry, semaphore),
120126
task_store=InMemoryTaskStore(),
127+
agent_card=agent_card,
121128
)
122-
server = A2AStarletteApplication(agent_card=agent_card, http_handler=request_handler)
123-
# build() serves the agent card at /.well-known/agent-card.json natively
124-
# (a2a-sdk's default AGENT_CARD_WELL_KNOWN_PATH), plus the legacy
125-
# /.well-known/agent.json for back-compat — no custom route needed.
126-
app = server.build()
129+
# a2a-sdk 1.x replaced A2AStarletteApplication with route factories that we
130+
# assemble into a Starlette app ourselves. Serve the current well-known path
131+
# (/.well-known/agent-card.json) plus the legacy /.well-known/agent.json for
132+
# back-compat.
133+
# enable_v0_3_compat is needed because Kagenti uses A2A 0.3 client libraries
134+
routes = create_jsonrpc_routes(request_handler, rpc_url="/", enable_v0_3_compat=True)
135+
routes += create_agent_card_routes(agent_card)
136+
routes += create_agent_card_routes(agent_card, card_url="/.well-known/agent.json")
137+
app = Starlette(routes=routes)
127138

128139
uvicorn.run(app, host=config.host, port=config.port)

a2a/claude_agent/src/claude_agent/events.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import json
22
import logging
33

4-
from a2a.types import TaskState, TextPart
5-
from a2a.utils import new_agent_text_message
4+
from a2a.helpers import new_text_part
5+
from a2a.types import TaskState
66

77
logger = logging.getLogger(__name__)
88

@@ -33,8 +33,8 @@ async def _working(self, text: str) -> None:
3333
if not text.strip():
3434
return
3535
await self._tu.update_status(
36-
TaskState.working,
37-
new_agent_text_message(text, self._tu.context_id, self._tu.task_id),
36+
TaskState.TASK_STATE_WORKING,
37+
self._tu.new_agent_message([new_text_part(text)]),
3838
)
3939

4040
async def handle(self, event: dict) -> None:
@@ -70,8 +70,8 @@ async def finish(self) -> None:
7070
"""Emit the terminal A2A state based on what was accumulated."""
7171
if self.errored or self.final_text is None:
7272
reason = self.error_reason or "Claude produced no result"
73-
await self._tu.add_artifact([TextPart(text=f"Error: {reason}")])
73+
await self._tu.add_artifact([new_text_part(f"Error: {reason}")])
7474
await self._tu.failed()
7575
else:
76-
await self._tu.add_artifact([TextPart(text=self.final_text)])
76+
await self._tu.add_artifact([new_text_part(self.final_text)])
7777
await self._tu.complete()

a2a/claude_agent/tests/test_agent.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@
1010
def test_agent_card_has_streaming_and_url():
1111
card = get_agent_card("0.0.0.0", 8000)
1212
assert card.capabilities.streaming is True
13-
assert card.url.endswith("/")
13+
# a2a-sdk 1.x moved the URL from AgentCard.url into supported_interfaces.
14+
assert card.supported_interfaces[0].url.endswith("/")
1415
assert card.skills # at least one skill advertised
1516

1617

0 commit comments

Comments
 (0)