Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 18 additions & 7 deletions public/__redirects
Original file line number Diff line number Diff line change
Expand Up @@ -258,8 +258,9 @@
/agents/runtime/communication/readonly-connections/ /agents/agent-class/readonly-connections/ 301
/agents/runtime/communication/routing/ /agents/agent-class/routing/ 301
/agents/runtime/communication/websockets/ /agents/agent-class/websockets/ 301
/agents/runtime/execution/ /agents/skills/ 301
/agents/runtime/execution/agent-skills/ /agents/skills/execution/ 301
/agents/runtime/execution/ /agents/runtime/code-mode/ 301
/agents/runtime/execution/agent-skills/ /agents/runtime/code-mode/skill-scripts/ 301
/agents/skills/execution/ /agents/runtime/code-mode/skill-scripts/ 301
/agents/runtime/execution/agent-tools/ /agents/agent-class/agent-tools/ 301
/agents/runtime/execution/durable-execution/ /agents/agent-class/durable-execution/ 301
/agents/runtime/execution/queue-tasks/ /agents/agent-class/queue-tasks/ 301
Expand Down Expand Up @@ -317,7 +318,7 @@
/agents/api-reference/callable-methods/ /agents/agent-class/callable-methods/ 301
/agents/api-reference/chat-agents/ /agents/agent-class/communication-channels/chat/chat-agents/ 301
/agents/api-reference/client-sdk/ /agents/agent-class/communication-channels/chat/client-sdk/ 301
/agents/api-reference/codemode/ /agents/tools/codemode/api-reference/ 301
/agents/api-reference/codemode/ /agents/runtime/code-mode/legacy/ 301
/agents/api-reference/configuration/ /agents/runtime/routing/ 301
/agents/api-reference/durable-execution/ /agents/agent-class/durable-execution/ 301
/agents/api-reference/email/ /agents/agent-class/communication-channels/email/ 301
Expand Down Expand Up @@ -358,9 +359,10 @@
/agents/guides/test-remote-mcp-server/ /agents/model-context-protocol/guides/test-remote-mcp-server/ 301
/agents/guides/webhooks/ /agents/agent-class/communication-channels/webhooks/ 301
/agents/model-context-protocol/authorization/ /agents/model-context-protocol/protocol/authorization/ 301
/agents/model-context-protocol/protocol/codemode/ /agents/tools/codemode/ 301
/agents/model-context-protocol/codemode/ /agents/model-context-protocol/guides/build-codemode-mcp-server/ 301
/agents/model-context-protocol/guides/build-codemode-openapi-mcp-server/ /agents/model-context-protocol/guides/build-codemode-mcp-server/ 301
/agents/model-context-protocol/protocol/codemode/ /agents/concepts/code-mode/ 301
/agents/model-context-protocol/codemode/ /agents/concepts/code-mode/ 301
/agents/model-context-protocol/guides/build-codemode-openapi-mcp-server/ /agents/concepts/code-mode/ 301
/agents/model-context-protocol/guides/build-codemode-mcp-server/ /agents/concepts/code-mode/ 301
/agents/model-context-protocol/governance/ /agents/model-context-protocol/protocol/governance/ 301
/agents/model-context-protocol/mcp-portal/ /agents/model-context-protocol/cloudflare/mcp-portal/ 301
/agents/model-context-protocol/mcp-servers-for-cloudflare/ /agents/model-context-protocol/cloudflare/servers-for-cloudflare/ 301
Expand Down Expand Up @@ -395,7 +397,16 @@
/agents/communication-channels/voice/build-a-voice-agent/ /agents/examples/voice-agent/ 301
/agents/communication-channels/slack/slack-agent/ /agents/examples/slack-agent/ 301
/agents/tools/browser/browse-the-web/ /agents/tools/browser/ 301
/agents/tools/sandbox/codemode/ /agents/tools/codemode/ 301
/agents/tools/sandbox/codemode/ /agents/concepts/code-mode/ 301
/agents/tools/codemode/ /agents/concepts/code-mode/ 301
/agents/tools/codemode/how-it-works/ /agents/concepts/code-mode/ 301
/agents/tools/codemode/ai-sdk/ /agents/runtime/code-mode/computer/ 301
/agents/tools/codemode/tanstack-ai/ /agents/runtime/code-mode/computer/ 301
/agents/tools/codemode/mcp/ /agents/runtime/code-mode/computer/ 301
/agents/tools/codemode/openapi/ /agents/runtime/code-mode/computer/ 301
/agents/tools/codemode/durable-runtime/ /agents/runtime/code-mode/legacy/ 301
/agents/tools/codemode/browser/ /agents/runtime/code-mode/legacy/ 301
/agents/tools/codemode/api-reference/ /agents/runtime/code-mode/legacy/ 301
/agents/tools/payments/mpp/charge-for-http-content/ /agents/tools/payments/mpp-charge-for-http-content/ 301
/agents/tools/payments/mpp/protect-an-origin/ /agents/tools/payments/mpp-charge-for-http-content/ 301
/agents/agentic-payments/mpp/charge-for-http-content/ /agents/tools/payments/mpp-charge-for-http-content/ 301
Expand Down
2 changes: 1 addition & 1 deletion src/content/docs/agents/concepts/agent-skills.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ The Agents SDK reads the open format in `agents/skills` and checks every `SKILL.
| [R2](/agents/skills/sources/r2/) | Many agents share one set of skills managed outside your Worker |
| [Code](/agents/skills/sources/code/) | Tests, or a small fixed set of skills that ships with your Worker |

The SDK uses the `.agents/skills/` folder convention that several agents share, so `/workspace/.agents/skills/` in a Workspace holds the agent's skills. The model loads skills with the [skill tools](/agents/tools/skills/) `activate_skill` and `read_skill_resource`. With a Workspace backend, the model runs skill scripts with the Workspace `exec` tool. Refer to [Execution](/agents/skills/execution/).
The SDK uses the `.agents/skills/` folder convention that several agents share, so `/workspace/.agents/skills/` in a Workspace holds the agent's skills. The model loads skills with the [skill tools](/agents/tools/skills/) `activate_skill` and `read_skill_resource`. With a Workspace backend, the model runs skill scripts with the Workspace `exec` tool. Refer to [Run skill scripts](/agents/runtime/code-mode/skill-scripts/).

## Related

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ title: Human-in-the-loop patterns
pcx_content_type: how-to
sidebar:
order: 2
description: Implement human-in-the-loop functionality using Workflow approvals, durable Code Mode approvals, and MCP elicitation.
description: Implement human-in-the-loop functionality using Workflow approvals, Code Mode approvals, and MCP elicitation.
products:
- agents
---
Expand Down Expand Up @@ -31,7 +31,7 @@ Choose the pattern based on who introduces the pause and where it occurs:
| ---------------------- | ------------------------------------------ | --------------------------- | ----------------------- | ------------------------------------------- |
| **MCP elicitation** | MCP request handled by your Agent client | MCP server developer | Minutes | `configureElicitationHandlers()` |
| **Workflow approval** | Durable application task or tool operation | Agent application developer | Months or years | `waitForApproval()` |
| **Code Mode approval** | Connector call in model-generated code | Code Mode Agent developer | Until configured expiry | `requiresApproval`, `approve()`, `reject()` |
| **Code Mode approval** | Host module call in model-generated code | Code Mode Agent developer | Until answered | `ctx.interrupt()`, `runtime.respond()` |

## Workflow-based approval

Expand Down Expand Up @@ -362,107 +362,36 @@ export class MyAgent extends Agent<Env> {

For the complete form, URL, and browser forwarding patterns, refer to [MCP client elicitation](/agents/model-context-protocol/apis/client-api/#elicitation). For the server side, refer to [Elicitation with a stateless handler](/agents/model-context-protocol/apis/handler-api/#elicitation-with-a-stateless-handler).

## Durable Code Mode approvals
## Code Mode approvals

Use the [durable Code Mode runtime](/agents/tools/codemode/durable-runtime/) for coding agents and other Agents that use the Code Mode pattern. Mark a connector method with `requiresApproval: true` to pause model-generated code before it invokes the underlying tool.

The following example marks a GitHub MCP tool as approval-gated, adds the connector to a durable runtime, and exposes methods that a UI can use to inspect, approve, or reject the pending action:
When an agent uses [Code Mode](/agents/concepts/code-mode/), the model's code calls your tools through host modules. With [Computer](/agents/runtime/code-mode/computer/), a host module function can pause the run until a person answers. The code calls the function as usual and gets its result once the answer arrives.

<TypeScriptExample>

```ts
import { AIChatAgent } from "@cloudflare/ai-chat";
import {
createCodemodeRuntime,
DynamicWorkerExecutor,
McpConnector,
type CodemodeRuntimeHandle,
type ConnectorTool,
type McpConnectionLike,
type PendingAction,
} from "@cloudflare/codemode";
import { callable } from "agents";
import { convertToModelMessages, stepCountIs, streamText } from "ai";
import { model } from "./model";

class GitHubConnector extends McpConnector<Env> {
private connection: McpConnectionLike;

constructor(
ctx: DurableObjectState,
env: Env,
connection: McpConnectionLike,
) {
super(ctx, env);
this.connection = connection;
}

override name() {
return "github";
}

protected override createConnection() {
return this.connection;
}

protected override tool(name: string, tool: ConnectorTool): ConnectorTool {
if (name === "create_issue") {
return { ...tool, requiresApproval: true };
}
return tool;
}
}

export class CodingAgent extends AIChatAgent<Env> {
private runtime(): CodemodeRuntimeHandle {
const server = this.mcp
.listServers()
.find((item) => item.name === "GitHub");
if (!server) throw new Error("GitHub MCP server is not registered.");

const connection = this.mcp.mcpConnections[server.id];
if (!connection) throw new Error("GitHub MCP connection is unavailable.");

return createCodemodeRuntime({
ctx: this.ctx,
executor: new DynamicWorkerExecutor({ loader: this.env.LOADER }),
connectors: [new GitHubConnector(this.ctx, this.env, connection)],
});
}

async onChatMessage() {
const result = streamText({
model,
messages: await convertToModelMessages(this.messages),
tools: { codemode: this.runtime().tool() },
stopWhen: stepCountIs(10),
});

return result.toUIMessageStreamResponse();
}

@callable()
async pendingApprovals(): Promise<PendingAction[]> {
return this.runtime().pending();
}

@callable()
async approveExecution(executionId: string) {
return this.runtime().approve({ executionId });
}

@callable()
async rejectExecution(executionId: string, seq: number): Promise<boolean> {
return this.runtime().reject({ executionId, seq });
}
}
new WorkerJavaScriptBackend({
loader: this.env.LOADER,
onInterrupt: "replay",
modules: {
"codemode:github": {
createIssue: async ([repo, title], ctx) => {
const { approved } = await ctx.interrupt<{ approved: boolean }>({
repo,
title,
});
if (!approved) throw new Error("The issue was rejected.");
return this.createIssue(String(repo), String(title), {
idempotencyKey: ctx.callId,
});
},
},
},
});
```

</TypeScriptExample>

When generated code calls `github.create_issue()`, the runtime records the pending method and arguments, then pauses before the MCP tool executes. Approval starts another pass with the same source code and execution ID. Previously completed calls replay from the durable log, the approved call executes, and the generated code continues.

Pending approvals and execution history survive request completion and Durable Object hibernation. For the execution and replay model, refer to [Approvals through abort and replay](/agents/tools/codemode/how-it-works/#approvals-through-abort-and-replay).
A UI lists the waiting calls with `workspace.runtime.pending()` and answers one with `workspace.runtime.respond()`. The run survives restarts while it waits. On approval, it replays from a journal to the waiting call, and continues. For the details and current limits, refer to [Ask for approval](/agents/runtime/code-mode/computer/#ask-for-approval).

## Build Workflow approval UIs

Expand Down Expand Up @@ -593,7 +522,7 @@ class MultiApprovalAgent extends Agent<Env, State> {
/>

<LinkCard
title="Durable Code Mode runtime"
href="/agents/tools/codemode/durable-runtime/"
description="Pause model-generated code for approval before connector calls."
title="Run code with Computer"
href="/agents/runtime/code-mode/computer/"
description="Pause model-generated code for approval inside a host module call."
/>
123 changes: 123 additions & 0 deletions src/content/docs/agents/concepts/code-mode.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
---
title: Code Mode
description: Why agents on Cloudflare let the model write code that calls tools, instead of calling each tool one at a time.
pcx_content_type: concept
sidebar:
order: 4.5
tags:
- AI
- MCP
products:
- agents
---

import { LinkCard } from "~/components";

Code Mode means letting the model write code to get work done. The model does not ask for one tool call, wait for the result, and then ask for the next. It writes a short program that calls the tools, loops over what comes back, keeps what matters, and returns an answer. A sandbox runs the program, and only the result goes back to the model.

Any time an agent runs code that a model wrote, it is using Code Mode. This page covers why that works well. To set it up, refer to [Code Mode in the runtime](/agents/runtime/code-mode/).

## Models are better at writing code

A tool call is a special token sequence that a model learns during fine-tuning, from a fairly small set of examples. Code is different. Models have trained on huge amounts of real programs, written by people solving real problems. They know how to call functions, read a type signature, write a loop, and handle an error.

Code Mode gives the model the task in the form it knows best. The tools become functions it can import, and the model writes ordinary JavaScript against them. For the longer argument, refer to [Code Mode: the better way to use MCP](https://blog.cloudflare.com/code-mode/).

## Code is a compact plan

Say a user asks for every blocked task across their active projects. With direct tool calls, the model lists the projects, reads the result, and then lists the tasks of each project in turn. Each step is a round trip through the model, and every intermediate result lands in its context.

With Code Mode, the model writes the whole plan once:

```js
import { listProjects, listTasks } from "codemode:projects";

export default async function () {
const blocked = [];
for (const project of await listProjects("active")) {
const tasks = await listTasks(project.id);
blocked.push(...tasks.filter((task) => task.status === "blocked"));
}
return blocked.map((task) => `${task.projectName}: ${task.title}`);
}
```

The program runs in one step and returns a short list. This changes a few things:

- **Fewer model turns.** Ten projects take one model turn, not eleven.
- **Less context.** The project and task records stay inside the sandbox. The model sees only the list it asked for.
- **Real control flow.** Loops, branches, `try`/`catch`, and `Promise.all()` work as the model expects. It does not have to fake them with a chain of tool calls.
- **A plan you can read.** The code says exactly what the agent did. You can log it, review it, and save it as a file to run again.

## Tools become modules

With direct tool calls, the agent sends the definition of every tool to the model on every turn. That cost grows with each tool you add. The Cloudflare API has more than 2,500 endpoints. Described as one tool each, their definitions would take about 1.17 million tokens, more than most models can read at once.

With Code Mode, tools are exports of a module that the code imports. The model gets one code tool and a short list of the modules it can import. Adding a tool adds an export, not another entry in every prompt. This is why an agent with Code Mode can have far more tools than an agent that calls them directly.

## The sandbox and the tools stay apart

Model-written code runs in an isolated [Dynamic Worker](/dynamic-workers/). It starts in milliseconds, and each run gets a fresh isolate. By default it has no network access, and it cannot read the agent's environment variables, bindings, or storage.

The tools do not run in the sandbox. When code calls `listTasks()`, the call crosses to the agent, and the function runs there with the agent's credentials. The sandbox sees only the arguments and the result. API keys and OAuth tokens never enter the sandbox, and they never enter the model's context.

## Code Mode in the agent

The agent can run the code itself. In MCP terms, this is Code Mode on the client: the agent owns the sandbox, so it can combine tools from any source in one program. That includes its own functions, the tools of every MCP server it is connected to, files in its workspace, and external APIs.

```mermaid
flowchart LR
Model["Model"] -->|"exec: code"| Agent
subgraph Agent["Agent (Durable Object)"]
Sandbox["Dynamic Worker<br/>runs the code"]
Tools["Tools as codemode:* modules"]
Sandbox -->|"import and call"| Tools
end
Tools --> Own["Your functions"]
Tools --> MCP["MCP servers"]
Tools --> APIs["APIs and bindings"]
```

This is the recommended way to use Code Mode. [Cloudflare Computer](/agents/runtime/code-mode/computer/) gives the model an `exec` tool, and you give the code your tools as `codemode:*` modules. For example, `codemode:tools` exposes every tool the agent already has, and `codemode:projects` could expose your own functions.

## Code Mode on the server

An MCP server can also do Code Mode for its clients, so that a client without its own sandbox still gets the benefit. The [Cloudflare API MCP server](/agents/model-context-protocol/cloudflare/servers-for-cloudflare/) works this way. It exposes two tools, `search` and `execute`. The model writes code against the OpenAPI document to find the endpoints it needs, then writes code against an API client to call them.

| Approach | Tools | Token cost |
| ---------------------------------- | ----- | ----------- |
| Native MCP (full schemas) | 2,594 | ~1,170,000 |
| Native MCP (required params only) | 2,594 | ~244,000 |
| Code Mode with `search`, `execute` | 2 | ~1,000 |

Server-side Code Mode composes only that server's tools. When the agent does Code Mode itself, one program can call tools from many servers at once. For the design of the Cloudflare server, refer to [Code Mode: give agents an entire API in 1,000 tokens](https://blog.cloudflare.com/code-mode-mcp/). For code to start from, refer to the [Cloudflare MCP server source](https://github.com/cloudflare/mcp) and the [search and execute example](https://github.com/cloudflare/agents/tree/main/examples/codemode-mcp-openapi).

## When to call tools directly

Code Mode is not always the better choice. Call tools directly when:

- The agent has a few tools, and most tasks need one call.
- A tool needs a person to approve each call before it runs.
- A tool runs in the browser, such as one that reads the user's location.

Many agents do both. They offer a handful of direct tools, plus a code tool for work that needs several calls.

## Related resources

<LinkCard
title="Code Mode in the runtime"
href="/agents/runtime/code-mode/"
description="Run model-written code with Computer, the Code Mode executor, or a container."
/>

<LinkCard
title="Tools"
href="/agents/concepts/tools/"
description="How tools are exposed to models, and where they run."
/>

<LinkCard
title="Dynamic Workers"
href="/dynamic-workers/"
description="The isolates that run model-written code."
/>
Loading
Loading