npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@a2x/sdk

v0.15.0

Published

A2A (Agent-to-Agent) protocol SDK for TypeScript

Downloads

369

Readme

@a2x/sdk

npm version License: MIT

A self-contained TypeScript SDK for building A2A (Agent-to-Agent) protocol agents with multi-provider LLM support, built-in authentication, and SSE streaming.

Why a2x?

  • Auto-extractionA2XServer infers AgentCard fields from your runtime objects. No manual JSON authoring.
  • Multi-version AgentCard — Generate v0.3 and v1.0 AgentCards from the same instance.
  • Multi-provider — Anthropic Claude, OpenAI GPT, and Google Gemini out of the box.
  • Framework-agnostic — Works with Express, Fastify, Hono, Next.js, or any HTTP framework.
  • SSE streaming — First-class message/stream support via Server-Sent Events.
  • Multi-modal artifacts — Agents can yield text, file, and data events; the default executor maps each into A2A TextPart / FilePart / DataPart artifacts.
  • Built-in auth — API Key, Bearer, OAuth 2.0 (Authorization Code, Client Credentials, Device Code), OpenID Connect, and Mutual TLS.
  • x402 payments — Charge per call via the a2a-x402 v0.2 extension. Express payment gating inline in agent.run() with x402RequestPayment(); the agent calls facilitator.verify() and facilitator.settle() directly using the SDK's stateless helpers — no SDK-owned flow, full control over what runs between verify and settle.
  • Zero runtime dependencies — Core module uses only Node.js built-in APIs.
  • TypeScript-first — Full type safety with types derived from A2A JSON Schema.

Installation

npm install @a2x/sdk

Install the LLM provider SDK you plan to use:

# Pick one (or more)
npm install @google/genai        # Google Gemini
npm install @anthropic-ai/sdk    # Anthropic Claude
npm install openai               # OpenAI GPT

Quick Start

import { LlmAgent, toA2x } from '@a2x/sdk';
import { GoogleProvider } from '@a2x/sdk/google';

const agent = new LlmAgent({
  name: 'my_assistant',
  description: 'A helpful assistant.',
  instruction: 'You are a helpful assistant.',
  provider: new GoogleProvider({
    model: 'gemini-2.5-flash',
    apiKey: process.env.GOOGLE_API_KEY!,
  }),
});

const app = toA2x(agent, {
  port: 4000,
  defaultUrl: 'http://localhost:4000/a2a',
});

This starts an A2A-compliant server with:

  • GET /.well-known/agent.json — Agent discovery
  • POST /a2a — JSON-RPC endpoint (message/send, message/stream, tasks/get, tasks/cancel)

Providers

Google Gemini

import { GoogleProvider } from '@a2x/sdk/google';

const provider = new GoogleProvider({
  model: 'gemini-2.5-flash',
  apiKey: process.env.GOOGLE_API_KEY!,
});

Anthropic Claude

import { AnthropicProvider } from '@a2x/sdk/anthropic';

const provider = new AnthropicProvider({
  model: 'claude-sonnet-4-20250514',
  apiKey: process.env.ANTHROPIC_API_KEY!,
});

OpenAI GPT

import { OpenAIProvider } from '@a2x/sdk/openai';

const provider = new OpenAIProvider({
  model: 'gpt-4o',
  apiKey: process.env.OPENAI_API_KEY!,
});

Server Setup (Manual Wiring)

For full control over routing and middleware:

import {
  LlmAgent,
  InMemoryRunner,
  AgentExecutor,
  StreamingMode,
  InMemoryTaskStore,
  A2XServer,
  DefaultRequestHandler,
  createSSEStream,
} from '@a2x/sdk';
import type { RequestContext } from '@a2x/sdk';
import { GoogleProvider } from '@a2x/sdk/google';

// 1. Define your agent
const agent = new LlmAgent({
  name: 'my_agent',
  description: 'My A2A agent.',
  instruction: 'You are a helpful assistant.',
  provider: new GoogleProvider({
    model: 'gemini-2.5-flash',
    apiKey: process.env.GOOGLE_API_KEY!,
  }),
});

// 2. Wire up the runtime
const runner = new InMemoryRunner({ agent, appName: agent.name });
const executor = new AgentExecutor({
  runner,
  runConfig: { streamingMode: StreamingMode.SSE },
});
const taskStore = new InMemoryTaskStore();

// 3. Create A2XServer (auto-extracts name, description, streaming from runtime)
const a2xServer = new A2XServer({ taskStore, executor })
  .setDefaultUrl('https://my-agent.example.com/a2a')
  .addSkill({
    id: 'chat',
    name: 'Chat',
    description: 'General conversation',
    tags: ['chat'],
  });

// 4. Create the request handler
const handler = new DefaultRequestHandler(a2xServer);

Express

import express from 'express';

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

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

app.post('/a2a', async (req, res) => {
  const context: RequestContext = { headers: req.headers, query: req.query };
  const result = await handler.handle(req.body, context);

  if (result && typeof result === 'object' && Symbol.asyncIterator in result) {
    res.setHeader('Content-Type', 'text/event-stream');
    res.setHeader('Cache-Control', 'no-cache');
    const stream = createSSEStream(result);
    const reader = stream.getReader();
    while (true) {
      const { done, value } = await reader.read();
      if (done) break;
      res.write(typeof value === 'string' ? value : new TextDecoder().decode(value));
    }
    res.end();
  } else {
    res.json(result);
  }
});

app.listen(4000);

Next.js App Router

export async function GET() {
  return Response.json(handler.getAgentCard());
}

export async function POST(request: Request) {
  const body = await request.json();
  const result = await handler.handle(body);

  if (result && typeof result === 'object' && Symbol.asyncIterator in result) {
    const stream = createSSEStream(result);
    return new Response(stream, {
      headers: { 'Content-Type': 'text/event-stream', 'Cache-Control': 'no-cache' },
    });
  }
  return Response.json(result);
}

Client

import { A2XClient } from '@a2x/sdk/client';

const client = new A2XClient('https://agent.example.com/.well-known/agent.json');

// Send a message
const task = await client.sendMessage({
  message: { role: 'user', parts: [{ text: 'Hello!' }] },
});

// Stream a response
for await (const event of client.sendMessageStream({
  message: { role: 'user', parts: [{ text: 'Tell me a story' }] },
})) {
  console.log(event);
}

// Task management
const existing = await client.getTask('task-id');
const canceled = await client.cancelTask('task-id');

Tools

FunctionTool

import { FunctionTool } from '@a2x/sdk';

const weatherTool = new FunctionTool({
  name: 'get_weather',
  description: 'Get weather for a location',
  parameters: {
    type: 'object',
    properties: {
      location: { type: 'string', description: 'City name' },
    },
    required: ['location'],
  },
  execute: async ({ location }) => {
    return { temp: 72, condition: 'sunny', location };
  },
});

const agent = new LlmAgent({
  name: 'weather_bot',
  description: 'Weather assistant',
  instruction: 'Use the get_weather tool to answer weather questions.',
  provider,
  tools: [weatherTool],
});

AgentTool

Use another agent as a callable tool:

import { AgentTool } from '@a2x/sdk';

const researchAgent = new LlmAgent({ /* ... */ });

const mainAgent = new LlmAgent({
  name: 'orchestrator',
  description: 'Orchestrates sub-agents',
  instruction: 'Delegate research tasks to the research agent.',
  provider,
  tools: [new AgentTool({ agent: researchAgent })],
});

Agent Patterns

| Pattern | Description | |---|---| | LlmAgent | Single LLM-powered agent | | SequentialAgent | Pipeline of agents executed in order | | ParallelAgent | Agents executed concurrently | | LoopAgent | Iterative refinement until exit condition |

Authentication

import { ApiKeyAuthorization, HttpBearerAuthorization } from '@a2x/sdk';

a2xServer
  .addSecurityScheme('apiKey', new ApiKeyAuthorization({
    in: 'header',
    name: 'x-api-key',
    keys: ['your-secret-key'],
  }))
  .addSecurityScheme('bearer', new HttpBearerAuthorization({
    validator: async (token) => {
      const valid = token === process.env.AUTH_TOKEN;
      return { authenticated: valid };
    },
  }))
  // OR logic: either scheme satisfies auth
  .addSecurityRequirement({ apiKey: [] })
  .addSecurityRequirement({ bearer: [] });

Supported schemes: ApiKeyAuthorization, HttpBearerAuthorization, OAuth2AuthorizationCodeAuthorization, OAuth2ClientCredentialsAuthorization, OAuth2DeviceCodeAuthorization, OpenIdConnectAuthorization, MutualTlsAuthorization.

x402 Payments

Gate agent calls behind on-chain cryptocurrency payments using the a2a-x402 v0.2 extension.

Install the optional peers:

npm install x402 viem

Server (the agent owns the flow; X402Context bundles the offering store + facilitator + event builders into one object):

import { AgentExecutor, BaseAgent, StreamingMode } from '@a2x/sdk';
import { X402Context, X402_EXTENSION_URI } from '@a2x/sdk/x402';

const ACCEPTS = [{
  network: 'base-sepolia',
  amount: '10000',                                      // 0.01 USDC (6 decimals)
  asset: '0x036CbD53842c5426634e7929541eC2318f3dCF7e',  // USDC on Base Sepolia
  payTo: process.env.MERCHANT_ADDRESS!,
  resource: 'https://api.example.com/premium',
  description: 'Premium agent access',
}];

class PaidAgent extends BaseAgent {
  constructor(private readonly x402: X402Context) {
    super({ name: 'paid_agent' });
  }

  async *run(ctx) {
    const result = await this.x402.classify(ctx);

    switch (result.kind) {
      case 'no-submission':
        yield* this.x402.requestPayment(ctx, { accepts: ACCEPTS, expiresInSeconds: 600 });
        return;
      case 'rejected':
      case 'no-stored-offering':
      case 'unmatched':
      case 'invalid-shape':
        yield this.x402.failedEvent({ code: result.code, reason: result.reason });
        return;
      case 'valid':
        break;
    }

    const verify = await this.x402.verify(ctx, result);
    if (!verify.isValid) {
      yield this.x402.failedEvent({
        code: 'VERIFY_FAILED',
        reason: verify.invalidReason ?? 'Payment verification failed.',
      });
      return;
    }

    // [insert any custom logic between verify and settle]

    const receipt = await this.x402.settle(ctx, result);
    if (!receipt.success) {
      yield this.x402.failedEvent({
        code: 'SETTLEMENT_FAILED',
        reason: receipt.errorReason ?? 'Settlement failed.',
        failureReceipt: receipt,
      });
      return;
    }

    await this.x402.clearOffering(ctx);
    yield { type: 'text', role: 'agent', text: 'thanks for paying' };
    yield this.x402.completedEvent({ receipt });
  }
}

const x402 = new X402Context();
const executor = new AgentExecutor({
  runner,
  runConfig: { streamingMode: StreamingMode.SSE },
});

const agent = new A2XServer({ taskStore, executor })
  .addExtension({ uri: X402_EXTENSION_URI, required: true });

For deployments that need full bespoke control (multiple facilitators, custom store routing, inserting logic mid-validation), the lower-level stateless helpers X402Context is built on (parseX402PaymentSubmission, pickX402Requirement, validateX402PayloadShape, buildX402Payment*Metadata, …) remain exported.

Client (unchanged):

import { A2XClient } from '@a2x/sdk/client';
import { privateKeyToAccount } from 'viem/accounts';

const client = new A2XClient(url, {
  x402: { signer: privateKeyToAccount(process.env.PRIVATE_KEY as `0x${string}`) },
});
const task = await client.sendMessage({ message: { role: 'user', parts: [{ text: '...' }] } });

Full guide: docs/guides/advanced/x402-payments.md. Migration from x402PaymentHook (SDK 0.13.x): docs/guides/advanced/migration-x402-v2.md.

AgentCard Versions

a2x handles the structural differences between A2A protocol versions transparently. Each agent is bound to one wire format at construction:

const a2xServerV10 = new A2XServer({ taskStore, executor });                          // v1.0 (default)
const a2xServerV03 = new A2XServer({ taskStore, executor, protocolVersion: '0.3' });  // v0.3

a2xServerV10.getAgentCard(); // v1.0 card
a2xServerV03.getAgentCard(); // v0.3 card

| Field | v0.3 | v1.0 | |---|---|---| | URL | AgentCard.url | supportedInterfaces[].url | | Transport | preferredTransport | supportedInterfaces[].protocolBinding | | Security | security + securitySchemes | securityRequirements + securitySchemes |

Exports

| Path | Description | |---|---| | @a2x/sdk | Core SDK (agents, tools, runner, transport, types) | | @a2x/sdk/client | A2XClient for calling remote A2A agents | | @a2x/sdk/auth | DeviceFlowClient for OAuth 2.0 Device Code flow | | @a2x/sdk/anthropic | AnthropicProvider | | @a2x/sdk/openai | OpenAIProvider | | @a2x/sdk/google | GoogleProvider | | @a2x/sdk/x402 | a2a-x402 v0.2 payments (server + client) |

Requirements

  • Node.js >= 20
  • TypeScript >= 5.6 (recommended)

Links

License

MIT