Agent2Agent Protocol · A2A v1.0

Let independently deployed agents work together.

A2A gives an AI agent a standard way to introduce itself to another agent, accept a job or task, report progress, ask for more information, and return useful results—even when the other agent runs in a different AI service, uses a different programming language or agent framework, or is deployed in another cloud. Neither agent needs to understand how the other is built. They use the A2A standard to communicate and work together.

11 v1 operationsAgent CardsJSON-RPC + RESTSSE streamingMulti-turn tasksAuthenticated pushRemoteA2aAgent

ADK-Rust A2A reference architecture

Architecture of A2A remote agents

The network contract stays separate from the agent's model, tools, memory, and internal orchestration.

01

Calling system

The agent or application asking another agent to do work.

Coordinator agent

Decides which remote specialist should receive the task.

A2A client

Discovers the card, chooses streaming, and sends protocol messages.

HTTPS

02

A2A service boundary

The public contract every compatible client can understand.

Agent Card

Name, skills, endpoint, protocol version, security, and declared capabilities.

Request checks

Version, content type, IDs, message parts, metadata, identity, and limits.

Request handler

Dispatches JSON-RPC or REST operations through one shared implementation.

typed call

03

ADK-Rust runtime

The framework executes the task and produces typed progress.

Runner

Creates the invocation context and streams agent events.

Agent system

LLM, workflow, graph, custom, or multi-agent logic.

Tools

Rust tools and MCP

State

Sessions and memory

task state and events are recorded while the agent works

04

Task lifecycle

A validated state machine makes long-running work inspectable.

Task store

Status, context, history, artifacts, metadata, and push configuration.

State machine

Only valid transitions are accepted; terminal tasks stay terminal.

05

Progress delivery

The caller chooses how it wants to receive change.

Direct response

Return the complete task and its artifacts.

SSE stream

Task first, then status and artifact updates.

06

Work after the request

Long tasks can report later without holding one connection open.

Subscription

A client listens to updates for an existing task.

Push webhook

Authenticated delivery with retry and SSRF checks.

ADK-Rust keeps the A2A wire contract, task lifecycle, agent execution, and delivery channels as separate pieces so each can be secured, tested, and replaced independently.

Start with the idea

How do I work with an externally hosted AI agent?

Inside one ADK-Rust process, agents can share Rust types, sessions, tools, and direct function calls. Once an agent belongs to another service—or another organisation—those private implementation details are no longer a safe contract.

A2A defines the shared language at that boundary. The caller discovers what the remote agent offers, sends a structured message, follows a task through known states, and receives artifacts without needing to know which model, framework, or tools run behind the endpoint.

ADK-Rust implements A2A v1 in adk-server and connects the protocol directly to the Runner. The same agent you test locally can become a network service, while RemoteA2aAgent lets another ADK-Rust system consume it through the normal Agent interface.

Agent Card

A service profile for an agent

A small public document tells callers the agent’s name, endpoint, skills, protocol version, security requirements, and whether it supports streaming or notifications.

Message

What one agent says to another

A message carries a role, a unique ID, and one or more parts such as text or structured data. The unique ID makes safe retries possible.

Task

The job both systems can follow

A task gives remote work an ID, a conversation context, a state, message history, metadata, and any artifacts produced along the way.

Artifact

The useful output of the work

An artifact is a named result attached to the task: a report, decision, plan, generated file, or other structured output another system can use.

Follow one job

The protocol carries both the request and the life of the work.

A caller can wait for one response, open a live event stream, subscribe to an existing task, or register a webhook for later updates. Task identity and context keep every delivery mode attached to the same piece of work.

Task state machine

A remote job has a life you can follow.

A2A does more than return text. It gives work an identity, a conversation context, a current state, history, and artifacts. ADK-Rust validates every transition before saving it.

SUBMITTED

The server accepted the task.

WORKING

The agent is executing it.

INPUT REQUIRED

The agent needs more information.

AUTH REQUIRED

The caller must provide authorization.

COMPLETED

Work and artifacts are ready.

FAILED

Execution ended with an error.

CANCELED

An allowed cancellation ended the task.

REJECTED

The server declined the task.

Multi-turn work: when a task reaches INPUT_REQUIRED, the caller sends another message with the same contextId. ADK-Rust finds the task, returns it to WORKING, appends the message, and continues the same job.

Real-world logic flow

Case Study: Resolve a customer's damaged order across two distinct agent services.

A customer tells the company's support agent that an order arrived damaged. The support agent remains responsible for the conversation: it understands the request, keeps the customer informed, collects any missing evidence, and presents the final decision. It does not have direct access to warehouse stock, delivery records, or replacement policy.

That operational information belongs to a separately deployed fulfilment agent. Through A2A, the support agent can discover what the fulfilment agent does, send it the investigation as a task, follow its progress, answer requests for more information, and receive the final replacement decision. Each service keeps its own code, data, tools, model provider, and security controls; they share only the messages, task state, and artifacts defined by the A2A contract.

01

Discover the specialist

A support coordinator reads the fulfilment agent’s card and confirms it handles order investigation and streams progress.

02

Send one clear job

It sends the order number, the customer’s request, a unique messageId, and a new conversation context.

03

Route inside the service

The remote ADK-Rust agent checks order tools, inventory, delivery history, and company policy without exposing those internals to the caller.

04

Ask for what is missing

If proof of damage is required, the task becomes INPUT_REQUIRED instead of guessing or silently failing.

05

Resume the same task

The coordinator supplies the approved evidence using the same contextId; history and task identity remain intact.

06

Return an auditable result

The task completes with status history and an artifact containing the replacement decision and next steps.

Sequence diagram

The task pauses and resumes without losing its identity.

Read from top to bottom. The A2A service owns the network contract and task record. The fulfilment agent owns its reasoning and private tools.

Support coordinator

Calling agent

A2A service

Protocol boundary

Fulfilment agent

ADK-Rust Runner

Business systems

Orders · inventory · policy

calls through A2A
dispatches to Runner
uses approved tools

GET /.well-known/agent-card.json

Discover skills and streaming

Agent Card

Fulfilment capability published

SendStreamingMessage

ORD-1042 · messageId msg-order-1042

Runner invocation

Create task and execute agent

order.lookup + policy.check

Use private business tools

Evidence required

Damage photo is missing

INPUT_REQUIRED

Persist state and context

SSE status update

Ask support for evidence

SendMessage · same contextId

Approved photo reference

Resume task

INPUT_REQUIRED → WORKING

inventory.reserve

Reserve replacement stock

Artifact + COMPLETED

Replacement decision

Final SSE events

Auditable result returned

The support coordinator never receives database credentials or fulfilment code. It receives only the Agent Card, protocol events, task state, and final artifact.

Code and wire responses

See what each side sends and receives.

These examples use the same v1 operation names, message fields, task states, and SSE response shapes as the ADK-Rust implementation. IDs and order details are fixed so the whole conversation is easy to follow.

fulfilment.rsFULFILMENT SERVICE · RUST
let fulfilment = LlmAgentBuilder::new("fulfilment")
    .description("Investigates orders and delivery")
    .model(model)
    .instruction(
        "Use the approved order, inventory, and policy tools.          Ask for evidence when the replacement policy requires it."
    )
    .build()?;

A2aServer::builder()
    .agent(Arc::new(fulfilment))
    .agent_card_name("Fulfilment Agent")
    .streaming(true)
    .build()?
    .serve()
    .await?;
support.rsSUPPORT COORDINATOR · RUST
let fulfilment = RemoteA2aAgent::builder("fulfilment")
    .description("Investigates orders and delivery")
    .agent_url("https://agents.example.com/fulfilment")
    .streaming(true)
    .build()?;

let support = LlmAgentBuilder::new("support")
    .model(model)
    .instruction("Own the customer conversation.")
    .sub_agent(Arc::new(fulfilment))
    .build()?;
SendStreamingMessage.json1 · SEND THE JOB
{
  "jsonrpc": "2.0",
  "id": "replace-1",
  "method": "SendStreamingMessage",
  "params": {
    "message": {
      "messageId": "msg-order-1042",
      "role": "ROLE_USER",
      "parts": [{
        "text": "Investigate damaged order ORD-1042 and prepare a replacement decision."
      }]
    }
  }
}
text/event-stream2 · STREAM TASK PROGRESS
data: {
  "jsonrpc":"2.0", "id":"replace-1",
  "result":{"task":{
    "id":"task-order-1042",
    "contextId":"ctx-order-1042",
    "status":{"state":"TASK_STATE_SUBMITTED"}
  }}
}

data: {
  "jsonrpc":"2.0", "id":"replace-1",
  "result":{"statusUpdate":{
    "taskId":"task-order-1042",
    "contextId":"ctx-order-1042",
    "status":{"state":"TASK_STATE_WORKING"}
  }}
}
input-required.event.json3 · REQUEST THE MISSING EVIDENCE
{
  "statusUpdate": {
    "taskId": "task-order-1042",
    "contextId": "ctx-order-1042",
    "status": {
      "state": "TASK_STATE_INPUT_REQUIRED",
      "message": {
        "role": "ROLE_AGENT",
        "parts": [{
          "text": "Please provide a photo showing the damaged item."
        }]
      }
    }
  }
}
SendMessage.follow-up.json4 · RESUME THE SAME TASK
{
  "jsonrpc": "2.0",
  "id": "replace-2",
  "method": "SendMessage",
  "params": {
    "message": {
      "messageId": "msg-order-1042-photo",
      "contextId": "ctx-order-1042",
      "role": "ROLE_USER",
      "parts": [{
        "text": "Evidence received and approved: damage-photo-8841.jpg"
      }]
    }
  }
}
final-events.json5 · RECEIVE THE ARTIFACT AND COMPLETION
{
  "artifactUpdate": {
    "taskId": "task-order-1042",
    "contextId": "ctx-order-1042",
    "artifact": {
      "artifactId": "replacement-decision-1042",
      "name": "Replacement decision",
      "parts": [{
        "text": "Approved. Reserve SKU-RED-42 and dispatch with priority shipping."
      }]
    }
  }
}

{
  "statusUpdate": {
    "taskId": "task-order-1042",
    "contextId": "ctx-order-1042",
    "status": { "state": "TASK_STATE_COMPLETED" }
  }
}

The A2A v1 API

Everything a client needs to start, follow, and finish work on a remote agent.

ADK-Rust implements all 11 operations in A2A v1. For a short job, call SendMessage and wait for the task result. When the work may take longer, use SendStreamingMessage to receive the task first, followed by live status and artifact events over SSE.

The returned task ID lets your client reconnect without submitting the job again. It can fetch the latest state, list related tasks, subscribe to further updates, or request cancellation. If the client cannot keep a connection open, it can register an authenticated webhook and let the remote agent deliver later changes.

01

Start work

Send a message and receive either a complete task or a live stream.

SendMessageSendStreamingMessage
02

Inspect and control

Read current work, list matching tasks, or cancel a task when its state permits it.

GetTaskListTasksCancelTask
03

Follow progress

Open an SSE subscription for updates from a task that already exists.

SubscribeToTask
04

Receive later updates

Create, read, list, and remove authenticated webhook destinations for a task.

CreatePushConfigGetPushConfigListPushConfigsDeletePushConfig
05

Discover more

Request the extended version of an agent’s published service profile.

GetExtendedAgentCard

One handler for two bindings

JSON-RPC and REST routes dispatch into the same RequestHandler, so task behavior does not drift between transports.

Runner-backed execution

Incoming A2A messages become ADK-Rust content. The Runner executes the selected agent and converts its events into task status and artifacts.

Safe retries

A repeated messageId returns the existing task rather than running the same work twice. Production deployments should persist this mapping across restarts.

Streaming that starts with context

The first SSE event is the complete Task. Later events carry status and artifact updates, so a client always knows what the stream belongs to.

Remote agents feel local

RemoteA2aAgent implements the ADK-Rust Agent trait. A coordinator can include a network service in its agent hierarchy and receive normal framework events.

Protection at the boundary

Version negotiation, message validation, bearer authentication, rate limiting, audit interceptors, webhook authentication, and SSRF checks can guard the service.

Choose the right boundary

Local subagent vs remote A2A agent

A2A introduces a network, a public contract, authentication, failure handling, and remote task state. Those costs are valuable when they create real independence; they are unnecessary when every agent already lives in the same process.

Local sub-agent

Remote A2A agent

Best fit
Agents owned by one application
Agents deployed or owned independently
Communication
In-process Agent calls and typed events
HTTP, JSON-RPC or REST, and SSE
Shared state
Can use the same sessions and services
Shares only declared messages, tasks, and artifacts
Failure boundary
One runtime and deployment
Network, timeout, retry, and remote-service failures
Interoperability
ADK-Rust components
Any A2A-compatible language or framework

From Rust agent to network service

Expose an agent, then consume it as an agent.

The convenience server creates an Axum application with an agent card, sessions, A2A routes, and streaming enabled. The remote adapter discovers that service and converts its task updates back into ADK-Rust events.

serve.rsExpose an agent
use adk_server::a2a::convenience::A2aServer;

let app = A2aServer::quick_start(agent);
let listener = tokio::net::TcpListener::bind(
    "0.0.0.0:8080"
).await?;

axum::serve(listener, app).await?;
coordinator.rsCall it from another agent
use adk_server::a2a::RemoteA2aAgent;

let fulfilment = RemoteA2aAgent::builder("fulfilment")
    .description("Investigates orders and delivery")
    .agent_url("https://agents.example.com/fulfilment")
    .build()?;

let coordinator = LlmAgentBuilder::new("support")
    .model(model)
    .sub_agent(Arc::new(fulfilment))
    .build()?;
For a fully configured v1 service: use the documented RequestHandler::with_runner path to choose the task store, push sender, Agent Card, Runner services, JSON-RPC route, REST router, and version-negotiation middleware explicitly.

Before production

Deploying A2A agents

ADK-Rust supplies the v1 types, handlers, lifecycle, clients, validation, delivery primitives, and integration with the Runner. Production readiness still depends on the storage, identity, network, observability, and operating policies selected for your service.

01

Publish an honest card

Advertise only the skills, bindings, streaming, push delivery, and security schemes the deployment really supports.

02

Choose durable state

The included InMemoryTaskStore and in-memory idempotency map are useful for development. Long-running production work needs storage that survives process restarts.

03

Secure both directions

Authenticate inbound calls and protect outbound push delivery. The HTTP push sender supports bearer credentials, notification tokens, retries, and private-address rejection.

04

Design cancellation and timeouts

Remote work can outlive a request. Define client timeouts, cancellation policy, retry behavior, and what happens when either service becomes unavailable.

Connect the agent system

Expose your agent through a standard A2A interface.

Begin with one honest Agent Card and one useful task. Add streaming, multi-turn input, task persistence, subscriptions, authenticated push, and boundary controls as the work becomes longer and the service becomes more important.