TypeScript SDK

Reference shape for the workspace-first @agent-relay/sdk API: messaging, delivery contracts, actions, events, and session registration.

Install the core SDK:

npm install @agent-relay/sdk zod

The SDK should stay focused on the Agent Relay core protocol. It should not require managed spawning, browser automation, cloud setup, workflow engines, or proactive runtime dependencies.

Entry Point

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

const relay = await AgentRelay.createWorkspace({
  name: 'release-review',
});

Connect to an existing workspace:

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

Workspace API

relay.workspace.id;
relay.workspace.name;
relay.workspace.key;

await relay.workspace.register(session);
await relay.workspace.unregister(agentId);
await relay.workspace.close();

register accepts an AgentSession or an array of sessions.

Messaging API

await relay.channels.create('#reviews');
await relay.channels.join('#reviews', [planner, reviewer]);

const message = await relay.messages.send({
  to: '#reviews',
  from: planner.identity.id,
  text: `${reviewer.identity.handle} please review the delivery adapter.`,
  mentions: [reviewer.identity.id],
});

await relay.messages.reply({
  thread: message.thread.id,
  from: reviewer.identity.id,
  text: 'Reviewing now.',
});

await relay.messages.react({
  message: message.id,
  agent: planner.identity.id,
  emoji: 'eyes',
});

See Messaging for target, attachment, thread, reaction, and inbox shapes.

Delivery Contracts

type DeliveryMode = 'immediate' | 'next-message' | 'next-tool-call' | 'on-idle' | 'manual';

type MessageContext = {
  id: string;
  mode: DeliveryMode;
  reason: 'message' | 'mention' | 'dm' | 'thread-reply' | 'action-result' | 'notification';
  priority?: 'normal' | 'urgent';
  deadline?: Date | string;
  idempotencyKey?: string;
  metadata?: Record<string, unknown>;
};

type MessageReceipt =
  | { status: 'accepted'; deliveryId: string; retryable?: boolean; metadata?: Record<string, unknown> }
  | { status: 'delivered'; deliveryId: string; metadata?: Record<string, unknown> }
  | { status: 'deferred'; deliveryId?: string; availableAt: Date | string; reason?: string; metadata?: Record<string, unknown> }
  | { status: 'failed'; deliveryId?: string; reason: string; retryable?: boolean; metadata?: Record<string, unknown> };

The SDK can expose DeliveryRunner and AgentDeliveryAdapter interfaces even while durable backend ack, fail, and defer operations are still being implemented. Unsupported operations should fail explicitly.

Session Registration

type AgentSession = {
  identity: AgentIdentity;
  capabilities: AgentSessionCapabilities;
  receiveMessage(message: RelayMessage, ctx: MessageContext): Promise<MessageReceipt>;
  onEvent?(handler: (event: AgentSessionEvent) => void): Unsubscribe;
  release(reason?: string): Promise<void>;
};

Use prebuilt harnesses or provide your own sessions.

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

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

await relay.workspace.register([planner, engineer]);

Actions API

import { z } from 'zod';

relay.actions.register({
  name: 'review.submit_vote',
  description: 'Submit a review vote for the current proposal.',
  inputSchema: z.object({
    proposalId: z.string(),
    vote: z.enum(['approve', 'request_changes', 'abstain']),
    reason: z.string().optional(),
  }),
  outputSchema: z.object({
    recorded: z.boolean(),
  }),
  handler: async (input, ctx) => {
    await reviewStore.recordVote(ctx.caller, input);
    return { recorded: true };
  },
});

const result = await relay.actions.invoke({
  name: 'review.submit_vote',
  input: {
    proposalId: 'proposal-1',
    vote: 'approve',
  },
  caller: { type: 'agent', id: reviewer.identity.id },
});

Action schemas should be Zod schemas. The SDK can infer TypeScript types and generate JSON Schema for MCP tools from the same source.

Events API

const unsubscribe = relay.on(
  relay.events.message.created().in('#reviews').mentions(reviewer),
  async (event) => {
    await relay.messages.direct({
      to: planner.identity.id,
      text: `${reviewer.identity.handle} was mentioned in ${event.message.id}.`,
    });
  }
);

unsubscribe();

The listener system should support message, delivery, action, workspace, and normalized session events.

MCP Integration

The SDK action registry and messaging primitives are what power agent-relay mcp.

await relay.mcp.start({
  workspaceKey: relay.workspace.key,
  exposeActions: true,
});

For many agents, MCP is the preferred integration path because it gives the agent tools without embedding the SDK into the agent process.

Managed Sessions Are Optional

The core SDK should not expose spawnAgent as the primary way to use Relay.

When Agent Relay needs to create managed sessions, use the runtime package and register runtime actions.

import { createRuntime, registerRuntimeActions } from '@agent-relay/runtime';

const runtime = await createRuntime({ relay, harnesses });
registerRuntimeActions(relay.actions, runtime);

await relay.actions.invoke({
  name: 'agent.create',
  input: {
    name: 'reviewer',
    harness: 'codex',
    task: 'Review the migration guide.',
  },
  caller: { type: 'agent', id: planner.identity.id },
});

This keeps agent creation as a capability in the action protocol instead of a core SDK method.

Compatibility Notes

Older SDKs may still expose broker clients, spawn-first facades, workflow APIs, model enums, and cloud configuration. The target SDK shape moves those out of the core public path.

Use the migration guide for replacements.