A2AAgent class. It connects to any remote agent implementing A2A 1.0 or above (when the peer only offers 0.3, the official SDK falls back to a compatible transport), turns the messages, statuses, and artifacts returned by the remote agent into AgentScope messages and events, and sends user input (multimodal data included) to the remote agent.
A2AAgent is only a local proxy for the remote agent’s logic; it holds no logic of its own. Its interface matches the Agent class, with the following differences:
Quickstart
1
Install the dependency
A2A support relies on the official SDK, installed with the
a2a extra.Install the dependency
2
Fetch the agent card
An agent card is the remote agent’s self-description: a JSON document at a well-known address recording its name, summary, capabilities, and the transports and endpoints it offers.
A2AAgent uses it to identify the peer and pick a transport, so a connection starts by fetching the card.Resolve an agent card
3
Create an A2AAgent and talk to it
Hand the card to
A2AAgent. It owns an A2A client of its own and closes it when leaving the context manager, so one instance serves one conversation and cannot be reopened after closing.The conversation interface matches a local agent’s: reply_stream yields events in real time, while reply consumes them internally and returns the final message.A2AAgent.reply_stream takes no yield_final_msg argument: the final message is assembled by A2AAgent after the stream ends, so use reply when you need it.4
(Optional) Hand it to the console
The event stream is identical to a local agent’s, so a remote agent can be dropped straight into the console for interactive debugging.
Talk to a remote agent in the terminal
client and state are keyword-only:
Protocol Translation
AllA2AAgent does is translate A2A concepts into AgentScope concepts, at three levels: conversation identifiers, response payloads, and content parts.
Conversations and Tasks
A2A organizes a conversation with two identifiers. They do not map one-to-one onto AgentScope concepts, which is the easiest thing to get wrong in practice:
Both are stored in
A2AAgentState. That state also carries a local session_id, used only to group the events this adapter produces and unrelated to the remote side.
Response Payloads
Every kind of remote response payload is broken down into content parts for translation; the payload itself only decides which task the content belongs to and how the reply ends:Content Parts
Each part becomes a content block of the matching type:
The event stream therefore only carries reply start/end events and text / data block events, so filtering on
TextBlockDeltaEvent as the streaming example above does covers almost every text scenario. The metadata["a2a"] of a block-end event records which A2A object it came from (task_id, artifact_id, message_id), and the metadata["a2a"] of the final message records the context_id.
Thinking blocks, tool call blocks, hint blocks, and push notifications are out of translation scope: A2A carries the final product, so the remote agent’s reasoning and tool calls never show up in the event stream.
Ending a Reply
A suspended remote task is suspended on the server, with nothing suspended locally, so every response stream that ends means the reply has ended. The task status the stream stops at decides thefinished_reason of that reply:
The
task_id is kept only while the remote side waits for input (INPUT_REQUIRED / AUTH_REQUIRED), so the next message continues that task; every other status clears it and the next message starts a new task within the same context_id. Two edge cases exist: a task the remote side has already forgotten degrades into a new task, and a task still running remotely raises a RuntimeError outright, because sending a message would make it run a second time.
Further Reading
Console
Hand a remote agent to the terminal and start chatting.
Message and Event
Learn what each event in the stream means.