Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/cloudflare/agents/llms.txt

Use this file to discover all available pages before exploring further.

A project management chat app where the LLM writes and executes code to orchestrate tools, instead of calling them one at a time. Built with @cloudflare/codemode and @cloudflare/ai-chat.

What it demonstrates

Server (src/server.ts):
  • AIChatAgent with createCodeTool - the LLM gets a single “write code” tool
  • DynamicWorkerExecutor - runs LLM-generated code in isolated Worker sandboxes
  • NodeServerExecutor - alternative executor using a Node.js VM (for local dev)
  • SQLite-backed tools (projects, tasks, sprints, comments) via SqlStorage
  • Switchable executor at runtime via HTTP endpoint
Client (src/client.tsx):
  • useAgentChat for streaming chat with message persistence
  • Collapsible tool cards showing generated code, results, and console output
  • Settings panel to switch between Dynamic Worker and Node Server executors
  • Kumo design system components with dark/light mode
Tools (src/tools.ts):
  • 10 project management tools: createProject, listProjects, createTask, listTasks, updateTask, deleteTask, createSprint, listSprints, addComment, listComments
  • All backed by SQLite - data persists across conversations

Why Codemode?

Traditional tool calling requires the LLM to call tools one at a time:
User: "Create a project Alpha with 3 tasks"

LLM: → Call createProject("Alpha")
← Returns projectId
LLM: → Call createTask(projectId, "Task 1")
← Returns taskId
LLM: → Call createTask(projectId, "Task 2")
← Returns taskId
LLM: → Call createTask(projectId, "Task 3")
← Returns taskId
LLM: "Done!"
With Codemode, the LLM writes code to orchestrate multiple operations:
User: "Create a project Alpha with 3 tasks"

LLM: → Writes and executes code:
```typescript
const projectId = await codemode.createProject("Alpha");
await Promise.all([
  codemode.createTask(projectId, "Task 1"),
  codemode.createTask(projectId, "Task 2"),
  codemode.createTask(projectId, "Task 3")
]);
return "Created project Alpha with 3 tasks";
← Returns result LLM: “Done!”

Benefits:
- **Fewer round-trips** - complex operations complete in one step
- **Better composition** - LLM can use loops, conditionals, async/await
- **More control** - LLM can handle errors, retry, format results

## Server Implementation

```typescript src/server.ts
import { createWorkersAI } from "workers-ai-provider";
import { routeAgentRequest } from "agents";
import { AIChatAgent } from "@cloudflare/ai-chat";
import { createCodeTool } from "@cloudflare/codemode";
import { DynamicWorkerExecutor } from "@cloudflare/codemode/executors/dynamic-worker";
import { streamText } from "ai";
import { tools } from "./tools";

export class CodeModeAgent extends AIChatAgent {
  async onChatMessage() {
    const workersai = createWorkersAI({ binding: this.env.AI });
    
    // Create executor for running LLM-generated code
    const executor = new DynamicWorkerExecutor();

    const result = streamText({
      model: workersai("@cf/zai-org/glm-4.7-flash"),
      system:
        "You are a project management assistant. You can create projects, tasks, " +
        "sprints, and comments. Use the codemode tool to write TypeScript code " +
        "that orchestrates multiple operations efficiently.",
      messages: await convertToModelMessages(this.messages),
      tools: {
        // Single "write code" tool instead of individual tools
        ...createCodeTool({
          executor,
          tools,  // Tools available to the LLM's code
          storage: new SqlStorage(this.sql)  // SQLite backend
        })
      }
    });

    return result.toUIMessageStreamResponse();
  }
}

Tool Definitions

src/tools.ts
import { z } from "zod";
import type { ToolDefinition } from "@cloudflare/codemode";

export const tools: Record<string, ToolDefinition> = {
  createProject: {
    description: "Create a new project",
    parameters: z.object({
      name: z.string().describe("Project name")
    }),
    returns: z.object({
      projectId: z.string(),
      name: z.string()
    })
  },

  listProjects: {
    description: "List all projects",
    parameters: z.object({}),
    returns: z.array(z.object({
      projectId: z.string(),
      name: z.string(),
      createdAt: z.string()
    }))
  },

  createTask: {
    description: "Create a new task in a project",
    parameters: z.object({
      projectId: z.string(),
      title: z.string(),
      description: z.string().optional()
    }),
    returns: z.object({
      taskId: z.string(),
      projectId: z.string(),
      title: z.string()
    })
  },

  listTasks: {
    description: "List tasks in a project",
    parameters: z.object({
      projectId: z.string()
    }),
    returns: z.array(z.object({
      taskId: z.string(),
      title: z.string(),
      status: z.enum(["todo", "in_progress", "done"])
    }))
  },

  updateTask: {
    description: "Update a task's status or details",
    parameters: z.object({
      taskId: z.string(),
      status: z.enum(["todo", "in_progress", "done"]).optional(),
      title: z.string().optional()
    }),
    returns: z.object({
      taskId: z.string(),
      updated: z.boolean()
    })
  }
};

Example Conversations

Simple creation:
User: Create a project called Alpha

LLM generates code:
const project = await codemode.createProject("Alpha");
return `Created project ${project.name} with ID ${project.projectId}`;

Result: "Created project Alpha with ID abc-123"
Batch operations:
User: Add 5 tasks to project xyz-789

LLM generates code:
const tasks = await Promise.all([
  codemode.createTask("xyz-789", "Task 1"),
  codemode.createTask("xyz-789", "Task 2"),
  codemode.createTask("xyz-789", "Task 3"),
  codemode.createTask("xyz-789", "Task 4"),
  codemode.createTask("xyz-789", "Task 5")
]);
return `Created ${tasks.length} tasks`;

Result: "Created 5 tasks"
Complex query:
User: List all projects and their task counts

LLM generates code:
const projects = await codemode.listProjects();
const results = await Promise.all(
  projects.map(async (p) => {
    const tasks = await codemode.listTasks(p.projectId);
    return { name: p.name, taskCount: tasks.length };
  })
);
return JSON.stringify(results, null, 2);

Result: JSON with project names and task counts

Executors

Codemode supports two execution modes:

Dynamic Worker Executor (Production)

Runs code in isolated Cloudflare Workers:
import { DynamicWorkerExecutor } from "@cloudflare/codemode/executors/dynamic-worker";

const executor = new DynamicWorkerExecutor();
  • Secure - Full sandbox isolation
  • Fast - V8 isolates, no cold starts
  • Scalable - Runs on Cloudflare’s edge

Node Server Executor (Development)

Runs code in a Node.js VM:
import { NodeServerExecutor } from "@cloudflare/codemode/executors/node-server";

const executor = new NodeServerExecutor({
  url: "http://localhost:3001"
});
  • Debugging - Full Node.js inspector support
  • Local - No network latency
  • Quick iteration - Hot reload
Start the Node executor:
npm run start:node-executor

Running the Example

1

Install dependencies

npm install   # from repo root
npm run build # from repo root
2

Start the example

cd examples/codemode
npm start
3

Try it out

Visit http://localhost:5173 and try:
  • “Create a project called Alpha”
  • “Add 3 tasks to Alpha”
  • “What is 17 + 25?” (simple calculation)
  • “List all projects and their tasks”
4

(Optional) Start Node executor

For local debugging:
npm run start:node-executor
Then switch to Node executor in the Settings panel.
This example uses Workers AI (no API key needed) with @cf/zai-org/glm-4.7-flash.

Key Concepts

Code Generation

The LLM receives a special “write code” tool:
{
  name: "codemode",
  description: "Execute TypeScript code with access to these tools: createProject, listProjects, createTask, ...",
  inputSchema: z.object({
    code: z.string().describe("TypeScript code to execute")
  })
}
When called, the code is:
  1. Validated and transpiled
  2. Executed in a secure sandbox
  3. Results returned to the LLM

Tool Access

Generated code has access to tools via the codemode object:
// LLM-generated code
const project = await codemode.createProject("My Project");
const tasks = await codemode.listTasks(project.projectId);
return `Found ${tasks.length} tasks`;

Error Handling

The LLM can handle errors in its code:
try {
  const project = await codemode.createProject(name);
  return `Created project ${project.projectId}`;
} catch (error) {
  return `Failed to create project: ${error.message}`;
}

Security

Codemode is safe because:
  • Sandboxed execution - Code runs in isolated Workers/VMs
  • No file system access - Can’t read/write files
  • No network access - Can’t make arbitrary HTTP requests
  • Limited APIs - Only approved tools are available
  • Timeout enforcement - Code execution is time-limited

AI Chat

Traditional tool calling with streaming

Dynamic Tools

Client-defined tools at runtime

Workflows

Multi-step workflows with approval gates

Codemode Package

Full Codemode package documentation

Build docs developers (and LLMs) love