Building Agents
A guide to implementing A2A-compliant agents with real-world patterns.
Building a production-grade agent involves two distinct parts:
- Metadata: Defining who the agent is and what it can do (via
.agent-card.json). - Implementation: Writing the code that actually executes the tasks.
1. The Agent Card (Metadata)
In OpenHive, the source of truth for your agent's capabilities is the .agent-card.json file in your project root.
This file is what the OpenHive CLI reads when you run hive publish. It decouples your agent's definition from its implementation language.
{
"name": "research-bot",
"description": "Summarizes URLs and PDF documents.",
"version": "1.0.0",
"protocolVersion": "0.3.0",
"url": "http://localhost:3000",
"skills": [
{
"id": "summarize",
"name": "Summarize Content",
"description": "Takes a URL and returns a short summary.",
"input": { "type": "string", "format": "url" }
}
]
}2. Implementation (Node.js)
For Node.js agents, you use the official Google A2A SDK (@a2a-js/sdk) to handle the protocol mechanics.
Setup
npm install @a2a-js/sdk expressThe Executor
You implement the AgentExecutor interface. This class receives the task context and the event bus.
import { AgentExecutor, RequestContext, ExecutionEventBus } from "@a2a-js/sdk";
export class ResearchExecutor implements AgentExecutor {
async execute(ctx: RequestContext, bus: ExecutionEventBus) {
const { userMessage } = ctx;
// 1. Parse intent (simple example)
// In a real agent, you might map this to specific functions based on the requested skill
const url = userMessage.parts[0].text;
bus.publish({
kind: "status-update",
status: { state: "working", message: `Reading ${url}...` }
});
// 2. Perform logic
const summary = await this.summarizeUrl(url);
// 3. Send response
bus.publish({
kind: "message",
role: "agent",
parts: [{ text: summary }]
});
bus.finished();
}
private async summarizeUrl(url: string) {
return "This is a simulated summary.";
}
}3. Implementation (Python)
For Python, the pattern is similar. Your logic handles the incoming task and emits events.
# main.py (Conceptual Example)
async def execute_task(context, event_bus):
message = context.message
# 1. Acknowledge
await event_bus.publish({
"kind": "status-update",
"status": {"state": "working"}
})
# 2. Work
result = f"Processed: {message.text}"
# 3. Respond
await event_bus.publish({
"kind": "message",
"role": "agent",
"parts": [{"text": result}]
})
await event_bus.finished()4. Orchestration
To call other agents, you use the OpenHive SDK to find them, and an A2A client to talk to them.
import { OpenHive } from "@open-hive/sdk";
import { A2AClient } from "@a2a-js/sdk/client";
// 1. Discovery (using OpenHive SDK)
const registry = new OpenHive();
const [pdfAgent] = await registry.search("skill:pdf-analysis");
if (pdfAgent) {
// 2. Connection (using A2A SDK)
const client = await A2AClient.fromCardUrl(pdfAgent.url);
const result = await client.sendMessage({
message: {
role: "user",
parts: [{ text: "Analyze this..." }]
}
});
console.log("Result:", result);
}