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

@nolag/agents

v0.1.1

Published

Multi-agent coordination SDK for NoLag — handoff, blackboard, inbox, tools, approval, observe patterns

Downloads

258

Readme

@nolag/agents

Multi-agent coordination SDK for NoLag — dispatch tasks, share state, observe decisions, gate actions with human approval, and invoke remote tools across connected agents.

How It Works with NoLag

NoLag is a real-time messaging platform that handles WebSocket connections, message routing, persistence, and scaling. This SDK wraps the low-level @nolag/js-sdk and gives you a purpose-built multi-agent coordination API — task handoff, shared blackboard state, tool invocation, approval gates, and observability — without needing to manage topics or subscriptions yourself.

Getting Your Token

  1. Sign up at nolag.app
  2. Create a new project in the portal
  3. Choose the Agents blueprint when creating an app — this pre-configures the topics (tasks, results, state, events, inbox, tools, approval), rooms, and lobbies your agent workflow needs
  4. Go to the app's Tokens page and generate an actor token for each agent
  5. Use that token when connecting with this SDK

Each token identifies a unique agent (actor) in NoLag. The blueprint handles all the infrastructure setup — you just write your agent logic.

Install

npm install @nolag/js-sdk @nolag/agents

Quick Start

import { NoLagAgents, Handoff } from "@nolag/agents";

// --- Orchestrator ---
const orchestrator = new NoLagAgents("ORCHESTRATOR_TOKEN", {
  agentId: "orchestrator-1",
  presence: { name: "orchestrator-1", role: "orchestrator" },
});
await orchestrator.connect();

const room = orchestrator.room("default-workflow");
const handoff = new Handoff(room);

// Dispatch a task and wait for the result
const result = await handoff.dispatch("summarize", { text: "..." }, {
  waitForResult: true,
  timeout: 30_000,
});
console.log("Result:", result?.payload);

// --- Worker ---
const worker = new NoLagAgents("WORKER_TOKEN", {
  agentId: "worker-1",
  presence: {
    name: "worker-1",
    role: "agent",
    capabilities: ["summarize"],
  },
});
await worker.connect();

const workerRoom = worker.room("default-workflow");
const workerHandoff = new Handoff(workerRoom);

workerHandoff.onTask(["summarize"], async (task, respond) => {
  const summary = await summarize(task.payload.text);
  respond("success", { summary });
});

Coordination Patterns

Handoff — Task Dispatch & Results

Dispatch tasks to agents by capability. The SDK uses presence-based service discovery to verify a capable agent is connected before dispatching.

import { Handoff } from "@nolag/agents";

const handoff = new Handoff(room);

// Orchestrator: dispatch work
const result = await handoff.dispatch("translate", { text, lang: "es" }, {
  waitForResult: true,
  priority: "high",
});

// Worker: handle tasks
handoff.onTask(["translate"], async (task, respond) => {
  const translated = await translate(task.payload.text, task.payload.lang);
  respond("success", { translated });
});

// Check who can handle a capability
const agents = handoff.getCapableAgents("translate");

Blackboard — Shared State

Read and write key-value pairs visible to all agents in the room. State is retained so new agents receive current values on join.

import { Blackboard } from "@nolag/agents";

const board = new Blackboard(room, agentId);

// Write state
board.set("progress", { completed: 3, total: 10 });

// Read state
const progress = board.get("progress");

// React to changes
board.onChange("progress", (envelope) => {
  console.log(`Progress updated by ${envelope.updatedBy}:`, envelope.value);
});

Tools — Remote Tool Invocation

Register tool handlers on one agent, invoke them from another. Uses correlated request/response over pub/sub.

import { Tools } from "@nolag/agents";

const tools = new Tools(room, agentId);

// Tool server: register handlers
tools.register("web_search", async (args) => {
  return await search(args.query as string);
});

// Caller: invoke a remote tool
const response = await tools.invoke("web_search", { query: "NoLag docs" });
console.log(response.result);

Approve — Human-in-the-Loop Gates

Request approval before taking actions. Humans or supervisor agents approve, reject, or defer.

import { Approve } from "@nolag/agents";

const approve = new Approve(room, agentId);

// Agent: request approval
const response = await approve.request("delete_record", { recordId: 42 }, {
  urgency: "high",
  timeout: 60_000,
});
if (response.decision === "approved") {
  await deleteRecord(42);
}

// Human/supervisor: handle approval requests
approve.onRequest((request, respond) => {
  console.log(`Action: ${request.action}`, request.context);
  respond("approved", "Looks good");
});

Inbox — Direct Agent Messaging

Send messages directly to a specific agent. Messages are addressed by agent ID.

import { Inbox } from "@nolag/agents";

const inbox = new Inbox(room, agentId);

// Send a direct message
inbox.send("worker-2", { instruction: "re-process item 7" });

// Receive messages
inbox.onMessage((msg) => {
  console.log(`From ${msg.from}:`, msg.payload);
});

Observe — Observability Events

Emit structured events for monitoring dashboards. Events have severity, category, and agent attribution.

import { Observe } from "@nolag/agents";

const observe = new Observe(room, agentId);

// Emit events
observe.emit("task.completed", { taskId: "t-1", duration: 1200 }, "info");
observe.emit("rate_limit", { service: "openai" }, "warning");

// Listen for events (with optional filters)
observe.on((event) => {
  console.log(`[${event.severity}] ${event.category}:`, event.payload);
}, { severity: "warning" });

API Reference

NoLagAgents

Constructor

const agents = new NoLagAgents(token: string, options?: NoLagAgentsOptions);

Options:

| Option | Type | Default | Description | |--------|------|---------|-------------| | appName | string | "agents" | App slug for the agents workflow | | agentId | string | auto-generated | Unique agent ID | | debug | boolean | false | Enable debug logging | | rooms | string[] | ["default-workflow"] | Rooms to auto-join on connect | | lobby | string | — | Lobby slug for cross-room presence observation | | presence | AgentPresenceData | — | Presence data advertised to other agents | | clientOptions | Partial<NoLagOptions> | — | Additional options passed to @nolag/js-sdk |

Methods

| Method | Returns | Description | |--------|---------|-------------| | connect() | Promise<void> | Connect to NoLag and join configured rooms | | disconnect() | void | Disconnect and clean up | | room(name) | AgentRoom | Get or create a room (auto-joins if not already joined) | | subscribeLobby(slug) | Promise<Record> | Subscribe to a lobby for cross-room presence |

Properties

| Property | Type | Description | |----------|------|-------------| | agentId | string | The agent's unique ID | | connected | boolean | Whether currently connected | | rooms | ReadonlyMap<string, AgentRoom> | All joined rooms |

Events

| Event | Payload | Description | |-------|---------|-------------| | connected | — | Connected to NoLag | | disconnected | reason: string | Disconnected | | reconnected | — | Reconnected after disconnect | | error | Error | Connection or protocol error |

AgentRoom

Methods

| Method | Returns | Description | |--------|---------|-------------| | getConnectedAgents() | ConnectedAgent[] | Get all connected agents | | findAgents(capability) | ConnectedAgent[] | Find agents with a capability | | hasCapability(capability) | boolean | Check if any agent has a capability | | getAvailableCapabilities() | string[] | Get all capabilities across connected agents | | setPresence(data) | void | Update this agent's presence | | fetchPresence() | Promise<ConnectedAgent[]> | Fetch current presence snapshot | | publishTask(envelope) | void | Publish to tasks topic | | publishResult(envelope) | void | Publish to results topic | | publishState(data) | void | Publish to state topic (retained) | | publishEvent(data) | void | Publish to events topic | | publishInbox(data) | void | Publish to inbox topic | | publishTools(data) | void | Publish to tools topic | | publishApproval(data) | void | Publish to approval topic (retained) |

Properties

| Property | Type | Description | |----------|------|-------------| | name | string | Room name | | agentId | string | This agent's ID | | context | RoomContext | Underlying @nolag/js-sdk room context |

Events

| Event | Payload | Description | |-------|---------|-------------| | task | TaskEnvelope | Task dispatched | | result | ResultEnvelope | Task result received | | stateChange | StateEnvelope | Shared state updated | | event | EventEnvelope | Observability event | | inbox | Record<string, unknown> | Inbox message received | | approvalRequest | ApprovalRequestEnvelope | Approval requested | | approvalResponse | ApprovalResponseEnvelope | Approval decision received | | toolRequest | ToolRequestEnvelope | Tool invocation requested | | toolResponse | ToolResponseEnvelope | Tool result received | | presenceJoin | actorId, AgentPresenceData | Agent joined | | presenceLeave | actorId | Agent left | | presenceUpdate | actorId, AgentPresenceData | Agent presence updated |

Types

interface AgentPresenceData {
  name: string;
  role: string; // "orchestrator" | "agent" | "observer" | "human" | "tool-server"
  capabilities?: string[];
  metadata?: Record<string, unknown>;
}

interface ConnectedAgent {
  actorId: string;
  name: string;
  role: string;
  capabilities: string[];
  metadata?: Record<string, unknown>;
  connectedAt: number;
}

interface TaskEnvelope {
  type: "task";
  taskId: string;
  correlationId: string;
  capability: string;
  priority: "low" | "medium" | "high" | "critical";
  payload: Record<string, unknown>;
  tags?: string[];
  metadata?: Record<string, unknown>;
  createdAt: number;
  createdBy?: string;
  timeout?: number;
}

interface ResultEnvelope {
  type: "result";
  taskId: string;
  correlationId: string;
  status: "success" | "error" | "partial";
  payload: Record<string, unknown>;
  error?: { code: string; message: string };
  completedAt: number;
  completedBy?: string;
}

interface StateEnvelope {
  type: "state";
  key: string;
  value: unknown;
  version: number;
  updatedAt: number;
  updatedBy: string;
}

interface EventEnvelope {
  type: "event";
  eventId: string;
  severity: "debug" | "info" | "warning" | "error" | "critical";
  category: string;
  payload: Record<string, unknown>;
  timestamp: number;
  emittedBy: string;
}

License

MIT