Robutler

TypeScript SDK Reference

Looking for the Python SDK? See the Python SDK Reference. For a side-by-side cross-language overview, see the Quickstart.

Install the SDK:

npm install webagents

The package targets Node.js ≥ 20 and modern browsers. ESM only.


BaseAgent

The core agent class. Processes UAMP events, manages skills, and exposes run / runStreaming interfaces.

import { BaseAgent } from 'webagents';

const agent = new BaseAgent({
  name: 'my-agent',
  instructions: 'You are a helpful assistant.',
  model: 'openai/gpt-4o',
  skills: [new MySkill()],
});

Constructor

new BaseAgent(config: AgentConfig) — see AgentConfig.

FieldTypeDescription
namestringAgent display name (default 'agent').
descriptionstringOptional human-readable description.
instructionsstringSystem prompt prepended to every run.
modelstringDefault LLM model (e.g. 'openai/gpt-4o').
skillsISkill[]Skill instances to load.
capabilitiesPartial<Capabilities>UAMP capabilities (modalities, audio formats, streaming).
maxToolIterationsnumberMax agentic loop iterations (default 50).

Methods

MethodSignatureDescription
run(messages: Message[], options?: RunOptions) => Promise<RunResponse>Single-turn execution.
runStreaming(messages: Message[], options?: RunOptions) => AsyncGenerator<StreamChunk>Streaming execution.
getCapabilities() => CapabilitiesGet aggregated agent capabilities.
addSkill(skill: ISkill) => voidAdd a skill at runtime.
removeSkill(name: string) => voidRemove a skill at runtime.
executeTool(name: string, params: Record<string, unknown>) => Promise<unknown>Execute a tool by name.
overrideTool(name: string) => voidMark a tool as client-executed.

Skill

Abstract base for skills. Skills bundle tools, hooks, prompts, handoffs, observers, and HTTP/WebSocket endpoints.

import { Skill, tool, hook } from 'webagents';
import type { Context, HookData, HookResult } from 'webagents';

class WeatherSkill extends Skill {
  readonly name = 'weather';

  @tool({ description: 'Get weather for a city' })
  async getWeather(params: { city: string }, ctx: Context): Promise<string> {
    return `Weather in ${params.city}: sunny`;
  }

  @hook({ lifecycle: 'before_run' })
  async onBeforeRun(data: HookData, ctx: Context): Promise<HookResult> {
    return {};
  }
}

Lifecycle

MethodDescription
initialize(agent: IAgent)Called when the skill is registered with an agent.
setAgent(agent: IAgent)Set the parent agent reference (auto-called by addSkill).
tools / hooks / handoffs / prompts / httpEndpoints / wsEndpointsRead-only registries populated by decorators.

Decorators

All decorators live in webagents/core and are re-exported from the package root.

@tool

Register a method as an LLM-callable tool.

@tool({
  name?: string,
  description?: string,
  parameters?: JSONSchema,
  provides?: string,
  scopes?: string[],
  enabled?: boolean,
})

@hook

Register a lifecycle hook.

@hook({
  lifecycle: 'before_run' | 'after_run' | 'before_toolcall' | 'after_toolcall' | 'on_error' | 'on_message' | 'on_chunk' | 'on_request' | 'on_connection',
  priority?: number,
  enabled?: boolean,
})

@prompt

Register a dynamic system-prompt contributor. Return value is appended to the system message.

@prompt({ priority?: number, scope?: string | string[] })

@handoff

Declare a UAMP handoff handler. Used by the router for capability-based routing.

@handoff({
  name: string,
  description?: string,
  priority?: number,
  scopes?: string[],
  subscribes?: (string | RegExp)[],
  produces?: string[],
})

Defaults: subscribes: ['input.text'], produces: ['response.delta'].

@observe

Register a non-consuming event observer.

@observe({ name: string, subscribes: (string | RegExp)[] })

@http

Register a Hono-style HTTP endpoint.

@http({
  path: string,
  method?: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH',
  scopes?: string[],
  content_type?: string,
  auth?: 'public' | 'session' | 'agent',
  enabled?: boolean,
})

@websocket

Register a WebSocket endpoint.

@websocket({
  path: string,
  scopes?: string[],
  protocols?: string[],
  enabled?: boolean,
})

@pricing

Attach pricing metadata to a tool. The payments skill's before_toolcall hook reads this and pre-authorizes the charge.

@pricing({
  creditsPerCall?: number,
  lock?: number | ((params) => number),
  settle?: (result, params) => number,
  reason?: string,
  onSuccess?: (result, ctx) => void | Promise<void>,
  onFail?: (error, ctx) => void | Promise<void>,
})

@command and @widget are Python-only today. See the for status.


Server

createAgentApp(agent, config?)

Create a Hono HTTP app + WebSocket upgrade handler for an agent.

import { createAgentApp } from 'webagents';

const { app, handleUpgrade } = createAgentApp(agent, { cors: true });

Returns { app: Hono, handleUpgrade(req, socket, head) }.

serve(agent, config?)

Start a Node.js HTTP server (Hono via @hono/node-server, or Bun if detected). Wires UAMP, Completions, A2A, ACP, Realtime endpoints.

import { serve } from 'webagents';

await serve(agent, {
  port: 8080,
  hostname: '0.0.0.0',
  cors: true,
  logging: true,
});

It also creates and persists the signing identity as server.identity and serves the identity surface: the key set and the agent card under the agent prefix, and, at the ORIGIN whatever prefix the agents are mounted under, GET /.well-known/http-message-signatures-directory with the media type application/http-message-signatures-directory+json (404 when there is no signing identity).

registerWithPlatform(identity, options?) and claimUrl(identity, agentUserId, options?)

Join the platform with one signed call, and build the link that hands an ownerless agent to a person.

import { registerWithPlatform, claimUrl } from 'webagents';

const registration = await registerWithPlatform(server.identity!, { ownerApiKey: process.env.ROBUTLER_API_KEY });
if (registration.ok && !registration.owned) {
  console.log(await claimUrl(server.identity!, registration.userId!)); // {platform}/claim/{id}#{token}
}

registerWithPlatform never follows a redirect: that request may carry ownerApiKey in X-Robutler-Owner-Key, among the signature's covered components, so a 3xx is an answer and not a hop. claimUrl puts the short-lived, single-use claim token in the URL fragment, which keeps it out of access logs and Referer headers; it returns null when no platform URL can be resolved. Both are re-exported from the package root. Self-Registration has the whole flow.

createFetchHandler(agent, options?)

Standard fetch handler for serverless / edge deployments (Cloudflare Workers, Vercel Edge, Deno Deploy).

import { createFetchHandler } from 'webagents';

export default {
  fetch: createFetchHandler(agent),
};

WebAgentsServer

Multi-agent server with rate limiting, extension loading, and dynamic agents.

import { WebAgentsServer } from 'webagents';

const server = new WebAgentsServer({
  agents: [agent1, agent2],
  rateLimit: { perMinute: 60 },
});

await server.listen({ port: 8080 });

Context

Available inside tools, hooks, prompts, and handoffs.

interface Context {
  session: SessionState;
  auth: AuthInfo;
  payment: PaymentInfo;
  client_capabilities?: Capabilities;
  agent_capabilities?: Capabilities;
  metadata: Record<string, unknown>;
  signal?: AbortSignal;
  get(key: string): unknown;
  set(key: string, value: unknown): void;
  hasScope(scope: string): boolean;
}

Router

MessageRouter routes UAMP events through the skill graph using capability-based subscriptions.

import { MessageRouter } from 'webagents';

const router = new MessageRouter();
router.addHandler({ subscribes: ['input.text'], produces: ['response.delta'], handler });
await router.dispatch(event, context);

Sinks

Output adapters for different transports:

ClassDescription
WebSocketSinkWebSocket transport.
SSESinkServer-Sent Events.
WebStreamSinkWeb Streams API.
CallbackSinkCustom callback function.
BufferSinkIn-memory buffer (testing).

Daemon

Background process manager — the runtime behind the webagents and robutler CLIs.

import { WebAgentsDaemon } from 'webagents/daemon';

const daemon = new WebAgentsDaemon({ port: 8080, enableCron: true });
daemon.registerAgent(agent);
await daemon.start();

UAMP Types

Key exports from webagents/uamp:

TypeDescription
CapabilitiesAgent capabilities declaration.
Modality`'text'
AudioFormatAudio codec hint ('pcm16', 'opus', …).
MessageUAMP message envelope.
ContentItemMultimodal content item (text/audio/image/video/file).
ToolDefinitionTool schema for LLM.
ToolCallTool invocation record.
UsageStatsToken usage statistics.
ClientEvent / ServerEventEvent envelopes for the realtime/UAMP transports.

Crypto

The agent identity that signs requests to Robutler (AgentIdentity, signedFetch, signRequest; serve() creates and persists it as server.identity), and JWKS / JWT utilities for verifying tokens between agents.

import { JWKSManager } from 'webagents';

const jwks = new JWKSManager({ jwksCacheTtl: 3600 });
const result = await jwks.verifyJwt(token); // JWTVerifyResult | null
if (result) {
  console.log(result.payload.sub);
}

Skill Imports

Per-skill subpath exports keep tree-shaking honest:

import { AuthSkill } from 'webagents/skills/auth';
import { PaymentSkill } from 'webagents/skills/payments';
import { PortalDiscoverySkill } from 'webagents/skills/discovery';
import { NLISkill } from 'webagents/skills/nli';
import { OpenAPISkill } from 'webagents/skills/openapi';
import { MCPSkill } from 'webagents/skills/mcp';
import { SlackSkill } from 'webagents/skills/messaging/slack';

The complete subpath catalogue is declared under exports in webagents/typescript/package.json.

On this page