5.3 内置工具源码逐个剖析

模型: claude-opus-4-6 (anthropic/claude-opus-4-6) 生成日期: 2025-02-17


OpenCode 内置了 20+ 个工具,按功能可分为六大类。本节对每一类的代表工具进行源码分析。

5.3.1 文件操作类

read.ts — 文件读取

parameters: z.object({
  filePath: z.string(),           // 文件绝对路径
  offset: z.number().optional(),  // 起始行号(1-indexed)
  limit: z.number().optional(),   // 最大行数(默认 2000)
})

关键实现:

  • 每行输出添加行号前缀(如 "1: import fs from 'fs'"),帮助 LLM 定位代码位置

  • 支持读取目录(返回目录条目列表)

  • 支持读取图片/PDF(返回为 FilePart 附件)

  • 自动检测二进制文件并拒绝读取

  • 超长行(>2000 字符)会被截断

edit.ts — 精确字符串替换

这是最复杂的工具之一。参数设计:

核心算法

  1. 读取文件内容

  2. 搜索 oldString 的精确匹配

  3. 如果匹配 0 次 → 尝试模糊匹配修正(处理 LLM 常见的缩进错误、空行差异等)

  4. 如果匹配多次且 replaceAll 为 false → 报错要求提供更多上下文

  5. 执行替换

  6. 生成 diff 用于展示

  7. 执行 LSP diagnostics 检查修改后的文件

模糊匹配修正(源自 Cline 和 Gemini CLI 的开源实现):

这说明 OpenCode 积极借鉴了社区的最佳实践——AI 在生成代码替换时经常出现缩进不一致的问题,模糊匹配可以大幅提高编辑成功率。

write.ts — 文件写入

创建新文件或完整覆盖现有文件。会自动创建中间目录。

glob.ts — 文件模式匹配

基于 Bun 内置的 Glob 实现,支持 **/*.ts 等模式。有安全限制(60秒超时、100文件上限)。

grep.ts — 正则搜索

底层使用 ripgrep(file/ripgrep.ts),支持正则表达式和文件类型过滤。

5.3.2 执行类

bash.ts — Shell 命令执行

安全特性

  • Tree-sitter 解析:使用 web-tree-sitter 的 Bash 语法解析器分析命令,提取可能涉及的文件路径

  • 权限粒度控制BashArity):基于解析结果,将命令归类为不同的权限粒度

  • 超时保护:默认 2 分钟,可通过参数或环境变量调整

  • 工作目录隔离:默认在项目目录下执行,支持 workdir 参数

batch.ts — 批量工具调用

batch 工具允许 LLM 在一次调用中并行执行多个工具——例如同时读取 5 个文件、同时执行 3 个 grep 搜索。这显著减少了 Agentic Loop 的轮次。

5.3.3 代码智能类

lsp.ts — LSP 操作集合

衍生概念:LSP(Language Server Protocol)

LSP 是微软提出的协议标准,定义了代码编辑器与"语言服务器"之间的通信方式。语言服务器提供代码智能功能:自动补全、跳转定义、查找引用、诊断错误等。通过 LSP,OpenCode 可以获得与 IDE 相当的代码理解能力。

lsp.ts 封装了以下 LSP 操作:

操作
功能

goto_definition

跳转到符号定义

find_references

查找符号的所有引用

document_symbols

获取文件内所有符号

workspace_symbols

在整个项目中搜索符号

diagnostics

获取文件的诊断信息(错误/警告)

prepare_rename

检查符号是否可重命名

rename

重命名符号(跨文件)

5.3.4 网络类

webfetch.ts — URL 内容获取

获取指定 URL 的内容,支持转换为 Markdown、纯文本或 HTML 格式。

websearch.ts — 网络搜索

使用搜索引擎 API 搜索网络内容。

5.3.5 Agent 协作类

task.ts — 子 Agent 任务委托

task 工具是多 Agent 协作的核心。它创建一个子 Session,使用指定的 Agent 执行任务:

执行流程:

  1. 根据 subagent_type 查找对应的 Agent 配置

  2. 进行权限检查(ctx.ask({ permission: "task", patterns: [subagent_type] })

  3. 创建子 Session(Session.create({ parentID: ... }))或恢复已有 Session(通过 task_id

  4. 在子 Session 中执行对话

  5. 将子 Session 的最终结果返回给父 Session

  6. 返回结果中包含 session_id,方便后续恢复

question.ts — 交互式提问

允许 Agent 向用户发起结构化的问答(如多选题)。

5.3.6 辅助类

todo.ts — Todo 列表管理

TodoWriteToolTodoReadTool 为 Agent 提供了任务追踪能力。LLM 可以创建 Todo 列表来规划工作步骤,并在完成后更新状态。

skill.ts — Skill 加载

加载 Markdown 格式的 Skill 文件到对话上下文中。

plan.ts — Plan 模式

PlanEnterToolPlanExitTool 让 Agent 在只读的 "规划模式" 和可写的 "执行模式" 之间切换。

apply_patch.ts — Diff 补丁应用

接受标准的 unified diff 格式补丁并应用到文件系统。

5.3.7 工具的 Prompt Template

每个工具都有一个对应的 .txt 描述文件(如 bash.txtedit.txt),包含发送给 LLM 的工具描述文本。这种代码与 Prompt 分离的设计使得:

  • Prompt 调优不需要修改 TypeScript 代码

  • 描述文本可以包含复杂的 Markdown 格式和示例

  • 支持模板变量(如 ${directory} 会被替换为当前目录)

例如 bash.txt 中可能包含:

BashToolinit 中:

Last updated