A2A

Introduction

Overview

The Agent-to-Agent (A2A) protocol lets agents communicate directly over a network. Unlike MCP, which connects an agent to external tools, A2A connects agents to other agents. A remote agent advertises its skills through a card. The calling agent loads those skills as local tools and calls them the same way it calls any other tool. One agent can research, another can code, a third can review.

How it works

The REST transport communicates over standard HTTP and JSON. Both transports expose the remote agent’s skills as local LLM::Tool subclasses.

require "llm"

llm   = LLM.deepseek(key: ENV["KEY"])
a2a   = LLM::A2A.rest(url: "https://agent.example.com")
agent = LLM::Agent.new(llm, tools: a2a.skills)
agent.talk "What's happening, fellow agent?"

Why would I use it?

A2A lets you compose autonomous agents that delegate and collaborate. One agent researches a topic. Another writes code. A third reviews the result. Each agent runs independently and communicates over the network.

Notes

An agent’s capabilities are advertised through a card. The LLM::A2A::Card#interfaces method lists which transports a remote agent supports.

Persistent connections

A persistent connection reuses the same HTTP connection across requests to the same A2A agent. Both REST and JSON-RPC transports accept the persistent: true option. Persistent connections matter when an agent makes many requests to the same remote agent in a short window, since reusing the connection avoids the handshake and teardown overhead of a fresh TCP connection per request. The option defaults to false; for a single request or an infrequent pattern, the overhead is negligible. When you want to avoid reopening a TCP connection for every request, pass persistent: true to the transport constructor. This uses Net::HTTP::Persistent under the hood:

a2a = LLM::A2A.rest(url: "https://agent.example.com", persistent: true)
a2a = LLM::A2A.jsonrpc(url: "https://agent.example.com", persistent: true)

JSON-RPC

Overview

JSON-RPC is an alternative transport for A2A agents. It uses a more structured protocol than REST, with request and response objects that follow the JSON-RPC 2.0 spec. Some agents advertise only JSON-RPC, others advertise both. The LLM::A2A::Card#interfaces method lists which transports a remote agent supports.

How it works

When you want to connect to a remote A2A agent using JSON-RPC, provide a URL and optional headers. The agent’s skill list is fetched and translated into LLM::Tool subclasses the model can call.

require "llm"

llm   = LLM.deepseek(key: ENV["KEY"])
a2a   = LLM::A2A.jsonrpc(url: "https://agent.example.com")
agent = LLM::Agent.new(llm, tools: a2a.skills)
agent.talk "What's happening, fellow agent?"

Why would I use it?

JSON-RPC provides typed request and response objects that follow the 2.0 spec, offering a more structured protocol than REST. Some agents advertise only JSON-RPC, while others advertise both. The LLM::A2A::Card#interfaces method lists which transports a remote agent supports.

Notes

JSON-RPC request and response objects are typed and follow the 2.0 spec. The LLM::A2A.jsonrpc transport provides structured message envelopes rather than plain HTTP.