5.3 KiB
5.3 KiB
Code Mode (Experimental)
Code Mode generates executable JavaScript instead of making individual tool calls. This significantly reduces token usage and enables complex multi-tool workflows.
Why Code Mode?
Traditional tool calling:
- One tool call per LLM request
- Multiple round-trips for chained operations
- High token usage for complex workflows
Code Mode:
- LLM generates code that orchestrates multiple tools
- Single execution for complex workflows
- Self-debugging and error recovery
- Ideal for MCP server orchestration
Setup
1. Wrangler Config
{
"name": "my-agent-worker",
"compatibility_flags": ["experimental", "enable_ctx_exports"],
"durable_objects": {
// "class_name" must match your Agent class name exactly
"bindings": [{ "name": "MyAgent", "class_name": "MyAgent" }]
},
"migrations": [
// Required: list all Agent classes for SQLite storage
{ "tag": "v1", "new_sqlite_classes": ["MyAgent"] }
],
"services": [
{
"binding": "globalOutbound",
// "service" must match "name" above
"service": "my-agent-worker",
"entrypoint": "globalOutbound"
},
{
"binding": "CodeModeProxy",
"service": "my-agent-worker",
"entrypoint": "CodeModeProxy"
}
],
"worker_loaders": [{ "binding": "LOADER" }]
}
2. Export Required Classes
// Export the proxy for tool execution (required for codemode)
export { CodeModeProxy } from "@cloudflare/codemode/ai";
// Define outbound fetch handler for security filtering
export const globalOutbound = {
fetch: async (input: string | URL | RequestInfo, init?: RequestInit) => {
const url = new URL(
typeof input === "string"
? input
: typeof input === "object" && "url" in input
? input.url
: input.toString()
);
// Block certain domains if needed
if (url.hostname === "blocked.example.com") {
return new Response("Not allowed", { status: 403 });
}
return fetch(input, init);
}
};
3. Install Dependencies
npm install @cloudflare/codemode ai @ai-sdk/openai zod
4. Use Code Mode in Agent
import { Agent } from "agents";
import { experimental_codemode as codemode } from "@cloudflare/codemode/ai";
import { streamText, tool, convertToModelMessages } from "ai";
import { openai } from "@ai-sdk/openai";
import { env } from "cloudflare:workers";
import { z } from "zod";
const tools = {
getWeather: tool({
description: "Get weather for a location",
parameters: z.object({ location: z.string() }),
execute: async ({ location }) => `Weather: ${location} 72°F`
}),
sendEmail: tool({
description: "Send an email",
parameters: z.object({ to: z.string(), subject: z.string(), body: z.string() }),
execute: async ({ to, subject, body }) => `Email sent to ${to}`
})
};
export class MyAgent extends Agent<Env, State> {
tools = {};
// Method called by codemode proxy
callTool(functionName: string, args: unknown[]) {
return this.tools[functionName]?.execute?.(args, {
abortSignal: new AbortController().signal,
toolCallId: "codemode",
messages: []
});
}
async onChatMessage() {
this.tools = { ...tools, ...this.mcp.getAITools() };
const { prompt, tools: wrappedTools } = await codemode({
prompt: "You are a helpful assistant...",
tools: this.tools,
globalOutbound: env.globalOutbound,
loader: env.LOADER,
proxy: this.ctx.exports.CodeModeProxy({
props: {
binding: "MyAgent", // Class name
name: this.name, // Instance name
callback: "callTool" // Method to call
}
})
});
const result = streamText({
system: prompt,
model: openai("gpt-4o"),
messages: await convertToModelMessages(this.state.messages),
tools: wrappedTools // Use wrapped tools, not original
});
// ... handle stream
}
}
Generated Code Example
When user asks "Check the weather in NYC and email me the forecast", codemode generates:
async function executeTask() {
const weather = await codemode.getWeather({ location: "NYC" });
await codemode.sendEmail({
to: "user@example.com",
subject: "NYC Weather Forecast",
body: `Current weather: ${weather}`
});
return { success: true, weather };
}
MCP Server Orchestration
Code Mode excels at orchestrating multiple MCP servers:
async function executeTask() {
// Query file system MCP
const files = await codemode.listFiles({ path: "/projects" });
// Query database MCP
const status = await codemode.queryDatabase({
query: "SELECT * FROM projects WHERE name = ?",
params: [files[0].name]
});
// Conditional logic based on results
if (status.length === 0) {
await codemode.createTask({
title: `Review: ${files[0].name}`,
priority: "high"
});
}
return { files, status };
}
When to Use
| Scenario | Use Code Mode? |
|---|---|
| Single tool call | No |
| Chained tool calls | Yes |
| Conditional logic across tools | Yes |
| MCP multi-server workflows | Yes |
| Token budget constrained | Yes |
| Simple Q&A chat | No |
Limitations
- Experimental - API may change
- Requires Cloudflare Workers
- JavaScript execution only (Python planned)
- Requires additional wrangler config