Packages
@lucid-agents/a2a
Agent-to-Agent protocol for discovery and communication.
The A2A extension enables agents to discover and communicate with other agents using the Agent-to-Agent protocol.
Installation
bun add @lucid-agents/a2aBasic usage
import { createAgent } from '@lucid-agents/core';
import { http } from '@lucid-agents/http';
import { a2a } from '@lucid-agents/a2a';
const agent = await createAgent({
name: 'my-agent',
version: '1.0.0',
})
.use(http())
.use(a2a())
.build();
// Call another agent
const result = await agent.a2a.client.fetchAndInvoke(
'https://other-agent.com',
'skillId',
{ message: 'Hello' }
);API reference
a2a()
Creates the A2A extension.
function a2a(): Extension<A2AExtensionContext>A2ARuntime
When A2A is configured, agent.a2a provides:
type A2ARuntime = {
buildCard: (origin: string) => AgentCardWithEntrypoints;
fetchCard: (baseUrl: string, fetch?: FetchFunction) => Promise<AgentCard>;
client: A2AClient;
};Agent Cards
Agent Cards describe an agent's capabilities and are served at /.well-known/agent.json.
AgentCard structure
type AgentCard = {
protocolVersion?: string; // Default: "1.0"
name: string;
description?: string;
version?: string;
supportedInterfaces?: AgentInterface[];
capabilities?: AgentCapabilities;
skills?: Skill[];
payments?: PaymentMethod[];
registrations?: RegistrationEntry[];
trustModels?: TrustModel[];
};Fetching Agent Cards
// Fetch another agent's card
const card = await agent.a2a.fetchCard('https://other-agent.com');
console.log(card.name); // Agent name
console.log(card.skills); // Available skills/entrypoints
console.log(card.payments); // Payment methodsCard utilities
import { findSkill, hasCapability, supportsPayments } from '@lucid-agents/a2a';
const card = await agent.a2a.fetchCard('https://other-agent.com');
// Find a specific skill
const chatSkill = findSkill(card, 'chat');
// Check capabilities
const canStream = hasCapability(card, 'streaming');
// Check payment support
const hasPaidEndpoints = supportsPayments(card);A2A Client
The A2A client provides methods for calling other agents.
Direct invocation
// Invoke an agent's entrypoint
const result = await agent.a2a.client.invoke(
card, // AgentCard
'skillId', // Entrypoint key
{ input: 'data' }
);
console.log(result.output);
console.log(result.usage);Streaming
// Stream from an agent
await agent.a2a.client.stream(
card,
'chat',
{ message: 'Hello' },
async (chunk) => {
if (chunk.type === 'delta') {
process.stdout.write(chunk.data);
}
}
);Convenience methods
// Fetch card and invoke in one call
const result = await agent.a2a.client.fetchAndInvoke(
'https://other-agent.com',
'skillId',
{ input: 'data' }
);Task-based operations
For long-running operations, use task-based methods:
Send message
Creates a task and returns immediately:
const response = await agent.a2a.client.sendMessage(
card,
'skillId',
{ message: 'Process this' },
undefined, // fetch function
{ contextId: 'conversation-123' } // for multi-turn
);
console.log(response.taskId); // Task ID for polling
console.log(response.status); // 'running'Get task
Poll for task status:
const task = await agent.a2a.client.getTask(card, taskId);
console.log(task.status); // 'running' | 'completed' | 'failed' | 'cancelled'
console.log(task.result); // Output when completed
console.log(task.error); // Error details if failedSubscribe to task
Stream task updates via SSE:
await agent.a2a.client.subscribeTask(
card,
taskId,
async (event) => {
switch (event.type) {
case 'statusUpdate':
console.log('Status:', event.data.status);
break;
case 'resultUpdate':
console.log('Result:', event.data.result);
break;
case 'error':
console.error('Error:', event.data.error);
break;
}
}
);List tasks
const response = await agent.a2a.client.listTasks(card, {
contextId: 'conversation-123', // Filter by conversation
status: 'running', // Filter by status
limit: 10,
offset: 0,
});
console.log(response.tasks);
console.log(response.total);
console.log(response.hasMore);Cancel task
const cancelled = await agent.a2a.client.cancelTask(card, taskId);
console.log(cancelled.status); // 'cancelled'Multi-turn conversations
Group related tasks with contextId:
const contextId = crypto.randomUUID();
// First message
await agent.a2a.client.sendMessage(
card, 'chat', { message: 'Hello' },
undefined, { contextId }
);
// Follow-up in same conversation
await agent.a2a.client.sendMessage(
card, 'chat', { message: 'Tell me more' },
undefined, { contextId }
);
// Get all messages in conversation
const conversation = await agent.a2a.client.listTasks(card, { contextId });Task types
type Task = {
taskId: string;
status: 'running' | 'completed' | 'failed' | 'cancelled';
result?: {
output: unknown;
usage?: Usage;
model?: string;
};
error?: {
code: string;
message: string;
details?: unknown;
};
contextId?: string;
createdAt: string;
updatedAt: string;
};Exports
// Extension
export { a2a } from '@lucid-agents/a2a';
// Runtime
export { createA2ARuntime } from '@lucid-agents/a2a';
// Card operations
export {
buildAgentCard,
fetchAgentCard,
parseAgentCard,
findSkill,
hasCapability,
supportsPayments,
} from '@lucid-agents/a2a';
// Client operations
export {
invokeAgent,
streamAgent,
sendMessage,
getTask,
subscribeTask,
listTasks,
cancelTask,
} from '@lucid-agents/a2a';
// Types
export type {
AgentCard,
AgentCardWithEntrypoints,
A2ARuntime,
A2AClient,
Task,
TaskStatus,
TaskResult,
TaskError,
SendMessageRequest,
SendMessageResponse,
} from '@lucid-agents/a2a';