dsh-tool-gateway:把 DSH 工具目录收成 find_tools / call_tool / call_tools

前言

在 DSH 里接 MCP、装插件、换 preset 之后,注册表里的工具会越来越多。模型侧往往只能看到一份被截断或精简后的工具表:表一长就容易挑错工具;表被截断时,没出现在表里的工具容易被忽略,模型会反复用几个熟面孔凑合。

另外,工具定义通常排在每次请求的最前部。工具表一变,整段前缀缓存就会失效,带来重新计费和首字延迟变长——而工具表又恰恰是最容易变动的一块。

下面介绍社区插件 dsh-tool-gateway(维护者 leolee9086),它把模型可见的工具表收成少量「元工具」,其余工具仍可通过元工具调用,并配套会话开关、工具箱面板、工具组与硬禁用名单。分类为工作流;仓库当前星标为 0。目录页:https://www.skillhub.cn/plugins/leolee9086/dsh-tool-gateway,源码:https://github.com/leolee9086/dsh-tool-gateway。

这是什么

dsh-tool-gateway 挂在 DSH profile 层(根作用域),对 preset 与会话施加同一套网关逻辑(会话级总开关除外)。它做两件事:

  1. 可见性:在装配系统提示时过滤 assembled.tools,让模型可见的工具表主要是 find_tools、call_tool,以及在条件满足时的 call_tools。
  2. 执行守卫:拒绝模型对其它工具的直接调用;通过 call_tool(带 parent 的子分发)发起的调用仍走 ctx.tools.execute(),审批、守卫、沙箱与会话日志与直接调用一致。

因此,长列表不再堆在模型眼前,而是先 find_tools 查、再 call_tool 调;装插件或改面板开关时,模型可见的工具表字节可以保持不变,变的只是检索索引与守卫判定。

三个元工具

工具 作用 何时用
find_tools 按名字、描述、中文或拼音检索,返回完整参数 schema 不知道有什么工具,或不清楚参数怎么写
call_tool 调用单个工具,参数为 {tool_name, arguments} 一次调一个
call_tools 用一段 TypeScript 程序批量调用 连续调多个,中间结果不必进对话

find_tools 的结果按 token 估算收缩(默认预算 10000,可配置);单个 schema 不截断。被截断时可用返回的 offset 继续查同一查询。普通查询不会列出会话里关掉的工具;要用 find_tools({scope: "disabled"}) 查看关着的工具——该路径每次需审批,在 danger-full-access 下会直接拒绝。

call_tools 在 DSH PTC 运行时中执行模型写的程序,程序内仅可调用 tools.find_tools({query}) 与 tools.call_tool({tool_name, arguments});只有 return 的值回到对话。参数与输出对齐官方 PTC 的 run_code(含 description 必填、结构化输出与 CodeRunFailedError),但 SDK 声明只保留上述两条,避免把整份注册表再喂给模型。

何时不挂 call_tools:

  • 已开启 PTC 模式(mode: 'ptc' 或 'both'),且可见集里已有 run_code。
  • 部署未提供 ctx.ptcRuntime。

检测按会话进行;读不出时保守地不挂载 call_tools。

会话开关、工具箱与工具组

会话级总开关

Web 会话标题栏有「工具箱 开 / 工具箱 关」chip,控制当前会话是否施加网关约束,默认开。状态持久在 $DSH_HOME/storages/tool_gateway/sessions;子代理跟随父会话。关闭后模型看到完整工具表,可直接调用任意工具;执行守卫立即生效,工具表与提示段落在下一轮请求生效。切换时会通过 agent.inject() 注入一条用户可见通知。无 webServer 的 headless 部署不挂界面,开关固定为默认「开」。

工具箱面板

右侧栏「工具」面板列出该会话可见的全部工具(含被网关收起来的)。单工具三态:未设置(跟随组默认)、显式开、显式关。关掉后从 find_tools 结果消失,直接调用会被守卫拒绝;三个元工具不可关。面板改动同样会通知模型。网关开启时,开关只改目录索引与守卫,不用 restrict() 改可见工具表,以免破坏前缀缓存。

工具组

注册方可声明一批工具默认关着,避免一次注册几百个工具时面板爆满。示例(摘自 README):

const gateway = ctx.get('toolGateway')
if (gateway !== undefined) {
  const group = gateway.registerGroup({
    id: 'siyuan-http',
    title: '思源 HTTP 端点',
    origin: 'dsh-plugin-siyuan',
    defaultEnabled: false,
  })
  ctx.effect(() => () => group.dispose(), 'siyuan: gateway group')
  for (const tool of tools) {
    ctx.tools.register(tool)
    group.add(tool.name)
  }
}

未安装网关时 ctx.get('toolGateway') 为 undefined,插件应照常注册工具,只是没有「默认关着」语义。

硬禁用名单

部分工具在任何会话、任何路径(含 call_tool 子分发)都不允许执行。默认禁用 ask_user_question。配置 ban: { deny: [] } 表示显式清空禁用列表;完全不写 deny 才使用默认名单。配置项中的名字在面板里也不可切换。

安装与启用

插件以当前 DSH 进程权限运行,安装前请自行查看源码与 MIT 许可证。要求 Node >=22.19.0。

dsh plugin --profile web add github:leolee9086/dsh-tool-gateway#v0.3.0

安装会依据包内 dsh.bundle.patch 追加到 dsh.profile.bundles,无需手工改 profile 的 cordis.patch.yml。仓库提交的是 lib/ 产物,从 git 安装不需要 pnpm 构建授权。重启 DSH 生效,不需要改 preset。

典型用法(模型侧)

网关开启且会话约束为「开」时,模型侧流程可以概括为:

  1. 用 find_tools 按任务关键词检索,必要时用 offset 翻页,拿到目标工具的完整 schema。
  2. 用 call_tool 传入 tool_name 与 arguments 执行。
  3. 若需连续多步且中间结果不必进上下文,在 PTC 可用且未与官方 run_code 冲突时,用 call_tools 写短程序,内部只调用 tools.find_tools 与 tools.call_tool。

人在 Web 界面可通过标题栏 chip 关闭单会话约束,或在工具箱面板按工具/按组开关;需要看被关工具时用 find_tools({scope: "disabled"})(受审批策略约束)。

适用场景与注意

适合: 工具数量多、经常接 MCP 或热插拔插件,希望模型「先查再调」、并稳定前缀缓存的 DSH 用户;插件作者希望大批量工具默认关着、由用户按需打开。

注意:

  • 插件版本以安装标签为准(资料中为 v0.3.0);锁版本可把 #v0.3.0 换成 commit sha。
  • 硬禁用与 danger-full-access 下对 scope: "disabled" 的限制属于安全设计,部署时需理解审批服务行为。
  • 社区目录 SkillHub 与 DeepSeek / 幻方无官方从属关系;DSH 生态是「一切皆插件」,本文事实均来自上述仓库 README 与 package.json。

结尾

dsh-tool-gateway 用可见性过滤加执行守卫,把工具入口收成检索与调用元工具,并用面板与工具组管理「谁能被查到、谁能被执行」,同时尽量保持模型可见工具表稳定。进一步了解请见目录页 https://www.skillhub.cn/plugins/leolee9086/dsh-tool-gateway 与 GitHub https://github.com/leolee9086/dsh-tool-gateway。

羽毛球分组比赛记分
小程序二维码

欢迎使用《羽毛球分组比赛记分》微信小程序

Xiaoye