A2A Agent Implementation

Purpose

Within the broader scope of enabling distributed multi-agent communication via the Agent-To-Agent (A2A) protocol (Remote Agent Communication (A2A)), the A2A Agent Implementation subtopic specifically addresses how a local agent can act as a client interface to a remote agent over the A2A protocol. This implementation abstracts the communication details and protocol handling, enabling seamless invocation of remote agents as if they were local, thus facilitating distributed AI workflows and multi-agent orchestration across different hosts or processes.

This subtopic fills the gap between the low-level protocol operations handled in other subtopics (like message translation and server execution) and the high-level agent framework, providing a concrete agent.Agent implementation that integrates with the ADK agent lifecycle and session model.

Functionality

The A2A Agent Implementation provides:

Key Workflow Outline

  1. Agent Card Resolution:

    • If an AgentCard is directly provided in config, use it.

    • Otherwise, fetch and parse the card from a URL or load from a local file.

  2. Client Creation:

    • Use a client factory or default constructor to create an A2A client based on the resolved agent card.

  3. Message Creation:

    • Examine the invocation context’s session events.

    • If the last event is a user function call, convert it to an A2A message.

    • Otherwise, build a message representing missing parts of the remote session.

  4. Message Sending and Response Streaming:

    • Send the message via the A2A client using a streaming API.

    • For each streamed A2A event response:

      • Convert it back into an ADK session event.

      • Yield the event to the caller.

      • Attach custom metadata with request/response details.

  5. Error Handling:

    • On any failure, yield a special error event with error details embedded.

Critical Code Snippet Illustrating Message Sending Loop

for a2aEvent, err := range client.SendStreamingMessage(ctx, req) {
    if err != nil {
        yield(toErrorEvent(ctx, err), nil)
        return
    }
    event, err := adka2a.ToSessionEvent(ctx, a2aEvent)
    if err != nil {
        yield(toErrorEvent(ctx, err), nil)
        return
    }
    if event == nil {
        continue
    }
    updateCustomMetadata(event, req, a2aEvent)
    if !yield(event, nil) {
        break
    }
}

This loop continuously receives streaming responses from the remote agent, converts them into session events, and yields them to the ADK framework.

Integration

The A2A Agent Implementation acts as a bridge between:

It complements other subtopics such as:

By encapsulating remote communication details, this subtopic enables higher-level agents and workflows to delegate tasks transparently to remote agents, supporting distributed AI system designs.

Diagram

sequenceDiagram
participant LocalAgent as Local A2A Agent
participant Client as A2A Client
participant RemoteAgent as Remote A2A Agent Server
LocalAgent->>LocalAgent: Resolve AgentCard (URL/File)
LocalAgent->>Client: Create client from AgentCard
LocalAgent->>LocalAgent: Convert InvocationContext events to A2A Message
LocalAgent->>Client: SendStreamingMessage(Message)
Client->>RemoteAgent: Transmit A2A Message (gRPC/HTTP)
RemoteAgent->>RemoteAgent: Process message, generate events
RemoteAgent->>Client: Stream A2A Events (responses)
Client->>LocalAgent: Receive streamed events
LocalAgent->>LocalAgent: Convert A2A Events to Session Events
LocalAgent->>Caller: Yield session events (stream)

This sequence diagram visualizes how the A2A Agent Implementation resolves the remote agent card, creates a client, converts session events into protocol messages, streams requests to the remote agent, receives streaming responses, converts them back, and yields events to the caller within the local agent framework.