Skip to main content

ai-code-mode

LLM-generated TypeScript execution in sandboxed environments: createCodeModeTool() with isolate drivers (createNodeIsolateDriver, createQuickJSIsolateDriver, createQuickJSBunIsolateDriver, createCloudflareIsolateDriver), codeModeWithSnippets() for persistent snippet libraries, trust strategies, snippet storage (FileSystem, LocalStorage, InMemory, Mongo), client-side execution progress via code_mode:* custom events in useChat.

Source facts

Repository
TanStack/ai
Last source activity
September 9, 2026 at 06:08
Detected SKILL.md language
English
Stars
3,199
Forks
366

Install options

The review-first prompt is selected by default. You can switch to a direct command or download a local copy.

Review the source files

Read SKILL.md and any companion files shown by SkillsMP before deciding whether to install.

Showing SKILL.md

SKILL.md
Source instructions · Read-only preview
name
ai-code-mode
description
LLM-generated TypeScript execution in sandboxed environments: createCodeModeTool() with isolate drivers (createNodeIsolateDriver, createQuickJSIsolateDriver, createQuickJSBunIsolateDriver, createCloudflareIsolateDriver), codeModeWithSnippets() for persistent snippet libraries, trust strategies, snippet storage (FileSystem, LocalStorage, InMemory, Mongo), client-side execution progress via code_mode:* custom events in useChat.
type
core
library
tanstack-ai
library_version
0.3.8
sources
["TanStack/ai:docs/code-mode/code-mode.md","TanStack/ai:docs/code-mode/code-mode-isolates.md","TanStack/ai:docs/code-mode/code-mode-with-snippets.md","TanStack/ai:docs/code-mode/client-integration.md","TanStack/ai:docs/code-mode/lazy-tools.md"]
> **Note**: This skill requires familiarity with ai-core and ai-core/chat-experience. Code Mode is always used on top of a chat experience. ## Setup Complete Code Mode setup with Node.js isolate driver: ```typescript import { chat, toServerSentEventsResponse, toolDefinition } from '@tanstack/ai' import { openaiText } from '@tanstack/ai-openai' import { createCodeModeTool } from '@tanstack/ai-code-mode' import { createNodeIsolateDriver } from '@tanstack/ai-isolate-node' import { z } from 'zod' // Define a tool that code can call const fetchWeather = toolDefinition({ name: 'fetchWeather', description: 'Get current weather for a city', inputSchema: z.object({ city: z.string() }), outputSchema: z.object({ temp: z.number(), condition: z.string() }), }).server(async ({ city }) => { const res = await fetch(`https://api.weather.com/${city}`) return res.json() }) // Create code mode tool with Node isolate const codeModeTool = createCodeModeTool({ driver: createNodeIsolateDriver({ memoryLimit: 128, timeout: 30000, }), tools: [fetchWeather], }) // Use in chat export async function POST(request: Request) { const { messages } = await request.json() const stream = chat({ adapter: openaiText('gpt-5.5'), messages, tools: [codeModeTool], }) return toServerSentEventsResponse(stream) } ``` The recommended higher-level entry point is `createCodeMode()`, which returns both the tool and a matching system prompt: ```typescript import { chat, toServerSentEventsResponse, toolDefinition } from '@tanstack/ai' import { createCodeMode } from '@tanstack/ai-code-mode' import { createNodeIsolateDriver } from '@tanstack/ai-isolate-node' import { openaiText } from '@tanstack/ai-openai' import { z } from 'zod' const fetchWeather = toolDefinition({ name: 'fetchWeather', description: 'Get current weather for a city', inputSchema: z.object({ city: z.string() }), outputSchema: z.object({ temp: z.number(), condition: z.string() }), }).server(async ({ city }) => { const res = await fetch(`https://api.weather.com/${city}`) return res.json() }) const { tool, systemPrompt } = createCodeMode({ driver: createNodeIsolateDriver(), tools: [fetchWeather], timeout: 30_000, }) export async function POST(request: Request) { const { messages } = await request.json() const stream = chat({ adapter: openaiText('gpt-5.5'), systemPrompts: ['You are a helpful assistant.', systemPrompt], tools: [tool], messages, }) return toServerSentEventsResponse(stream) } ``` `createCodeMode` calls `createCodeModeTool` and `createCodeModeSystemPrompt` internally. The system prompt includes generated TypeScript type stubs for each tool so the LLM writes correct calls. ## Core Patterns ### 1. Choosing an Isolate Driver Four drivers implement the `IsolateDriver` interface. All are interchangeable. **Node.js** (`createNodeIsolateDriver`) -- Full V8 with JIT. Fastest option. Requires `isolated-vm` native C++ addon. ```typescript import { createNodeIsolateDriver } from '@tanstack/ai-isolate-node' const driver = createNodeIsolateDriver({ memoryLimit: 128, // MB, default 128 timeout: 30_000, // ms, default 30000 // skipProbe: false -- set true only after verifying compatibility }) ``` **QuickJS** (`createQuickJSIsolateDriver`) -- WASM-based, no native deps. Works in Node.js, browsers, Deno, Bun, and edge runtimes. Slower (interpreted, no JIT). Limited stdlib (no File I/O). ```typescript import { createQuickJSIsolateDriver } from '@tanstack/ai-isolate-quickjs' const driver = createQuickJSIsolateDriver({ memoryLimit: 128, // MB, default 128 timeout: 30_000, // ms, default 30000 maxStackSize: 524288, // bytes, default 512 KiB }) ``` **QuickJS Bun** (`createQuickJSBunIsolateDriver`) -- Native QuickJS on the Bun runtime via `bun:ffi`. Requires Bun >= 1.3.14 (throws a descriptive error on Node.js). No native deps or build step. Each context gets a dedicated QuickJS runtime with its own memory limit, stack size, and interrupt-based timeout. Recommended QuickJS option on Bun, where the WASM driver's asyncify bridge is unreliable for async host tool calls. ```typescript import { createQuickJSBunIsolateDriver } from '@tanstack/ai-isolate-quickjs-bun' const driver = createQuickJSBunIsolateDriver({ memoryLimit: 128, // MB, default 128 timeout: 30_000, // ms, default 30000 maxStackSize: 524288, // bytes, default 512 KiB }) ``` **Cloudflare** (`createCloudflareIsolateDriver`) -- Edge execution via a deployed Cloudflare Worker. Requires a `workerUrl` pointing to your deployed worker. Network latency on each tool call. ```typescript import { createCloudflareIsolateDriver } from '@tanstack/ai-isolate-cloudflare' const driver = createCloudflareIsolateDriver({ workerUrl: 'https://my-code-mode-worker.my-account.workers.dev', authorization: process.env.CODE_MODE_WORKER_SECRET, timeout: 30_000, // ms, default 30000 maxToolRounds: 10, // max tool-call/result cycles, default 10 }) ``` | Driver | Best for | Native deps | Browser support | Performance | | ----------- | --------------------------- | --------------- | --------------- | --------------------- | | Node | Server-side Node.js | Yes (C++ addon) | No | Fast (V8 JIT) | | QuickJS | Browsers, edge, portability | None (WASM) | Yes | Slower (interpreted) | | QuickJS Bun | Bun servers | None | No | Fast (native QuickJS) | | Cloudflare | Edge deployments | None | N/A | Fast (V8 on edge) | ### 2. Adding Persistent Snippets with codeModeWithSnippets() Snippets let the LLM save reusable code snippets. On future requests, relevant snippets are loaded and exposed as callable tools. ```typescript import { chat, maxIterations, toServerSentEventsResponse, toolDefinition, } from '@tanstack/ai' import { createNodeIsolateDriver } from '@tanstack/ai-isolate-node' import { codeModeWithSnippets, createDefaultTrustStrategy, } from '@tanstack/ai-code-mode-snippets' import { createFileSnippetStorage } from '@tanstack/ai-code-mode-snippets/storage' import { openaiText } from '@tanstack/ai-openai' import { z } from 'zod' const fetchWeather = toolDefinition({ name: 'fetchWeather', description: 'Get current weather for a city', inputSchema: z.object({ city: z.string() }), outputSchema: z.object({ temp: z.number(), condition: z.string() }), }).server(async ({ city }) => { const res = await fetch(`https://api.weather.com/${city}`) return res.json() }) // Trust strategies control how snippets earn trust through executions // Default (createDefaultTrustStrategy): untrusted -> provisional (10+ runs, >=90%) -> trusted (100+ runs, >=95%) // Relaxed (createRelaxedTrustStrategy): untrusted -> provisional (3+ runs, >=80%) -> trusted (10+ runs, >=90%) // Always trusted (createAlwaysTrustedStrategy): immediately trusted (dev/testing) // Custom (createCustomTrustStrategy): configurable thresholds const trustStrategy = createDefaultTrustStrategy() // Storage options: file system (production) or memory (testing) const storage = createFileSnippetStorage({ directory: './.snippets', trustStrategy, }) const driver = createNodeIsolateDriver() export async function POST(request: Request) { const { messages } = await request.json() // High-level API: automatic LLM-based snippet selection const { toolsRegistry, systemPrompt } = await codeModeWithSnippets({ config: { driver, tools: [fetchWeather], timeout: 60_000, memoryLimit: 128, }, adapter: openaiText('gpt-5-mini'), // cheap model for snippet selection snippets: { storage, maxSnippetsInContext: 5, }, messages, }) const stream = chat({ adapter: openaiText('gpt-5.5'), tools: toolsRegistry.getTools(), messages, systemPrompts: ['You are a helpful assistant.', systemPrompt], agentLoopStrategy: maxIterations(15), }) return toServerSentEventsResponse(stream) } ``` The registry includes: `execute_typescript`, `search_snippets`, `get_snippet`, `register_snippet`, and one tool per selected snippet. Custom trust strategy example: ```typescript import { createCustomTrustStrategy } from '@tanstack/ai-code-mode-snippets' const strategy = createCustomTrustStrategy({ initialLevel: 'untrusted', provisionalThreshold: { executions: 5, successRate: 0.85 }, trustedThreshold: { executions: 50, successRate: 0.95 }, }) ``` Storage implementations: ```typescript // File storage (production) -- persists snippets as files on disk import { createFileSnippetStorage } from '@tanstack/ai-code-mode-snippets/storage' const fileStorage = createFileSnippetStorage({ directory: './.snippets' }) // Memory storage (testing) -- in-memory, lost on restart import { createMemorySnippetStorage } from '@tanstack/ai-code-mode-snippets/storage' const memStorage = createMemorySnippetStorage() ``` ### 3. Client-Side Execution Progress Display Code Mode emits custom events during sandbox execution. Handle them in `useChat` via `onCustomEvent`. Events emitted: | Event | When | Key fields | | ----------------------------- | ------------------------------------ | -------------------------------- | | `code_mode:execution_started` | Sandbox begins | `timestamp`, `codeLength` | | `code_mode:console` | Each console.log/error/warn/info | `level`, `message`, `timestamp` | | `code_mode:external_call` | Before an external\_\* function runs | `function`, `args`, `timestamp` | | `code_mode:external_result` | After successful external\_\* call | `function`, `result`, `duration` | | `code_mode:external_error` | When external\_\* call fails | `function`, `error`, `duration` | ```tsx import { useCallback, useRef, useState } from 'react' import { useChat, fetchServerSentEvents } from '@tanstack/ai-react' interface VMEvent { id: string eventType: string data: unknown timestamp: number } export function CodeModeChat() { const [toolCallEvents, setToolCallEvents] = useState< Map<string, Array<VMEvent>> >(new Map()) const eventIdCounter = useRef(0) const handleCustomEvent = useCallback( (eventType: string, data: unknown, context: { toolCallId?: string }) => { const { toolCallId } = context if (!toolCallId) return const event: VMEvent = { id: `event-${eventIdCounter.current++}`, eventType, data, timestamp: Date.now(), } setToolCallEvents((prev) => { const next = new Map(prev) const events = next.get(toolCallId) || [] next.set(toolCallId, [...events, event]) return next }) }, [], ) const { messages, sendMessage, isLoading } = useChat({ connection: fetchServerSentEvents('/api/chat'), onCustomEvent: handleCustomEvent, }) return ( <div> {messages.map((message) => ( <div key={message.id}> {message.parts.map((part, index) => { if (part.type === 'text') { return <p key={index}>{part.content}</p> } if ( part.type === 'tool-call' && part.name === 'execute_typescript' ) { const events = toolCallEvents.get(part.id) || [] return ( <div key={part.id}> <pre>{JSON.parse(part.arguments)?.typescriptCode}</pre> {events.map((evt) => ( <div key={evt.id}> {evt.eventType}: {JSON.stringify(evt.data)} </div>
View on GitHub
This SKILL.md is very large, so SkillsMP previews the first section here. View on GitHub