Vercel's AI SDK Ships Code Mode, Cutting Agent Token Use by 99.9%

Vercel's AI SDK adds an experimental Code Mode tool that lets models write sandboxed JS or TS to orchestrate tool calls in a single shot.

·
·
Vercel's AI SDK Ships Code Mode, Cutting Agent Token Use by 99.9%
Read5 min
  • AI SDK adds experimental Code Mode, letting models write JS/TS that calls tools inside a QuickJS sandbox.
  • One generated program can Promise.all, branch, and transform, replacing multiple tool-call round-trips.
  • Shipped as @ai-sdk/code-mode; requires Node.js 22, not for browser or edge runtimes.
  • New experimental_toolCallers API controls which tools are reachable via code versus directly.
  • Sandbox blocks process, fetch, filesystem, and eval; every capability must be exposed as a tool.
  • Follows Cloudflare's Code Mode pattern, which cut MCP token usage by up to 99.9%.

Vercel's AI SDK just picked up an experimental feature that changes how models drive tool use. Instead of the usual back-and-forth where a model emits one JSON tool call, waits for the result, then emits the next, Code Mode lets the model write a small JavaScript or TypeScript program that calls your tools directly. The generated code runs in an isolated QuickJS sandbox and returns a JSON-serializable result.

The pattern itself is not new. It traces back to the CodeACT idea and was popularized by Cloudflare's Code Mode, which argued that LLMs are better at writing code to call MCP, than at calling MCP directly. What is new is that this pattern is now a first-class primitive inside one of the most widely used TypeScript agent SDKs.

Why chaining tools as code beats chaining them as JSON

In classic tool calling, every intermediate result has to travel through the model. With the traditional approach, the output of each tool call must feed into the LLM's neural network, just to be copied over to the inputs of the next call, wasting time, energy, and tokens. Code Mode collapses that loop: the model writes the plan once, the sandbox executes it, and only the final answer comes back.

Cloudflare's follow-up work found this can be dramatic at scale. In their MCP experiment exposing the full Cloudflare API, Code Mode reduces the number of input tokens used by 99.9%. An equivalent MCP server without Code Mode would consume 1.17 million tokens , more than the entire context window of the most advanced foundation models.

How it fits into the AI SDK

The feature ships as a separate package, @ai-sdk/code-mode, and slots into the existing tool-calling API. You register a codeModeTool alongside your normal tools, then use a new experimental_toolCallers map to decide which tools the model can reach through code versus directly.

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. Add the DIRECT_TOOL_CALL sentinel if you want a tool to remain callable both ways.

A minimal setup looks like this:

import { experimental_codeModeTool as codeModeTool } from '@ai-sdk/code-mode';
import { generateText, tool } from 'ai';
const tools = {
  code_mode: codeModeTool({ executionPolicy: { timeoutMs: 30_000 } }),
  getInventory,
  getDemand,
};
await generateText({
  model: 'xai/grok-4.6',
  tools,
  experimental_toolCallers: {
    getInventory: ['code_mode'],
    getDemand: ['code_mode'],
  },
  prompt: 'Compare inventory and demand for product sku_123.',
});

The model then generates something like a Promise.all over both tools and returns a computed summary in a single step, rather than two turns.

What the sandbox can and cannot do

Generated programs get a reasonably capable JavaScript environment: 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, plus console methods. TypeScript annotations get stripped before execution, but there is no type checking.

Everything else is walled off. Each invocation receives a fresh QuickJS context. Sandboxed code cannot access: Node.js globals such as process, require, or module, the host file system, fetch, WebCrypto, or dynamic Function construction. If the model needs network or system access, you have to expose it explicitly as a tool.

The docs are blunt about the threat model: Treat the sandbox as defense in depth. Generated code and tool arguments are untrusted. Every capability you hand a tool becomes available to whatever program the model writes, so authorization still belongs inside your tool logic.

Guardrails you actually have to set

Because you are handing an LLM a runtime, the API exposes execution limits you can tune per invocation:

  • timeoutMs: total execution time
  • memoryLimitBytes and maxStackSizeBytes: QuickJS memory and stack
  • maxSourceBytes: cap on the size of generated source
  • maxResultBytes, maxToolInputBytes, maxToolOutputBytes: payload sizes
  • maxBridgeRequests and maxInFlightBridgeRequests: total and concurrent tool calls per program

There is also a process-wide experimental_setMaxWorkers knob. Without an explicit cap, code mode chooses one based on available memory, up to 32 workers.

Caveats worth flagging

This is experimental in the literal sense. The experimental_ prefix on nearly every export is a hint that shapes will change. Two constraints are worth noting up front:

  • 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.
  • Approval flows do not compose with nested calls yet. Tools that require approval are rejected rather than executed from inside a program.

Where it fits in your stack

Code Mode is most interesting when your agent has to fan out over many tools, transform results before returning them, or run multi-step logic that would otherwise burn several round-trips. Think portfolio comparisons, batch data enrichment, filtering large MCP responses before returning them to the model, or any workflow where you would have written a Promise.all yourself in glue code. For simple single-tool calls, plain tool calling is still fine and probably cheaper.

The broader signal is that the industry is converging on code-as-plan for agents. Anthropic hinted at it with code execution over MCP, Cloudflare shipped it in Workers, TanStack AI ships it with multiple isolate drivers, and now the AI SDK bakes it into its core tool loop. If you build agents in TypeScript, this is a pattern worth learning even if you do not adopt this particular implementation.

Comments

avatar