Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

germankuber/python-a2a

Folders and files

NameName
Last commit message
Last commit date

Latest commit

History

3 Commits

Repository files navigation

A2A Demo — Agent2Agent

Demo of the A2A (Agent2Agent) protocol with the official a2a-sdk (v1.1.0).

It shows the two situations side by side:

  1. You calling an agent (a plain client → agent). hello / translator / math.
  2. An agent intelligently routing to another agent — the real Agent2Agent — where the Orchestrator uses an LLM (OpenAI) to pick the right worker agent for your request and delegates to it over A2A.

A2A is an open protocol (created by Google, donated to the Linux Foundation) that lets AI agents discover (via an AgentCard) and communicate with each other, regardless of the framework each one is built with.


Architecture

Independent A2A agents, each its own HTTP server with its own AgentCard. The Orchestrator is a smart router: at routing time it discovers each worker's real AgentCard over A2A, builds the capability catalog from those cards (not from any hardcoded text), asks an LLM which worker fits the user's message, then delegates to it over A2A. config.py only stores where each worker is (URL) — what it does always comes from its live card.

graph TD
 subgraph clients["clients/"]
 CLI["a2a-client (CLI)"]
 end
 subgraph orchestrator["orchestrator/ :8883"]
 OA["OrchestratorAgent"]
 RT["router (OpenAI)<br/>discovers cards + picks worker + normalizes input"]
 OA --> RT
 end
 subgraph workers["worker agents (each owns its AgentCard)"]
 TA["Translator :8882<br/>card: ES → EN"]
 MA["Math :8884<br/>card: arithmetic"]
 end
 subgraph shared["shared/"]
 BE["BaseTextExecutor"]
 SA["server_app"]
 CALL["call_agent() / fetch_card()"]
 CFG["config (WORKERS = key+URL only)"]
 ENV[".env → OPENAI_API_KEY"]
 end
 CLI -->|A2A| OA
 RT -.reads URLs.-> CFG
 RT -.auth.-> ENV
 RT -->|"GET /.well-known card"| TA
 RT -->|"GET /.well-known card"| MA
 OA -->|"A2A (chosen worker)"| TA
 OA -->|"A2A (chosen worker)"| MA
 TA -.uses.-> BE
 MA -.uses.-> BE
 OA -.uses.-> CALL
 BE -.served by.-> SA
Loading
Folder What it is
shared/base_executor.py The A2A task lifecycle (WORKING → artifact → COMPLETED), reused by all agents.
shared/server_app.py Builds the AgentCard + Starlette routes + uvicorn.
shared/a2a_call.py fetch_card(url) (discover an agent's real card) + call_agent(url, text) (send it a message).
shared/router.py LLM router (OpenAI): discovers worker cards, builds the catalog from them, picks the worker and normalizes the input. Reads OPENAI_API_KEY from .env.
shared/config.py Ports/URLs + WORKERS (just key + url — capabilities come from each card).
agents/*/agent.py The brain of each agent (swap for a real LLM).
agents/*/main.py Wires brain + card + executor and serves it.
clients/cli.py Generic CLI to talk to any agent.

Flow (smart routing + delegation)

When you send the Orchestrator a request, it first discovers each worker's real card, builds the catalog from those cards, asks the LLM which worker fits (and how to phrase the input), then delegates over A2A.

sequenceDiagram
 actor User
 participant O as Orchestrator :8883
 participant M as Math :8884
 participant T as Translator :8882
 participant LLM as OpenAI (router)
 User->>O: "cuánto es 3 * (4 + 5)?"
 rect rgb(255, 245, 235)
 Note over O,T: Discover capabilities from REAL cards
 O->>M: GET /.well-known/agent-card.json
 M-->>O: card (skills: arithmetic)
 O->>T: GET /.well-known/agent-card.json
 T-->>O: card (skills: ES→EN)
 end
 O->>LLM: message + catalog built from those cards
 LLM-->>O: {agent: "math", input: "3 * (4 + 5)"}
 rect rgb(235, 245, 255)
 Note over O,M: Agent → Agent (A2A delegation)
 O->>M: A2A message: "3 * (4 + 5)"
 M-->>O: artifact: "3 * (4 + 5) = 27"
 end
 O-->>User: chose math → 27
Loading

The capability catalog is never hardcoded — it is read from each agent's live AgentCard. Change a worker's skill description and the router sees it on the next request, no orchestrator changes needed. The LLM only decides and normalizes; the work happens in the chosen worker, reached over A2A.


Setup

uv sync
cp .env.example .env # then put your real key in .env
# .env contains: OPENAI_API_KEY=sk-...

.env is gitignored — your key never gets committed.

Run

The Orchestrator needs its worker agents running. Open three terminals for the workers + orchestrator:

uv run translator-agent # terminal 1 (:8882)
uv run math-agent # terminal 2 (:8884)
uv run orchestrator-agent # terminal 3 (:8883)

Then talk to the orchestrator — it routes automatically:

uv run a2a-client orchestrator "cuánto es 3 * (4 + 5)?" # → math → 27
uv run a2a-client orchestrator "sumame 2 + 2 por favor" # → math → 4
uv run a2a-client orchestrator "el sol es una estrella" # → translator → the sun is a star

You can also hit each worker directly (no routing):

uv run a2a-client math "3 * (4 + 5)"
uv run a2a-client translator "el sol es una estrella"

Or the simplest possible standalone echo agent:

uv run hello-agent # terminal 1
uv run a2a-client hello "hi there" # terminal 2

Get an agent's card directly

The AgentCard is published at the A2A well-known path:

curl http://127.0.0.1:8884/.well-known/agent-card.json # math agent's card

Add another worker agent

  1. Create agents/<name>/agent.py (the brain) + main.py (copy an existing one). Describe what it does in its AgentSkill — that text is what the router reads.
  2. Add a port + URL in shared/config.py and append a WorkerInfo(key, url) to WORKERS (just where it lives — no description, the card provides that).
  3. Register its entry point in pyproject.toml.

The router discovers its card and starts considering it automatically — no orchestrator or router changes.

Where to plug in a real LLM

In any agents/<name>/agent.py, replace the body of invoke with a call to your LLM, a tool, or a LangGraph/CrewAI/ADK graph. The whole A2A layer (discovery, tasks, artifacts, routing, delegation) stays exactly the same.

About

A2A (Agent2Agent) protocol demo with the official a2a-sdk: an orchestrator agent that discovers and delegates to a translator agent over A2A.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

Contributors

Languages

AltStyle によって変換されたページ (->オリジナル) /