Docs · 08 / 13

Integrations

Faustine built this library for its own code mode in the browser, where the agent's program runs on the customer's page. It is meant for custom code mode implementations like that one, for the code mode libraries below, and for any other system, agentic loop or not, that has to run agent-generated code in the browser.

AI SDK (useChat, Chat)

The AI SDK has one onToolCall per chat and answers through addToolOutput. The sandbox's tool is one entry in a map you build here; the rest of your client tools keep working.

import { createSandbox, defineFunctions } from '@faustine-ai/browser-sandbox';
import { runCodeTool, clientTools, fromTools } from '@faustine-ai/browser-sandbox/ai';

const sandbox = createSandbox({ frame: { url: '/sandbox' }, warm: true });

const functions = defineFunctions({
  ...fromTools(myClientTools, { namespace: 'app' }),        // AI SDK tools with `execute` → sdk.app.<name>
  'orders.list':   (input) => api.orders.list(input),
  'orders.cancel': { call: (input) => api.orders.cancel(input), approval: true },
});

const runCode = runCodeTool({
  sandbox, functions,
  approval: { mode: 'collect', onApproval: (pending) => showBatchCard(pending) },
});

const tools = clientTools({
  runCode,                                                  // the sandbox's tool (name "runCode")
  getLocation: async () => geo.current(),                   // your own client tools
  confirmPayment: 'external',                               // answered later by your UI
});

const chat = useChat({ transport, onToolCall: tools.onToolCall });
tools.attach(chat);                                         // hands the helper addToolOutput
  • Dispatch is by toolCall.toolName. A plain function runs and its value goes to addToolOutput; 'external' is left alone for your UI; an unknown name is logged and never answered. Dynamic tools dispatch by name too.
  • Outputs produced before attach are delivered when you attach.
  • With your own onToolCall, skip clientTools and call runCode.handle(toolCall) from your switch.
  • fromTools maps needsApproval: true to approval: true; inside the sandbox the run's approval mode governs it.

On the server, runCode is a tool without execute (the client answers):

tools: {
  runCode: tool({
    description: 'Runs JavaScript in the user\'s browser against `sdk`. Return the value you need.',
    inputSchema: z.object({ code: z.string() }),
  }),
}

Put describe(functions) in the system prompt so the model writes the names the code will find.

Isn't code mode already in the AI SDK? On the server. The program of @ai-sdk/code-mode runs in QuickJS inside a Node worker, "is not available in browser or edge runtimes", and reaches server tools only. In the browser the AI SDK gives you client tools and nothing that runs a program against them; runCode is that piece. The two can combine in one chat: server tools behind code_mode, page functions behind runCode.

Cloudflare @cloudflare/codemode

Cloudflare's createCodeTool owns the prompt and the tool wiring and delegates the run to an Executor. It ships two: Dynamic Workers on the server, and IframeSandboxExecutor for the browser, an iframe without a worker, which cannot stop a synchronous loop (documented, 30 s timeout), needs 'unsafe-inline' in its CSP and has no approval hook. asExecutor(sandbox) is a third executor for the same createCodeTool: a worker it can terminate, a frame that works under a strict CSP, and the approval modes. Their server executor stays for server tools.

import { asExecutor } from '@faustine-ai/browser-sandbox/codemode';

const executor = asExecutor(sandbox);                        // Executor { execute(code, fns) }
const codemode = createCodeTool({ tools, executor });

A plain record of functions is exposed as codemode.<name>(...args); providers as codemode.<provider>.<fn>. asExecutor(sandbox, { root, needsApproval, approval, caps }) for the policies.

TanStack AI

TanStack's createCodeMode writes the prompt and compiles the bindings; the program runs through a pluggable IsolateDriver, and the driver it ships is QuickJS compiled to WASM, with no approval step. asIsolateDriver(sandbox) is a driver for the same createCodeMode: the page's own engine instead of a second one, structured clone instead of re-encoding File and Blob by hand, about 8 KB instead of a 1 MB WASM payload, and the approval modes. Their QuickJS driver stays the choice on the server or when you want an engine separate from the page's.

import { asIsolateDriver } from '@faustine-ai/browser-sandbox/tanstack';

createCodeMode({ tools, driver: asIsolateDriver(sandbox) });

Bindings become bare external_<name>(input) functions, as TanStack's generated code expects. createContext({ timeout }) maps to timeoutMs.