Documentation
¶
Overview ¶
Package a2a implements the v0.1 synchronous A2A client from docs/a2a-design.md ("Mast as A2A client", client-only phasing row): agent-card discovery and caching, JSON-RPC 2.0 message/send on the single A2A v0.3 endpoint (A2A-Version header, bearer auth from an env-var reference), direct-message and task-opened reply handling with bounded tasks/get polling to a terminal state, and tasks/cancel on caller cancellation. Static agent configs load from .agents/a2a/*.yaml (see AgentConfig / LoadDir; wired into pkg/config root scanning).
Build-vs-reuse note (docs/a2a-design.md v0.1 phasing row asks that ADK v2.1.0's agentregistry package be evaluated before hand-building client machinery): evaluated 2026-07-26 and declined for v0.1. That package is a Google Cloud Agent Registry client — ADC-authenticated discovery plus RemoteAgent factories over github.com/a2aproject/ a2a-go/v2, aimed at the registry-discovery story that is explicitly v0.2 here. Using its factories for the static-config path would add a2a-go/v2 as a direct dependency and an ADK RemoteAgent abstraction on top, to obtain three JSON-RPC methods and a card GET that fit in this file against stdlib net/http. Revisit at v0.2, where streaming (message/stream over SSE) and registry discovery make the SDK earn its place.
Layering note: Send returns *federation.Result and wraps the federation sentinel errors directly rather than defining a parallel error/result vocabulary — pkg/federation is protocol-neutral and does not import this package, so the dependency is one-way.
Index ¶
Constants ¶
const AuthTypeBearer = "bearer"
AuthTypeBearer is the only auth type the v0.1 client supports. google-iam (docs/a2a-design.md static-registration example) joins in v0.2 alongside the pluggable token-resolver surface.
const DefaultTimeout = 120 * time.Second
DefaultTimeout bounds a Send when neither the per-agent config nor the caller supplies one. v0.1 calls block to a bounded timeout — long-running remote tasks need programmatic pause, which is v0.2 per docs/durable-execution-design.md phasing.
const ProtocolVersion = "0.3"
ProtocolVersion is the A2A spec line this client implements and advertises in the A2A-Version request header (docs/a2a-design.md resolved open question 1: pin to the v0.3 line, send the header, document tested-against versions per release).
const Scheme = "a2a"
Scheme is the federation reference scheme this adapter serves: a2a://<name>/<skill> (docs/federation-design.md reference grammar).
const TransportJSONRPC = "JSONRPC"
TransportJSONRPC is the card transport identifier for JSON-RPC 2.0 over HTTP — the only transport this client speaks (docs/a2a-design.md endpoint layout: "JSON-RPC only at first"). An absent preferredTransport defaults to JSON-RPC per spec.
const VersionHeader = "A2A-Version"
VersionHeader is the HTTP request header carrying ProtocolVersion.
const WellKnownCardPath = "/.well-known/agent-card.json"
WellKnownCardPath is the spec-defined agent-card discovery path.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Adapter ¶
type Adapter struct {
// contains filtered or unexported fields
}
Adapter is the A2A protocol adapter for the federation registry — the v0.1 slice of docs/federation-design.md's "A2A adapter": static references only; registry-discovered references (a2a://<registry>/ <agent-id>) are v0.2.
func NewAdapter ¶
func NewAdapter(cfgs []AgentConfig, opts ...ClientOption) (*Adapter, error)
NewAdapter builds the adapter from static agent configs (normally pkg/config's .agents/a2a/*.yaml scan). opts apply to every client.
func (*Adapter) Invoke ¶
func (a *Adapter) Invoke(ctx context.Context, ref federation.Reference, inputs map[string]any, opts federation.InvokeOptions) (federation.Handle, error)
Invoke implements federation.Adapter. Per the frozen contract it returns an error only for dispatch-time failures (unknown agent); the synchronous remote call runs inside Invoke — v0.1 blocks to a bounded timeout — and its outcome, success or failure, surfaces from the returned Handle's Wait.
type AgentCard ¶
type AgentCard struct {
Name string `json:"name"`
Description string `json:"description,omitempty"`
URL string `json:"url"`
Version string `json:"version,omitempty"`
ProtocolVersion string `json:"protocolVersion,omitempty"`
PreferredTransport string `json:"preferredTransport,omitempty"`
AdditionalInterfaces []AgentInterface `json:"additionalInterfaces,omitempty"`
Capabilities Capabilities `json:"capabilities,omitempty"`
DefaultInputModes []string `json:"defaultInputModes,omitempty"`
DefaultOutputModes []string `json:"defaultOutputModes,omitempty"`
Skills []AgentSkill `json:"skills,omitempty"`
}
AgentCard is the discovery-time contract served at /.well-known/agent-card.json. Note: spec AgentSkill has NO I/O schemas — only inputModes/outputModes media types. Structured I/O contracts are conveyed in skill descriptions or out of band (docs/a2a-design.md, protocol overview).
type AgentConfig ¶
type AgentConfig struct {
// Name is the reference name: a2a://<name>/<skill>. Must be
// lowercase because the name travels in the URI host position of a
// federation reference, where RFC 3986 case-insensitivity means
// parsers normalize to lowercase (see federation.ParseReference).
Name string `yaml:"name"`
// AgentCardURL locates the agent card. A base URL (empty or "/"
// path) gets WellKnownCardPath appended. The JSON-RPC endpoint is
// then resolved from the card.
AgentCardURL string `yaml:"agent_card_url,omitempty"`
// Endpoint is the JSON-RPC endpoint, bypassing card discovery.
// When both Endpoint and AgentCardURL are set, Endpoint wins for
// transport and the card is still fetched for skill validation.
Endpoint string `yaml:"endpoint,omitempty"`
// Skills is the subset of the agent's skills mast may invoke;
// empty = all (docs/a2a-design.md).
Skills []string `yaml:"skills,omitempty"`
// Auth is optional; absent means unauthenticated calls.
Auth *AuthConfig `yaml:"auth,omitempty"`
// TimeoutSeconds bounds each invocation; 0 = DefaultTimeout.
TimeoutSeconds int `yaml:"timeout_seconds,omitempty"`
// Filename records provenance for error messages.
Filename string `yaml:"-"`
}
AgentConfig is one static A2A agent registration from .agents/a2a/<name>.yaml (docs/a2a-design.md, "Static registration").
func LoadDir ¶
func LoadDir(dir string) ([]AgentConfig, error)
LoadDir loads every *.yaml / *.yml in dir (flat, non-recursive, per the pkg/config scan rules). A missing dir yields zero entries. Any invalid file is a fatal load error. Name-collision checking across files is the caller's job (pkg/config does it alongside its other same-directory collision checks).
func (AgentConfig) Timeout ¶
func (c AgentConfig) Timeout() time.Duration
Timeout returns the effective invocation bound.
func (AgentConfig) Validate ¶
func (c AgentConfig) Validate() error
Validate checks an AgentConfig for load-time errors. All errors are fatal per the config-layout v0.1 rule (fail fast on invalid config).
type AgentInterface ¶
AgentInterface is one (transport, url) alternative from the card.
type AgentSkill ¶
type AgentSkill struct {
ID string `json:"id"`
Name string `json:"name,omitempty"`
Description string `json:"description,omitempty"`
Tags []string `json:"tags,omitempty"`
InputModes []string `json:"inputModes,omitempty"`
OutputModes []string `json:"outputModes,omitempty"`
}
AgentSkill is one named capability. Per the v0.3 spec it carries media types, not JSON Schemas.
type Artifact ¶
type Artifact struct {
ArtifactID string `json:"artifactId,omitempty"`
Name string `json:"name,omitempty"`
Description string `json:"description,omitempty"`
Parts []Part `json:"parts,omitempty"`
}
Artifact is a task output artifact.
type AuthConfig ¶
type AuthConfig struct {
// Type is the auth mechanism; v0.1: "bearer" only.
Type string `yaml:"type"`
// TokenEnv names the environment variable holding the bearer
// token. Resolved at request time, not load time, so rotation
// does not require a config reload.
TokenEnv string `yaml:"token_env"`
}
AuthConfig is the static-registration auth block. Tokens are env-var references, never file-embedded (docs/a2a-design.md).
type Capabilities ¶
type Capabilities struct {
Streaming bool `json:"streaming,omitempty"`
PushNotifications bool `json:"pushNotifications,omitempty"`
}
Capabilities is the card's capability declaration.
type Client ¶
type Client struct {
// contains filtered or unexported fields
}
Client is a synchronous A2A v0.3 client for one configured agent. Safe for concurrent use.
func NewClient ¶
func NewClient(cfg AgentConfig, opts ...ClientOption) (*Client, error)
NewClient validates cfg and returns a Client. No network I/O happens until the first call (card fetch is lazy).
func (*Client) Card ¶
Card returns the agent card, fetching and caching it on first use. Endpoint-only configs (no agent_card_url) return (nil, nil): the card is optional when the operator pinned the endpoint directly.
func (*Client) Send ¶
func (c *Client) Send(ctx context.Context, skill string, inputs map[string]any, timeout time.Duration) (*federation.Result, error)
Send invokes skill on the remote agent with inputs and blocks until a terminal state or the bounded timeout (opts precedence: timeout argument > config timeout_seconds > DefaultTimeout). The reply may be a direct message (returned as a completed Result) or an opened task, which Send polls via tasks/get. If the caller's ctx is canceled or the bound expires mid-task, Send issues tasks/cancel (best effort, on a detached context) before returning.
Skill selection: A2A v0.3 message/send has no first-class skill selector — AgentSkill is card-level metadata and MessageSendParams carries only the message. Mast conveys the chosen skill as message metadata under "skillId" (and validates it against the fetched card and the config's skills allowlist). Servers that route by content ignore the hint harmlessly.
type ClientOption ¶
type ClientOption func(*Client)
ClientOption customizes a Client.
func WithHTTPClient ¶
func WithHTTPClient(h *http.Client) ClientOption
WithHTTPClient substitutes the transport (tests, custom TLS/proxies).
func WithPollInterval ¶
func WithPollInterval(d time.Duration) ClientOption
WithPollInterval overrides the tasks/get polling cadence.
type Message ¶
type Message struct {
Kind string `json:"kind"`
MessageID string `json:"messageId"`
Role string `json:"role"`
Parts []Part `json:"parts"`
TaskID string `json:"taskId,omitempty"`
ContextID string `json:"contextId,omitempty"`
Metadata map[string]any `json:"metadata,omitempty"`
}
Message is an A2A message (kind: "message").
type Part ¶
type Part struct {
Kind string `json:"kind"`
Text string `json:"text,omitempty"`
Data map[string]any `json:"data,omitempty"`
Metadata map[string]any `json:"metadata,omitempty"`
}
Part is a message/artifact content part. Exactly one of Text / Data is populated for the kinds this client produces and consumes ("text", "data"); other kinds ("file") pass through with only Kind set.
type RPCError ¶
type RPCError struct {
Code int `json:"code"`
Message string `json:"message"`
Data json.RawMessage `json:"data,omitempty"`
}
RPCError is a JSON-RPC 2.0 error object (A2A-specific codes included, e.g. -32001 TaskNotFound).
type Task ¶
type Task struct {
Kind string `json:"kind"`
ID string `json:"id"`
ContextID string `json:"contextId,omitempty"`
Status TaskStatus `json:"status"`
Artifacts []Artifact `json:"artifacts,omitempty"`
}
Task is an A2A task (kind: "task").
type TaskState ¶
type TaskState string
TaskState is the A2A v0.3 task lifecycle vocabulary.
const ( TaskStateSubmitted TaskState = "submitted" TaskStateWorking TaskState = "working" TaskStateInputRequired TaskState = "input-required" TaskStateAuthRequired TaskState = "auth-required" TaskStateCompleted TaskState = "completed" TaskStateFailed TaskState = "failed" TaskStateCanceled TaskState = "canceled" TaskStateRejected TaskState = "rejected" )
type TaskStatus ¶
type TaskStatus struct {
State TaskState `json:"state"`
Message *Message `json:"message,omitempty"`
}
TaskStatus is the task's current lifecycle position.