Skip to main content

Code Mode

还没翻译译自英文(ai-sdk.dev)本页 44 段都还没译

Code mode lets a model write JavaScript or TypeScript that calls your AI SDK tools. The generated code runs in an isolated QuickJS sandbox and returns a JSON-serializable result.

Instead of calling tools one at a time, a model can use code mode to:

  • call independent tools concurrently
  • transform and combine tool results
  • filter large tool responses before returning them to the model
  • use JavaScript control flow for multi-step operations

Code mode is provided by the @ai-sdk/code-mode package.

Warning

Code mode is experimental and its APIs may change in future releases. It requires Node.js 22 or newer and is not available in browser or edge runtimes.

Installation

pnpm add ai @ai-sdk/code-mode zod

Using Code Mode with generateText

Define your tools in one tool set and use experimental_toolCallers to select which tools code mode can call:

import {
  DIRECT_TOOL_CALL,
  experimental_codeModeTool as codeModeTool,
} from '@ai-sdk/code-mode';
import { generateText, isStepCount, tool } from 'ai';
import { z } from 'zod';

const getInventory = tool({
  description: 'Get available inventory for a product.',
  inputSchema: z.object({
    productId: z.string(),
  }),
  outputSchema: z.object({
    productId: z.string(),
    availableUnits: z.number(),
  }),
  execute: async ({ productId }) => ({
    productId,
    availableUnits: 42,
  }),
});

const getDemand = tool({
  description: 'Get requested units for a product.',
  inputSchema: z.object({
    productId: z.string(),
  }),
  outputSchema: z.object({
    productId: z.string(),
    requestedUnits: z.number(),
  }),
  execute: async ({ productId }) => ({
    productId,
    requestedUnits: 31,
  }),
});

const tools = {
  code_mode: codeModeTool({
    executionPolicy: {
      timeoutMs: 30_000,
    },
  }),
  getInventory,
  getDemand,
} as const;

const result = await generateText({
  model: 'anthropic/claude-sonnet-5.5',
  tools,
  experimental_toolCallers: {
    getInventory: ['code_mode'],
    getDemand: ['code_mode'],
  },
  stopWhen: isStepCount(10),
  prompt: 'Compare inventory and demand for product sku_123.',
});

The keys in experimental_toolCallers are the tools being governed. The values identify their allowed callers. In this example, getInventory and getDemand are available through code_mode, but they are not exposed to the model as directly callable tools. Include DIRECT_TOOL_CALL when a tool should also be callable directly:

experimental_toolCallers: {
  getInventory: ['code_mode', DIRECT_TOOL_CALL],
};

Tools without an experimental_toolCallers entry keep their existing direct tool-calling behavior.

The code mode tool description includes TypeScript signatures generated from the input and output schemas of its allowed tools. Descriptions, inputExamples, and precise schemas help the model write correct code.

Discovering Tools Through Conversation

By default, changing the tools routed through code mode also changes the provider-visible code_mode tool description. Set toolDiscovery to 'conversation' to keep that tool definition stable and provide the current host-tool catalog in a user message instead:

const codeMode = codeModeTool({
  toolDiscovery: 'conversation',
});

const tools = {
  code_mode: codeMode,
  getInventory,
  getDemand,
} as const;

const result = await generateText({
  model: 'anthropic/claude-sonnet-5.5',
  tools,
  experimental_toolCallers: {
    getInventory: ['code_mode'],
    getDemand: ['code_mode'],
  },
  prompt: 'Compare inventory and demand for product sku_123.',
});

The AI SDK adds a complete code mode capability catalog to the conversation before calling the model. The catalog contains TypeScript signatures and call examples for the tools routed through code mode. When the effective tools or their definitions change in a later step or generation call, the SDK adds a new catalog that replaces earlier catalogs.

This mode can improve prompt-cache reuse because the provider-visible tool definition stays unchanged. Actual cache behavior depends on the model provider.

For the example above, the model can generate a program like:

const [inventory, demand] = await Promise.all([
  tools.getInventory({ productId: 'sku_123' }),
  tools.getDemand({ productId: 'sku_123' }),
]);

return {
  sufficient: inventory.availableUnits >= demand.requestedUnits,
  remaining: inventory.availableUnits - demand.requestedUnits,
};

Each provided tool is available through the global tools object. Tool names that are not valid JavaScript identifiers use bracket notation:

const user = await tools['lookup-user']({ userId: 'user_123' });
return { id: user.id, plan: user.plan };

Searching Deferred Tools

Use toolSearch() with deferLoading: true to expose tools only when the model needs them. With toolDiscovery: 'conversation', discovered definitions arrive in user messages, preserving the tool-definition cache by keeping the provider-visible code mode tool unchanged. Actual prompt-cache reuse depends on the provider.

See Tool Search for direct-calling and code mode examples.

Writing Code Mode Programs

Generated programs support:

  • JavaScript and type-stripped TypeScript
  • top-level await and return
  • standard JavaScript control flow and data transformations
  • Promise.all for concurrent tool calls
  • JSON.parse and JSON.stringify
  • console.log, console.info, console.debug, and console.error

Every tool call is asynchronous and must be awaited or otherwise observed. Returning while tool calls are still detached fails the invocation and aborts the outstanding work.

Programs and tool inputs and outputs cross the sandbox boundary as JSON. Return only JSON-serializable values. TypeScript support is limited to removing type syntax; code mode does not perform type checking or provide a full TypeScript compiler.

Direct Execution

Use experimental_runCodeMode when you want to execute a program directly instead of exposing code mode to a model:

import { experimental_runCodeMode as runCodeMode } from '@ai-sdk/code-mode';

const result = await runCodeMode({
  js: `
    const inventory = await tools.getInventory({
      productId: 'sku_123',
    });

    return {
      productId: inventory.productId,
      available: inventory.availableUnits > 0,
    };
  `,
  tools: { getInventory },
});

runCodeMode returns the value returned by the program. It uses the same sandbox and execution limits as the AI SDK tool.

Tool Approval

Code mode does not currently integrate with AI SDK tool approval flows. Tool calls made by generated code are nested inside the code mode invocation, so they cannot pause the generation and surface a tool approval request to your application.

Do not expose tools that rely on user approval to code mode. Keep those tools directly callable by the model instead. If a nested tool requires approval, the call is rejected rather than executed.

Execution Limits

Every invocation has limits for runtime, memory, source size, results, tool payloads, console output, and tool calls. Override them with executionPolicy:

const codeMode = codeModeTool({
  executionPolicy: {
    timeoutMs: 30_000,
    cpuTimeoutMs: 10_000,
    memoryLimitBytes: 64 * 1024 * 1024,
    maxResultBytes: 1024 * 1024,
    maxBridgeRequests: 100,
    maxInFlightBridgeRequests: 10,
  },
});

The available limits are:

  • timeoutMs: total execution time, including time spent waiting on tools
  • cpuTimeoutMs: CPU time spent running sandboxed code, excluding tool waits
  • memoryLimitBytes: QuickJS memory
  • maxStackSizeBytes: QuickJS stack
  • maxSourceBytes: generated source code
  • maxResultBytes: returned result
  • maxConsoleOutputBytes: combined console output
  • maxToolInputBytes: input for each tool call
  • maxToolOutputBytes: output from each tool call
  • maxBridgeRequests: total tool calls
  • maxInFlightBridgeRequests: concurrent tool calls

Use experimental_setMaxWorkers to set a process-wide cap on concurrent code mode workers:

import { experimental_setMaxWorkers as setMaxWorkers } from '@ai-sdk/code-mode';

setMaxWorkers(4);

Without an explicit cap, code mode chooses one based on available memory, up to 32 workers.

Isolation and Tool Access

Each invocation receives a fresh QuickJS context. Sandboxed code cannot access:

  • Node.js globals such as process, require, or module
  • the host file system or module loader
  • fetch, WebCrypto, or performance APIs
  • eval or dynamic Function construction

Network or system access must be implemented in a tool and explicitly provided to code mode.

Warning

Treat the sandbox as defense in depth. Generated code and tool arguments are untrusted. Tools execute in your host application, outside the QuickJS sandbox, and every capability exposed by a provided tool is available to the generated program. Enforce authorization and validate inputs inside each tool.

Tool input schemas are validated before their execute functions run. Abort signals and AI SDK tool execution context are forwarded to nested tool calls.