Think 在每轮次提供内置工作区文件工具,并提供自定义工具、代码执行与动态扩展的集成点。
每轮次 Think 从多个来源合并工具。若名称冲突,后出现的来源覆盖较早的:
- 工作区工具 —
read、write、edit、list、find、grep、delete、bash(内置) getTools()— 你的自定义服务端工具- 扩展工具 — 已加载扩展的工具(以扩展名前缀)
- 会话工具 —
set_context、load_context、search_context(来自configureSession) - 技能工具 —
activate_skill、read_skill_resource、run_skill_script(来自getSkills(),请参阅 Agent Skills) - MCP 工具 — 当
includeMcpTools为true时,来自已连接 MCP 服务器 - 客户端工具 — 来自浏览器(请参阅 客户端工具)
工具属于执行轮次的 agent。父子编排请使用 Agent 作为工具,而非通过 chat() 传递一次性工具。
每个 Think agent 拥有 this.workspace——由 Durable Object SQLite 支持的虚拟文件系统。工作区工具自动对模型可用,无需配置。
| 工具 | 描述 |
|---|---|
read |
带行号读取文本;将图片与 PDF 传给多模态模型 |
write |
将内容写入文件(创建父目录) |
edit |
对现有文件应用查找替换编辑(支持模糊匹配) |
list |
列出路径中的文件与目录 |
find |
按 glob 模式查找文件 |
grep |
按正则或固定字符串搜索文件内容 |
delete |
删除文件或目录 |
bash |
针对工作区文件运行沙箱化 Bash 脚本 |
bash 工具默认启用。它将工作区文件挂载到 just-bash 虚拟文件系统,禁用网络访问,并将创建、更新、删除的文件与空目录写回工作区。适用于组合多个文件操作的 shell 式工作流;简单读写编辑请用更窄的工具。
为限制工具调用范围,Bash 工具默认快照最多 1,000 个工作区文件,并跳过大于 1 MB 的文件。跳过的文件会在工具结果中报告,写回时视为受保护,脚本无法意外覆盖或删除未挂载的内容。可通过 workspaceBash 调整 maxWorkspaceFiles、maxWorkspaceFileBytes、maxOutputBytes、timeout 与 network。
保守部署可禁用默认 Bash 工具:
export class MyAgent extends Think {
workspaceBash = false;
getModel() {
/* ... */
}
}export class MyAgent extends Think<Env> {
workspaceBash = false;
getModel() {
/* ... */
}
}默认工作区将所有内容存储在 SQLite 中。大文件可覆盖 workspace 以添加 R2 溢出:
import { Think } from "@cloudflare/think";
import { Workspace } from "@cloudflare/shell";
export class MyAgent extends Think {
workspace = new Workspace({
sql: this.ctx.storage.sql,
r2: this.env.R2,
name: () => this.name,
});
getModel() {
/* ... */
}
}import { Think } from "@cloudflare/think";
import { Workspace } from "@cloudflare/shell";
export class MyAgent extends Think<Env> {
override workspace = new Workspace({
sql: this.ctx.storage.sql,
r2: this.env.R2,
name: () => this.name,
});
getModel() {
/* ... */
}
}需要 R2 存储桶绑定(binding):
{
"$schema": "./node_modules/wrangler/config-schema.json",
"r2_buckets": [
{
"binding": "R2",
"bucket_name": "agent-files"
}
]
}[[r2_buckets]]
binding = "R2"
bucket_name = "agent-files"覆盖 getTools() 以添加自定义工具。这些是带 Zod schema 的标准 AI SDK tool() 定义:
import { Think } from "@cloudflare/think";
import { tool } from "ai";
import { z } from "zod";
export class MyAgent extends Think {
getModel() {
/* ... */
}
getTools() {
return {
getWeather: tool({
description: "Get the current weather for a city",
inputSchema: z.object({
city: z.string().describe("City name"),
}),
execute: async ({ city }) => {
const res = await fetch(
`https://api.weather.com/v1/current?q=${city}&key=${this.env.WEATHER_KEY}`,
);
return res.json();
},
}),
};
}
}import { Think } from "@cloudflare/think";
import { tool } from "ai";
import type { ToolSet } from "ai";
import { z } from "zod";
export class MyAgent extends Think<Env> {
getModel() {
/* ... */
}
getTools(): ToolSet {
return {
getWeather: tool({
description: "Get the current weather for a city",
inputSchema: z.object({
city: z.string().describe("City name"),
}),
execute: async ({ city }) => {
const res = await fetch(
`https://api.weather.com/v1/current?q=${city}&key=${this.env.WEATHER_KEY}`,
);
return res.json();
},
}),
};
}
}自定义工具会自动与工作区工具合并。若自定义工具与工作区工具同名,自定义工具优先。
工具可在执行前通过 needsApproval 选项要求用户审批:
getTools(): ToolSet {
return {
deleteFile: tool({
description: "Delete a file from the system",
inputSchema: z.object({ path: z.string() }),
needsApproval: async ({ path }) => path.startsWith("/important/"),
execute: async ({ path }) => {
await this.workspace.rm(path);
return { deleted: path };
},
}),
};
}当 needsApproval 返回 true 时,工具调用会发送到客户端等待审批。对话暂停,直到客户端以 CF_AGENT_TOOL_APPROVAL 响应。
beforeTurn 钩子可限制或添加特定轮次的工具:
beforeTurn(ctx: TurnContext) {
return {
activeTools: ["read", "write", "getWeather"],
tools: { emergencyTool: this.createEmergencyTool() },
};
}activeTools 限制模型可调用的工具。tools 仅在本轮次添加额外工具(合并到现有工具之上)。
Think 从 Agent 基类继承 MCP 客户端支持。默认 Think 将已连接 MCP 服务器的工具转换为 AI SDK 工具并添加到每轮次。
设置 waitForMcpConnections 以确保推理运行前 MCP 服务器已连接:
export class MyAgent extends Think {
waitForMcpConnections = true; // default 10s timeout
// or: waitForMcpConnections = { timeout: 5000 };
getModel() {
/* ... */
}
}export class MyAgent extends Think<Env> {
waitForMcpConnections = true; // default 10s timeout
// or: waitForMcpConnections = { timeout: 5000 };
getModel() {
/* ... */
}
}若通过 Code Mode 或 Think 自动工具集之外的机制暴露 MCP 工具,请关闭直接 AI SDK 工具暴露:
export class MyAgent extends Think {
includeMcpTools = false;
waitForMcpConnections = true;
getModel() {
/* ... */
}
}export class MyAgent extends Think<Env> {
includeMcpTools = false;
waitForMcpConnections = true;
getModel() {
/* ... */
}
}includeMcpTools 仅控制自动模型工具合并。MCP 连接仍会注册、恢复、发现并等待。原始目录访问、直接调用、Code Mode 连接器与显式 this.mcp.getAITools() 调用仍可用。
请使用此属性,而非在 beforeTurn 中通过 activeTools 移除 MCP 工具名称。Think 在调用 beforeTurn 之前转换 MCP schema,因此 activeTools 无法避免该转换。配置连接器运行时请参阅将 MCP 工具与 Code Mode 配合使用。
可通过编程或 @callable 方法添加 MCP 服务器:
import { callable } from "agents";
export class MyAgent extends Think {
getModel() {
/* ... */
}
@callable()
async addServer(name, url) {
return await this.addMcpServer(name, url);
}
@callable()
async removeServer(serverId) {
await this.removeMcpServer(serverId);
}
}import { callable } from "agents";
export class MyAgent extends Think<Env> {
getModel() {
/* ... */
}
@callable()
async addServer(name: string, url: string) {
return await this.addMcpServer(name, url);
}
@callable()
async removeServer(serverId: string) {
await this.removeMcpServer(serverId);
}
}让 LLM 在沙箱化 Worker 中编写并运行 JavaScript,记录在持久 Code Mode 运行时上(中止并重放、人工审批、审计追踪、可复用代码片段)。需要 @cloudflare/codemode 与 worker_loaders 绑定(binding)。
npm install @cloudflare/codemode一行代码从 agent 推断一切——state.* 来自 this.workspace,执行器来自 env.LOADER,若已绑定则实时浏览器(cdp.*)来自 env.BROWSER:
import { Think } from "@cloudflare/think";
import { createExecuteTool } from "@cloudflare/think/tools/execute";
export class MyAgent extends Think {
getModel() {
/* ... */
}
getTools() {
return {
execute: createExecuteTool(this),
};
}
}import { Think } from "@cloudflare/think";
import { createExecuteTool } from "@cloudflare/think/tools/execute";
export class MyAgent extends Think<Env> {
getModel() {
/* ... */
}
getTools() {
return {
execute: createExecuteTool(this),
};
}
}设置清单:
{
"$schema": "./node_modules/wrangler/config-schema.json",
"worker_loaders": [
{
"binding": "LOADER"
}
],
"browser": {
"binding": "BROWSER"
}
}[[worker_loaders]]
binding = "LOADER"
[browser]
binding = "BROWSER" # 可选 — 启用 cdp.*// worker 入口 — runtime 位于 Durable Object facet,因此必须导出类
// (@cloudflare/codemode/vite 插件会自动处理;Think 框架生成的入口已包含)
export { CodemodeRuntime } from "@cloudflare/codemode";// worker 入口 — runtime 位于 Durable Object facet,因此必须导出类
// (@cloudflare/codemode/vite 插件会自动处理;Think 框架生成的入口已包含)
export { CodemodeRuntime } from "@cloudflare/codemode";缺少任一部分会以命名该步骤的错误失败。
沙箱内模型可见类型化命名空间及平台 SDK:
tools.*— 你的 AI SDK 工具(对象参数,按 schema 验证)。仅暴露带execute函数的工具——客户端工具无法在沙箱中运行。state.*— 工作区文件系统(state.readFile({ path })、state.glob({ pattern })、state.planEdits(...)等)。cdp.*— 配置 Browser Run 绑定时可用浏览器。execute 工具默认为session: { mode: "dynamic" }:除非模型用cdp.startSession()提升,否则每次执行一个会话。codemode.search/codemode.describe/codemode.step/codemode.run— 发现、副作用边界与保存代码片段。
超出默认项可传入覆盖——例如 agent 派生状态旁添加自定义 tools.*:
execute: createExecuteTool(this, { tools: myDomainTools });execute: createExecuteTool(this, { tools: myDomainTools });或完全显式选项(无 agent 推断):
import { createWorkspaceStateBackend } from "@cloudflare/shell";
createExecuteTool({
ctx: this.ctx,
tools: myDomainTools,
state: createWorkspaceStateBackend(this.workspace),
browser: this.env.BROWSER,
loader: this.env.LOADER,
});import { createWorkspaceStateBackend } from "@cloudflare/shell";
createExecuteTool({
ctx: this.ctx,
tools: myDomainTools,
state: createWorkspaceStateBackend(this.workspace),
browser: this.env.BROWSER,
loader: this.env.LOADER,
});带 needsApproval 的 AI SDK 工具在沙箱内不会立即运行——调用会持久化暂停运行。暂停以普通工具输出返回({ status: "paused", executionId, pending }),模型告知用户所需内容,轮次结束。这与普通 getTools() 工具的客户端审批流程不同:沙箱内函数型 needsApproval 无法提前针对调用参数求值,因此保守地始终需要审批。Think 提供内置可调用方法来解决:
approveExecution(executionId)— 从暂停处恢复运行。已完成工作重放,不重新执行。结果替换转录中的暂停输出,聊天自动继续。rejectExecution(executionId, reason?)— 以{ status: "rejected", reason }结束运行,供模型调整。pendingExecutions()— 待处理操作(含完整参数),用于渲染审批 UI。
可工作的审批卡片请参阅 assistant 示例 ↗。
当宿主需要的不止工具时,createExecuteRuntime 返回活动部件——从 agent 创建时句柄也会赋给 this.codemode:
import { createExecuteRuntime } from "@cloudflare/think/tools/execute";
const { runtime, connectors, tool } = createExecuteRuntime(this);
await runtime.executions(); // 审计追踪
await runtime.expirePaused(); // 回收从未审批的过期暂停(从定时任务调用)
await runtime.saveSnippet("name", { executionId }); // 提升脚本供复用import { createExecuteRuntime } from "@cloudflare/think/tools/execute";
const { runtime, connectors, tool } = createExecuteRuntime(this);
await runtime.executions(); // 审计追踪
await runtime.expirePaused(); // 回收从未审批的过期暂停(从定时任务调用)
await runtime.saveSnippet("name", { executionId }); // 提升脚本供复用为 agent 提供 Chrome DevTools Protocol (CDP) 访问,用于网页检查、抓取、截图与调试。需要 @cloudflare/codemode 与 Browser Run 绑定(binding)。
import { Think } from "@cloudflare/think";
import { createBrowserTools } from "@cloudflare/think/tools/browser";
export class MyAgent extends Think {
getModel() {
/* ... */
}
getTools() {
return {
...createBrowserTools({
ctx: this.ctx,
browser: this.env.BROWSER,
loader: this.env.LOADER,
}),
};
}
}import { Think } from "@cloudflare/think";
import { createBrowserTools } from "@cloudflare/think/tools/browser";
export class MyAgent extends Think<Env> {
getModel() {
/* ... */
}
getTools() {
return {
...createBrowserTools({
ctx: this.ctx,
browser: this.env.BROWSER,
loader: this.env.LOADER,
}),
};
}
}{
"$schema": "./node_modules/wrangler/config-schema.json",
"browser": {
"binding": "BROWSER"
},
"worker_loaders": [
{
"binding": "LOADER"
}
]
}[browser]
binding = "BROWSER"
[[worker_loaders]]
binding = "LOADER"存在 browser 绑定时,会添加持久 CDP 工具以及无状态 Quick Action 工具:
| 工具 | 描述 |
|---|---|
browser_execute |
通过 CDP 对实时浏览器运行 JavaScript(截图、DOM 读取、JS 求值)。 |
browser_markdown |
将页面或原始 HTML 读取为 Markdown。 |
browser_extract |
用 AI 从页面提取结构化数据。 |
browser_links |
列出页面链接。 |
browser_scrape |
按 CSS 选择器抓取特定元素。 |
传入 quickActions: false 仅保留 browser_execute,或传入 quickActions: { actions, maxChars, options } 配置无状态工具。Quick Action 工具共享 browser 绑定,无需 Worker Loader,并自动从当前 Agent 解析 ctx。仅使用无状态工具时,从 @cloudflare/think/tools/browser 导入 createQuickActionTools。
该工具由带 cdp 连接器的 Code Mode 运行时支持:模型编写在沙箱化 Worker isolate 中运行的 async 箭头函数,含 cdp.send()、cdp.attachToTarget()、cdp.spec()(实时规范化协议描述)、会话辅助(cdp.startSession()、cdp.sessionInfo()、cdp.closeSession())与调试日志辅助。执行被记录以支持中止并重放,浏览器会话可在审批暂停后继续存活。
默认每次执行获得全新浏览器会话(one-shot),运行结束时拆除。传入 session: { mode: "dynamic" } 让模型用 cdp.startSession() 提升会话,后续执行在同一浏览器中继续;或 session: { mode: "reuse", key } 使用命名长生命周期会话。过期会话由连接器的 sweep() 回收——从定时任务调用。
自定义 Chrome 端点可传入 cdpUrl 替代 browser:
createBrowserTools({
ctx: this.ctx,
cdpUrl: "http://localhost:9222",
loader: this.env.LOADER,
});createBrowserTools({
ctx: this.ctx,
cdpUrl: "http://localhost:9222",
loader: this.env.LOADER,
});完整 CDP connector API 请参阅浏览 Web。
扩展是运行时动态加载的沙箱化 Worker,可添加工具。LLM 可编写扩展源码、加载它,并在下一轮次使用新工具。
扩展需要 worker_loaders 绑定(binding):
import { Think } from "@cloudflare/think";
export class MyAgent extends Think {
extensionLoader = this.env.LOADER;
getModel() {
/* ... */
}
}import { Think } from "@cloudflare/think";
export class MyAgent extends Think<Env> {
extensionLoader = this.env.LOADER;
getModel() {
/* ... */
}
}定义启动时加载的扩展:
export class MyAgent extends Think {
extensionLoader = this.env.LOADER;
getModel() {
/* ... */
}
getExtensions() {
return [
{
manifest: {
name: "math",
version: "1.0.0",
permissions: { network: false },
},
source: `({
tools: {
add: {
description: "Add two numbers",
parameters: { a: { type: "number" }, b: { type: "number" } },
execute: async ({ a, b }) => ({ result: a + b })
}
}
})`,
},
];
}
}export class MyAgent extends Think<Env> {
extensionLoader = this.env.LOADER;
getModel() {
/* ... */
}
getExtensions() {
return [
{
manifest: {
name: "math",
version: "1.0.0",
permissions: { network: false },
},
source: `({
tools: {
add: {
description: "Add two numbers",
parameters: { a: { type: "number" }, b: { type: "number" } },
execute: async ({ a, b }) => ({ result: a + b })
}
}
})`,
},
];
}
}扩展工具有命名空间——math 扩展的 add 工具在模型工具集中变为 math_add。
向模型提供 createExtensionTools,使其可动态加载扩展:
import { createExtensionTools } from "@cloudflare/think/tools/extensions";
export class MyAgent extends Think {
extensionLoader = this.env.LOADER;
getModel() {
/* ... */
}
getTools() {
return {
...createExtensionTools({ manager: this.extensionManager }),
...this.extensionManager.getTools(),
};
}
}import { createExtensionTools } from "@cloudflare/think/tools/extensions";
export class MyAgent extends Think<Env> {
extensionLoader = this.env.LOADER;
getModel() {
/* ... */
}
getTools() {
return {
...createExtensionTools({ manager: this.extensionManager! }),
...this.extensionManager!.getTools(),
};
}
}这会向模型提供两个工具:
load_extension— 从 JavaScript 源码加载新扩展list_extensions— 列出当前已加载扩展
扩展可在清单中声明上下文块,自动注册到 Session:
getExtensions() {
return [{
manifest: {
name: "notes",
version: "1.0.0",
permissions: { network: false },
context: [
{ label: "scratchpad", description: "Extension scratch space", maxTokens: 500 },
],
},
source: `({ tools: { /* ... */ } })`,
}];
}上下文块注册为 notes_scratchpad(以扩展名命名空间)。
各工具工厂已导出,可与自定义存储后端配合使用:
import {
createReadTool,
createWriteTool,
createEditTool,
createListTool,
createFindTool,
createGrepTool,
createDeleteTool,
createWorkspaceTools,
} from "@cloudflare/think/tools/workspace";import {
createReadTool,
createWriteTool,
createEditTool,
createListTool,
createFindTool,
createGrepTool,
createDeleteTool,
createWorkspaceTools,
} from "@cloudflare/think/tools/workspace";为存储后端实现操作接口:
const myReadOps = {
readFile: async (path) => fetchFromMyStorage(path),
stat: async (path) => getFileInfo(path),
};
const readTool = createReadTool({ ops: myReadOps });import type { ReadOperations } from "@cloudflare/think/tools/workspace";
const myReadOps: ReadOperations = {
readFile: async (path) => fetchFromMyStorage(path),
stat: async (path) => getFileInfo(path),
};
const readTool = createReadTool({ ops: myReadOps });或从 Workspace 创建完整工具集,可选禁用 Bash 工具:
import { createWorkspaceTools } from "@cloudflare/think/tools/workspace";
const tools = createWorkspaceTools(myCustomWorkspace);
const toolsWithoutBash = createWorkspaceTools(myCustomWorkspace, {
bash: false,
});import { createWorkspaceTools } from "@cloudflare/think/tools/workspace";
const tools = createWorkspaceTools(myCustomWorkspace);
const toolsWithoutBash = createWorkspaceTools(myCustomWorkspace, {
bash: false,
});