dsh-tool-search
已验证@anionex/dsh-tool-search · v0.1.2 · MIT · Web 界面
Codex-style deferred tool loading for DSH with deterministic local BM25 search
安装
dsh plugin add @anionex/dsh-tool-search 用 dsh --profile default --dump-config 确认 layer 已生效 —— 参见安装指南。
源码
标签
说明文档
dsh-tool-search
面向 DeepSeek Harness(DSH) 的 Codex 风格延迟工具加载插件。
dsh-tool-search 保留真实的 DSH 工具注册表,只缩小模型可见的工具集合。新 Agent 起初只看到维护中的核心工具和 tool_search。调用 tool_search 后,插件在本地延迟工具元数据上运行确定性 BM25,将 Top-K 结果加入该 Agent 的已选集合,并在下一次模型调用中暴露它们的完整原生 schema。模型随后用真实工具名调用,仍经过 DSH 原有执行链。
安装
dsh plugin --profile web add @anionex/dsh-tool-search
需要时可把 web 换成 headless 或其他 DSH profile。安装后应重启运行中的 profile,并新建会话。
部分 Node.js 24+ 版本的 DSH 独立启动器无法解析 Profile 中的裸包名。若启动时报 Cannot find package '@anionex/dsh-tool-search',请使用 node --expose-internals "$(command -v dsh)" --profile <name> ...;这是 DSH 上游 loader 的限制,不是插件通过其他路径加载。
要求:
- DSH
0.1.1-rc.1至当前0.1.5-rc.1预发布版本线 - Node.js
^22.19.0 || >=24.0.0 - 任意工具展示模式:
native、ptc(DSH ≤0.1.1里叫code)或both
行为
初始模型可见工具集合包含:
tool_searchapply_patchDEFAULT_CORE_TOOLS中维护的 DSH 核心工具alwaysVisible中配置的精确名称
默认策略把以下名称视为核心工具:
apply_patch, ask_user_question, bash, create_goal, exit_plan_mode, get_goal,
interrupt_agent, job_kill, job_list, job_output, list_agents, ralph, report,
send_message, skill, subagent, subagent_fork, todo_write, update_goal, workflow
其他已注册工具都可搜索,但默认不显示。neverSearch 同时从初始集合和搜索语料中隐藏名称,并在与 alwaysVisible 冲突时优先。tool_search 自身不能被拉黑,避免配置后无工具可发现。
已选集合具备以下语义:
- 每个活跃 Agent 相互隔离;
- 一个 Agent 生命周期内只增长;
- resume 时从成功的
tool_search结果恢复; - fork 时从复制的历史前缀恢复;
- 设置变化只改变当前有效可见性,不删除已选历史。
工具或提示词注册表变化会让全部缓存目录失效。下一次 assembly 或搜索按当前作用域 schema 重建索引。
展示模式
DSH 按作用域渲染工具面:native 直接列出 JSON schema;ptc(DSH 0.1.2 之前叫 code)把 schema 列表收缩为保留传输 run_code,再加一段生成的 tools:sdk 提示词段;both 同时渲染原生 schema 与 SDK。插件会过滤 assembly 实际携带的每一层:
assembly.tools只保留可见名称,因此run_code保留、延迟工具的 schema 不出现;- 隐藏工具对应的
tool:<name>指引段被删除; tools:sdk段用 DSH 自己的渲染器(renderToolsSdk/renderToolsSdkPy,与当前 code runtime 语言一致)重新生成,使 SDK 恰好宣传可见工具集合。
搜索语料来自该 Agent 的作用域注册表视图,而不是 assembly;因此即使 PTC 下 assembly 只有 run_code,全部延迟工具依然可被搜索。tool_search 选中的工具会在下一次模型轮次按当前部署的渲染方式出现,并可通过 run_code 调用。
设置
DSH Web 设置页提供:
- 默认结果数,范围
1-20,默认5; - 精确工具名常驻白名单;
- 精确工具名搜索黑名单;
- 可筛选的实时工具目录及逐工具策略选择。
等价配置:
- id: dsh-tool-search
config:
defaultLimit: 5
alwaysVisible:
- my_frequent_tool
neverSearch:
- internal_debug_tool
搜索合同
每个函数工具的搜索文档按顺序包含:
tool.nametool.name.replaceAll("_", " ")tool.description- 递归遍历 schema:先输出当前节点描述,再按排序后的属性名逐项输出“属性名 + 该属性的嵌套描述”;随后处理
items和anyOf
本地索引使用 k1=1.2、b=0.75 的 BM25,包含英语停用词移除和 Porter2 词干化。精确原始名称命中固定排第一;其他结果先按 BM25 分数降序,再按工具名 Unicode 码点字典序稳定处理同分。搜索结果只有名称、短描述和分数,不重复参数 schema。
Codex 对齐
实现对照了源码调研期间 openai/codex 最新 main 提交 3fde89f。Codex 的通用函数文档构造器是字段顺序和递归 schema 遍历的依据;Codex 同样使用 bm25 2.3.2 的英语 tokenizer 与相同 BM25 默认参数。
DSH 适配差异:
| 范围 | Codex | 本插件 |
|---|---|---|
| 默认 Top-K | 当前上游为 8 | 5 |
| 加载协议 | Responses API 的 tool_search_output 在历史中携带可加载定义 |
普通 DSH tool_search 返回摘要,下一请求加入原生 schema |
| 已加载状态 | 定义保留在模型历史时可用 | 每 Agent 单调已选集合,并从 DSH session 事件恢复 |
| 同分排序 | 上游候选顺序可能不稳定 | 工具名字典序 tie-break |
| 精确名称 | 普通 BM25 排名 | 显式保证 Recall@1 |
| 字符转写 | Rust deunicode |
Unicode NFKD 变音符号折叠 |
| 结果载荷 | 定义,无分数 | 摘要和分数,无 schema |
这些差异是有意设计。DSH 没有 Responses API 的 tool_search_output 历史类型,而需求要求下一模型轮注入 schema、稳定恢复已选集合。
执行语义
插件只过滤 PromptAssembly.tools 和匹配的 tool:<name> 指引段,不注销工具,也不调用 ctx.tools.restrict()。
发现后的真实工具调用仍经过 DSH 标准链:
tool/call
-> tools/pre-execute
-> 用户审批
-> guards
-> tools/execute
-> ToolDefinition.execute
-> tools/post-execute
-> finalizer
-> tools/result
-> tool/result
延迟可见性是上下文与 token 优化,不是授权边界。模型或调用方若已知隐藏工具的真实名称,仍可尝试调用;审批、guard、sandbox 和工具自身校验继续承担安全职责。
已选集合只在 post-execute 策略之后、最终 tools/result 成功时提交。finalizer 会持久化驱动实时提交的同一份紧凑、无 schema JSON 结果,因此 resume/fork 重放不会与内存中的已选集合分叉。
Token 基准
pnpm benchmark 使用 gpt-tokenizer 默认的 o200k_base 编码器,对确定性的嵌套 OpenAI function-tool wire schema 计数:
| 延迟工具数 | 完整初始 schema | 仅 tool_search |
初始减少 | 加载 Top-5 后 |
|---|---|---|---|---|
| 10 | 1,822 | 103 | 94.3% | 1,013 |
| 30 | 5,462 | 103 | 98.1% | 1,013 |
| 50 | 9,102 | 103 | 98.9% | 1,013 |
| 100 | 18,202 | 103 | 99.4% | 1,013 |
随包发布的生成器和完整 fixture 构造位于 scripts/benchmark.mjs。docs/benchmark-results.json 记录包版本、生成器与语料 SHA-256、fixture 规模、tokenizer 和机器可读结果。应用总量还包含核心 schema 和系统提示词 token,生产环境的百分比取决于实际安装工具集合。
验证
pnpm install --frozen-lockfile
pnpm validate
pnpm run e2e:profile
测试覆盖文档构造、精确名称 Recall@1、能力 Recall@5、同分稳定性、Agent 隔离、集合单调增长、注册表刷新、结果形状、最终成功后提交、post-execute 拒绝与改写、只多一轮加载、resume/fork 恢复、实时设置、Web 控件、native/PTC/both 三种 assembly 过滤,以及真实 DSH approval/guard/event/execute 链。Profile E2E 会把打包产物安装到全新 DSH_HOME,并两次驱动脚本化真实 Agent:一次用部署默认的 native 展示,一次把 DSH_TOOLS_MODE 设成该 DSH 版本对应的 PTC 名称。PTC 那一轮会断言:直接可见工具只有保留传输 run_code、生成的 SDK 隐藏延迟工具、被选中的工具出现在下一轮 SDK、并且该选择确实通过 run_code 完成派发。发布验收会在 DSH 0.1.1-rc.1(code)、0.1.2-rc.1 与 0.1.5-rc.1(ptc)上运行该 E2E。
已知限制
- 重新生成
tools:sdk依赖 DSH 导出的渲染器(renderToolsSdk、renderToolsSdkPy)。若未来 DSH 改名该段或不再导出渲染器,插件会让该 Agent 明确报错,而不是降级成未过滤的 SDK。 - PTC 下模型若直接点名“延迟但未选中”的工具,会在
run_code内得到UNKNOWN_TOOL:插件不提供其 schema,注册表仍然拒绝派发,伪造的定义无法进入执行。 - 部分 Node.js 24+ 版本下,DSH
0.1.2-rc.1独立启动器无法访问 Node 内部 ESM loader,因而不能解析任何 Profile 中以裸包名安装的外部插件。若启动时报Cannot find package '@anionex/dsh-tool-search',请改用node --expose-internals "$(command -v dsh)" --profile <name> ...。CI 会在 Node 22 上强制验证标准裸包名加载;Profile E2E 也会记录本地运行是否用到了这一启动器兼容方案。 - 工具定义不提供包来源。新加入的 DSH 核心工具默认延迟,直到本包更新
DEFAULT_CORE_TOOLS,或用户加入白名单。 - 插件会随隐藏 schema 一起过滤精确
tool:<name>指引。任意第三方提示词段没有工具来源,无法可靠改写。 - 英语词干化和 NFKD 折叠不是语义或多语言检索;没有 reranker 或 embedding fallback。
- 协作式 prompt waterfall 不是抵御恶意插件的安全边界。
许可证
MIT