Archived · v0.13.0 · Agent (Server)
Build an Agent
The Quickstart shows the shortest path. This guide explains each field so you can tailor the agent to your use case.
Anatomy of LlmAgent
import { LlmAgent } from '@a2x/sdk';
import { GoogleProvider } from '@a2x/sdk/google';
const agent = new LlmAgent({
name: 'support_agent',
description: 'Answers customer support questions about the Acme API.',
instruction: `
You are a support agent for Acme.
Always cite the section of the docs you used to answer.
If you don't know, say so.
`,
provider: new GoogleProvider({
model: 'gemini-2.5-flash',
apiKey: process.env.GOOGLE_API_KEY!,
}),
});| Field | Purpose |
|---|---|
name |
Stable identifier; surfaced on the AgentCard and used for routing when composed. Use snake_case. |
description |
One-liner that tells other agents (and humans reading the card) what this agent does. |
instruction |
System prompt — shapes every response. Treat this as product copy; iterate on it. |
provider |
The LLM backend. See Choose an LLM Provider. |
tools |
Optional functions the agent can invoke. See Add Tools. |
Serving the agent
toA2x() is the one-liner that turns an agent into a running HTTP server:
import { toA2x } from '@a2x/sdk';
toA2x(agent, {
port: 4000,
defaultUrl: 'http://localhost:4000/a2a',
});defaultUrl is the public URL other agents should use to reach you. In production this is your deployed domain; locally it's fine to use localhost. This value ends up on the AgentCard.
When toA2x() is too opinionated — e.g. you already have an Express app, you need custom middleware, or you want fine-grained control over the AgentCard — see Manual Wiring.
Verifying the agent is up
With the server running, hit the well-known endpoint:
curl http://localhost:4000/.well-known/agent.json | jqYou should see an AgentCard echoing your name, description, and the transport (JSONRPC by default). If another agent or a client calls this URL, they get exactly the same answer — that's how discovery works in A2A.
Iterating on the instruction
The instruction field is where most of your agent's behavior lives. A few practical tips:
- Describe the persona and the guardrails separately. Persona first ("You are…"), then what to do and what not to do.
- Tell the model how to handle unknowns. "If you don't know, say so" prevents hallucination more reliably than "be accurate".
- Keep tool usage hints here, not in the tool definitions. "Always call
get_weatherbefore guessing a temperature" belongs in the instruction; the tool's owndescriptionshould just describe the tool.
AgentEvent variants
Custom agents that extend BaseAgent directly express their output by yielding AgentEvents. The default AgentExecutor knows how to map each variant onto an A2A artifact or task status update.
| Variant | Use it for |
|---|---|
text |
Streaming or final text output. Multiple text events accumulate into one text artifact. |
file |
An attached file (URL or base64 raw). One artifact per event. |
data |
A structured non-text payload (mediaType indicates the shape). One artifact per event. |
toolCall / toolResult |
LLM-style tool turns (consumed by LlmAgent plumbing; surface only when you're modeling the round-trip yourself). |
request-input |
Halt the agent and ask the client for input — most often a payment (via x402RequestPayment) or an approval. The executor sets the task to input-required and persists a small bookkeeping record so the resume turn can read what was asked for. See Protocol Extensions and x402 Payments. |
done |
Mark the run finished. Required at the end of every successful run. |
error |
Mark the task failed with the given Error. |
Next
- Choose an LLM Provider — swap between Gemini, Claude, and GPT.
- Add Tools — give the agent functions it can call.
- Multi-Agent Patterns — delegate, pipeline, fan out.