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

a2a-lite

v0.3.9

Published

Build A2A agents in 8 lines. Add enterprise features when you need them.

Readme

A2A Lite — TypeScript

npm GitHub

A2A Lite is designed for learning and prototyping. It's the friendly on-ramp to Google's A2A Protocol — get familiar with agent-to-agent concepts with minimal boilerplate before diving into the full google/a2a-js SDK. Perfect for courses, POCs, and demos.

Build A2A agents in 8 lines. Add features when you need them.

Wraps the official @a2a-js/sdk with a simple, intuitive API. 100% protocol-compatible.

import { Agent } from 'a2a-lite';

const agent = new Agent({ name: 'Bot', description: 'My bot' });

agent.skill('greet', async ({ name }: { name: string }) =>
  `Hello, ${name}!`
);

agent.run();

Installation

npm install a2a-lite

Quick Start

1. Create an agent

import { Agent } from 'a2a-lite';

const agent = new Agent({
  name: 'Calculator',
  description: 'Does math'
});

agent.skill('add', async ({ a, b }: { a: number; b: number }) =>
  a + b
);

agent.skill('multiply', async ({ a, b }: { a: number; b: number }) =>
  a * b
);

agent.run(); // Listening on http://localhost:8787

2. Test it (no HTTP needed)

import { AgentTestClient } from 'a2a-lite';

const client = new AgentTestClient(agent);
const result = await client.call('add', { a: 2, b: 3 });
expect(result).toBe(5);

Features

Skills

agent.skill('greet', async ({ name }: { name: string }) =>
  `Hello, ${name}!`
);

// With description and tags
agent.skill('greet', async ({ name }) => `Hello, ${name}!`, {
  description: 'Greet someone by name',
  tags: ['greeting']
});

Streaming

Use async function* to stream responses:

agent.skill('chat', async function* ({ message }) {
  for (const word of message.split(' ')) {
    yield word + ' ';
  }
}, { streaming: true });

Middleware

Cross-cutting concerns without touching skill code:

agent.use(async (ctx, next) => {
  console.log(`Calling: ${ctx.skill}`);
  const result = await next();
  console.log(`Result: ${result}`);
  return result;
});

Authentication

API keys are hashed in memory using SHA-256 — plaintext keys are never stored.

import { Agent, APIKeyAuth, BearerAuth } from 'a2a-lite';

// API Key
const agent = new Agent({
  name: 'SecureBot',
  description: 'A secure bot',
  auth: new APIKeyAuth({ keys: new Set(['secret-key']) }),
});

// Bearer token with custom validator
const agent2 = new Agent({
  name: 'JWTBot',
  description: 'JWT-protected bot',
  auth: new BearerAuth({
    validator: async (token) => valid(token) ? 'user-id' : null
  }),
});

File Handling

Accept files and return rich artifacts:

import { FilePart, Artifact } from 'a2a-lite';

agent.skill('analyze', async ({ file }: { file: FilePart }) => {
  const content = await file.readText();
  return { name: file.name, size: content.length };
});

Lifecycle Hooks

agent.onStartup(() => console.log('Agent starting'));
agent.onShutdown(() => console.log('Agent stopping'));
agent.onComplete((skill, result) => console.log(`Completed: ${skill}`));
agent.onError((e) => ({ error: e.message }));

Testing

AgentTestClient lets you test without starting an HTTP server:

import { AgentTestClient } from 'a2a-lite';

const client = new AgentTestClient(agent);

// Regular call
const result = await client.call('greet', { name: 'World' });
expect(result).toBe('Hello, World!');

// Streaming (collects all chunks)
const results = await client.stream('chat', { message: 'hello world' });
expect(results.length).toBe(2);

// Inspect the agent
const skills = client.listSkills();
const card = client.getAgentCard();

AgentTestClient returns a TestResult with .data, .text, and .json().


Agent Constructor

const agent = new Agent({
  name: 'Bot',              // Required
  description: '...',       // Required
  version: '1.0.0',         // Optional, default "1.0.0"
  url: undefined,           // Optional, auto-detected
  auth: undefined,          // Optional: APIKeyAuth, BearerAuth
  corsOrigins: ['...'],     // Optional: CORS allowed origins
});

Run Options

agent.run({
  host: '0.0.0.0',          // Default
  port: 8787,               // Default
});

Multi-Agent Communication

TaskHandle -- track remote tasks

When delegating to a remote agent, you can get back a TaskHandle that includes the A2A task ID alongside the result. This is useful for polling or cancelling long-running tasks.

import { Agent, AgentNetwork, TaskHandle, getRemoteTask, cancelRemoteTask } from 'a2a-lite';

const network = new AgentNetwork();
network.add('data', 'http://localhost:8787');

const agent = new Agent({ name: 'Orchestrator', network });

agent.skill('process', async ({ query }: { query: string }) => {
  // Get a TaskHandle instead of just the result
  const handle = await agent.delegate('data', 'fetch', { query }, { returnHandle: true }) as TaskHandle;
  console.log(`Task ID: ${handle.taskId}`);
  console.log(`Agent: ${handle.agentUrl}`);
  console.log(`Result: ${handle.result}`);
  return String(handle.result);
});

Task Lifecycle -- poll and cancel remote tasks

Use convenience methods directly on the handle, or via the network by name:

// Poll status directly on the handle
const status = await handle.getStatus();
const status2 = await handle.getStatus(15);  // custom timeout in seconds

// Or poll via network name
const status3 = await network.getTask('data', handle.taskId);
const status4 = await network.getTask('data', handle.taskId, 15);

// Cancel directly on the handle
await handle.cancel();
await handle.cancel(15);

// Or cancel via network name
await network.cancelTask('data', handle.taskId);
await network.cancelTask('data', handle.taskId, 15);

Low-level functions are also available:

const status = await getRemoteTask('http://localhost:8787', taskId);
await cancelRemoteTask('http://localhost:8787', taskId);

Client-Side SSE Streaming

When calling a remote streaming agent, consume its chunks as they arrive:

import { streamRemoteSkill } from 'a2a-lite';

// Via agent.delegate with stream: true
agent.skill('display', async ({ topic }: { topic: string }) => {
  const chunks: string[] = [];
  const stream = agent.delegate('story', 'tellStory', { topic }, { stream: true }) as AsyncGenerator<string>;
  for await (const chunk of await stream) {
    process.stdout.write(chunk);
    chunks.push(chunk);
  }
  return chunks.join('');
});

// Or directly
for await (const chunk of streamRemoteSkill('http://localhost:8787', 'tellStory', { topic: 'dragons' })) {
  process.stdout.write(chunk);
}

Agent Card Discovery

Fetch a remote agent's card to inspect its capabilities before delegating:

import { discoverAgent, AgentCardInfo } from 'a2a-lite';

const card: AgentCardInfo = await discoverAgent('http://localhost:8787');
console.log(`Agent: ${card.name} v${card.version}`);
console.log(`Skills: ${card.skills.map(s => s.name).join(', ')}`);
console.log(`Streaming: ${card.supportsStreaming}`);

// Auto-discover when registering
network.add('data', 'http://localhost:8787', { autoDiscover: true });

// Validate skill exists before delegating
const result = await agent.delegate('data', 'fetch', { query: 'hello' }, { discover: true });

Per-Task Push Notifications

import { setTaskPushNotification } from 'a2a-lite';

const handle = await agent.delegate('worker', 'process', { data: '...' }, { returnHandle: true }) as TaskHandle;

// Register webhook for this specific task
await handle.subscribe('https://my-app.com/webhook', 'secret-token');

// Or directly
await setTaskPushNotification('http://localhost:8787', handle.taskId, 'https://my-app.com/webhook');

// Retrieve / remove
const config = await handle.getPushConfig();
await handle.unsubscribe();

CLI

a2a-lite info <url>    Show agent info in compact plain-text format

A2A Protocol Mapping

Everything maps directly to the underlying protocol — no magic, no lock-in.

| A2A Lite | A2A Protocol | |----------|--------------| | agent.skill() | Agent Skills | | { streaming: true } | SSE Streaming | | FilePart | A2A File parts | | DataPart | A2A Data parts | | Artifact | A2A Artifacts | | APIKeyAuth / BearerAuth | Security schemes | | AgentNetwork | Multi-agent orchestration | | TaskHandle | Task ID + result wrapper | | AgentCardInfo | Agent card metadata | | discoverAgent() | /.well-known/agent.json | | getRemoteTask() | tasks/get JSON-RPC | | cancelRemoteTask() | tasks/cancel JSON-RPC | | streamRemoteSkill() | SSE streaming consumer |


Full API Reference

See AGENT.md for the complete multi-language API reference.


License

MIT