Skip to main content

A2A Protocol

TypeScript SDK support for A2A routing, direct task execution, and multi-agent delegation.

note

See A2A Architecture for protocol concepts.

A2AClient

A2AClient talks to the Sekuire API A2A endpoints and supports task routing, JSON-RPC task APIs, and SSE subscriptions.

import { A2AClient } from '@sekuire/sdk';

const client = new A2AClient({
baseUrl: 'https://api.sekuire.ai',
authToken: process.env.SEKUIRE_API_KEY!,
timeout: 30_000,
});

// Route by skill
const route = await client.sendBySkill({
skill: 'document:summarize',
message: {
role: 'user',
parts: [{ type: 'text', text: 'Summarize this incident report.' }],
},
traceId: 'trace-123',
});

// Poll final task
const task = await client.getTask(route.taskId);
console.log(task.status.state);

// Or stream updates
for await (const event of client.subscribe(route.taskId)) {
console.log(event.status, event.message?.parts);
}

Task endpoint auth behavior

For /api/v1/tasks/* endpoints used by delegation fallback:

  1. tokenResolver runtime token (dynamic, preferred for SDK-managed agents).
  2. Runtime token set with setRuntimeToken (backward compatibility).
  3. If authToken looks like a JWT, it is sent as Authorization: Bearer.
  4. Otherwise, authToken is sent as X-API-Key (+ X-Device-Fingerprint).
client.setRuntimeToken(process.env.SEKUIRE_RUNTIME_TOKEN!);

You can override fingerprint via deviceFingerprint in constructor or SEKUIRE_DEVICE_FINGERPRINT. When a request uses a runtime token and gets a 401, onUnauthorized can refresh and retry once.

A2AServer

A2AServer is an in-memory JSON-RPC server implementation. You provide an agent card and skill handlers, then wire it to your HTTP framework.

import express from 'express';
import type { AgentCard } from '@sekuire/sdk';
import { A2AServer } from '@sekuire/sdk';

const card: AgentCard = {
agentId: 'sekuire:acme:analysis-agent',
name: 'Analysis Agent',
description: 'Analyzes logs and incidents',
version: '1.0.0',
protocolVersions: ['0.2'],
capabilities: {
streaming: true,
pushNotifications: false,
extendedAgentCard: false,
},
skills: [
{ id: 'incident:summarize', name: 'Incident Summarizer' },
],
url: 'https://agent.example.com/a2a',
};

const server = new A2AServer({
card,
handlers: {
'incident:summarize': async (message) => ({
role: 'agent',
parts: [{ type: 'text', text: `Handled: ${JSON.stringify(message.parts)}` }],
}),
},
});

const app = express();
app.use(express.json());

app.post('/a2a', async (req, res) => {
const response = await server.handleRequest(req.body);
res.json(response);
});

app.get('/.well-known/agent.json', (_req, res) => {
res.json(server.getAgentCard());
});

app.listen(8000);

A2ATaskDelegator

A2ATaskDelegator handles routing, waiting, retries, optional direct fallback, and cancellation.

import { SekuireSDK } from '@sekuire/sdk';

const sdk = SekuireSDK.fromEnv();
await sdk.start();

const delegator = sdk.createDelegator({
timeout: 60_000,
pollInterval: 1_000,
maxRetries: 2,
retryDelayMs: 1_000,
retryBackoffMultiplier: 2,
});

const result = await delegator.delegate({
skill: 'github:issues',
message: 'Create an issue for login timeout regressions',
traceId: 'trace-123',
// Optional direct fallback target if routed mode fails
targetUrl: 'https://github-agent.example.com/a2a',
targetAgentId: 'agent_github',
});

console.log(result.status, result.taskId);

If you construct A2ATaskDelegator directly, setRuntimeToken(...) is still supported for compatibility.

Streaming delegation

for await (const event of delegator.delegateWithStreaming({
skill: 'document:summarize',
message: 'Summarize the release notes.',
})) {
console.log(event.status, event.message?.parts?.[0]);
}

Cancel delegation

delegator.cancelDelegation('task_id_here');
// or
// delegator.cancelAllDelegations();

Platform /a2a/tasks Compatibility

When using platform routing (/a2a/route), your target agent should expose:

  • POST /a2a/tasks (required for forwarded task execution)
  • GET /.well-known/agent.json (recommended for discovery metadata)

Typical forwarded payload:

{
"task_id": "uuid",
"type": "summarize",
"input": {
"skill": "summarize",
"message": {
"role": "user",
"parts": [{ "type": "text", "text": "Summarize this text" }]
}
},
"context": {
"workspace_id": "ws_123",
"requester_id": "agent_router"
}
}

Return shape (success):

{
"task_id": "uuid",
"status": "completed",
"result": { "message": "..." },
"output": { "message": "..." }
}

Also ensure your manifest advertises matching capabilities:

sekuire.yml
capabilities:
provides:
- "summarize"
- "chat"
a2a:
upstream_url: "https://your-agent.example.com/a2a/tasks"

Next Steps