Skip to content

API reference

Published imports, public methods, structural contracts, and events in XSAF 0.1.0-alpha.0.

Updated View as Markdown

XSAF is ESM-only. Import core runtime symbols and contracts from @xsaf/agent; use published subpaths for bundled adapters.

Published imports

Import Main exports
@xsaf/agent xsaf, XsafBuilder, XsafAgent, HonoBackbone, XsaiModelAdapter, memory and scheduler implementations, parseCron, public contracts, tool errors
@xsaf/agent/channel/http default http, HttpChannel
@xsaf/agent/channel/mock default mock, MockChannel
@xsaf/agent/model/mock default mockModel, MockModelAdapter
@xsaf/agent/mcp default mcp
@xsaf/agent/sandbox/local default local
@xsaf/agent/sandbox/host default host, HostSandbox

Source-internal imports such as @xsaf/agent/core/agent and @xsaf/agent/memory/in-memory are not public exports.

Builder API

xsaf.agent(config): XsafBuilder

builder
  .sandbox(driver)
  .tool(config)
  .delegate(agent, options?)
  .mcp(driver)
  .memory(driver)
  .channel(driver)
  .serve(config)
  .schedule(config)
  .on(type, handler)
  .approve(handler)

Terminal and runtime methods:

builder.name: string | undefined
builder.description: string | undefined
builder.asAgent(name?, description?): XsafAgent
builder.start(): Promise<XsafAgent>
builder.stop(): Promise<void>
builder.invoke(prompt, sessionId?): Promise<InvokeResult>
builder.run(prompt, sessionId?): Promise<InvokeResult>
builder.ask(prompt, schema, sessionId?): Promise<Output>
builder.fetch(request): Promise<Response>
builder.app
builder.channels

Runtime use through builder requires successful startup. .asAgent() returns a sealed agent for reuse and delegation, using the configured name and description unless compatibility override arguments are supplied.

Agent API

agent.start(): Promise<XsafAgent>
agent.stop(): Promise<void>
agent.invoke(prompt, sessionId?): Promise<InvokeResult>
agent.ask(prompt, schema, sessionId?): Promise<Output>
agent.prompt(name, args?): Promise<string>
agent.fetch(request): Promise<Response>
agent.app
agent.channels
agent.started

Prefer obtaining an agent from .start() or .asAgent() over constructing XsafAgent or HonoBackbone directly.

Configuration

interface ServeConfig {
  transport: "http";
  path?: string;
  name?: string;
  version?: string;
  driver?: XsafServeDriver;
}

Default MCP path is /mcp; default name is the agent name or xsaf; default version is 0.1.0-alpha.0. The built-in transport only mounts a route.

interface ScheduleConfig {
  cron: string;
  prompt: string | (() => Promise<string>);
  sessionId?: string;
  delegate?: string;
  onResult?: (result: AgentResult) => Promise<void>;
  timezone?: string;
  runImmediately?: boolean;
}

Public contracts

XSAF drivers are narrow structural interfaces. Implement them without extending an XSAF base class.

Results

interface AgentResult {
  text: string;
  usage?: Readonly<Record<string, number>>;
}

interface AgentStreamResult {
  textStream: AsyncIterable<string>;
  completed: Promise<AgentResult>;
}

type InvokeResult = AgentResult | AgentStreamResult;

Model adapter

interface XsafModelAdapter {
  generate(request: ModelRequest): Promise<ModelResponse>;
  stream?(request: ModelRequest): ModelStreamResponse | Promise<ModelStreamResponse>;
  ask?<Output>(request: ModelRequest, schema: StandardSchemaV1<unknown, Output>): Promise<Output>;
}

ModelRequest contains model, endpoint, API key, messages, model-visible tools, maximum steps, and reasoning effort.

Tool

interface ToolExecutionContext {
  sessionId: string;
  signal?: AbortSignal;
}

interface ToolConfig<Schema extends XsafToolSchema> {
  name: string;
  description: string;
  input: Schema;
  execute(
    input: StandardSchemaV1.InferOutput<Schema>,
    context: ToolExecutionContext,
  ): unknown | Promise<unknown>;
  approval?: "auto" | "human" | ApprovalFn;
  retries?: number;
  timeout?: number;
  onError?: (error: unknown) => unknown | Promise<unknown>;
  sandbox?: XsafSandboxDriver;
}

See Tools for the dual-schema requirement.

Memory

interface XsafMemoryDriver {
  get(sessionId: string): Promise<Message[]>;
  append(sessionId: string, message: Message): Promise<void>;
  clear(sessionId: string): Promise<void>;
  close?(): Promise<void>;
}

Channel

interface XsafChannelDriver {
  name: string;
  listen(context: ChannelContext): void | Promise<void>;
  send(target: ChannelTarget, payload: ChannelPayload): Promise<void>;
  close?(): Promise<void>;
}

type ChannelTarget = string | Readonly<Record<string, unknown>>;
type ChannelPayload = string | AsyncIterable<string> | { text: string; meta?: unknown };

ChannelContext includes the shared Hono app, an inbound dispatch function, and a compatibility message registration hook.

Sandbox

interface XsafSandboxDriver {
  name: string;
  permissions?: SandboxPermissions;
  run(
    fn: (...args: unknown[]) => Promise<unknown>,
    args: unknown[],
    options?: { signal?: AbortSignal },
  ): Promise<unknown>;
  close?(): Promise<void>;
}

MCP

interface XsafMcpDriver {
  name: string;
  trust?: "trusted" | "untrusted";
  connect(context: McpContext): Promise<McpConnection | void>;
  close?(): Promise<void>;
}

A connection can provide tools, resources.get(uri), and prompts.get(name, args).

Scheduler

interface XsafSchedulerDriver {
  schedule(config: ScheduleConfig, run: () => Promise<void>): Promise<ScheduledTask>;
}

interface ScheduledTask {
  close(): Promise<void>;
}

interface ParsedCron {
  readonly fields: readonly Set<number>[];
  matches(date: Date, timezone: string): boolean;
}

function parseCron(expression: string): ParsedCron;

Driver methods may close external resources, so start them only from lifecycle hooks. Keep optional runtime-specific imports out of core-facing contract modules and avoid leaking mutable registries through driver APIs.

Events

Register typed handlers while configuring the builder:

builder.on("tool.failed", (event) => {
  console.error(event.tool, event.sessionId);
});

Handlers can be synchronous or asynchronous. Event failures are isolated so they cannot corrupt runtime state.

Event Payload fields
tool.called tool, sessionId
tool.completed tool, sessionId
tool.failed tool, sessionId, error
delegate.started delegate, sessionId
delegate.completed delegate, sessionId
message.sent channel?, sessionId
approval.required tool, sessionId
approval.granted tool, sessionId
mcp.connected server
heartbeat.fired sessionId
heartbeat.completed sessionId
heartbeat.failed sessionId, error
sandbox.escalated sandbox, tool
sandbox.denied sandbox, tool, reason

sandbox.escalated and sandbox.denied are public event variants for sandbox integrations. The bundled local and host adapters do not emit them.

type EventType = XsafEvent["type"];
type EventFor<Type extends EventType> = Extract<XsafEvent, { type: Type }>;
type EventHandler<Type extends EventType> = (event: EventFor<Type>) => unknown | Promise<unknown>;

approval.required does not carry tool arguments. Register .approve(handler) for privileged approval decisions that require validated input. Failure events expose a string error message; classify and redact it before exporting telemetry. Never serialize raw authorization headers, API keys, MCP payloads, channel metadata, or memory content by default.

A schedule emits heartbeat.fired before running. Success emits heartbeat.completed; failure emits heartbeat.failed. Overlapping ticks are skipped and do not emit a second heartbeat.fired for work that never starts.

See also

Navigation

Type to search…

↑↓ navigate↵ selectEsc close