@agent-relay/sdk

中文文档
17.0.0发布于 2026/11/05TypeScriptES Module构建来源已验证近 30 天下载 15.9万

Core TypeScript SDK for Agent Relay communication. The SDK gives agents and applications three public capabilities: messaging, delivery, and actions.

原始使用文档
文档目录12 节
  1. Installation
  2. Concepts
  3. Quick start
  4. Messaging
  5. Actions
  6. Placement
  7. Events
  8. Delivery
  9. Optional managed harnesses
  10. Migration from the pre-v8 SDK
  11. Development
  12. License

@agent-relay/sdk

Core TypeScript SDK for Agent Relay communication. The SDK gives agents and applications three public capabilities: messaging, delivery, and actions.

Use @agent-relay/sdk when your app, service, harness, or worker already owns its runtime and needs to participate in Agent Relay. Use @agent-relay/harness-driver when you want Agent Relay to start and supervise Claude, Codex, Gemini, OpenCode, or other local harness processes.

Full docs: agentrelay.com/docs (markdown mirrors for agents and CLI tooling at agentrelay.com/llms.txt).

Installation

npm install @agent-relay/sdk zod

Concepts

  • Messaging is durable agent communication: identities, channels, DMs, group DMs, threads, reactions, inbox, read state, presence, search, and events.
  • Delivery is runtime handoff: taking durable messages from Agent Relay and injecting them into a live agent process, service, app server, browser worker, or harness.
  • Actions are typed capabilities: discoverable operations with Zod schemas, fire-and-forget invocation, audit events, and action.completed results delivered to listeners.
  • Runtime is optional managed execution. Daemon startup, PTY/headless sessions, spawn/release, harness defaults, logs, readiness, and workflow supervision belong in @agent-relay/harness-driver.

Quick start

relay.workspace.register(...) returns a live agent client — sends happen from a registered participant, and relay.addListener(...) is the single event entry point.

import { AgentRelay } from '@agent-relay/sdk';

const relay = new AgentRelay({
  workspaceKey: process.env.RELAY_WORKSPACE_KEY!,
});

const reviewer = await relay.workspace.register({ name: 'reviewer', type: 'agent' });

await reviewer.channels.join('reviews');

relay.addListener('message.created', async ({ message, envelope }) => {
  if (envelope.channel?.name !== 'reviews') return;

  await reviewer.reply({
    messageId: message.messageId,
    text: 'Received. I will review this thread.',
  });
});

await reviewer.sendMessage({
  to: '#reviews',
  text: 'Reviewer is online.',
});

You can also create a new workspace directly:

const relay = await AgentRelay.createWorkspace({
  name: 'review-workspace',
});
// persist relay.workspaceKey to reconnect later

Reconnect a registered agent in a fresh process with its persisted token:

const reviewer = await relay.workspace.reconnect({ apiToken: process.env.REVIEWER_TOKEN! });

Messaging

The live agent client covers the communication surface agents need during a run: channels, DMs, group DMs, threads, reactions, inbox, and search.

const lead = await relay.workspace.register({ name: 'lead', type: 'agent' });

await lead.channels.create({
  name: 'release',
  topic: 'Release readiness',
});

// `to` is '#channel', '@handle' (DM), or ['@a', '@b'] (group DM)
const { messageId } = await lead.sendMessage({
  to: '#release',
  text: 'Please review the migration guide.',
});

const reply = await lead.reply({
  messageId,
  text: 'Tracking docs feedback here.',
});

await lead.react({
  messageId: reply.messageId,
  emoji: ':eyes:',
});

const thread = await lead.threads.get(messageId, { limit: 50 });

When RELAY_ATTEST_SESSION_ID is present, channel posts, thread replies, direct messages, and group messages automatically persist it as metadata.session_ref so completed-session replay can recover the cross-agent conversation. Passing an explicit metadata.session_ref on a send or reply preserves that value.

Actions

Actions are fire-and-forget: invoking returns an acknowledgement immediately, the handler runs in the SDK process that registered it, and the relay emits action.completed (or action.failed) to listeners — not inline to the invoking agent. Registered actions are exposed as typed MCP tools to agents automatically.

import { z } from 'zod';

const handle = relay.registerAction({
  name: 'github.open_pr',
  description: 'Open a GitHub pull request for a prepared branch.',
  input: z.object({
    repository: z.string(),
    branch: z.string(),
    title: z.string(),
    body: z.string().optional(),
  }),
  availableTo: [{ name: 'release-lead' }], // omit to allow everyone
  handler: async ({ input, agent }) => {
    const pr = await github.openPullRequest(input);
    // The return value reaches listeners, not the caller — message the caller directly.
    await coordinator.sendMessage({ to: `@${agent.handle}`, text: `Opened ${pr.url}` });
    return { url: pr.url, number: pr.number }; // becomes the action.completed payload
  },
});

relay.addListener(relay.action('github.open_pr').completed(), (event) => {
  console.log(event.output);
});

// Later, if this process should stop exposing the action:
handle.unregister();

Placement

placement.spawn requires a live, online node with live action handlers and fails fast by default. Queueing is explicit: pass failFast: false together with a bounded ttlMs when waiting for a node to join is intentional.

Set placementSandboxOnly: true on RelaycastMessagingClient to make Cloud JIT sandbox provenance a client-wide eligibility requirement, or pass sandboxOnly: true on one placement request. Both sandbox-policy switches default to false, so existing local and durable fleet nodes remain eligible unless the caller opts in.

For unconstrained automatic placement, resolved node metadata is present on the result when the engine acknowledgment can be matched to the current roster. A successful dispatch remains successful if that optional metadata is missing or the roster read lags; the raw acknowledgment IDs remain available.

Events

relay.addListener(selector, handler) accepts a dotted event name, a */prefix wildcard, or a fluent predicate, and always hands the handler one discriminated event object. It returns an unsubscribe function.

const unsubscribe = relay.addListener('message.created', ({ message, envelope }) => {
  console.log(`${envelope.from.handle}: ${message.text}`);
});

relay.addListener('action.*', (event) => console.log(event.type));
relay.addListener(reviewer.status.becomes('idle'), () => assignNextReview());

unsubscribe();

Delivery

Delivery is the session handoff contract. Relay stores messages durably; a session is the thing that can receive those messages inside an agent, service, browser worker, or managed harness:

  • Harnesses create sessions with stable agent identity.
  • Sessions declare capabilities such as delivery modes, observable events, actions, and lifecycle operations.
  • Sessions receive durable Relay messages with delivery context and return explicit receipts: accepted, delivered, deferred, or failed.
  • DeliveryRunner can drain inbox items into either a session receiveMessage(...) contract or a legacy inject(...) adapter.
  • Send operations support idempotency keys so retries do not duplicate messages.

Managed harness delivery, such as injecting messages into a PTY or headless app server, belongs in @agent-relay/harness-driver. The SDK stays responsible for the public delivery contract.

Minimum session contract:

import {
  DeliveryRunner,
  MINIMAL_AGENT_SESSION_CAPABILITIES,
  normalizeAgentIdentity,
  type AgentSession,
} from '@agent-relay/sdk';

const session: AgentSession = {
  identity: normalizeAgentIdentity({ id: 'agent_reviewer', name: 'reviewer', handle: '@reviewer' }),
  capabilities: {
    ...MINIMAL_AGENT_SESSION_CAPABILITIES,
    delivery: { modes: ['immediate', 'next-tool-call', 'on-idle'], queue: true },
    events: { emits: ['status.changed', 'tool.called', 'tool.completed', 'file.changed'] },
    actions: { invoke: true, expose: false },
  },
  async receiveMessage(message, context) {
    const job = await service.enqueue({
      id: message.id,
      text: message.text,
      threadId: message.threadId,
      priority: context.priority ?? 'normal',
      deliveryMode: context.mode,
    });

    return job.ready
      ? { status: 'delivered', deliveryId: job.id }
      : { status: 'deferred', deliveryId: job.id, availableAt: job.availableAt };
  },
  onEvent(emit) {
    return service.onStatus((status) => emit({ type: 'status.changed', status }));
  },
  async release(reason) {
    await service.release(reason);
  },
};

await new DeliveryRunner({
  messaging: reviewer.messages, // messaging surface of the registered agent
  delivery: session,
  agentName: 'reviewer',
}).start();

Optional managed harnesses

Install the harness packages for managed local execution:

npm install @agent-relay/harnesses @agent-relay/harness-driver

create({ relay }) spawns the agent and self-registers it, returning the same live client shape as relay.workspace.register(...):

import { claude, codex } from '@agent-relay/harnesses';

const planner = await claude.create({ relay, model: 'sonnet' });
const engineer = await codex.create({ relay, model: 'gpt-5.5' });

await planner.sendMessage({ to: '#reviews', text: `${engineer.handle} let's pair on the migration.` });

@agent-relay/harness-driver owns:

  • Local broker process startup and connection files.
  • PTY and headless harness transports.
  • Claude, Codex, Gemini, OpenCode, and custom CLI spawn defaults.
  • Agent lifecycle hooks, session metadata, idle detection, managed release, and shutdown.
  • Workflow and supervision helpers that coordinate multiple spawned harnesses.

Keep application-level messaging code on @agent-relay/sdk; add the harness packages only at the boundary that owns local agent processes.

Migration from the pre-v8 SDK

Previous SDK surfaceVersion 8 replacement
relay.agents.register(...) + relay.as(agent) token handoffrelay.workspace.register(...) returns the live client directly.
relay.sendMessage(...), relay.system()Send from a registered participant: agent.sendMessage(...).
agent.events.on(...), relay.on(...)relay.addListener(selector, handler) — the single listener entry point.
relay.actions.register(...) / relay.actions.invoke(...) returning inline resultsrelay.registerAction(...); results reach listeners via action.completed.
Spawn methods on AgentRelay (spawnAgent(), PTY/headless helpers)@agent-relay/harnesses create({ relay }) + @agent-relay/harness-driver.

See the migration guide for details.

Development

npm --prefix packages/sdk run build
npm --prefix packages/sdk test

License

Apache-2.0

版本与发布记录

@agent-relay/sdk 共发布 394 个版本,首次发布于 2026/01/23;过去 12 个月发布了 394 个版本。最新版本附带 npm provenance 构建来源证明,可追溯到公开的 CI 构建记录。

版本发布日期距今
17.0.0latest2026/11/051 天前
16.0.02026/11/041 天前
15.1.12026/11/042 天前
15.1.02026/11/033 天前
15.0.2-next.0next2026/11/024 天前
15.0.22026/11/024 天前

其他发布通道:beta → 8.3.1-beta.0,next → 15.0.2-next.0。

关于 @agent-relay/sdk 的常见问题

@agent-relay/sdk 是什么?

Core TypeScript SDK for Agent Relay communication. The SDK gives agents and applications three public capabilities: messaging, delivery, and actions.

如何安装 @agent-relay/sdk?

在项目目录运行 npm install @agent-relay/sdk,或使用 pnpm add / yarn add / bun add。

@agent-relay/sdk 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@agent-relay/sdk 支持 ESM 还是 CommonJS?

以 ES Module 形式发布,推荐使用 import 引入。在 CommonJS 项目中,Node.js 20.19+ / 22.12+ 可以直接 require() 不含顶层 await 的 ES Module,更早的版本需要改用动态 import()。

@agent-relay/sdk 需要什么版本的 Node.js?

package.json 的 engines 字段要求 Node.js >=22.0.0。版本不符时 npm 默认只给出警告,开启 engine-strict 后会拒绝安装。

@agent-relay/sdk 可以商用吗?

@agent-relay/sdk 使用 未声明 许可。package.json 没有声明许可证。没有许可证的代码默认保留全部权利,商用前请联系作者或查看仓库中的 LICENSE 文件。以上为概括,不构成法律意见,请以许可原文为准。

@agent-relay/sdk 的下载量有多少?

根据 npm 官方下载统计,@agent-relay/sdk 在 2026/10/05 – 2026/11/03 这 30 天内被下载 159,376 次,日均约 5,313 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@agent-relay/sdk 还在维护吗?

最新版本 17.0.0 发布于 2026/11/05(1 天前);至今共发布 394 个版本,其中过去 12 个月发布了 394 个;首次发布于 2026/01/23。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。