# @cloudflare/think An Agent base class for AI assistants on Cloudflare Workers. Handles the full chat lifecycle — session management, agentic loop, streaming, persistence, workspace tools, and extensions — all backed by Durable Object SQLite. Works as both a **top-level agent** (WebSocket chat protocol for browser clients) and a **sub-agent** (RPC streaming from a parent agent). > **Experimental** — requires the `"experimental"` compatibility flag. ## Quick start ```ts import { Think } from "@cloudflare/think"; import { createWorkersAI } from "workers-ai-provider"; import { createWorkspaceTools } from "@cloudflare/think/tools/workspace"; import { Workspace } from "@cloudflare/shell"; export class ChatSession extends Think { workspace = new Workspace(this); getModel() { return createWorkersAI({ binding: this.env.AI })( "@cf/moonshotai/kimi-k2.5" ); } getSystemPrompt() { return "You are a helpful coding assistant."; } getTools() { return createWorkspaceTools(this.workspace); } } ``` That's it. `Think` handles the WebSocket chat protocol, session persistence, the agentic loop, message sanitization, and streaming. Connect from the browser with `useAgentChat` or `useChat` + `AgentChatTransport`. ## Exports | Export | Description | | ------------------------------------ | --------------------------------------------------------------- | | `@cloudflare/think` | `Think` — the main class, plus types | | `@cloudflare/think/session` | `SessionManager` — conversation persistence with branching | | `@cloudflare/think/tools/workspace` | `createWorkspaceTools()` — file operation tools | | `@cloudflare/think/tools/execute` | `createExecuteTool()` — sandboxed code execution via codemode | | `@cloudflare/think/tools/extensions` | `createExtensionTools()` — LLM-driven extension loading | | `@cloudflare/think/extensions` | `ExtensionManager`, `HostBridgeLoopback` — extension runtime | | `@cloudflare/think/transport` | `AgentChatTransport` — bridges `useChat` with Agent WebSocket | | `@cloudflare/think/message-builder` | `applyChunkToParts()` — reconstruct UIMessage parts from chunks | ## Think ### Override points | Method | Default | Description | | ------------------------- | -------------------------------- | ------------------------------------- | | `getModel()` | throws | Return the `LanguageModel` to use | | `getSystemPrompt()` | `"You are a helpful assistant."` | System prompt | | `getTools()` | `{}` | AI SDK `ToolSet` for the agentic loop | | `getMaxSteps()` | `10` | Max tool-call rounds per turn | | `assembleContext()` | prune older tool calls | Customize what's sent to the LLM | | `onChatMessage(options?)` | `streamText(...)` | Full control over inference | | `onChatError(error)` | passthrough | Customize error handling | | `getWorkspace()` | `null` | Workspace for extension host bridge | ### Session management Think manages multiple named sessions per agent instance. Sessions are created automatically on the first chat message, or explicitly: ```ts session.createSession("research"); session.switchSession(sessionId); session.getSessions(); // Session[] session.deleteSession(id); session.renameSession(id, "new name"); session.getCurrentSessionId(); ``` ### Sub-agent streaming via RPC When used as a sub-agent, the `chat()` method runs a full turn and streams events via a callback: ```ts // StreamCallback — implement as an RpcTarget in the parent interface StreamCallback { onEvent(json: string): void | Promise; onDone(): void | Promise; onError?(error: string): void | Promise; } const session = await this.subAgent(ChatSession, "agent-abc"); await session.chat("Summarize the project", relay, { tools: extraTools, signal: abortController.signal }); ``` ### Dynamic configuration Think accepts a `Config` type parameter for per-instance configuration persisted in SQLite: ```ts type MyConfig = { modelTier: "fast" | "capable"; systemPrompt: string }; export class ChatSession extends Think { getModel() { const tier = this.getConfig()?.modelTier ?? "fast"; return createWorkersAI({ binding: this.env.AI })(MODEL_IDS[tier]); } } // From the parent: const session = await this.subAgent(ChatSession, "agent-abc"); await session.configure({ modelTier: "capable", systemPrompt: "..." }); ``` ### Production features - **WebSocket protocol** — wire-compatible with `useAgentChat` / `useChat` - **Multi-session** — create, switch, list, delete, rename conversations - **Abort/cancel** — pass an `AbortSignal` or send a cancel message - **Partial persistence** — on error, the partial assistant message is saved - **Message sanitization** — strips ephemeral provider metadata before storage - **Row size enforcement** — compacts tool outputs exceeding 1.8MB - **Incremental persistence** — skips SQL writes for unchanged messages - **Storage bounds** — set `maxPersistedMessages` to cap stored history ## SessionManager Persistent conversation storage with tree-structured messages (branching) and compaction. Used internally by Think, but also usable standalone. ```ts import { SessionManager } from "@cloudflare/think/session"; const sessions = new SessionManager(agent); const session = sessions.create("my-chat"); sessions.append(session.id, userMessage); const history = sessions.getHistory(session.id); // UIMessage[] ``` Also exports truncation utilities (`truncateHead`, `truncateTail`, `truncateMiddle`, `truncateLines`) for managing large tool outputs. ## Workspace tools File operation tools backed by the Agents SDK `Workspace`: ```ts import { createWorkspaceTools } from "@cloudflare/think/tools/workspace"; const tools = createWorkspaceTools(this.workspace); // Tools: read, write, edit, list, find, grep, delete ``` Each tool is an AI SDK `tool()` with Zod schemas. The underlying operations are abstracted behind interfaces (`ReadOperations`, `WriteOperations`, etc.) so you can create tools backed by custom storage. ## Code execution tool Let the LLM write and run JavaScript in a sandboxed Worker: ```ts import { createExecuteTool } from "@cloudflare/think/tools/execute"; getTools() { const wsTools = createWorkspaceTools(this.workspace); return { ...wsTools, execute: createExecuteTool({ tools: wsTools, loader: this.env.LOADER }) }; } ``` Requires `@cloudflare/codemode` and a `worker_loaders` binding in `wrangler.jsonc`. ## Extensions Dynamic tool loading at runtime. The LLM can write extension source code, load it as a sandboxed Worker, and use the new tools on the next turn. ```ts import { ExtensionManager } from "@cloudflare/think/extensions"; import { createExtensionTools } from "@cloudflare/think/tools/extensions"; const extensions = new ExtensionManager({ loader: this.env.LOADER, workspace: this.workspace }); getTools() { return { ...createWorkspaceTools(this.workspace), ...createExtensionTools({ manager: extensions }), ...extensions.getTools() }; } ``` Extensions get permission-gated workspace access via `HostBridgeLoopback`. Re-export it from your worker entry point: ```ts export { HostBridgeLoopback } from "@cloudflare/think/extensions"; ``` ## Chat transport Client-side transport that bridges `useChat` with Agent WebSocket streaming: ```tsx import { AgentChatTransport } from "@cloudflare/think/transport"; import { useAgent } from "agents/react"; import { useChat } from "@ai-sdk/react"; const agent = useAgent({ agent: "ChatSession" }); const transport = useMemo(() => new AgentChatTransport(agent), [agent]); const { messages, sendMessage, status } = useChat({ transport }); ``` Options: `sendMethod` (RPC method name, default `"sendMessage"`), `resumeTimeout` (ms, default `500`). Call `transport.detach()` before switching agents. ## Message builder Reconstruct `UIMessage` parts from stream chunks: ```ts import { applyChunkToParts } from "@cloudflare/think/message-builder"; const msg = { id: "...", role: "assistant", parts: [] }; for (const chunk of streamChunks) { applyChunkToParts(msg.parts, chunk); } ``` Handles all AI SDK chunk types: `text-delta`, `reasoning-delta`, `tool-call`, `tool-result`, `source`, `file`, and more. ## Peer dependencies | Package | Required | Notes | | ---------------------- | -------- | --------------------------------- | | `agents` | yes | Cloudflare Agents SDK | | `ai` | yes | Vercel AI SDK v6 | | `zod` | yes | Schema validation (v3.25+ or v4) | | `@cloudflare/codemode` | optional | For `createExecuteTool` | | `@cloudflare/shell` | optional | For shell execution in extensions |