A2A

Connect agents across processes and services with the Agent-to-Agent protocol.

What it is

The a2a package implements the Agent-to-Agent (A2A) protocol, which defines a standard HTTP interface for agents to call each other across process and network boundaries.

A Phero agent can be exposed as an A2A server so other agents (or systems) can call it over HTTP. Conversely, any remote A2A server can be consumed from a Phero agent as an ordinary llm.Tool.

The two sides

Example: exposing an agent as an A2A server

See the full code in examples/a2a/server.

package main

import (
    "net/http"
    "os"

    "github.com/henomis/phero/a2a"
    "github.com/henomis/phero/agent"
    "github.com/henomis/phero/llm/openai"
)

func main() {
    client := openai.New(os.Getenv("OPENAI_API_KEY"))

    a, err := agent.New(
        client,
        "math-assistant",
        "You are a helpful math assistant. Answer concisely.",
    )
    if err != nil {
        panic(err)
    }

    srv, err := a2a.New(a, "http://localhost:8080")
    if err != nil {
        panic(err)
    }

    mux := http.NewServeMux()
    mux.Handle("/.well-known/agent.json", srv.AgentCardHandler())
    mux.Handle("/", srv.JSONRPCHandler())

    _ = http.ListenAndServe(":8080", mux)
}

AgentCardHandler() serves the well-known AgentCard endpoint used for discovery. JSONRPCHandler() handles the A2A JSON-RPC messages that actually drive the agent.

Example: calling a remote A2A agent as a tool

See the full code in examples/a2a/client.

package main

import (
    "context"
    "fmt"
    "os"

    "github.com/henomis/phero/a2a"
    "github.com/henomis/phero/agent"
    "github.com/henomis/phero/llm/openai"
)

func main() {
    ctx := context.Background()

    // Resolve the remote agent card and create a client
    remoteClient, err := a2a.NewClient(ctx, "http://localhost:8080")
    if err != nil {
        panic(err)
    }

    // Expose the remote agent as a local llm.Tool
    mathTool, err := remoteClient.AsTool()
    if err != nil {
        panic(err)
    }

    // Use the tool in a local orchestrator agent
    llmClient := openai.New(os.Getenv("OPENAI_API_KEY"))

    orchestrator, err := agent.New(
        llmClient,
        "orchestrator",
        "You are an orchestrator. Use the math-assistant tool for any math questions.",
    )
    if err != nil {
        panic(err)
    }

    if err := orchestrator.AddTool(mathTool); err != nil {
        panic(err)
    }

    result, err := orchestrator.Run(ctx, "What is the square root of 144?")
    if err != nil {
        panic(err)
    }

    fmt.Println(result.Content)
}

NewClient fetches the remote AgentCard from the well-known path and builds a transport client. AsTool() wraps the remote agent as an llm.Tool whose name and description come from the AgentCard itself — no manual wiring needed.

API reference

Server

Client

Errors

Run the examples

# Start the A2A server in one terminal
go run ./examples/a2a/server

# Call it from another terminal
go run ./examples/a2a/client

Related packages