branch:
README.md
9347 bytesRaw
# @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<Env> {
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<void>;
onDone(): void | Promise<void>;
onError?(error: string): void | Promise<void>;
}
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<Env, MyConfig> {
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 |