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 toaddToolOutput;'external'is left alone for your UI; an unknown name is logged and never answered. Dynamic tools dispatch by name too. - Outputs produced before
attachare delivered when you attach. - With your own
onToolCall, skipclientToolsand callrunCode.handle(toolCall)from yourswitch. fromToolsmapsneedsApproval: truetoapproval: 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.