☰
oh-my-opencode-slim 内置工具与能力全景:apply_patch 救援、webfetch 增强、结构化代码搜索与后台任务控制
2026/9/25 3:28:45 网站建设 项目流程
  • 人工智能
  • AI Agent
  • Agent 编排
  • AI 技能

【免费下载链接】oh-my-opencode-slim

Lean, fine tuned Opencode multi agent suite · Mix any models · Auto delegate tasks

项目地址:https://gitcode.com/gh_mirrors/oh/oh-my-opencode-slim
点击查看免费下载

oh-my-opencode-slim 是一套面向 OpenCode 的多 Agent 编排插件,除了标准文件与 Shell 操作外,还为 Agent 注入了大量内置工具能力。本文以仓库文档 docs/tools.md 为核心骨架,结合 src/hooks/apply-patch/、src/tools/smartfetch/、src/tools/ast-grep/、src/tools/task-message.ts 等源码实现,系统讲解 apply_patch 救援、webfetch 增强、grep/ast-grep 结构化搜索、后台任务控制、工具循环护栏与格式化能力。读完本文,你将掌握这套插件每个内置工具的职责边界、底层实现机制与实战使用方式,能够正确编排后台任务、规避搜索路径陷阱并理解故障安全策略。

apply_patch 救援(apply_patch rescue)

apply_patch是 Agent 修改文件的核心工具,但模型生成的补丁经常因空白字符、换行符漂移而失配。oh-my-opencode-slim 在原生apply_patch执行之前通过tool.execute.before钩子拦截调用,对其进行"救援式"重写。实现位于 src/hooks/apply-patch/index.ts,核心入口是rewritePatch(见 src/hooks/apply-patch/operations.ts),启用prefixSuffix: true与lcsRescue: true两组救援选项。

救援逻辑遵循以下原则:

  • 只重写可恢复的过期补丁:补丁行号或上下文已过期时,尝试基于真实文件重新对齐;
  • 宽容匹配:当 Unicode 或首尾空白差异(trim 漂移)是唯一失配原因时,对真实文件做规范化宽容匹配;
  • 保留作者意图:new_lines的原始字节保持不变,更新场景下维持文件既有的 EOL 与末尾换行状态;
  • 严格校验:在执行辅助操作之前,对格式错误的补丁做严格校验并失败;
  • 保守的 LCS 回退:使用有界的最长公共子序列(LCS)算法兜底,避免过度重写;
  • 累积状态:同一路径出现在多个Update File块中时,跨 hunk 累积辅助状态;
  • 工作区安全:任何补丁路径落在允许的 root/worktree 之外时,在原生执行前直接阻止该apply_patch;
  • 歧义即失败:无法唯一判定如何重写时,拒绝猜测,明确报错。

需要注意边界:该钩子不重写edit或write工具的输入,只针对apply_patch。从源码看,tool.execute.before仅在input.tool !== 'apply_patch'时提前返回,随后用replacePatchArgs把重写后的patchText替换回输出参数;若输出参数只读则记录skipped并放行(fail-open),其余错误按blocked/validation/verification/internal分类记录并抛出。

Web Fetch:增强版 webfetch(smartfetch)

webfetch本是 OpenCode 内置工具,本插件激活时以同名覆盖默认实现,增强版内部模块名为smartfetch,位于 src/tools/smartfetch/,工具在 src/index.ts 中注册。完整参数说明见 docs/webfetch.md。

参数一览

参数类型默认值说明
urlURL(string)必填要抓取的 URL,必须是合法的 HTTP/HTTPS 地址
format"text"|"markdown"|"html""markdown"抓取内容的输出格式
timeoutnumber30超时秒数(最大120)
promptstring可选交给次级模型对抓取内容执行的提取任务(见下文"次级模型")
extract_mainbooleantrue使用 Mozilla Readability 从 HTML 提取正文;关闭时返回完整页面 body
prefer_llms_txt"auto"|"always"|"never""auto"是否优先/llms.txt或/llms-full.txt;"auto"只对文档类域名探测(readthedocs、gitbook、netlify、vercel 等)
include_metadatabooleantrue是否在输出前附加含抓取元数据的 YAML frontmatter(状态码、内容类型、字符集、重定向链、缓存信息等)
save_binarybooleanfalse是否将二进制负载(图片、PDF、音视频)保存到系统临时目录;关闭时二进制内容仅报告元数据

输出与元数据

文本类内容(HTML、纯文本、llms.txt)按请求的format返回,默认在响应前附加 YAML frontmatter:

--- requested_url: "https://example.com/docs" final_url: "https://example.com/docs" canonical_url: "https://example.com/docs" status_code: 200 source_content_type: "text/html" source_kind: "html" title: "Documentation" headings: - "Getting Started" - "API Reference" used_llms_txt: false extracted_main: true redirect_chain: [] upgraded_to_https: true cache_hit: false word_count: 1420 quality_signals: [] truncated: false ---

其中quality_signals用于标记潜在问题:very_short_content(少于 60 词)、possible_paywall(内容命中付费墙/登录关键词)、high_boilerplate_ratio(HTML 与正文比例过大且未做 Readability 提取)。

二进制响应(图片、PDF、音频、视频)返回文件元数据:内容类型与大小、文件名(取自Content-Disposition或 URL 路径)、二进制类型(image/audio/video/pdf/binary)。存在两种模式:

  1. 仅元数据:内容超过下载上限(不开save_binary时为 2 MiB,开启后为 10 MiB),只报告大小与类型;
  2. 保存到磁盘:save_binary=true时写入<tmpdir>/opencode-smartfetch/<filename>,响应中给出文件系统路径。

次级模型(Secondary Model)

传入prompt参数时,webfetch可以把抓取内容路由给一个更廉价的次级模型做聚焦提取(例如"总结此页"或"提取代码示例")。流程:内容照常抓取并缓存 → 创建所有工具禁用的一次性 OpenCode 会话 → 把内容与 prompt 发给次级模型 → 完成后清理会话。实现见 src/tools/smartfetch/secondary-model.ts。

模型解析优先级(从高到低):

  1. webfetch.model(专用模型,最高优先级,支持数组形式做回退);
  2. OpenCode 配置中的small_model(opencode.json/opencode.jsonc);
  3. 插件配置的explorerAgent 模型;
  4. 插件配置的librarianAgent 模型。

次级模型仅在同时满足以下条件时才被调用:提供了prompt、已配置次级模型、抓取内容至少 25 个词。若次级模型失败(超时、报错、空响应),webfetch优雅回退,直接返回原始抓取内容。配置示例:

{ "webfetch": { "enabled": false // 关闭增强版,使用 OpenCode 内置 webfetch } }
{ "webfetch": { "model": [ "openai/gpt-4o-mini", { "id": "anthropic/claude-3-haiku", "variant": "low-latency" } ] } }

模型数组按顺序逐个尝试,第一个返回可用文本的生效;small_model可在opencode.jsonc顶层配置为"openai/gpt-4o-mini"之类。

缓存、llms.txt 探测与重定向策略

  • 内存 LRU 缓存:上限 50 MiB、TTL 15 分钟(见 src/tools/smartfetch/cache.ts)。缓存键包含 URL 及行为相关选项(extract_main、prefer_llms_txt、save_binary),修改这些选项会重新抓取。渲染格式(text/markdown/html)从缓存结果派生,不会引发冗余网络请求。
  • 条件重验证:带ETag/Last-Modified的缓存条目支持If-None-Match/If-Modified-Since条件请求,304 Not Modified只刷新 TTL 不重新下载;缓存的 llms.txt 结果会被校验,若实际不是 llms.txt 响应(路径错误、HTML、登录页)则驱逐后重抓。
  • llms.txt 探测:对文档站先探测/llms-full.txt再探测/llms.txt,最后才回退到页面本身。"auto"仅对文档类域名探测(.readthedocs.io、.gitbook.io、docs.rs后缀,docs.、developer.、dev.、wiki.前缀);"always"总是探测,两者皆不存在时报错;"never"跳过。探测遵循同源重定向策略,若 llms.txt 响应是 HTML 或登录页则拒绝。
  • 重定向策略:单次请求最多跟随 10 次重定向,但仅在同源范围内;跨源重定向被阻止,返回提示要求调用方直接抓取新 URL(可配合权限模式显式放行)。http://输入会先尝试https://,HTTPS 失败(连接错误、重定向被阻、非 2xx)再回退http://。
  • 二进制检测:显式二进制 MIME(image/*、audio/*、video/*、application/pdf、application/zip、application/octet-stream)直接视为二进制;application/octet-stream与已知文本类型会扫描前 2 KiB 的空字节与不可打印字符来区分文本;声明为text/plain但看起来像 HTML 的内容会被升级为text/html以改进提取。
  • 超时:默认 30 秒、最大 120 秒;llms.txt 探测在总超时内封顶 8 秒;探测与页面抓取相互独立,多个作用域超时并行运行。
  • 跨源重定向阻止:除非请求 URL 或派生的权限模式显式允许,webfetch会阻止跨源重定向;次级模型摘要不可用时回退到原始抓取内容。

代码搜索工具:grep 与 ast-grep

基于 ripgrep 的grep

grep使用 ripgrep 做快速内容搜索。在原生grep/glob执行前,插件通过 src/hooks/search-path-guard/ 预检请求的path是否有效,解析规则与宿主一致:v1 的grep用path.join拼接相对路径,v1 的glob用path.resolve解析,v2 对两者都用path.resolve。缺失路径或包含非目录组件的路径会快速失败并给出可操作的错误信息,而不是抛出难懂的 "ripgrep execution failed" 或静默搜索父目录。解析使用宿主进程的原生路径风格,保留 Windows 驱动器相对行为;无项目目录时保守放行。

AST 感知的ast_grep_search/ast_grep_replace

ast_grep理解代码结构,能匹配"所有返回 JSX 元素的箭头函数"这类模式,而非依赖精确文本。实现位于 src/tools/ast-grep/,通过 src/tools/ast-grep/cli.ts 调用 sg 二进制,支持25 种语言(见 src/tools/ast-grep/types.ts)。

ast_grep_search的参数包括:

  • pattern:带元变量的 AST 模式($VAR匹配单个节点,$$$匹配多个节点);必须写完整的 AST 节点(合法代码),例如函数要写export async function $NAME($$$) { $$$ }而非export async function $NAME,示例console.log($MSG)、def $FUNC($$$):、async function $NAME($$$);
  • lang:目标语言(CLI 支持列表内的枚举);
  • paths:搜索路径(默认['.']);
  • globs:包含/排除规则(前缀!排除);
  • context:匹配上下文行数。

ast_grep_replace做 AST 感知的重构,默认 dry-run,重写中可用元变量保留匹配内容,例如pattern='console.log($MSG)' rewrite='logger.info($MSG)'。匹配结果为空时会给出基于模式与语言的空结果提示(getEmptyResultHint)。

后台任务控制工具组

后台编排是 oh-my-opencode-slim 的默认编排模型,其完整概念见 docs/background-orchestration.md:orchestrator 从"主要执行者"变为"调度器"——规划 → 后台派发专家 → 监控 → 对账 → 验证。工具组如下:

工具说明
task启动一个专家任务并返回 task ID
task_status检查任务状态
task_result获取任务结果
task_message排队一条不打断的消息,返回queued
task_cancel停止一次生成但保留其会话
task_revive用新指令恢复被保留的会话
wait_for_user暂停自动 orchestrator 唤醒,直到下一条不同的外部用户消息

任务控制工具使用 task ID 或 Background Job Board 别名来定位被管理的任务。运行时要求原生后台子 Agent 可用,并以环境变量启动:OPENCODE_EXPERIMENTAL_BACKGROUND_SUBAGENTS=true opencode(可用opencode --version检查版本,缺后台任务则升级)。

task_message:非打断消息与消息租约

task_message的实现见 src/tools/task-message.ts,参数为task_id(受追踪的活跃任务 ID 或父作用域别名)与message(1–500 字符的短消息)。它不会打断当前生成:请求体以noReply: true发送,仅更新转录而不调度执行,绝不会通过合成消息或切换模型选择来完成。noReply: true防止启动一轮对话,而不是改变转录——延迟到达的更新(包括捕获的 agent/model/variant)可能改变被复用生成的上文。超时并不能证明消息未被送达。

核心安全机制是按任务的消息租约:

  • 本地超时到期但写入传输仍挂起时,保留该租约;
  • 写入未落定前,该 taskID 的进一步消息、task_cancel取消、同会话复活/复用以及受租约保护的终止通知全部被排除;
  • 写入永不落定时,这种控制面排除无限期持续,不承诺自动恢复;但不会停止子任务执行,也不阻塞其他 taskID,结果仍可通过其他观察/结果路径到达;
  • 落定(无论成功失败)即释放令牌,没有 TTL,也没有session.abort回滚。

这是遵循 job board 租约协议的本地互斥,不是与外部动作的隔离,也不保证恰好一次投递。用board.drop或clearParent删除 job 不会注销其租约:liveLeases与jobs相互独立。v2 上task_message继承会话持久化的 agent/model/variant(不再每次读取并固定选择),v1 保留权威查找;v2 写入使用delivery: "queue", resume: false,以queue语义更新转录但不调度执行。

task_cancel:停止生成、保留会话

task_cancel(见 src/tools/cancel-task.ts)停止一次生成但保留其会话,不回滚部分编辑。因此取消一个可写任务后,必须检查并对账文件变更再启动替代工作。它只应由 orchestrator 使用(assertOrchestrator校验:非 orchestrator agent 或非 orchestrator 管理的会话都会被拒绝),仅用于过时、错误、冲突或用户要求的取消。

取消流程(cancelTrackedExecution)获取取消租约,调用session.abort,然后通过 terminal gate 验证会话真正静默(verifyQuiescentSession:活动映射中idle或条目缺失即静默证据,需保持静默 300ms 稳定窗口)。若中止请求在挂起时超时,task_cancel报告不确定性并保留取消租约:迟到的中止绝不能影响被复用的会话。没有租约 TTL——永不落定的中止会一直阻塞复用;迟到落定释放令牌但不恢复验证,也不发布已确认的取消,恢复依赖后续观察。中止落定后验证有自己的时间预算;v2 的 session-info 读取只使用剩余预算:超时使任务保持不确定并释放租约,不确认取消也不消费迟到证据。v2 没有session.status映射时,回退到宿主 session info 的outcome终止值白名单或中止开始后的新 idle 时间戳来确认静默。

task_revive:恢复保留会话

task_revive(见 src/tools/task-revive.ts)参数为task_id与prompt,用新指令恢复被保留(cancelled / errored / stopped)的会话。被保留状态验证安全后可立即复活;acknowledgement 只控制父会话与 job board 消费及可复用池展示,不控制同会话复活。

关键时序约束:

  • 基线捕获有 5 秒截止:超期则失败且不发送 prompt,释放复活租约;
  • 本地准入等待有 10 秒截止:超期返回status: admission_unknown而非启动失败;报告的 generation/state 是准入前快照,即使接受在调用方收到截止结果前已落定;宿主可能已在运行该 prompt,不要重试,用task_status检查;
  • 挂起的发送保留租约直到落定:迟到接受注册一次新 generation,拒绝则释放且不注册;完成探测发生在租约释放后,探测错误记录为观察失败;
  • 观察不预留 generation:若在第一个调用方等待探测期间另一个task_revive替换了它,第一个调用以revive became stale拒绝,该取代拒绝不会使更新的启动失效;
  • 删除胜过挂起准入:删除子会话或其父会话后,接受到达也不会重建任一记录;若原复活租约仍持有缺失的子会话,独立补偿所有者恰好发送一次针对该子会话的 abort(不注册 generation、不清墓碑、不通知已删父、不中止兄弟节点);被撤销/替换的租约或已变更的 generation 保持 fenced,绝不触发对继任者的中止;
  • 若调用方仍在等待,会收到admission accepted but invalidated by loss of the record; compensation initiated;已返回的admission_unknown不变;准入拒绝无需补偿;
  • 补偿在 abort 挂起期间保留排除,无本地截止释放;只有真实 abort 落定后的新鲜有界 live-status 读取确认 idle/absence 才释放该租约;abort 失败或不可验证/忙碌状态记录compensation unconfirmed并无限期排除该 ID;
  • 历史结果不是停止证据;实时静默不保证排队 prompt 已被清除,租约释放后未来排队执行仍不确定。

task()拒绝无法恢复的显式task_id,而不是丢弃它另开会话。复活前必须先建立空闲验证机制:v1 的 live status 映射或 v2 的宿主 idle wait;缺失该能力时在 abort、基线捕获、prompt 之前就失败,重试无法补足该能力。v2 的 wait 有 5 秒本地预算;超时、拒绝、无效完成或在截止后处理的完成都不会发送 prompt 并释放准备租约;迟到落定不会恢复已结束的复活流程。被接受的复活可能返回status: started且status_uncertain: true附带观察诊断;不确定性单独永远不会在重试耗尽时成为终态,但也没有保证的恢复截止。

wait_for_user:面向外部人工工作的显式等待

wait_for_user同样仅限 orchestrator 使用(实现见 src/tools/wait-for-user.ts)。orchestrator 在给出外部人工操作的具体步骤后,把它作为最后一个工具动作调用。其reason仅作诊断文本,插件不解析 assistant 散文来判定某轮是否为 HITL。参数reason为 1–500 字符、非空、压缩空白后的描述。

  • 新的真实用户文本/文件/图片消息清除等待;合成/内部消息与等待之前用户消息的重复投递不清除;
  • 若有未完成的背景任务且启用了waitForUserGuardEnabled,返回state: waiting_for_user_skipped,指示立刻结束本轮,由 Background Job Board 与 orchestrator wake scheduler 自动恢复;
  • 正常路径返回state: waiting_for_user、protocol: oh-my-opencode-slim.wait_for_user.v1,指示"结束本轮,用户响应前不要调用更多工具";
  • 立即回答、选择、澄清与粘贴的命令输出继续使用question工具;若在disabled_tools中列出wait_for_user,orchestrator 用question工具作为阻塞边界。

重复工具调用循环护栏(Tool Loop Guard)

模型侧无限循环是现实风险:某个子 Agent(例如可能退化的模型在 Explorer 中)反复发出完全相同的工具调用、得到完全相同的结果、毫无进展。实现见 src/hooks/tool-loop-guard/hook.ts,按会话监控连续相同的工具调用——只统计返回结果与上次逐字节相同的调用,返回新信息的调用(例如文件被修改后的重读)永远不会计入阻断。响应策略:

  • 第 3 次确认相同结果后:向工具输出追加纠正性提示,要求模型停止重复、改变方法;适用于所有工具;
  • 第 5 次确认相同结果后:对只读文件工具read、grep、glob拒绝下一次相同调用,终止循环;其他工具保持仅警告。

计数在tool.execute.after中确认,因此重叠的并行调用无法在结果已知前虚增计数。tool.execute.before永不递增计数,拒绝只发生在运行已被确认相同之后。wait_for_user/wait_for_background_tasks这类等待工具使用按轮次、仅按键名的专用计数:其契约是"结束本轮",一轮内重复调用总是退化的,第 2 次警告、第 3 次拒绝。

整个护栏豁免:任务控制与等待工具(task、task_status、task_result、task_cancel、task_message、task_revive、wait_for_user、wait_for_background_tasks)——它们轮询长时后台任务时合法地重复相同调用。task_status/task_result使用独立的 task-ID/生命周期状态流,交替轮询仍可识别而不会被当作无进展。注意task_status输出的possibly_stuck字段(见 src/tools/task-status.ts)用于辅助判断任务是否停滞。

格式化器(Formatters)

OpenCode 在文件写入或编辑后自动使用语言对应的格式化器格式化,无需手动步骤。内置 Prettier、Biome、gofmt、rustfmt、ruff以及 20+ 其他格式化器;完整列表参见官方 OpenCode 格式化器文档。

小结

oh-my-opencode-slim 的内置工具能力围绕三条主线设计:可靠性(apply_patch 救援与严格校验、搜索路径预检、循环护栏)、效率(AST 感知的代码搜索与重构、带缓存与 llms.txt 探测的 webfetch)、编排(后台任务控制工具组与租约/对账/补偿机制)。对这些工具的理解,是正确使用后台编排模型的前提——更多调度器职责、任务提示契约与运行时集成细节,可继续阅读 docs/background-orchestration.md;webfetch 的完整实现细节见 docs/webfetch.md;背景任务管理的相关配置项见 docs/configuration.md。

  • 人工智能
  • AI Agent
  • Agent 编排
  • AI 技能

【免费下载链接】oh-my-opencode-slim

Lean, fine tuned Opencode multi agent suite · Mix any models · Auto delegate tasks

项目地址:https://gitcode.com/gh_mirrors/oh/oh-my-opencode-slim
点击查看免费下载

相关推荐

上一篇:构建区块链API:Japronto与Web3.py集成
下一篇:5分钟掌握WebGL太空场景生成:Space-3D完全指南

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询