15.4 自定义工具系统
模型: claude-opus-4-6 (anthropic/claude-opus-4-6) 生成日期: 2026-02-17
oh-my-opencode 通过 OpenCode 的 Plugin tool 接口注册了 15 个自定义工具,为 Agent 提供了远超 OpenCode 内置工具集的能力。本节将概览这些工具,并深入分析两个最具创新性的工具:AST-Grep 和 Hashline Edit。
15.4.1 工具列表与实现
以下是 oh-my-opencode 注册的全部工具:
ast_grep_search
tools/ast-grep/
AST 级代码模式搜索
ast-grep CLI
ast_grep_replace
tools/ast-grep/
AST 级代码模式替换
ast-grep CLI
background_output
tools/background-task/
获取后台任务输出
OpenCode SDK
background_cancel
tools/background-task/
取消后台任务
OpenCode SDK
call_omo_agent
tools/call-omo-agent/
直接调用指定 Agent
OpenCode SDK
delegate_task
tools/delegate-task/
将任务委托给子 Agent
OpenCode SDK
glob
tools/glob/
增强版文件模式匹配
Node.js fs
grep
tools/grep/
增强版内容搜索
ripgrep
hashline_edit
tools/hashline-edit/
基于行号哈希的精确编辑
xxHash32
interactive_bash
tools/interactive-bash/
tmux 交互式终端
tmux
look_at
tools/look-at/
多模态文件分析
多模态 LLM
lsp_*(6 个)
tools/lsp/
LSP 集成(定义跳转、引用查找等)
LSP 协议
session_*
tools/session-manager/
会话历史查询与搜索
OpenCode Storage
skill_mcp
tools/skill-mcp/
Skill 内嵌 MCP 调用
MCP SDK
skill
tools/skill/
Skill 文件加载
文件系统
slashcommand
tools/slashcommand/
斜杠命令执行
命令系统
task
tools/task/
增强版任务委托
OpenCode SDK
工具注册的入口在 tools/index.ts:
工具分为两种注册模式:
静态工具(如
builtinTools中的 LSP 工具):不需要运行时上下文,直接导出工厂工具(如
createAstGrepTools(ctx)):需要注入 Plugin 上下文(目录路径、客户端引用等),通过工厂函数创建
15.4.2 AST-Grep 工具深入分析
AST-Grep 是 oh-my-opencode 中最复杂的工具之一。它提供了基于**抽象语法树(AST)**的代码搜索和替换能力,远超传统的文本搜索(grep)。
衍生解释:什么是 AST(抽象语法树)?
AST(Abstract Syntax Tree)是编程语言编译器/解释器在解析源代码时生成的树状数据结构。它将代码的语法结构表示为一棵树,其中每个节点代表一个语法构造(如变量声明、函数调用、if 语句等)。
例如,代码
const x = 1 + 2的 AST 大致如下:AST 级搜索 与 文本级搜索 的关键区别在于:
文本搜索
grep "console.log"会匹配所有包含该字符串的行,包括注释中的// console.log和字符串中的"console.log"AST 搜索
ast-grep -p "console.log($MSG)"只匹配真正的console.log函数调用,忽略注释和字符串AST 搜索还支持元变量(Meta-variables):
$VAR匹配单个 AST 节点,$$$匹配多个节点。这使得搜索模式可以表达复杂的代码结构。
架构设计
AST-Grep 工具的实现涉及 13 个源文件,架构如下:
工具定义
oh-my-opencode 提供了两个 AST-Grep 工具:搜索 和 替换。
空结果智能提示
一个贴心的设计是 getEmptyResultHint() 函数——当搜索没有结果时,它会分析搜索模式并给出修正建议:
这利用了 AST-Grep 的一个常见陷阱:AST 模式必须是完整的 AST 节点。搜索 function $NAME 不会匹配任何内容,因为这不是一个有效的 JavaScript AST 节点——它缺少参数列表和函数体。正确的模式应该是 function $NAME($$$) { $$$ }。
CLI 进程管理
AST-Grep 的底层是通过调用 ast-grep CLI 二进制文件实现的:
oh-my-opencode 自动处理了 ast-grep 二进制文件的获取——如果系统中没有安装,它会自动下载对应平台的预编译二进制。
15.4.3 Hashline Edit 的创新设计
Hashline Edit 是 oh-my-opencode 独创的文件编辑工具。它通过给每一行代码附加一个行号哈希,解决了 LLM 编辑文件时的一个根本问题:编辑目标定位的准确性。
问题背景
传统的文本编辑工具(如 OpenCode 内置的 Edit 工具)使用"旧文本 → 新文本"的替换模式:
这种模式的问题是:如果文件中有多处 const x = 1,工具无法确定应该替换哪一个。OpenCode 的 Edit 工具要求 oldString 必须唯一匹配——如果匹配到多处,编辑会失败。
这迫使 LLM 不得不提供更多的上下文代码来确保唯一性,增加了 Token 消耗和出错概率。
Hashline 解决方案
Hashline Edit 的核心思想是:给每一行代码附加一个短哈希值,作为行级别的"身份标识"。
格式为 行号:哈希|内容,其中:
行号:1-based 的行号
哈希:行内容的 xxHash32 哈希值的前 2 个十六进制字符(256 种可能值)
内容:行的原始文本
哈希计算
哈希计算的几个设计选择:
去除空白后哈希:
content.replace(/\s+/g, "")。这意味着缩进变化不会改变哈希值,增强了稳健性。使用 xxHash32:一种非常快速的非加密哈希函数,适合大量小字符串的快速哈希。
256 种可能值:哈希值只有 2 个十六进制字符(
00到ff),这是有意的设计——太短可能碰撞,太长浪费 Token。256 种值在"定位准确性"和"Token 效率"之间取得了平衡。
四种编辑操作
Hashline Edit 支持四种编辑操作:
哈希不匹配保护
Hashline Edit 的最重要特性是哈希验证。当 LLM 引用一行时提供的哈希与文件当前内容的哈希不匹配时,编辑会失败并返回错误:
这解决了"陈旧编辑"问题——如果文件在 LLM 读取后被修改了(可能被另一个并行 Agent 修改),Hashline Edit 会拒绝编辑而不是在错误的位置写入内容。
自底向上应用
编辑操作按照从下到上的顺序应用(最高行号优先)。这是一个关键的设计——因为插入或删除行会改变后续行的行号。如果从上到下应用,前面的编辑会使后面的行号引用失效;从下到上应用则避免了这个问题。
与 Read 工具的集成
Hashline Edit 不是孤立的工具——它需要与 Read 工具配合使用。oh-my-opencode 通过 hashline-read-enhancer Hook 增强了 OpenCode 的 Read 工具输出:
这样,LLM 在读取文件时就自动获得了每行的哈希值,可以直接用于 Hashline Edit 操作。
衍生解释:AST 级代码搜索的优势
传统的代码搜索(如
grep、ripgrep)是基于文本的——它将代码视为字符串序列,使用正则表达式进行模式匹配。这种方式简单快速,但有明显的局限性:
无法理解代码结构:搜索
function add会匹配函数定义、注释中的描述、字符串里的引用,无法区分它们无法处理格式差异:
function add(a, b)和function add( a, b )在文本上不同,但在 AST 上是相同的无法表达结构化模式:"找到所有接受两个参数的函数"这种需求几乎无法用正则表达式表达
AST 搜索通过先解析代码为 AST,再在 AST 上进行模式匹配,克服了这些局限。ast-grep 支持 25 种编程语言的 AST 解析,使用 Tree-sitter 解析器(一种增量解析库,被 GitHub、Neovim 等广泛使用)。
但 AST 搜索也有代价:它需要完整解析源文件,因此比文本搜索慢。oh-my-opencode 通过调用
ast-grepCLI 而非在进程内解析来缓解这个问题——CLI 使用 Rust 实现,性能极高。
本节小结
oh-my-opencode 的自定义工具系统通过 Plugin 的 tool 接口注册了 15 个工具,覆盖了从代码搜索到后台任务管理的各个方面。
两个最具创新性的工具是:
AST-Grep:基于抽象语法树的代码搜索和替换,支持 25 种语言,通过元变量表达结构化模式。它包含自动二进制下载、空结果智能提示和进程超时管理等完善的工程实现。
Hashline Edit:通过行号 + xxHash32 短哈希的组合,为每行代码提供精确的"身份标识"。这解决了 LLM 编辑文件时的定位准确性问题,同时通过哈希验证防止了对陈旧文件内容的错误编辑。
Last updated
