---
title: AI SDK integration
description: Use AI SDK tools with Code Mode through createCodeTool(), namespaced providers, or ToolSetConnector for durable execution.
image: https://developers.cloudflare.com/dev-products-preview.png
---

> Documentation Index  
> Fetch the complete documentation index at: https://developers.cloudflare.com/agents/llms.txt  
> Use this file to discover all available pages before exploring further. 

[Skip to content](#%5Ftop) 

# AI SDK integration

The `@cloudflare/codemode/ai` entry point converts AI SDK tools into one Code Mode tool. The model writes JavaScript that calls your tools, and an executor runs that code in an isolated sandbox.

Choose between two integration patterns:

| Pattern                                | Use case                                                    | Approval behavior                              |
| -------------------------------------- | ----------------------------------------------------------- | ---------------------------------------------- |
| createCodeTool()                       | Simple, stateless execution with one or more tool providers | Excludes tools that use needsApproval          |
| ToolSetConnector or toolSetConnector() | Durable execution through a Code Mode runtime               | Maps needsApproval to durable runtime approval |

## Create a stateless Code Mode tool

`createCodeTool()` accepts an AI SDK `ToolSet` or an array of tool providers. It also requires an executor. It returns a standard AI SDK tool for use with `streamText()` or `generateText()`.

1. Install Code Mode, the AI SDK, and Zod:  
 npm  yarn  pnpm  bun  
```  
npm i @cloudflare/codemode agents ai zod  
```  
```  
yarn add @cloudflare/codemode agents ai zod  
```  
```  
pnpm add @cloudflare/codemode agents ai zod  
```  
```  
bun add @cloudflare/codemode agents ai zod  
```
2. Add a Worker Loader binding for `DynamicWorkerExecutor`:

  * [  wrangler.jsonc ](#tab-panel-6571)
  * [  wrangler.toml ](#tab-panel-6572)  
JSONC  
```  
{  "$schema": "./node_modules/wrangler/config-schema.json",  // Set this to today's date  "compatibility_date": "2026-06-25",  "compatibility_flags": [    "nodejs_compat"  ],  "worker_loaders": [    {      "binding": "LOADER"    }  ]}  
```  
TOML  
```  
# Set this to today's datecompatibility_date = "2026-06-25"compatibility_flags = ["nodejs_compat"]  
[[worker_loaders]]binding = "LOADER"  
```
3. Define executable AI SDK tools. Code Mode uses their schemas to generate types and validate arguments before calling `execute`.

  * [  JavaScript ](#tab-panel-6575)
  * [  TypeScript ](#tab-panel-6576)  
src/tools.js  
```  
import { tool } from "ai";import { z } from "zod";  
export const weatherTools = {  getWeather: tool({    description: "Get the weather for a city",    inputSchema: z.object({      city: z.string().describe("City name"),    }),    outputSchema: z.object({      city: z.string(),      conditions: z.string(),    }),    execute: async ({ city }) => ({      city,      conditions: "sunny",    }),  }),};  
```  
src/tools.ts  
```  
import { tool } from "ai";import { z } from "zod";  
export const weatherTools = {  getWeather: tool({    description: "Get the weather for a city",    inputSchema: z.object({      city: z.string().describe("City name")    }),    outputSchema: z.object({      city: z.string(),      conditions: z.string()    }),    execute: async ({ city }) => ({      city,      conditions: "sunny"    })  })};  
```  
Each sandbox-callable tool needs an `execute` function. Client-side or provider-executed tools cannot run through this server-side executor.
4. Create the Code Mode tool and pass it to an AI SDK model call:

  * [  JavaScript ](#tab-panel-6579)
  * [  TypeScript ](#tab-panel-6580)  
src/index.js  
```  
import { DynamicWorkerExecutor } from "@cloudflare/codemode";import { createCodeTool } from "@cloudflare/codemode/ai";import { generateText, stepCountIs } from "ai";import { model } from "./model";import { weatherTools } from "./tools";  
export default {  async fetch(request, env) {    const executor = new DynamicWorkerExecutor({ loader: env.LOADER });    const codemode = createCodeTool({ tools: weatherTools, executor });  
    const response = await generateText({      model,      prompt: await request.text(),      tools: { codemode },      stopWhen: stepCountIs(5),    });  
    return new Response(response.text);  },};  
```  
src/index.ts  
```  
import { DynamicWorkerExecutor } from "@cloudflare/codemode";import { createCodeTool } from "@cloudflare/codemode/ai";import { generateText, stepCountIs } from "ai";import { model } from "./model";import { weatherTools } from "./tools";  
export default {   async fetch(request, env): Promise<Response> {     const executor = new DynamicWorkerExecutor({ loader: env.LOADER });     const codemode = createCodeTool({ tools: weatherTools, executor });  
     const response = await generateText({       model,       prompt: await request.text(),       tools: { codemode },       stopWhen: stepCountIs(5),     });  
     return new Response(response.text);   },} satisfies ExportedHandler<Env>;  
```

The example uses `generateText()` for a completed response. You can pass the same `codemode` tool to `streamText()` for streaming. The generated tool description includes TypeScript definitions for `getWeather`. The model still writes JavaScript, such as:

JavaScript

```
async () => {  const weather = await codemode.getWeather({ city: "Lisbon" });  return weather.conditions;};
```

The default namespace is `codemode`. `createCodeTool()` also accepts a custom `description`. Include `{{types}}` in that description where Code Mode should insert the generated definitions.

## Organize tools with providers

A tool provider groups tools under one sandbox namespace. Pass the tool set directly when every tool belongs under `codemode.*`.

Use `aiTools()` when combining AI SDK tools with providers from other packages. The following optional workspace example also requires `@cloudflare/shell`:

 npm  yarn  pnpm  bun 

```
npm i @cloudflare/shell
```

```
yarn add @cloudflare/shell
```

```
pnpm add @cloudflare/shell
```

```
bun add @cloudflare/shell
```

* [  JavaScript ](#tab-panel-6577)
* [  TypeScript ](#tab-panel-6578)

JavaScript

```
import { AIChatAgent } from "@cloudflare/ai-chat";import { DynamicWorkerExecutor } from "@cloudflare/codemode";import { aiTools, createCodeTool } from "@cloudflare/codemode/ai";import { Workspace } from "@cloudflare/shell";import { stateTools } from "@cloudflare/shell/workers";import { weatherTools } from "./tools";
export class Chat extends AIChatAgent {  workspace = new Workspace({ sql: this.ctx.storage.sql });
  codemodeTool() {    return createCodeTool({      tools: [aiTools(weatherTools), stateTools(this.workspace)],      executor: new DynamicWorkerExecutor({ loader: this.env.LOADER }),    });  }}
```

TypeScript

```
import { AIChatAgent } from "@cloudflare/ai-chat";import { DynamicWorkerExecutor } from "@cloudflare/codemode";import { aiTools, createCodeTool } from "@cloudflare/codemode/ai";import { Workspace } from "@cloudflare/shell";import { stateTools } from "@cloudflare/shell/workers";import { weatherTools } from "./tools";
export class Chat extends AIChatAgent<Env> {  workspace = new Workspace({ sql: this.ctx.storage.sql });
  codemodeTool() {    return createCodeTool({      tools: [aiTools(weatherTools), stateTools(this.workspace)],      executor: new DynamicWorkerExecutor({ loader: this.env.LOADER }),    });  }}
```

This example exposes AI SDK tools as `codemode.*` and workspace tools as `state.*`.

To assign custom namespaces, pass provider objects instead:

* [  JavaScript ](#tab-panel-6573)
* [  TypeScript ](#tab-panel-6574)

JavaScript

```
const executor = new DynamicWorkerExecutor({ loader: env.LOADER });
const codemode = createCodeTool({  tools: [    { name: "weather", tools: weatherTools },    { name: "notifications", tools: notificationTools },  ],  executor,});
```

TypeScript

```
const executor = new DynamicWorkerExecutor({ loader: env.LOADER });
const codemode = createCodeTool({  tools: [    { name: "weather", tools: weatherTools },    { name: "notifications", tools: notificationTools },  ],  executor,});
```

The generated code can then call `weather.getWeather()` and `notifications.send()`. Provider names must be unique, valid JavaScript identifiers.

## Use AI SDK tools with the durable runtime

Use `ToolSetConnector` or its `toolSetConnector()` convenience function when runs need durable state. The connector adapts an AI SDK `ToolSet` for `createCodemodeRuntime()`. The helper returns `new ToolSetConnector(ctx, options)`.

Create the connector from inside an Agent or another Durable Object:

* [  JavaScript ](#tab-panel-6581)
* [  TypeScript ](#tab-panel-6582)

src/server.js

```
import { AIChatAgent } from "@cloudflare/ai-chat";import {  createCodemodeRuntime,  DynamicWorkerExecutor,} from "@cloudflare/codemode";import { toolSetConnector } from "@cloudflare/codemode/ai";import { convertToModelMessages, streamText } from "ai";import { model } from "./model";import { operationTools } from "./tools";
// Export this manually when the @cloudflare/codemode/vite plugin is not configured.export { CodemodeRuntime } from "@cloudflare/codemode";
export class OperationsAgent extends AIChatAgent {  async onChatMessage() {    const operations = toolSetConnector(this.ctx, {      name: "operations",      instructions: "Use these tools to manage customer requests.",      tools: operationTools,    });
    const runtime = createCodemodeRuntime({      ctx: this.ctx,      executor: new DynamicWorkerExecutor({ loader: this.env.LOADER }),      connectors: [operations],    });
    const result = streamText({      model,      messages: await convertToModelMessages(this.messages),      tools: { codemode: runtime.tool() },    });
    return result.toUIMessageStreamResponse();  }}
```

src/server.ts

```
import { AIChatAgent } from "@cloudflare/ai-chat";import {  createCodemodeRuntime,  DynamicWorkerExecutor,} from "@cloudflare/codemode";import { toolSetConnector } from "@cloudflare/codemode/ai";import { convertToModelMessages, streamText } from "ai";import { model } from "./model";import { operationTools } from "./tools";
// Export this manually when the @cloudflare/codemode/vite plugin is not configured.export { CodemodeRuntime } from "@cloudflare/codemode";
export class OperationsAgent extends AIChatAgent<Env> {  async onChatMessage() {    const operations = toolSetConnector(this.ctx, {      name: "operations",      instructions: "Use these tools to manage customer requests.",      tools: operationTools,    });
    const runtime = createCodemodeRuntime({      ctx: this.ctx,      executor: new DynamicWorkerExecutor({ loader: this.env.LOADER }),      connectors: [operations],    });
    const result = streamText({      model,      messages: await convertToModelMessages(this.messages),      tools: { codemode: runtime.tool() },    });
    return result.toUIMessageStreamResponse();  }}
```

The example exports `CodemodeRuntime` manually. If you configure the Code Mode Vite plugin as described in [Create a durable Code Mode runtime](https://developers.cloudflare.com/agents/tools/codemode/durable-runtime/), remove that manual export because the plugin adds it.

The connector defaults to the `tools` namespace when `name` is omitted. It excludes tools without an `execute` function from both generated types and sandbox bindings.

The durable runtime adds an execution log, pause and resume behavior, and on-demand connector discovery. The model can find methods with `codemode.search()` and inspect their types with `codemode.describe()`.

## Approval behavior

The two integration patterns handle AI SDK approvals differently.

### `createCodeTool()` approvals

`createCodeTool()` filters out tools where `needsApproval` is `true` or a function. Filtered tools do not appear in generated types and cannot run from sandbox code. A tool with `needsApproval: false` remains available.

This stateless path does not pause execution for AI SDK approval. Use a standard AI SDK tool outside Code Mode if that tool needs the AI SDK approval flow.

### `ToolSetConnector` approvals

`ToolSetConnector` maps AI SDK `needsApproval` to the durable runtime's `requiresApproval` annotation. Calling that tool pauses the run. Your application can inspect pending actions and resume the same execution with `runtime.approve({ executionId })`.

A function-valued `needsApproval` cannot be evaluated before the sandbox supplies arguments. The connector therefore treats the tool as always requiring approval. `needsApproval: false` executes without pausing.

This approval uses the Code Mode runtime's durable pause, approval, and replay flow. It does not use the AI SDK per-call approval flow.

```json
{"@context":"https://schema.org","@type":"TechArticle","@id":"https://developers.cloudflare.com/agents/tools/codemode/ai-sdk/#page","headline":"AI SDK integration · Cloudflare Agents docs","description":"Use AI SDK tools with Code Mode through createCodeTool(), namespaced providers, or ToolSetConnector for durable execution.","url":"https://developers.cloudflare.com/agents/tools/codemode/ai-sdk/","inLanguage":"en","image":"https://developers.cloudflare.com/dev-products-preview.png","dateModified":"2026-06-24","publisher":{"@type":"Organization","name":"Cloudflare","url":"https://www.cloudflare.com/"},"isPartOf":{"@type":"WebSite","@id":"https://developers.cloudflare.com/#website","name":"Cloudflare Docs","url":"https://developers.cloudflare.com/"}}
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"item":{"@id":"/directory/","name":"Directory"}},{"@type":"ListItem","position":2,"item":{"@id":"/agents/","name":"Agents"}},{"@type":"ListItem","position":3,"item":{"@id":"/agents/tools/","name":"Tools"}},{"@type":"ListItem","position":4,"item":{"@id":"/agents/tools/codemode/","name":"Code Mode"}},{"@type":"ListItem","position":5,"item":{"@id":"/agents/tools/codemode/ai-sdk/","name":"AI SDK integration"}}]}
```
