Skip to content

Commit 58b04ce

Browse files
authored
[Dynamic Workers] Update bindings docs to be more verbose (#30454)
* [Dynamic Workers] Add links to KV, R2, and D1 docs * Add Python Workers section and TypeScriptExample wrappers to getting started * [Dynamic Workers] Add static assets documentation and update limits - Add new static-assets.mdx page with complete guide on serving static files - Update limits.mdx with improved intro and capitalization fixes * [Dynamic Workers] Rewrite Code Mode example page with clearer structure and links * [Dynamic Workers] Update playground and starter example pages * [Dynamic Workers] Add Dynamic Workflows Playground example page
1 parent 442984f commit 58b04ce

9 files changed

Lines changed: 704 additions & 93 deletions

File tree

416 KB
Loading
Lines changed: 87 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,94 @@
11
---
2-
title: Codemode
3-
description: Read the Codemode reference in Cloudflare Agents docs.
2+
title: Code Mode Example
3+
description: Project management chat app demonstrating code-as-tool. The LLM writes and executes JavaScript to orchestrate multiple tools in a single Dynamic Worker sandbox.
44
pcx_content_type: example
5-
external_link: https://github.com/cloudflare/agents/tree/main/examples/codemode
65
sidebar:
76
order: 3
87
products:
98
- dynamic-workers
9+
tags:
10+
- AI
11+
- AI Agents
12+
- JavaScript
13+
- TypeScript
1014
---
15+
16+
import { TypeScriptExample } from "~/components";
17+
18+
This example shows how to use the [`@cloudflare/codemode`](https://www.npmjs.com/package/@cloudflare/codemode) library with the [Agents SDK](https://www.npmjs.com/package/agents) to build an agent where the LLM writes code to orchestrate tool calls, instead of calling them one at a time. This approach, called [Code Mode](https://blog.cloudflare.com/code-mode/), reduces tokens spent by up to 80%, returns better results, and avoids bloating the context window.
19+
20+
[![Deploy to Workers](https://deploy.workers.cloudflare.com/button)](https://deploy.workers.cloudflare.com/?url=https://github.com/cloudflare/agents/tree/main/examples/codemode)
21+
22+
This example shows you how to:
23+
24+
- Define tools as plain functions with Zod schemas
25+
- Use `createCodeTool` to expose your tools to the LLM as a single "write code" tool
26+
- Use `DynamicWorkerExecutor` to safely run LLM-generated code
27+
- Wire it all together with `AIChatAgent` to handle chat over WebSockets
28+
29+
## How it works
30+
31+
The agent uses three components from the [`@cloudflare/codemode`](https://www.npmjs.com/package/@cloudflare/codemode) library and the [Agents SDK](https://www.npmjs.com/package/agents):
32+
33+
- **`AIChatAgent` (`@cloudflare/ai-chat`)**, your agent's base class. Handles chat over WebSockets, persists messages, and calls the LLM.
34+
- **`createCodeTool` (`@cloudflare/codemode/ai`)**, wraps your tools into a single `codemode` tool that accepts `{ code: string }`.
35+
- **`DynamicWorkerExecutor` (`@cloudflare/codemode`)**, runs the LLM-generated code in an isolated [Dynamic Worker](/dynamic-workers/).
36+
37+
The flow:
38+
39+
1. User sends a message over WebSocket.
40+
2. `AIChatAgent` passes it to the LLM with a single tool available: `codemode`.
41+
3. The LLM writes JavaScript, for example `const projects = await codemode.listProjects()`, instead of making individual tool calls.
42+
4. `DynamicWorkerExecutor` spins up an isolated Worker and runs the code. Inside the sandbox, `codemode.listProjects()` calls your real `listProjects` implementation.
43+
5. The result, any console output, and errors are returned to the LLM.
44+
6. The LLM uses the result to respond to the user, or writes more code if it needs to.
45+
46+
### `DynamicWorkerExecutor`
47+
48+
`DynamicWorkerExecutor` is part of the `@cloudflare/codemode` library. When the LLM writes code that orchestrates your tools, that code needs to run somewhere safe. `DynamicWorkerExecutor` spins up an isolated Dynamic Worker for each execution using the Worker Loader binding. Inside the sandbox:
49+
50+
- A `codemode` proxy object routes calls like `codemode.createTask(...)` back to your real tool implementations over Workers RPC
51+
- Setting `globalOutbound` to `null` blocks `fetch()`, so the code can only reach the outside world through your tools
52+
- `console.log` output is captured and returned alongside the result
53+
- Each execution gets its own Worker instance with a 30-second timeout
54+
55+
<TypeScriptExample>
56+
57+
```ts
58+
import { DynamicWorkerExecutor } from "@cloudflare/codemode";
59+
60+
const executor = new DynamicWorkerExecutor({
61+
loader: env.LOADER, // WorkerLoader binding from wrangler.jsonc
62+
timeout: 30000, // default: 30s
63+
globalOutbound: null, // null = fetch blocked
64+
});
65+
```
66+
67+
</TypeScriptExample>
68+
69+
### `createCodeTool`
70+
71+
`createCodeTool` is part of `@cloudflare/codemode`. It takes your tools and an executor, and returns a single AI SDK `tool()`. It:
72+
73+
- Generates TypeScript type declarations from your tools' Zod schemas, so the LLM knows what is available and what the argument shapes look like.
74+
- Puts those types in the tool's description, so the LLM sees a single tool with parameter `{ code: string }` and a description that includes the full typed API surface.
75+
- On execution, normalizes the LLM's code (strips markdown fences, wraps bare statements in async functions, auto-returns the last expression), then passes it to the executor.
76+
77+
<TypeScriptExample>
78+
79+
```ts
80+
import { createCodeTool } from "@cloudflare/codemode/ai";
81+
82+
const codemode = createCodeTool({
83+
tools: myTools, // Record<string, tool()> with Zod schemas
84+
executor, // DynamicWorkerExecutor
85+
});
86+
87+
// The LLM sees: one tool called "codemode" with input { code: string }
88+
// The description includes TypeScript types for all your tools
89+
```
90+
91+
</TypeScriptExample>
92+
93+
The LLM writes an async arrow function. `createCodeTool` normalizes it and hands it to the executor. The executor builds a Worker module with a `codemode` proxy, runs the code, and returns `{ code, result, logs }`.
94+
Lines changed: 107 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,115 @@
11
---
22
title: Dynamic Workers Playground
3-
description: Explore a playground built with Dynamic Workers.
3+
description: Bundle, execute, and observe Dynamic Workers with real-time logs and timing.
44
pcx_content_type: example
5-
external_link: https://github.com/cloudflare/agents/tree/main/examples/dynamic-workers-playground
65
sidebar:
76
order: 2
87
products:
98
- dynamic-workers
9+
tags:
10+
- JavaScript
11+
- TypeScript
12+
- Logging
1013
---
14+
15+
import { TypeScriptExample } from "~/components";
16+
17+
Try the Dynamic Workers [playground](https://github.com/cloudflare/agents/tree/main/examples/dynamic-workers-playground) to write or import code from GitHub, bundle it at runtime, execute it in a Dynamic Worker, and view real-time logs.
18+
19+
[![Deploy to Workers](https://deploy.workers.cloudflare.com/button)](https://deploy.workers.cloudflare.com/?url=https://github.com/cloudflare/agents/tree/main/examples/dynamic-workers-playground)
20+
21+
![Dynamic Workers Playground UI](~/assets/images/dynamic-workers/dw-playground.png)
22+
23+
## What this demo shows
24+
25+
- **Runtime bundling** — Uses [`@cloudflare/worker-bundler`](https://www.npmjs.com/package/@cloudflare/worker-bundler) to resolve npm dependencies and compile TypeScript inside a Worker
26+
- **Dynamic execution** — Loads bundled code into an isolated Dynamic Worker
27+
- **Caching** — Reuses previously bundled Workers when the source has not changed
28+
- **Real-time output** — Streams the response body, console logs, execution timing, and bundle metadata back to the client
29+
30+
## Bundling code at runtime
31+
32+
The playground uses [`@cloudflare/worker-bundler`](https://www.npmjs.com/package/@cloudflare/worker-bundler) to compile TypeScript, resolve npm dependencies, and produce modules the Worker Loader can execute.
33+
34+
Pass source files and a `package.json` to `createWorker()`, which resolves dependencies and returns bundled modules ready to load as a Dynamic Worker:
35+
36+
<TypeScriptExample>
37+
38+
```ts
39+
import { createWorker } from "@cloudflare/worker-bundler";
40+
41+
const { mainModule, modules, warnings } = await createWorker({
42+
files: {
43+
"src/index.ts": userCode,
44+
"package.json": JSON.stringify({
45+
dependencies: { hono: "^4.0.0" },
46+
}),
47+
},
48+
bundle: true,
49+
minify: false,
50+
});
51+
```
52+
53+
</TypeScriptExample>
54+
55+
## Caching Dynamic Workers
56+
57+
`env.LOADER.load()` creates a new Dynamic Worker on every call. To avoid re-bundling unchanged code, use `env.LOADER.get(id, callback)` instead. The runtime returns an existing Worker on a cache hit, or calls your callback to build one on a miss:
58+
59+
<TypeScriptExample>
60+
61+
```ts
62+
const worker = env.LOADER.get(workerId, async () => {
63+
// This callback only runs on cache miss
64+
const { mainModule, modules } = await createWorker({ files });
65+
66+
return {
67+
mainModule,
68+
modules,
69+
compatibilityDate: "2026-05-01",
70+
tails: [
71+
contextExports.DynamicWorkerTail({ props: { workerId } }),
72+
],
73+
};
74+
});
75+
76+
const response = await worker.getEntrypoint().fetch(request);
77+
```
78+
79+
</TypeScriptExample>
80+
81+
In the playground, you can see this in action — run the same Dynamic Worker twice and the second request shows a cached result with 0ms cold start, since the build and load phases are skipped entirely.
82+
83+
## Observability with Tail Workers
84+
85+
When you run code in the playground, console output from the Dynamic Worker streams back to the browser in real time. Under the hood, this works through a [Tail Worker](/workers/observability/logs/tail-workers/) pipeline:
86+
87+
1. A Tail Worker (`DynamicWorkerTail`) captures `console.log` output from the Dynamic Worker.
88+
2. Logs are forwarded to a `LogSession` Durable Object.
89+
3. The Durable Object streams them to the client over WebSocket.
90+
91+
To wire this up, include the Tail Worker in the `tails` array when creating the Dynamic Worker:
92+
93+
<TypeScriptExample>
94+
95+
```ts
96+
const worker = env.LOADER.get(workerId, async () => ({
97+
mainModule,
98+
modules,
99+
compatibilityDate: "2026-05-01",
100+
tails: [contextExports.DynamicWorkerTail({ props: { workerId } })],
101+
}));
102+
```
103+
104+
</TypeScriptExample>
105+
106+
For more information on how to capture and stream logs from Dynamic Workers, refer to [Observability with Dynamic Workers](/dynamic-workers/usage/observability/).
107+
108+
## Running locally
109+
110+
Clone the repo and start the dev server:
111+
112+
```sh
113+
npm install
114+
npm run dev
115+
```
Lines changed: 73 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,81 @@
11
---
22
title: Dynamic Workers Starter
3-
description: A starter template for building with Dynamic Workers.
3+
description: A starter template for deploying a Worker that loads and runs Dynamic Workers.
44
pcx_content_type: example
5-
external_link: https://github.com/cloudflare/agents/tree/main/examples/dynamic-workers
65
sidebar:
76
order: 1
87
products:
98
- dynamic-workers
9+
tags:
10+
- JavaScript
11+
- TypeScript
1012
---
13+
14+
import { TypeScriptExample, WranglerConfig } from "~/components";
15+
16+
A [starter template](https://github.com/cloudflare/agents/tree/main/examples/dynamic-workers) for deploying a Worker that loads and runs [Dynamic Workers](/dynamic-workers/).
17+
18+
[![Deploy to Workers](https://deploy.workers.cloudflare.com/button)](https://deploy.workers.cloudflare.com/?url=https://github.com/cloudflare/agents/tree/main/examples/dynamic-workers)
19+
20+
## What it does
21+
22+
This template demonstrates how to use the [Worker Loader API](/workers/runtime-apis/bindings/worker-loader/) to execute code at runtime. The host Worker exposes an `/api/run` endpoint that accepts code from the frontend, loads it into a sandboxed Dynamic Worker, and returns the result.
23+
24+
Use this pattern for AI agents that need to execute a snippet of code to complete an action.
25+
26+
## Configuration
27+
28+
Add a `worker_loaders` binding to your Wrangler file:
29+
30+
<WranglerConfig>
31+
32+
```jsonc
33+
{
34+
"worker_loaders": [
35+
{
36+
"binding": "LOADER"
37+
}
38+
]
39+
}
40+
```
41+
42+
</WranglerConfig>
43+
44+
## Loading and executing a Dynamic Worker
45+
46+
In this example:
47+
48+
- `env.LOADER.load()` creates a one-off dynamic isolate
49+
- `globalOutbound: null` blocks all outbound network access from the Dynamic Worker
50+
51+
<TypeScriptExample>
52+
53+
```ts
54+
export default {
55+
async fetch(request, env): Promise<Response> {
56+
const { code } = await request.json();
57+
58+
const worker = env.LOADER.load({
59+
compatibilityDate: "2026-05-01",
60+
mainModule: "worker.js",
61+
modules: {
62+
"worker.js": code,
63+
},
64+
// Block all outbound network access
65+
globalOutbound: null,
66+
});
67+
68+
const result = await worker.getEntrypoint().fetch(request);
69+
return result;
70+
},
71+
} satisfies ExportedHandler;
72+
```
73+
74+
</TypeScriptExample>
75+
76+
## Running locally
77+
78+
```sh
79+
npm install
80+
npm run dev
81+
```
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
---
2+
title: Dynamic Workflows Playground
3+
description: Write workflow logic in JavaScript and watch every step execute with live console.log streaming.
4+
pcx_content_type: example
5+
sidebar:
6+
order: 4
7+
products:
8+
- dynamic-workers
9+
tags:
10+
- JavaScript
11+
- TypeScript
12+
---
13+
14+
Try the [dynamic workflows playground](https://github.com/cloudflare/dynamic-workflows/tree/main/examples/basic), write workflow logic in JavaScript, execute it from a Dynamic Worker, and log every step in real time.
15+
16+
This example shows you how to run [Cloudflare Workflows](/workflows/) from a [Dynamic Worker](/dynamic-workers/) to get full durable execution, including step retries, sleep, hibernation, and `waitForEvent`, for any workflow you need to run on demand.
17+
18+
[![Deploy to Workers](https://deploy.workers.cloudflare.com/button)](https://deploy.workers.cloudflare.com/?url=https://github.com/cloudflare/dynamic-workflows/tree/main/examples/basic)
19+
20+
## How it works
21+
22+
There are two parts:
23+
24+
- **Worker Loader** — The Worker that runs your platform logic. It receives a request, loads the user's workflow code as a Dynamic Worker, and gives it a Workflow binding so it can create and run workflows.
25+
- **Dynamic Worker** — This is where the workflow is defined. You write the workflow logic here, including which steps need to run, how long it sleeps, and what events it waits for.
26+
27+
The [`@cloudflare/dynamic-workflows`](https://www.npmjs.com/package/@cloudflare/dynamic-workflows) library connects the two. When the Dynamic Worker creates a workflow, the library tags it with information about which Dynamic Worker created it. That tag is persisted by the Workflows engine, so when a workflow needs to resume after a sleep, a failure, or a server restart, the engine knows which Dynamic Worker to reload to continue execution.
28+
29+
For a full walkthrough of the library and how to set it up, refer to the [Dynamic Workflows guide](/dynamic-workers/usage/dynamic-workflows/).
30+
31+
## What this playground includes
32+
33+
- **Worker Loader and Dynamic Worker setup** — A full working example of a Worker Loader that loads workflow code at runtime and a Dynamic Worker that runs it with durable execution, using [`@cloudflare/dynamic-workflows`](https://www.npmjs.com/package/@cloudflare/dynamic-workflows).
34+
- **Live log streaming** — Every `console.log()` and `console.warn()` from the Dynamic Worker is captured and streamed to the browser in real time, so you can see what is happening inside each step as it runs.
35+
- **Source persistence** — The workflow code is saved so that if the workflow pauses (for example, during a `step.sleep()`) and the server recycles the process, it can reload the same code and resume where it left off.

src/content/docs/dynamic-workers/getting-started.mdx

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,6 @@ const worker = env.LOADER.get("hello-v1", async () => {
124124
};
125125
});
126126
```
127-
128127
</TypeScriptExample>
129128

130129
## Supported languages
@@ -133,12 +132,35 @@ Dynamic Workers support JavaScript (ES modules and CommonJS) and Python. The cod
133132

134133
For the full list of supported module types, refer to the [API reference](/dynamic-workers/api-reference/#modules).
135134

135+
### Python Workers
136+
To run Python code in a Dynamic Worker, you must include the `python_workers` compatibility flag. Without this flag, the Dynamic Worker will fail to load the Python runtime.
137+
138+
<TypeScriptExample>
139+
140+
```ts
141+
const worker = env.LOADER.load({
142+
compatibilityDate: "$today",
143+
compatibilityFlags: ["python_workers"],
144+
mainModule: "worker.py",
145+
modules: {
146+
"worker.py": `
147+
from workers import Response
148+
149+
def on_fetch(request):
150+
return Response("Hello from Python!")
151+
`,
152+
},
153+
});
154+
```
155+
</TypeScriptExample>
156+
136157
### Using TypeScript and npm dependencies
137158

138159
If your Dynamic Worker needs TypeScript compilation or npm dependencies, the code must be transpiled and bundled before passing to the Worker Loader.
139160

140161
[`@cloudflare/worker-bundler`](https://www.npmjs.com/package/@cloudflare/worker-bundler) is a library that handles this for you. Use it to bundle source files into a format that `load()` and `get()` accept:
141162

163+
<TypeScriptExample>
142164
```ts
143165
import { createWorker } from "@cloudflare/worker-bundler";
144166

@@ -157,8 +179,9 @@ const worker = env.LOADER.get("my-worker", async () => {
157179
},
158180
});
159181

160-
return { mainModule, modules, compatibilityDate: "2026-01-01" };
182+
return { mainModule, modules, compatibilityDate: "$today" };
161183
});
162184
```
185+
</TypeScriptExample>
163186

164187
`createWorker()` handles TypeScript compilation, dependency resolution from npm, and bundling. It returns `mainModule` and `modules` ready to pass directly to `load()` or `get()`.

0 commit comments

Comments
 (0)