The A2A JavaScript SDK provides a JavaScript/TypeScript client library for building agents that interact with A2A agents following the Agent2Agent (A2A) Protocol.Use this SDK to build agents that:
During agent initialisation, fetch an Agent Card for every A2A agent you want to send messages to.
This is typically a setup step as opposed to a tool.
Ensure to include the agent information in the agent’s context (e.g. system message).
Copy
import { A2AClient } from '@a2a-js/sdk/client';import { AgentCard } from '@a2a-js/sdk';const STACKONE_API_KEY = '<stackone_api_key>';const base64EncodedApiKey = Buffer.from(`${STACKONE_API_KEY}:`).toString('base64');interface AgentCardWithAccountId { accountId: string; agentCard: AgentCard;}/** * Fetch Agent Cards from StackOne A2A agents for multiple accounts. * * The Agent URL is fixed to https://a2a.stackone.com and dynamically loads * an Agent Card based on the account ID. */async function fetchAgentCards(accountIds: string[]): Promise<Map<string, AgentCardWithAccountId>> { const agentCards = new Map<string, AgentCardWithAccountId>(); for (const accountId of accountIds) { try { // Create authenticated fetch for this account const authenticatedFetch: typeof fetch = async (url, init) => { const headers = new Headers(init?.headers); headers.set('Authorization', `Basic ${base64EncodedApiKey}`); headers.set('x-account-id', accountId); return fetch(url, { ...init, headers }); }; const client = await A2AClient.fromCardUrl( 'https://a2a.stackone.com/.well-known/agent-card.json', { fetchImpl: authenticatedFetch } ); const agentCard = client.agentCard; agentCards.set(agentCard.name, { accountId, agentCard }); } catch (error) { console.error(`Failed to fetch agent card for account ${accountId}:`, error); } } return agentCards;}/** * Get A2A agent information for agent context. */function getA2AAgentInfo(agentCards: Map<string, AgentCardWithAccountId>): string { const a2aAgentInfo: Array<{ name: string; description: string; skills: string[] }> = []; for (const { agentCard } of agentCards.values()) { a2aAgentInfo.push({ name: agentCard.name, description: agentCard.description, skills: (agentCard.skills || []).map((skill) => skill.name), }); } return ['<agents>', JSON.stringify(a2aAgentInfo, null, 4), '</agents>'].join('\n');}async function main() { // Fetch agent cards from multiple StackOne accounts const accountIds = ['<account_id_1>', '<account_id_2>', '<account_id_3>']; const agentCards = await fetchAgentCards(accountIds); // Get agent information for LLM context (e.g. system message) const a2aAgentInfo = getA2AAgentInfo(agentCards); console.log(a2aAgentInfo);}main();
To send messages to A2A agents, give your agent access to a tool like below.
The tool below gives the agent relatively high autonomy.
You might want to abstract context IDs and task IDs outside of the tool.
Copy
import { A2AClient, SendMessageSuccessResponse } from '@a2a-js/sdk/client';import { AgentCard, Message, MessageSendParams, Task } from '@a2a-js/sdk';import { v4 as uuidv4 } from 'uuid';const STACKONE_API_KEY = '<stackone_api_key>';const base64EncodedApiKey = Buffer.from(`${STACKONE_API_KEY}:`).toString('base64');interface AgentCardWithAccountId { accountId: string; agentCard: AgentCard;}// Map of agent names to their cards and account IDsconst agentCards = new Map<string, AgentCardWithAccountId>();interface SendMessageResult { Message?: { messageId: string; role: string; parts: Array<{ kind: string; text?: string }>; contextId?: string; }; Task?: { status: { state: string; timestamp: string }; artifacts: Array<{ artifactId: string; name?: string; parts: Array<{ kind: string; text?: string }> }>; contextId: string; taskId: string; }; error?: { code: number; message: string };}/** * Send a message to an agent and receive a response. * The response can be a Task, Message, or Error. * * To start a new conversation, set `contextId` and `taskId` to undefined. * * To continue a conversation, set `contextId` to the `contextId` of the previous conversation. * - If the previous Task has not terminated (input_required, auth_required), * set `taskId` to the `taskId` of the previous Task. * - If the previous Task has terminated (completed, canceled, rejected, or failed), * set `taskId` to undefined. */async function sendMessageToAgent( agentName: string, message: string, contextId?: string, taskId?: string): Promise<SendMessageResult> { const agentEntry = agentCards.get(agentName); if (!agentEntry) { throw new Error(`Agent ${agentName} not found`); } const { accountId, agentCard } = agentEntry; // Create authenticated fetch for this account const authenticatedFetch: typeof fetch = async (url, init) => { const headers = new Headers(init?.headers); headers.set('Authorization', `Basic ${base64EncodedApiKey}`); headers.set('x-account-id', accountId); return fetch(url, { ...init, headers }); }; const client = await A2AClient.fromCardUrl(agentCard.url, { fetchImpl: authenticatedFetch, }); const sendParams: MessageSendParams = { message: { messageId: uuidv4(), role: 'user', parts: [{ kind: 'text', text: message }], kind: 'message', }, contextId, taskId, }; const response = await client.sendMessage(sendParams); // Handle error if ('error' in response) { return { error: response.error }; } const result = (response as SendMessageSuccessResponse).result; if (result.kind === 'message') { // Agent responded with a Message (i.e. didn't start a Task) const msg = result as Message; return { Message: { messageId: msg.messageId, role: msg.role, parts: msg.parts, contextId: msg.contextId, }, }; } else { // Agent responded with a Task (i.e. started a Task) // Tasks contain the whole message history. We typically want the // Task's status, and Artifacts (if the Task has completed). const task = result as Task; return { Task: { status: task.status, artifacts: task.artifacts || [], contextId: task.contextId, taskId: task.id, }, }; }}
See a complete working example in the StackOne A2A Agents Orchestrator Demo, which shows how to build an orchestrator agent that routes requests to multiple StackOne A2A agents, manages multi-turn conversations, and serves as an A2A server itself.