diff --git a/public/__redirects b/public/__redirects
index d0b1f57af1c..b2becb07f1c 100644
--- a/public/__redirects
+++ b/public/__redirects
@@ -228,7 +228,8 @@
/agents/concepts/long-running-agents/ /agents/concepts/agentic-patterns/long-running-agents/ 301
/agents/api-reference/agents-api/ /agents/runtime/agents-api/ 301
/agents/api-reference/ /agents/runtime/ 301
-/agents/api-reference/chat-sdk/ /agents/runtime/execution/chat-sdk/ 301
+/agents/api-reference/chat-sdk/ /agents/runtime/communication/chat-sdk/ 301
+/agents/runtime/execution/chat-sdk/ /agents/runtime/communication/chat-sdk/ 301
/agents/api-reference/agent-tools/ /agents/runtime/execution/agent-tools/ 301
/agents/api-reference/browse-the-web/ /agents/tools/browser/ 301
/agents/api-reference/callable-methods/ /agents/runtime/lifecycle/callable-methods/ 301
diff --git a/src/content/docs/agents/communication-channels/chat/chat-agents.mdx b/src/content/docs/agents/communication-channels/chat/chat-agents.mdx
index fc19650f6fd..7f7667ab400 100644
--- a/src/content/docs/agents/communication-channels/chat/chat-agents.mdx
+++ b/src/content/docs/agents/communication-channels/chat/chat-agents.mdx
@@ -1582,7 +1582,7 @@ export class ChatAgent extends AIChatAgent {
:::note
-This section covers **in-process** subagents using the AI SDK's `ToolLoopAgent`. For **Durable Object sub-agents** with their own isolated storage and typed RPC, refer to [Sub-agents](/agents/runtime/execution/sub-agents/). To run Think or `AIChatAgent` sub-agents as retained, streaming tools, refer to [Agent tools](/agents/runtime/execution/agent-tools/).
+This section covers **in-process** subagents using the AI SDK's `ToolLoopAgent`. For **Durable Object sub-agents** with their own isolated storage and typed RPC, refer to [Sub-agents](/agents/runtime/execution/sub-agents/). To run Think or `AIChatAgent` sub-agents as retained, streaming tools, refer to [Agents as tools](/agents/runtime/execution/agent-tools/).
:::
diff --git a/src/content/docs/agents/communication-channels/chat/client-sdk.mdx b/src/content/docs/agents/communication-channels/chat/client-sdk.mdx
index 7fe18dd4742..ff7b3e47114 100644
--- a/src/content/docs/agents/communication-channels/chat/client-sdk.mdx
+++ b/src/content/docs/agents/communication-channels/chat/client-sdk.mdx
@@ -616,7 +616,7 @@ client.addEventListener("message", () => {});
## Agent-tool events
-If your chat UI renders retained child runs from [Agent tools](/agents/runtime/execution/agent-tools/), use `useAgentToolEvents()` alongside `useAgent()` and `useAgentChat()`. The hook subscribes to the parent connection, replays retained child timelines, and groups runs by parent tool call ID.
+If your chat UI renders retained child runs from [Agents as tools](/agents/runtime/execution/agent-tools/), use `useAgentToolEvents()` alongside `useAgent()` and `useAgentChat()`. The hook subscribes to the parent connection, replays retained child timelines, and groups runs by parent tool call ID.
diff --git a/src/content/docs/agents/concepts/tools.mdx b/src/content/docs/agents/concepts/tools.mdx
index 3ffba4ef643..caa6ee330f0 100644
--- a/src/content/docs/agents/concepts/tools.mdx
+++ b/src/content/docs/agents/concepts/tools.mdx
@@ -16,13 +16,13 @@ Tools enable AI systems to interact with external services and perform actions.
Cloudflare Agents support several tool patterns. Choose the smallest one that fits the job:
-| Pattern | Use when | Start here |
-| ----------------- | ----------------------------------------------------------------------------------------- | ------------------------------------------------------------------- |
+| Pattern | Use when | Start here |
+| ----------------- | ----------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------- |
| Server-side tools | The tool can run entirely in the Worker, such as fetching an API or querying SQL | [Chat agents](/agents/communication-channels/chat/chat-agents/#server-side-tools) |
| Client-side tools | The tool needs browser APIs such as geolocation, clipboard, or local storage | [Chat agents](/agents/communication-channels/chat/chat-agents/#client-side-tools) |
-| Human approvals | The tool is sensitive and needs a user decision before it runs | [Human-in-the-loop](/agents/concepts/agentic-patterns/human-in-the-loop/) |
-| MCP tools | You want to expose or consume tools through the Model Context Protocol | [Model Context Protocol](/agents/model-context-protocol/) |
-| Agent tools | You want a chat agent to run another chat-capable sub-agent as a retained, streaming tool | [Agent tools](/agents/runtime/execution/agent-tools/) |
+| Human approvals | The tool is sensitive and needs a user decision before it runs | [Human-in-the-loop](/agents/concepts/agentic-patterns/human-in-the-loop/) |
+| MCP tools | You want to expose or consume tools through the Model Context Protocol | [Model Context Protocol](/agents/model-context-protocol/) |
+| Agents as tools | You want a chat agent to run another chat-capable sub-agent as a retained, streaming tool | [Agents as tools](/agents/runtime/execution/agent-tools/) |
### Understanding tools
diff --git a/src/content/docs/agents/getting-started/add-to-existing-project.mdx b/src/content/docs/agents/getting-started/add-to-existing-project.mdx
index 326728cf0e8..5b42e32a303 100644
--- a/src/content/docs/agents/getting-started/add-to-existing-project.mdx
+++ b/src/content/docs/agents/getting-started/add-to-existing-project.mdx
@@ -12,7 +12,7 @@ import {
PackageManagers,
TypeScriptExample,
WranglerConfig,
- LinkCard,
+ Render,
} from "~/components";
This guide shows how to add agents to an existing Cloudflare Workers project. If you are starting fresh, refer to [Building a chat agent](/agents/examples/chat-agent/) instead.
@@ -304,6 +304,12 @@ function CounterWidget() {
+Key points:
+
+- `useAgent` connects to your agent via WebSocket
+- `onStateUpdate` fires whenever the agent's state changes
+- `agent.stub.methodName()` calls methods marked with `@callable()` on your agent
+
### Vanilla JavaScript
@@ -325,207 +331,18 @@ document.getElementById("increment").onclick = () => agent.call("increment");
-## Adding multiple agents
-
-Add more agents by extending the configuration:
-
-
-
-```ts
-// src/agents/chat.ts
-export class Chat extends Agent {
- // ...
-}
-
-// src/agents/scheduler.ts
-export class Scheduler extends Agent {
- // ...
-}
-```
-
-
-
-Update the Wrangler configuration file:
-
-
-
-```jsonc
-{
- "durable_objects": {
- "bindings": [
- { "name": "CounterAgent", "class_name": "CounterAgent" },
- { "name": "Chat", "class_name": "Chat" },
- { "name": "Scheduler", "class_name": "Scheduler" },
- ],
- },
- "migrations": [
- {
- "tag": "v1",
- "new_sqlite_classes": ["CounterAgent", "Chat", "Scheduler"],
- },
- ],
-}
-```
-
-
-
-Export all agents from your entry point:
-
-
-
-```ts
-export { CounterAgent } from "./agents/counter";
-export { Chat } from "./agents/chat";
-export { Scheduler } from "./agents/scheduler";
-```
-
-
-
-## Common integration patterns
-
-### Agents behind authentication
+
-Check auth before routing to agents:
-
-
-
-```ts
-export default {
- async fetch(request: Request, env: Env) {
- // Check auth for agent routes
- if (request.url.includes("/agents/")) {
- const authResult = await checkAuth(request, env);
- if (!authResult.valid) {
- return new Response("Unauthorized", { status: 401 });
- }
- }
-
- const agentResponse = await routeAgentRequest(request, env);
- if (agentResponse) return agentResponse;
-
- // ... rest of routing
- },
-} satisfies ExportedHandler;
-```
-
-
+## Deploy to Cloudflare
-### Custom agent path prefix
-
-By default, agents are routed at `/agents/{agent-name}/{instance-name}`. You can customize this:
-
-
-
-```ts
-import { routeAgentRequest } from "agents";
-
-const agentResponse = await routeAgentRequest(request, env, {
- prefix: "/api/agents", // Now routes at /api/agents/{agent-name}/{instance-name}
-});
-```
-
-
-
-Refer to [Routing](/agents/runtime/communication/routing/) for more options including CORS, custom instance naming, and location hints.
-
-### Accessing agents from server code
-
-You can interact with agents directly from your Worker code:
-
-
-
-```ts
-import { getAgentByName } from "agents";
-
-export default {
- async fetch(request: Request, env: Env) {
- if (request.url.endsWith("/api/increment")) {
- // Get a specific agent instance
- const counter = await getAgentByName(env.CounterAgent, "shared-counter");
- const newCount = await counter.increment();
- return Response.json({ count: newCount });
- }
- // ...
- },
-} satisfies ExportedHandler;
-```
-
-
-
-## Troubleshooting
-
-### Agent not found, or 404 errors
-
-1. **Check the export** - Agent class must be exported from your main entry point.
-2. **Check the binding** - `class_name` in the Wrangler configuration file must exactly match the exported class name.
-3. **Check the route** - Default route is `/agents/{agent-name}/{instance-name}`.
-
-### No such Durable Object class error
-
-Add the migration to the Wrangler configuration file:
-
-
-
-```jsonc
-{
- "migrations": [
- {
- "tag": "v1",
- "new_sqlite_classes": ["YourAgentClass"],
- },
- ],
-}
-```
-
-
-
-### WebSocket connection fails
-
-Ensure your routing passes the response unchanged:
-
-
-
-```ts
-// Correct - return the response directly
-const agentResponse = await routeAgentRequest(request, env);
-if (agentResponse) return agentResponse;
-
-// Wrong - this breaks WebSocket connections
-if (agentResponse) return new Response(agentResponse.body);
+```sh
+npm run deploy
```
-
-
-### State not persisting
-
-Check that:
-
-1. You are using `this.setState()`, not mutating `this.state` directly.
-2. The agent class is in `new_sqlite_classes` in migrations.
-3. You are connecting to the same agent instance name.
-
-## Next steps
-
-
+Your agent is now live on Cloudflare's global network, running close to your users.
-
+
-
+
-
+
diff --git a/src/content/docs/agents/getting-started/quick-start.mdx b/src/content/docs/agents/getting-started/quick-start.mdx
index e1ff81f5caf..64344a67415 100644
--- a/src/content/docs/agents/getting-started/quick-start.mdx
+++ b/src/content/docs/agents/getting-started/quick-start.mdx
@@ -12,7 +12,7 @@ import {
TypeScriptExample,
WranglerConfig,
PackageManagers,
- LinkCard,
+ Render,
} from "~/components";
Build AI agents that persist, think, and act. Agents run on Cloudflare's global network, maintain state across requests, and connect to clients in real-time via WebSockets.
@@ -150,6 +150,13 @@ Update `wrangler.jsonc` to register the agent:
+**Key points:**
+
+- `name` in bindings becomes the property on `env` (for example, `env.CounterAgent`)
+- `class_name` must exactly match your exported class name
+- `new_sqlite_classes` enables SQLite storage for state persistence
+- `nodejs_compat` flag is required for the agents package
+
## Connect from React
Replace `src/client.tsx`:
@@ -193,30 +200,7 @@ Key points:
- `onStateUpdate` fires whenever the agent's state changes
- `agent.stub.methodName()` calls methods marked with `@callable()` on your agent
-## What just happened?
-
-When you clicked the button:
-
-1. **Client** called `agent.stub.increment()` over WebSocket
-2. **Agent** ran `increment()`, updated state with `setState()`
-3. **State** persisted to SQLite automatically
-4. **Broadcast** sent to all connected clients
-5. **React** updated via `onStateUpdate`
-
-```mermaid
-flowchart LR
- A["Browser
(React)"] <-->|WebSocket| B["Agent
(Counter)"]
- B --> C["SQLite
(State)"]
-```
-
-### Key concepts
-
-| Concept | What it means |
-| -------------------- | ----------------------------------------------------------------------------------------------------- |
-| **Agent instance** | Each unique name gets its own agent. `CounterAgent:user-123` is separate from `CounterAgent:user-456` |
-| **Persistent state** | State survives restarts, deploys, and hibernation. It is stored in SQLite |
-| **Real-time sync** | All clients connected to the same agent receive state updates instantly |
-| **Hibernation** | When no clients are connected, the agent hibernates (no cost). It wakes on the next request |
+
## Connect from vanilla JavaScript
@@ -250,117 +234,8 @@ npm run deploy
Your agent is now live on Cloudflare's global network, running close to your users.
-## Troubleshooting
-
-### "Agent not found" or 404 errors
-
-Make sure:
-
-1. Agent class is exported from your server file
-2. `wrangler.jsonc` has the binding and migration
-3. Agent name in client matches the class name (case-insensitive)
-
-### State not syncing
-
-Check that:
-
-1. You are calling `this.setState()`, not mutating `this.state` directly
-2. The `onStateUpdate` callback is wired up in your client
-3. WebSocket connection is established (check browser dev tools)
-
-### "Method X is not callable" errors
-
-Make sure your methods are decorated with `@callable()`:
+
-
-
-```ts
-import { Agent, callable } from "agents";
-
-export class MyAgent extends Agent {
- @callable()
- increment() {
- // ...
- }
-}
-```
-
-
-
-### Type errors with `agent.stub`
+
-Add the agent and state type parameters:
-
-
-
-```ts
-import { useAgent } from "agents/react";
-import type { CounterAgent, CounterState } from "./server";
-
-// Pass the agent and state types to useAgent
-const agent = useAgent({
- agent: "CounterAgent",
- onStateUpdate: (state) => setCount(state.count),
-});
-
-// Now agent.stub is fully typed
-agent.stub.increment();
-```
-
-
-
-### `SyntaxError: Invalid or unexpected token` with `@callable()`
-
-If your dev server fails with `SyntaxError: Invalid or unexpected token`, set `"target": "ES2021"` in your `tsconfig.json`. This ensures that Vite's esbuild transpiler downlevels TC39 decorators instead of passing them through as native syntax.
-
-```json
-{
- "compilerOptions": {
- "target": "ES2021"
- }
-}
-```
-
-:::caution
-Do not set `"experimentalDecorators": true` in your `tsconfig.json`. The Agents SDK uses [TC39 standard decorators](https://github.com/tc39/proposal-decorators), not TypeScript legacy decorators. Enabling `experimentalDecorators` applies an incompatible transform that silently breaks `@callable()` at runtime.
-:::
-
-## Next steps
-
-Now that you have a working agent, explore these topics:
-
-### Common patterns
-
-| Learn how to | Refer to |
-| ------------------------ | --------------------------------------------------------- |
-| Add AI/LLM capabilities | [Using AI models](/agents/runtime/operations/using-ai-models/) |
-| Expose tools via MCP | [MCP servers](/agents/model-context-protocol/apis/agent-api/) |
-| Run background tasks | [Schedule tasks](/agents/runtime/execution/schedule-tasks/) |
-| Handle emails | [Email routing](/agents/communication-channels/email/) |
-| Use Cloudflare Workflows | [Run Workflows](/agents/runtime/execution/run-workflows/) |
-
-### Explore more
-
-
-
-
-
-
-
-
+
diff --git a/src/content/docs/agents/harnesses/think/index.mdx b/src/content/docs/agents/harnesses/think/index.mdx
index 55c1ddab27c..701f56467fe 100644
--- a/src/content/docs/agents/harnesses/think/index.mdx
+++ b/src/content/docs/agents/harnesses/think/index.mdx
@@ -185,7 +185,7 @@ Think has several ways to start or continue a turn. Choose based on who starts t
Use `saveMessages()` when the caller owns the trigger and can wait for the turn to finish. Use [`submitMessages()`](/agents/harnesses/think/programmatic-submissions/) when timeout ambiguity would make retries unsafe.
-Use `chat()` for low-level parent-to-child streaming when your code owns forwarding, cancellation, and replay policy. Use [Agent tools](/agents/runtime/execution/agent-tools/) when a parent model or workflow delegates to a child agent and you want retained child runs, event replay, abort bridging, and UI drill-in.
+Use `chat()` for low-level parent-to-child streaming when your code owns forwarding, cancellation, and replay policy. Use [Agents as tools](/agents/runtime/execution/agent-tools/) when a parent model or workflow delegates to a child agent and you want retained child runs, event replay, abort bridging, and UI drill-in.
Use [`startFiber()`](/agents/runtime/execution/durable-execution/#startfiber) outside Think when the durable unit is an application job around a turn: accepting a webhook once, restoring a serialized channel or thread target, posting a visible reply, or recording app-level recovery policy. Think submissions own conversation admission and turn serialization; managed fibers own external job acceptance, idempotent side effects, and application recovery.
diff --git a/src/content/docs/agents/harnesses/think/messengers.mdx b/src/content/docs/agents/harnesses/think/messengers.mdx
index 601af04155f..ca99f07f7f6 100644
--- a/src/content/docs/agents/harnesses/think/messengers.mdx
+++ b/src/content/docs/agents/harnesses/think/messengers.mdx
@@ -196,4 +196,4 @@ Every custom messenger must provide `verifyWebhook` or explicitly use `verifyWeb
The `examples/think-chat-sdk` example demonstrates the Think-native `getMessengers()` path with a small Vite dashboard that inspects the root Think conversation over the Agent WebSocket.
-The `examples/chat-sdk-messenger` example demonstrates a larger manual ingress agent with an admin dashboard, menu handling, and application-owned reply fibers. Use `getMessengers()` for the simple Think-native path. Use the example when you need to own the Chat SDK runtime and control-plane UI yourself. Refer to [Chat SDK state](/agents/runtime/execution/chat-sdk/) for the underlying state adapter.
+The `examples/chat-sdk-messenger` example demonstrates a larger manual ingress agent with an admin dashboard, menu handling, and application-owned reply fibers. Use `getMessengers()` for the simple Think-native path. Use the example when you need to own the Chat SDK runtime and control-plane UI yourself. Refer to [Chat SDK state](/agents/runtime/communication/chat-sdk/) for the underlying state adapter.
diff --git a/src/content/docs/agents/harnesses/think/tools.mdx b/src/content/docs/agents/harnesses/think/tools.mdx
index ea6a65e54f5..feb5df869c5 100644
--- a/src/content/docs/agents/harnesses/think/tools.mdx
+++ b/src/content/docs/agents/harnesses/think/tools.mdx
@@ -24,7 +24,7 @@ On every turn, Think merges tools from multiple sources. Later sources override
6. **MCP tools** — from connected MCP servers
7. **Client tools** — from the browser (refer to [Client tools](/agents/harnesses/think/client-tools/))
-Tools belong to the agent running the turn. For parent-child orchestration, use [Agent tools](/agents/runtime/execution/agent-tools/) instead of passing one-off tools through `chat()`.
+Tools belong to the agent running the turn. For parent-child orchestration, use [Agents as tools](/agents/runtime/execution/agent-tools/) instead of passing one-off tools through `chat()`.
## Built-in workspace tools
diff --git a/src/content/docs/agents/runtime/agents-api.mdx b/src/content/docs/agents/runtime/agents-api.mdx
index ad7907fd3d8..8347424197c 100644
--- a/src/content/docs/agents/runtime/agents-api.mdx
+++ b/src/content/docs/agents/runtime/agents-api.mdx
@@ -63,16 +63,16 @@ flowchart TD
E --> F["onClose"]
```
-| Method | When it runs |
-| --------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| Method | When it runs |
+| --------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `onStart(props?)` | When the instance starts, or wakes from hibernation. Receives optional [initialization props](/agents/runtime/communication/routing/#props) passed via `getAgentByName` or `routeAgentRequest`. |
-| `onRequest(request)` | For each HTTP request to the instance |
-| `onConnect(connection, ctx)` | When a WebSocket connection is established |
-| `onMessage(connection, message)` | For each WebSocket message received |
-| `onError(connection, error)` | When a WebSocket error occurs |
-| `onClose(connection, code, reason, wasClean)` | When a WebSocket connection closes |
-| `onEmail(email)` | When an email is routed to the instance |
-| `onStateChanged(state, source)` | When state changes (from server or client) |
+| `onRequest(request)` | For each HTTP request to the instance |
+| `onConnect(connection, ctx)` | When a WebSocket connection is established |
+| `onMessage(connection, message)` | For each WebSocket message received |
+| `onError(connection, error)` | When a WebSocket error occurs |
+| `onClose(connection, code, reason, wasClean)` | When a WebSocket connection closes |
+| `onEmail(email)` | When an email is routed to the instance |
+| `onStateChanged(state, source)` | When state changes (from server or client) |
## Core properties
@@ -85,28 +85,28 @@ flowchart TD
## Server-side API reference
-| Feature | Methods | Documentation |
-| --------------------- | ------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------- |
-| **State** | `setState()`, `onStateChanged()`, `initialState` | [Store and sync state](/agents/runtime/lifecycle/state/) |
-| **Callable methods** | `@callable()` decorator | [Callable methods](/agents/runtime/lifecycle/callable-methods/) |
-| **Scheduling** | `schedule()`, `scheduleEvery()`, `getScheduleById()`, `listSchedules()` | [Schedule tasks](/agents/runtime/execution/schedule-tasks/) |
-| **Durable execution** | `runFiber()`, `startFiber()`, `stash()`, `onFiberRecovered()`, `keepAlive()`, `keepAliveWhile()` | [Durable execution](/agents/runtime/execution/durable-execution/) |
-| **Queue** | `queue()`, `dequeue()`, `dequeueAll()`, `getQueue()` | [Queue tasks](/agents/runtime/execution/queue-tasks/) |
-| **WebSockets** | `onConnect()`, `onMessage()`, `onClose()`, `broadcast()` | [WebSockets](/agents/runtime/communication/websockets/) |
-| **HTTP/SSE** | `onRequest()` | [HTTP and SSE](/agents/runtime/communication/http-sse/) |
-| **Email** | `onEmail()`, `replyToEmail()` | [Email routing](/agents/communication-channels/email/) |
-| **Workflows** | `runWorkflow()`, `waitForApproval()` | [Run Workflows](/agents/runtime/execution/run-workflows/) |
-| **MCP Client** | `addMcpServer()`, `removeMcpServer()`, `getMcpServers()` | [MCP Client API](/agents/model-context-protocol/apis/client-api/) |
-| **AI Models** | Workers AI, OpenAI, Anthropic bindings | [Using AI models](/agents/runtime/operations/using-ai-models/) |
-| **Protocol messages** | `shouldSendProtocolMessages()`, `isConnectionProtocolEnabled()` | [Protocol messages](/agents/runtime/communication/protocol-messages/) |
-| **Context** | `getCurrentAgent()` | [getCurrentAgent()](/agents/runtime/lifecycle/get-current-agent/) |
-| **Observability** | `subscribe()`, diagnostics channels, Tail Workers | [Observability](/agents/runtime/operations/observability/) |
-| **Sub-agents** | `subAgent()`, `abortSubAgent()`, `deleteSubAgent()` | [Sub-agents](/agents/runtime/execution/sub-agents/) |
-| **Agent tools** | `runAgentTool()`, `clearAgentToolRuns()`, `hasAgentToolRun()` | [Agent tools](/agents/runtime/execution/agent-tools/) |
-| **Agent Skills** | `skills` registry, bundled skill sources, script runners | [Agent Skills](/agents/runtime/execution/agent-skills/) |
-| **Sessions** | `Session.create()`, context blocks, compaction, search | [Sessions](/agents/runtime/lifecycle/sessions/) |
-| **Think** | `Think` base class, workspace tools, lifecycle hooks, extensions | [Think](/agents/harnesses/think/) |
-| **Chat SDK** | `createChatSdkState()`, `ChatSdkStateAgent` | [Chat SDK](/agents/runtime/execution/chat-sdk/) |
+| Feature | Methods | Documentation |
+| --------------------- | ------------------------------------------------------------------------------------------------ | --------------------------------------------------------------------- |
+| **State** | `setState()`, `onStateChanged()`, `initialState` | [Store and sync state](/agents/runtime/lifecycle/state/) |
+| **Callable methods** | `@callable()` decorator | [Callable methods](/agents/runtime/lifecycle/callable-methods/) |
+| **Scheduling** | `schedule()`, `scheduleEvery()`, `getScheduleById()`, `listSchedules()` | [Schedule tasks](/agents/runtime/execution/schedule-tasks/) |
+| **Durable execution** | `runFiber()`, `startFiber()`, `stash()`, `onFiberRecovered()`, `keepAlive()`, `keepAliveWhile()` | [Durable execution](/agents/runtime/execution/durable-execution/) |
+| **Queue** | `queue()`, `dequeue()`, `dequeueAll()`, `getQueue()` | [Queue tasks](/agents/runtime/execution/queue-tasks/) |
+| **WebSockets** | `onConnect()`, `onMessage()`, `onClose()`, `broadcast()` | [WebSockets](/agents/runtime/communication/websockets/) |
+| **HTTP/SSE** | `onRequest()` | [HTTP and SSE](/agents/runtime/communication/http-sse/) |
+| **Email** | `onEmail()`, `replyToEmail()` | [Email routing](/agents/communication-channels/email/) |
+| **Workflows** | `runWorkflow()`, `waitForApproval()` | [Run Workflows](/agents/runtime/execution/run-workflows/) |
+| **MCP Client** | `addMcpServer()`, `removeMcpServer()`, `getMcpServers()` | [MCP Client API](/agents/model-context-protocol/apis/client-api/) |
+| **AI Models** | Workers AI, OpenAI, Anthropic bindings | [Using AI models](/agents/runtime/operations/using-ai-models/) |
+| **Protocol messages** | `shouldSendProtocolMessages()`, `isConnectionProtocolEnabled()` | [Protocol messages](/agents/runtime/communication/protocol-messages/) |
+| **Context** | `getCurrentAgent()` | [getCurrentAgent()](/agents/runtime/lifecycle/get-current-agent/) |
+| **Observability** | `subscribe()`, diagnostics channels, Tail Workers | [Observability](/agents/runtime/operations/observability/) |
+| **Sub-agents** | `subAgent()`, `abortSubAgent()`, `deleteSubAgent()` | [Sub-agents](/agents/runtime/execution/sub-agents/) |
+| **Agents as tools** | `runAgentTool()`, `clearAgentToolRuns()`, `hasAgentToolRun()` | [Agents as tools](/agents/runtime/execution/agent-tools/) |
+| **Agent Skills** | `skills` registry, bundled skill sources, script runners | [Agent Skills](/agents/runtime/execution/agent-skills/) |
+| **Sessions** | `Session.create()`, context blocks, compaction, search | [Sessions](/agents/runtime/lifecycle/sessions/) |
+| **Think** | `Think` base class, workspace tools, lifecycle hooks, extensions | [Think](/agents/harnesses/think/) |
+| **Chat SDK** | `createChatSdkState()`, `ChatSdkStateAgent` | [Chat SDK](/agents/runtime/communication/chat-sdk/) |
## SQL API
@@ -127,13 +127,13 @@ For state that needs to sync with clients, use the [State API](/agents/runtime/l
## Client-side API reference
-| Feature | Methods | Documentation |
-| --------------------- | ---------------------- | --------------------------------------------------------------------------------- |
-| **WebSocket client** | `AgentClient` | [Client SDK](/agents/communication-channels/chat/client-sdk/) |
-| **HTTP client** | `agentFetch()` | [Client SDK](/agents/communication-channels/chat/client-sdk/#http-requests-with-agentfetch) |
-| **React hook** | `useAgent()` | [Client SDK](/agents/communication-channels/chat/client-sdk/#react) |
-| **Chat hook** | `useAgentChat()` | [Client SDK](/agents/communication-channels/chat/client-sdk/) |
-| **Agent tool events** | `useAgentToolEvents()` | [Agent tools](/agents/runtime/execution/agent-tools/#render-child-timelines-in-react) |
+| Feature | Methods | Documentation |
+| --------------------- | ---------------------- | ------------------------------------------------------------------------------------------- |
+| **WebSocket client** | `AgentClient` | [Client SDK](/agents/communication-channels/chat/client-sdk/) |
+| **HTTP client** | `agentFetch()` | [Client SDK](/agents/communication-channels/chat/client-sdk/#http-requests-with-agentfetch) |
+| **React hook** | `useAgent()` | [Client SDK](/agents/communication-channels/chat/client-sdk/#react) |
+| **Chat hook** | `useAgentChat()` | [Client SDK](/agents/communication-channels/chat/client-sdk/) |
+| **Agent tool events** | `useAgentToolEvents()` | [Agents as tools](/agents/runtime/execution/agent-tools/#render-child-timelines-in-react) |
Module-level helper exports include `agentTool()` from `agents/agent-tools`, which converts a Think or `AIChatAgent` subclass into an AI SDK tool definition.
diff --git a/src/content/docs/agents/runtime/execution/chat-sdk.mdx b/src/content/docs/agents/runtime/communication/chat-sdk.mdx
similarity index 99%
rename from src/content/docs/agents/runtime/execution/chat-sdk.mdx
rename to src/content/docs/agents/runtime/communication/chat-sdk.mdx
index 9cfbb129eec..cbbfa760e8e 100644
--- a/src/content/docs/agents/runtime/execution/chat-sdk.mdx
+++ b/src/content/docs/agents/runtime/communication/chat-sdk.mdx
@@ -3,7 +3,7 @@ title: Chat SDK
description: Integrate Chat SDK with Agents, including durable state for subscriptions, locks, queues, and message history.
pcx_content_type: reference
sidebar:
- order: 23
+ order: 10
products:
- agents
---
diff --git a/src/content/docs/agents/runtime/execution/agent-tools.mdx b/src/content/docs/agents/runtime/execution/agent-tools.mdx
index f79da2f7b1b..ada19fb9bd0 100644
--- a/src/content/docs/agents/runtime/execution/agent-tools.mdx
+++ b/src/content/docs/agents/runtime/execution/agent-tools.mdx
@@ -1,5 +1,5 @@
---
-title: Agent tools
+title: Agents as tools
description: Run Think and AIChatAgent sub-agents as retained, streaming tools from a parent agent.
pcx_content_type: reference
sidebar:
@@ -10,11 +10,11 @@ products:
import { TypeScriptExample, LinkCard } from "~/components";
-Agent tools let one chat agent dispatch another chat-capable sub-agent as part of its work. The child is a real sub-agent with its own Durable Object storage, messages, tools, resumable stream, and drill-in URL. The parent keeps a small run registry so clients can render the child timeline, replay it after refresh, and clean it up later.
+Agents as tools let one chat agent dispatch another chat-capable sub-agent as part of its work. The child is a real sub-agent with its own Durable Object storage, messages, tools, resumable stream, and drill-in URL. The parent keeps a small run registry so clients can render the child timeline, replay it after refresh, and clean it up later.
-Agent tools support `@cloudflare/think` agents and `AIChatAgent` subclasses. `AIChatAgent` children run headlessly through `saveMessages()`, so they should use server-side tools. Browser-provided client tools are not available during an agent-tool turn unless you model that interaction as server-side state or a separate parent-mediated workflow.
+Agents as tools support `@cloudflare/think` agents and `AIChatAgent` subclasses. `AIChatAgent` children run headlessly through `saveMessages()`, so they should use server-side tools. Browser-provided client tools are not available during an agent-tool turn unless you model that interaction as server-side state or a separate parent-mediated workflow.
-## Agent tools vs sub-agent RPC
+## Agents as tools vs sub-agent RPC
Use `subAgent(...).chat()` when parent code needs direct streaming RPC to a specific child and your code owns forwarding, cancellation, and replay policy.
@@ -207,7 +207,7 @@ Imperative runs without a parent tool call are available as `agentTools.unboundR
## Drill in and gate access
-Agent tools are normal sub-agents. Connect to a retained child through the parent route:
+Agents as tools are normal sub-agents. Connect to a retained child through the parent route:
diff --git a/src/content/docs/agents/runtime/execution/sub-agents.mdx b/src/content/docs/agents/runtime/execution/sub-agents.mdx
index 1b173a5d06f..9dd53b2f787 100644
--- a/src/content/docs/agents/runtime/execution/sub-agents.mdx
+++ b/src/content/docs/agents/runtime/execution/sub-agents.mdx
@@ -16,7 +16,7 @@ Spawn child agents as co-located Durable Objects with their own isolated SQLite
Use sub-agents when a single user or entity owns an open-ended set of long-lived agents, such as chats, documents, sessions, shards, or projects. Each sub-agent runs in parallel with its own state while the parent coordinates discovery, access control, and lifecycle.
-If you want a parent chat agent to dispatch another chat-capable agent during a single turn and render that child's progress inline, use [Agent tools](/agents/runtime/execution/agent-tools/). Agent tools are built on sub-agents, but add a parent-side run registry, streaming `agent-tool-event` frames, replay, cancellation, and cleanup.
+If you want a parent chat agent to dispatch another chat-capable agent during a single turn and render that child's progress inline, use [Agents as tools](/agents/runtime/execution/agent-tools/). Agents as tools are built on sub-agents, but add a parent-side run registry, streaming `agent-tool-event` frames, replay, cancellation, and cleanup.
## Quick start
@@ -519,5 +519,5 @@ Calling `this.destroy()` inside a sub-agent delegates cleanup to the parent. The
- [Think](/agents/harnesses/think/) — `chat()` method for streaming AI turns through sub-agents
- [Long-running agents](/agents/concepts/agentic-patterns/long-running-agents/) — sub-agent delegation in the context of multi-week agent lifetimes
- [Callable methods](/agents/runtime/lifecycle/callable-methods/) — RPC via `@callable` and service bindings
-- [Agent tools](/agents/runtime/execution/agent-tools/) — run Think or `AIChatAgent` sub-agents as retained, streaming tools
-- [Schedule tasks](/agents/runtime/execution/schedule-tasks/) — scheduling primitives for top-level agents and sub-agents
\ No newline at end of file
+- [Agents as tools](/agents/runtime/execution/agent-tools/) — run Think or `AIChatAgent` sub-agents as retained, streaming tools
+- [Schedule tasks](/agents/runtime/execution/schedule-tasks/) — scheduling primitives for top-level agents and sub-agents
diff --git a/src/content/partials/agents/common-integration-patterns.mdx b/src/content/partials/agents/common-integration-patterns.mdx
new file mode 100644
index 00000000000..c596443ec91
--- /dev/null
+++ b/src/content/partials/agents/common-integration-patterns.mdx
@@ -0,0 +1,132 @@
+---
+{}
+---
+
+import { TypeScriptExample, WranglerConfig } from "~/components";
+
+## Common integration patterns
+
+### Agents behind authentication
+
+Check auth before routing to agents:
+
+
+
+```ts
+export default {
+ async fetch(request: Request, env: Env) {
+ // Check auth for agent routes
+ if (request.url.includes("/agents/")) {
+ const authResult = await checkAuth(request, env);
+ if (!authResult.valid) {
+ return new Response("Unauthorized", { status: 401 });
+ }
+ }
+
+ const agentResponse = await routeAgentRequest(request, env);
+ if (agentResponse) return agentResponse;
+
+ // ... rest of routing
+ },
+} satisfies ExportedHandler;
+```
+
+
+
+### Custom agent path prefix
+
+By default, agents are routed at `/agents/{agent-name}/{instance-name}`. You can customize this:
+
+
+
+```ts
+import { routeAgentRequest } from "agents";
+
+const agentResponse = await routeAgentRequest(request, env, {
+ prefix: "/api/agents", // Now routes at /api/agents/{agent-name}/{instance-name}
+});
+```
+
+
+
+Refer to [Routing](/agents/runtime/communication/routing/) for more options including CORS, custom instance naming, and location hints.
+
+### Accessing agents from server code
+
+You can interact with agents directly from your Worker code:
+
+
+
+```ts
+import { getAgentByName } from "agents";
+
+export default {
+ async fetch(request: Request, env: Env) {
+ if (request.url.endsWith("/api/increment")) {
+ // Get a specific agent instance
+ const counter = await getAgentByName(env.CounterAgent, "shared-counter");
+ const newCount = await counter.increment();
+ return Response.json({ count: newCount });
+ }
+ // ...
+ },
+} satisfies ExportedHandler;
+```
+
+
+
+### Adding multiple agents
+
+Add more agents by extending the configuration:
+
+
+
+```ts
+// src/agents/chat.ts
+export class Chat extends Agent {
+ // ...
+}
+
+// src/agents/scheduler.ts
+export class Scheduler extends Agent {
+ // ...
+}
+```
+
+
+
+Update the Wrangler configuration file:
+
+
+
+```toml
+[[durable_objects.bindings]]
+name = "CounterAgent"
+class_name = "CounterAgent"
+
+[[durable_objects.bindings]]
+name = "Chat"
+class_name = "Chat"
+
+[[durable_objects.bindings]]
+name = "Scheduler"
+class_name = "Scheduler"
+
+[[migrations]]
+tag = "v1"
+new_sqlite_classes = ["CounterAgent", "Chat", "Scheduler"]
+```
+
+
+
+Export all agents from your entry point:
+
+
+
+```ts
+export { CounterAgent } from "./agents/counter";
+export { Chat } from "./agents/chat";
+export { Scheduler } from "./agents/scheduler";
+```
+
+
diff --git a/src/content/partials/agents/next-steps.mdx b/src/content/partials/agents/next-steps.mdx
new file mode 100644
index 00000000000..5b5c8fba6aa
--- /dev/null
+++ b/src/content/partials/agents/next-steps.mdx
@@ -0,0 +1,57 @@
+---
+{}
+---
+
+import { LinkCard } from "~/components";
+
+## Next steps
+
+Now that you have a working agent, explore these topics:
+
+### Common next steps
+
+| Learn how to | Refer to |
+| ------------------------ | --------------------------------------------------------- |
+| Add AI/LLM capabilities | [Using AI models](/agents/runtime/operations/using-ai-models/) |
+| Expose tools via MCP | [MCP servers](/agents/model-context-protocol/apis/agent-api/) |
+| Run background tasks | [Schedule tasks](/agents/runtime/execution/schedule-tasks/) |
+| Handle emails | [Email routing](/agents/communication-channels/email/) |
+| Use Cloudflare Workflows | [Run Workflows](/agents/runtime/execution/run-workflows/) |
+
+### Explore more
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/content/partials/agents/troubleshooting.mdx b/src/content/partials/agents/troubleshooting.mdx
new file mode 100644
index 00000000000..de27431633f
--- /dev/null
+++ b/src/content/partials/agents/troubleshooting.mdx
@@ -0,0 +1,111 @@
+---
+{}
+---
+
+import { TypeScriptExample, WranglerConfig } from "~/components";
+
+## Troubleshooting
+
+### Agent not found, or 404 errors
+
+1. **Check the export** - Agent class must be exported from your main entry point.
+2. **Check the binding** - `class_name` in the Wrangler configuration file must exactly match the exported class name.
+3. **Check the route** - Default route is `/agents/{'{agent-name}'}/{'{instance-name}'}`. Agent name in client matches the class name (case-insensitive).
+
+### No such Durable Object class error
+
+Add the migration to the Wrangler configuration file:
+
+
+
+```toml
+[[migrations]]
+tag = "v1"
+new_sqlite_classes = ["YourAgentClass"]
+```
+
+
+
+### WebSocket connection fails
+
+Ensure your routing passes the response unchanged:
+
+
+
+```ts
+// Correct - return the response directly
+const agentResponse = await routeAgentRequest(request, env);
+if (agentResponse) return agentResponse;
+
+// Wrong - this breaks WebSocket connections
+if (agentResponse) return new Response(agentResponse.body);
+```
+
+
+
+### State not persisting
+
+Check that:
+
+1. You are calling `this.setState()`, not mutating `this.state` directly.
+2. The agent class is in `new_sqlite_classes` in migrations.
+3. You are connecting to the same agent instance name.
+4. The `onStateUpdate` callback is wired up in your client.
+5. WebSocket connection is established (check browser dev tools).
+
+### "Method X is not callable" errors
+
+Make sure your methods are decorated with `@callable()`:
+
+
+
+```ts
+import { Agent, callable } from "agents";
+
+export class MyAgent extends Agent {
+ @callable()
+ increment() {
+ // ...
+ }
+}
+```
+
+
+
+### Type errors with `agent.stub`
+
+Add the agent and state type parameters:
+
+
+
+```ts
+import { useAgent } from "agents/react";
+import type { CounterAgent, CounterState } from "./server";
+
+// Pass the agent and state types to useAgent
+const agent = useAgent({
+ agent: "CounterAgent",
+ onStateUpdate: (state) => setCount(state.count),
+});
+
+// Now agent.stub is fully typed
+agent.stub.increment();
+```
+
+
+
+### `SyntaxError: Invalid or unexpected token` with `@callable()`
+
+If your dev server fails with `SyntaxError: Invalid or unexpected token`, set `"target": "ES2021"` in your `tsconfig.json`. This ensures that Vite's esbuild transpiler downlevels TC39 decorators instead of passing them through as native syntax.
+
+```json
+{
+ "compilerOptions": {
+ "target": "ES2021"
+ }
+}
+```
+
+:::caution
+Do not set `"experimentalDecorators": true` in your `tsconfig.json`. The Agents SDK uses [TC39 standard decorators](https://github.com/tc39/proposal-decorators), not TypeScript legacy decorators. Enabling `experimentalDecorators` applies an incompatible transform that silently breaks `@callable()` at runtime.
+:::
\ No newline at end of file
diff --git a/src/content/partials/agents/what-just-happened.mdx b/src/content/partials/agents/what-just-happened.mdx
new file mode 100644
index 00000000000..dbcd1da0988
--- /dev/null
+++ b/src/content/partials/agents/what-just-happened.mdx
@@ -0,0 +1,28 @@
+---
+{}
+---
+
+## How it works
+
+When you clicked the button:
+
+1. **Client** called `agent.stub.increment()` over WebSocket
+2. **Agent** ran `increment()`, updated state with `setState()`
+3. **State** persisted to SQLite automatically
+4. **Broadcast** sent to all connected clients
+5. **React** updated via `onStateUpdate`
+
+```mermaid
+flowchart LR
+ A["Browser
(React)"] <-->|WebSocket| B["Agent
(Counter)"]
+ B --> C["SQLite
(State)"]
+```
+
+### Key concepts
+
+| Concept | What it means |
+| -------------------- | ----------------------------------------------------------------------------------------------------- |
+| **Agent instance** | Each unique name gets its own agent. `CounterAgent:user-123` is separate from `CounterAgent:user-456` |
+| **Persistent state** | State survives restarts, deploys, and hibernation. It is stored in SQLite |
+| **Real-time sync** | All clients connected to the same agent receive state updates instantly |
+| **Hibernation** | When no clients are connected, the agent hibernates (no cost). It wakes on the next request |