libfx API reference

This page documents the JavaScript API in libfx@0.0.10. The TypeScript interfaces below describe the API; they are not types exported by the package. For setup and examples, see the Node SDK or WebAssembly SDK.

API index

Agent

Function or methodReturnsPurpose
createFxAgent(options)Promise<Agent>Create one conversation.
agent.prompt(input, options?)TurnRun a prompt and stream events.
agent.checkpoint()Promise<Uint8Array>Export conversation history and usage.
agent.close()Promise<void>Stop the agent and release its runtime.

Turn

Function or methodReturnsPurpose
turn.cancel()voidCancel the active turn.

TerminalRuntime

Function or methodReturnsPurpose
createFxTerminal(options)Promise<TerminalRuntime>Start the interactive terminal.
terminal.write(data)voidSend terminal input.
terminal.resize()voidNotify fx of a size change.
terminal.abort()voidStop the terminal and release listeners.

McpAdapter

Function or methodReturnsPurpose
createMcpAdapter(client, options?)Promise<McpAdapter>Convert an MCP client's tools and context.
mcp.close()Promise<void>Close the adapter and its client.

SkillsAdapter

Function or methodReturnsPurpose
createSkillsAdapter(records)SkillsAdapterConvert loaded skill records.
loadSkillFile(path, options?)Promise<SkillRecord>Read one skill file in Node or Bun.

Helpers

Function or methodReturnsPurpose
listModels(options)Promise<string[]>List available language-model IDs.
getBackendInfo(options?)Promise<BackendInfo>Check backend availability in Node.
supportsJspi()booleanCheck WebAssembly JSPI support.
xtermAdapter(term)TerminalAdapterConnect an xterm.js instance.
encodeXtermKeyEvent(event)string | nullEncode special terminal keys.

Imports

import {
  createFxAgent,
  createFxTerminal,
  listModels,
  supportsJspi,
  xtermAdapter,
  encodeXtermKeyEvent,
} from 'libfx'

import { getBackendInfo } from 'libfx/node'
import { createMcpAdapter } from 'libfx/mcp'
import { createSkillsAdapter } from 'libfx/skills'
import { loadSkillFile } from 'libfx/skills/node'

libfx selects the Node or browser entry point for your environment. libfx/node uses a native addon when available; libfx/browser always uses WebAssembly. libfx/wasm exposes the WebAssembly host layer directly and requires an explicit wasm asset. getBackendInfo() is Node-only. CommonJS applications can use require('libfx') or require('libfx/node').

The main entry points also export fxSdkApiVersion, currently 2. The Node and browser wrappers export libfxApiVersion, also 2. These identify API revisions, not the npm package version.

Interfaces

InterfaceDescribes
AgentOptionsCredentials, model, instructions, tools, and checkpoint input.
AgentThe conversation's methods.
PromptInput and PromptOptionsText, resources, and cancellation.
TurnAn event stream, result promise, and cancel method.
TurnEventText, reasoning, and tool events.
TurnResult and UsageStop reason and token counts.
HostToolA tool's schema and execution callback.
DiagnosticEventRuntime diagnostics sent to onEvent.
BackendInfoSelected backend and attempted alternatives.
TerminalOptionsTerminal adapter, configuration, and stores.
TerminalRuntimeTerminal readiness, exit, and control methods.
TerminalAdapterInput, output, and geometry supplied by your UI.
McpAdapterAdapted tools, instructions, and cleanup.
SkillRecord and SkillsAdapterLoaded skill text, resources, and tools.

Shared notation used below:

type MaybePromise<T> = T | Promise<T>
type Bytes = ArrayBuffer | ArrayBufferView
type Fetch = typeof globalThis.fetch
type Backend = 'auto' | 'native' | 'wasm'
type WasmSource = string | Response | Bytes | WebAssembly.Module

For wasm, the browser accepts a URL string, response, bytes, or compiled module. Node also accepts a filesystem path or a URL object. A promise resolving to a response, bytes, or compiled module is accepted. The package wrappers supply their own assets when you omit wasm.

Agent

interface Agent {
  prompt(input: PromptInput, options?: PromptOptions): Turn
  checkpoint(): Promise<Uint8Array>
  close(): Promise<void>
}

An agent has no createSession(), setModel(), or history property. To change creation options, save a checkpoint and restore it into a new agent with those options.

createFxAgent

createFxAgent(options: AgentOptions): Promise<Agent>

Creates one in-memory conversation. On Node, the default backend tries the native addon and falls back to WebAssembly. Browser agents require JSPI. The promise resolves after initialization and any checkpoint restore finish.

AgentOptions

interface AgentOptions {
  apiKey: string
  model?: string
  instructions?: string | string[]
  tools?: HostTool[]
  checkpoint?: Bytes
  fetch?: Fetch
  onEvent?: (event: DiagnosticEvent) => void
  wasm?: WasmSource | URL | Promise<Response | Bytes | WebAssembly.Module>
  backend?: Backend
  nativeAddon?: string | URL | object | false
}
OptionRequiredDefaultBehavior
apiKeyYesNoneAI Gateway credential. Non-empty string, at most 64 KiB of UTF-8.
modelNofx's built-in modelModel ID, at most 1 KiB of UTF-8.
instructionsNoNo system messageComplete system instructions. An array joins non-empty entries with blank lines. At most 64 KiB of UTF-8 after joining.
toolsNo[]Up to 64 explicit host tools. No CLI tools are enabled automatically.
checkpointNoNew conversationOpaque bytes from agent.checkpoint(). The input is copied.
fetchNoglobalThis.fetchHost-controlled HTTP transport. Preserve the supplied AbortSignal.
onEventNoNoneSynchronous diagnostic callback. Model output is on the Turn stream instead.
wasmNo for package wrappersPackaged fx-core.wasmWebAssembly asset to load when using that backend.
backendNo'auto'Node-only backend selection. 'native' fails instead of falling back; 'wasm' requires JSPI.
nativeAddonNoPackaged platform addonNode-only custom addon module, path, or URL. false disables native loading. Treat this as trusted application configuration.

Do not pass env: the agent rejects it. Terminal settings, session stores, and CLI permission modes are not agent configuration. Your application supplies tools, authorizes their actions, and stores checkpoints.

Invalid options reject creation. Missing JSPI, asset-loading failures, incompatible addons, and invalid checkpoints can also reject the promise. See Errors and Advanced testing.

agent.prompt

agent.prompt(input: PromptInput, options?: PromptOptions): Turn

Starts a turn in the conversation and returns a Turn immediately, not a promise. Read events with for await, then await turn.result.

import { createFxAgent } from 'libfx'

const agent = await createFxAgent({ apiKey: process.env.AI_GATEWAY_API_KEY })
try {
  const turn = agent.prompt('Explain this schema.')
  for await (const event of turn) {
    if (event.type === 'text_delta') process.stdout.write(event.delta)
  }
  const result = await turn.result
  console.log(result.stopReason, result.usage)
} finally {
  await agent.close()
}

PromptInput and PromptOptions

type PromptInput = string | PromptBlock[]
type PromptBlock =
  | { type: 'text'; text: string }
  | { type: 'resource'; resource: { uri: string; text?: string } }

interface PromptOptions {
  signal?: AbortSignal
}

A string is equivalent to one text block. For a resource, pass its text explicitly; the URI identifies the resource and does not grant file access. A flat resource block with uri and text alongside type is also accepted. Image and audio prompt blocks are not supported.

const turn = agent.prompt([
  { type: 'text', text: 'Summarize this file.' },
  {
    type: 'resource',
    resource: {
      uri: 'file:///workspace/schema.sql',
      text: 'CREATE TABLE users (id INTEGER PRIMARY KEY);',
    },
  },
], { signal: controller.signal })

prompt() throws synchronously for malformed input, a closed agent, or another active prompt. An already-aborted signal returns a cancelled turn without making a model request or changing history. Network and runtime failures during execution reject the stream or result promise.

agent.checkpoint

agent.checkpoint(): Promise<Uint8Array>

Returns opaque, versioned conversation bytes while the agent is idle. It rejects while a prompt is active or after the agent closes. Store the bytes without editing them and restore them only through createFxAgent({ checkpoint, ...options }).

A checkpoint contains history and usage, not credentials, model selection, instructions, tools, MCP clients, or skills. Resupply those options on restoration. Protect stored checkpoints as conversation data.

const checkpoint = await agent.checkpoint()
await agent.close()
const restored = await createFxAgent({
  apiKey: process.env.AI_GATEWAY_API_KEY,
  checkpoint,
})
// Continue with restored.prompt(...), then await restored.close().

agent.close

agent.close(): Promise<void>

Cancels an active turn, releases blocked output, and waits for the runtime to exit. Repeated calls are safe. The agent cannot be prompted or checkpointed afterward. Closing an agent does not close host-owned database connections or MCP clients.

Turn

interface Turn extends AsyncIterable<TurnEvent> {
  result: Promise<TurnResult>
  cancel(): void
}

A turn permits one event consumer. Read the stream even when you only need the result:

const turn = agent.prompt('Summarize the discussion.')
for await (const _ of turn) {}
const result = await turn.result

A slow reader pauses output production instead of growing an unlimited queue. Awaiting only turn.result can stall while unread events wait to be consumed. Breaking out of the iterator cancels the turn. Do not start another prompt until the current one settles.

turn.cancel

turn.cancel(): void

Requests cancellation without waiting for completion. It aborts model requests and the signals passed to host tools. Continue draining the stream and await turn.result to observe completion. Calling cancel() again, or after the turn finishes, has no effect.

const controller = new AbortController()
const turn = agent.prompt('Review the schema.', { signal: controller.signal })
controller.abort() // Equivalent to requesting cancellation with turn.cancel().
for await (const _ of turn) {}
console.log((await turn.result).stopReason)

Cancellation stops waiting for tool callbacks; it cannot stop JavaScript work that ignores its signal. Late tool results and rejections are ignored.

TurnEvent

type TurnEvent =
  | { type: 'text_delta'; delta: string }
  | { type: 'reasoning_delta'; delta: string }
  | { type: 'tool_start'; id: string; name: string }
  | {
      type: 'tool_end'
      id: string
      name: string
      content?: string
      isError: boolean
    }
EventFieldsMeaning
text_deltadeltaAppend this text to the answer.
reasoning_deltadeltaReasoning text when the provider supplies it.
tool_startid, nameA tool call started.
tool_endid, name, content?, isErrorA tool call completed or failed. Match it to its start by id.

tool_end.content is the available text result, not the original JavaScript return value. There is no separate final-result event; use turn.result after reading the stream.

TurnResult and Usage

interface TurnResult {
  stopReason: StopReason
  usage: Usage
}

type StopReason =
  | 'end_turn'
  | 'max_output_tokens'
  | 'max_model_turns'
  | 'refused'
  | 'cancelled'

interface Usage {
  inputTokens?: number
  outputTokens?: number
  cacheReadTokens?: number
  cacheWriteTokens?: number
  reasoningTokens?: number
}
Stop reasonMeaning
end_turnThe turn ended normally.
max_output_tokensThe response reached its output-token limit.
max_model_turnsThe turn reached its model-step limit.
refusedThe model refused the request.
cancelledThe turn was cancelled.

usage is always an object. Its fields are optional: missing counts are omitted, not replaced with zero. A prompt cancelled before it starts returns { stopReason: 'cancelled', usage: {} }. Transport or decoding failures reject rather than returning a successful result with missing output.

HostTool

type JsonValue =
  | string | number | boolean | null
  | JsonValue[]
  | { [key: string]: JsonValue }

interface HostTool {
  name: string
  description: string
  inputSchema: Record<string, JsonValue>
  execute(
    input: unknown,
    context: { signal: AbortSignal },
  ): MaybePromise<JsonValue | undefined | RichToolResult>
}

interface RichToolResult {
  type: 'libfx.tool-result'
  text: string
  images: Array<{ type: 'image'; mimeType: string; data: string }>
  isError?: boolean
}

Tool names must be unique, contain 1–64 letters, digits, underscores, or hyphens, and have a JSON-serializable object schema. Your callback must validate and authorize actions before executing them.

Strings return as text. Other ordinary results are JSON-encoded; undefined becomes "null". A thrown error becomes a failed tool result with its message. Use RichToolResult for image results: data is base64, with PNG, JPEG, GIF, and WebP supported for image-capable models. Other models receive an omission notice. Ordinary objects are not interpreted as images.

Up to eight images are allowed, each with at most 5 MiB of base64 data and an 8 MiB serialized rich-result limit. The host-tool response frame has an 8 MiB limit. Keep tool results small and honor context.signal.

TerminalRuntime

interface TerminalRuntime {
  interactive: Promise<void>
  exited: Promise<number>
  write(data: string | Uint8Array): void
  resize(): void
  abort(): void
}
MemberBehavior
interactiveResolves after the terminal reaches its input loop and optional adapter drain() finishes. Rejects if fx exits before reaching that loop or draining fails.
exitedResolves with the exit code. An explicit abort uses 130.
write(data)Sends text or bytes as input. Ctrl+C string input also cancels host effects; it does not immediately destroy the runtime.
resize()Wakes fx to read the adapter's current cols and rows. It takes no dimensions.
abort()Stops the runtime and releases data, key, and resize subscriptions. Returns immediately; await exited for the exit code.

createFxTerminal

createFxTerminal(options: TerminalOptions): Promise<TerminalRuntime>

Starts the interactive terminal, not a headless Agent. The packaged terminal uses WebAssembly on both Node and browsers and requires JSPI. Await runtime.interactive before sending input.

TerminalOptions

interface TerminalOptions {
  terminal: TerminalAdapter
  env?: Record<string, string>
  args?: string[]
  fetch?: Fetch
  onEvent?: (event: DiagnosticEvent) => void
  interruptKey?: string
  wasm?: WasmSource | URL | Promise<Response | Bytes | WebAssembly.Module>
  backend?: Backend
  nativeAddon?: string | URL | object | false
  configStore?: ConfigStore
  promptHistoryStore?: PromptHistoryStore
  sessionStore?: SessionStore
  oauthSessionStore?: OAuthSessionStore
  openUrl?: (url: string) => MaybePromise<boolean>
  workspace?: WorkspaceAdapter
}
OptionDefaultBehavior
terminalRequiredUI adapter for input, output, and size.
env{}Terminal environment, including AI_GATEWAY_API_KEY when supplying a credential directly.
args[]Terminal CLI arguments, such as ['--resume', 'last'].
fetchglobalThis.fetchHost HTTP transport.
onEventNoneDiagnostic callback.
interruptKey'\x03' (Ctrl+C)String input containing this key also cancels active host effects. '' disables this detection.
wasmPackaged fx-term.wasmTerminal WebAssembly asset; required with the direct libfx/wasm entry.
backend'auto'Node-only selection. The package has no native terminal, so 'native' fails.
nativeAddonPackaged platform addonNode-only override for a custom addon.
Stores, openUrl, workspaceNot suppliedOptional terminal host integrations listed below.

Store methods can return their value directly or in a promise. See Terminal embedding for method signatures and revision rules:

InterfaceContract
ConfigStoreget(id) and set(id, value)
PromptHistoryStoreload, append, and clear
SessionStoreload, commit, list, and remove
OAuthSessionStoreload, commit, and remove
WorkspaceAdapterinfo, permission, and exec

These stores do not configure a headless agent. Use agent creation options and checkpoints instead.

TerminalAdapter

interface TerminalAdapter {
  readonly cols: number
  readonly rows: number
  write(bytes: Uint8Array): void
  onData(callback: (data: string) => void): () => void
  onResize(callback: () => void): () => void
  onKeyData?(callback: (data: string) => void): () => void
  drain?(): MaybePromise<void>
}

Subscription methods return unsubscribe functions. Keep dimensions current before emitting a resize. Use drain() when your UI needs to flush pending output before the terminal is considered interactive. The standard xterm adapter handles the subscriptions for you.

McpAdapter

createMcpAdapter

From libfx/mcp:

createMcpAdapter(client: McpClient, options?: McpOptions): Promise<McpAdapter>

interface McpOptions {
  prefix?: string
  resources?: string[]
  prompts?: Array<string | { name: string; arguments?: Record<string, string> }>
}

interface McpAdapter {
  tools: HostTool[]
  instructions: string
  close(): Promise<void>
}

McpClient is your already-connected MCP TypeScript SDK v1 client. It must implement listTools() and callTool(params, resultSchema?, options?). Resource options also require readResource({ uri }); prompt options require getPrompt({ name, arguments? }).

OptionDefaultBehavior
prefix''Prefix for model-facing tool names; letters, digits, underscores, and hyphens only.
resources[]Resource URIs whose text is added to instructions.
prompts[]Prompt names or name/arguments objects whose text is added to instructions.

Creation lists tools, follows pagination, and fetches the requested context. More than 64 tools, invalid or repeated cursors, duplicate original tool names, or instructions larger than 64 KiB fail creation. Tool names are normalized for model APIs; calls to the client retain the original names. Non-text prompt/resource context is replaced with an omission notice.

Pass adapter.tools and adapter.instructions into createFxAgent(). Tool cancellation reaches the client's third callTool argument as { signal }. adapter.close() calls client.close() if supplied, once. Close the agent first. The host chooses and authenticates the client and remains responsible for transport setup.

SkillsAdapter

createSkillsAdapter

From libfx/skills, also re-exported by libfx/skills/node:

createSkillsAdapter(records: SkillRecord[]): SkillsAdapter

interface SkillRecord {
  name: string
  description?: string
  instructions: string
  resources?: Array<{ uri: string; text: string }>
  tools?: HostTool[]
}

interface SkillsAdapter {
  instructions: string
  tools: HostTool[]
}

Combines up to 64 loaded records into instructions and a tool array. Skill names must be unique. Resource text is included directly; this function does not fetch resources or read files. Invalid records, duplicate names, or combined instructions larger than 64 KiB throw. Pass the returned fields into createFxAgent({ apiKey, ...skills }).

loadSkillFile

From libfx/skills/node, for Node or Bun:

loadSkillFile(path: string, options?: LoadSkillOptions): Promise<SkillRecord>

interface LoadSkillOptions {
  readFile?: (path: string, encoding: 'utf8') => MaybePromise<string>
  resources?: Array<{ uri: string; text: string }>
  tools?: HostTool[]
}

Reads one file as UTF-8 using Node's readFile, or the supplied function. It reads simple name: value and description: value frontmatter and returns the remaining text as instructions. Without a name, it uses the filename without .md. It is not a general YAML parser and does not scan directories or load referenced files. File errors and unterminated frontmatter reject the promise.

Helpers

listModels

listModels(options: ListModelsOptions): Promise<string[]>

interface ListModelsOptions {
  apiKey: string
  fetch?: Fetch
}

Returns sorted, unique language-model IDs. apiKey is required; fetch defaults to the global implementation. This performs one Gateway catalog request without creating an agent or loading a native or WebAssembly runtime.

The promise rejects on invalid options, a failed HTTP response, malformed catalog data, or a catalog exceeding 4 MiB or 10,000 entries. Agent creation does not call this function automatically.

getBackendInfo

Node-only, from libfx or libfx/node:

getBackendInfo(options?: BackendInfoOptions): Promise<BackendInfo>

interface BackendInfoOptions {
  surface?: 'agent' | 'terminal'
  backend?: Backend
  nativeAddon?: string | URL | object | false
  wasm?: WasmSource | URL | Promise<Response | Bytes | WebAssembly.Module>
}

surface defaults to 'agent' and backend to 'auto'. Asset options have the same meaning as factory options. No credentials are required. Unknown options reject with TypeError.

BackendInfo

interface BackendInfo {
  surface: 'agent' | 'terminal'
  backend: 'native' | 'wasm-jspi' | 'unavailable'
  attempts: BackendAttempt[]
}

interface BackendAttempt {
  backend: 'native' | 'wasm-jspi'
  available: boolean
  reason: null | {
    code: string
    message: string
    causeCode?: string | number
  }
}

Attempts appear in selection order and stop at the first available backend. A successful attempt has reason: null. Expected loading failures resolve with an unavailable result rather than rejecting.

Reason codeMeaning
LIBFX_UNSUPPORTED_PLATFORMNo packaged native addon supports this platform and architecture.
LIBFX_NATIVE_ARTIFACT_MISSINGThe selected native file is absent.
LIBFX_NATIVE_LOAD_FAILEDNode could not load the addon.
LIBFX_NATIVE_API_MISMATCHThe addon API revision is incompatible.
LIBFX_NATIVE_SURFACE_MISSINGThe addon does not implement the requested agent or terminal.
LIBFX_NATIVE_DISABLEDnativeAddon: false disabled native loading.
LIBFX_JSPI_UNAVAILABLEThe runtime has no JSPI support.
LIBFX_WASM_LOAD_FAILEDThe WebAssembly asset could not load or compile.

The probe loads the native module or compiles WebAssembly. It does not start an agent, validate credentials, or make a model request. A remote WebAssembly asset can still cause a network request. Availability does not guarantee a later initialization or prompt will succeed.

supportsJspi

supportsJspi(): boolean

Checks for WebAssembly.Suspending and WebAssembly.promising. It does not load WebAssembly. Use this feature check before creating a browser agent or terminal; native Node agents do not require JSPI.

xtermAdapter

xtermAdapter(term: import('@xterm/xterm').Terminal): TerminalAdapter

Wraps an xterm.js terminal and forwards input, output, geometry, and resize notifications. It installs a custom key handler for fx-specific key encodings when xterm supports that hook. The host still owns opening and disposing the xterm.js instance.

encodeXtermKeyEvent

encodeXtermKeyEvent(event: KeyboardEvent): string | null

Returns an escape sequence for Shift+Enter and supported Meta+Backspace or Meta+arrow key combinations. Returns null for keys it does not handle, non-keydown events, or Alt/Ctrl combinations. null means the terminal should use its normal handling.

DiagnosticEvent

onEvent receives runtime diagnostics, not the TurnEvent stream:

interface DiagnosticEvent {
  type: string
  timestamp: number
  [detail: string]: unknown
}

timestamp is milliseconds from performance.now(), not a Unix timestamp. The callback runs synchronously; exceptions thrown by it are ignored. Treat event-specific fields as diagnostics rather than the answer/result API.

EventAdditional fields
runtime.start, runtime.readyTerminal events include surface: 'terminal'.
runtime.exitcode; terminal events also include surface.
transport.startattempt, method, endpoint, model when selected.
transport.responseattempt, status, elapsedMs, requestId, generationId, model, provider. Header-derived values can be null or absent.
transport.errorattempt, elapsedMs, error (error name).
transport.retryattempt, nextAttempt, elapsedMs, error.
output.backpressurebufferedBytes, bufferedEvents.
output.discardedreason, bytes.
acp.send, acp.receivemessage, the protocol payload.
terminal.resize, terminal.sizecols, rows.
terminal.cleanup_errorsource, error.

Terminal adapters also emit config/history restore, update, and error diagnostics. Transport metadata omits credentials and raw headers, but protocol messages can contain prompts, instructions, tool content, and checkpoint data. Do not log the entire diagnostic stream as if it were free of sensitive data.

Errors

OperationFailure behavior
createFxAgent, createFxTerminalReject on invalid options, unavailable backend, asset failure, or initialization failure.
agent.promptThrows for invalid input, a closed agent, or a concurrent prompt.
Turn iteration and turn.resultReject on transport, decoding, or runtime failure. Normal cancellation resolves with stopReason: 'cancelled'.
agent.checkpointRejects during an active turn, after close, or if export fails.
listModelsRejects invalid options, HTTP errors, malformed data, or size limits.
getBackendInfoRejects invalid options; expected backend-loading failures are returned in attempts.
Host tool callbackA thrown error is sent to the model as a failed tool result.

The Node factories may report LIBFX_JSPI_REQUIRED when no native backend can be used and JSPI is unavailable, or LIBFX_NATIVE_UNAVAILABLE for a missing native surface. Loading and initialization errors can retain their original codes. These factory errors are distinct from the reason codes returned by getBackendInfo().

Advanced testing

Most applications should leave model-request routing at its default. gatewayChatUrl?: string is a low-level agent option for testing against a local Gateway-compatible HTTP server, not a general provider base URL. It changes where model inference requests are sent; it does not change listModels().

The only accepted destinations are the canonical Gateway inference URL and HTTP on localhost, 127.0.0.1, or [::1] with an explicit port. URLs with embedded credentials or fragments are rejected. Use only trusted application configuration. For production network policy or a proxy, provide a trusted fetch implementation and preserve cancellation.