DSH HUB
HomePlugin StorePlugin PacksCommunityRankingsResourcesPublish Guide
Plugin source
Back to catalog

bushizhanghan /

bushizhanghan/dsh-arg-guard

Verified

DSH plugin: validate every tool call against the schema the tool declared (tool-argument schema guard)

★ 0 Stars0 Forks0 IssuesN/A Community rating0 Confirmed installs
View on GitHub
READMESource: main@e0d928a9

dsh-arg-guard — 工具入参 schema 守卫(DSH 插件)

DSH 校验工具输出:output.schema 对不上就抛 ToolOutputError。 它从不校验工具输入:parameters 只是渲染进模型提示词的一张纸。 于是错类型一路走到工具函数体里,变成一句裸 Node TypeError—— The "path" argument must be of type string、p.replace is not a function、 slug.toLowerCase is not a function。对 5 个已发布插件做 148 次参数模糊调用, 47 次以这种裸错误结束,来自 12 个不同入口点。

这个插件补上那道缺口:在 host 的 tools/pre-execute 瀑布里,按工具自己声明的 parameters 校验入参;违规就拒绝,并把确切的 JSON 路径 + 期望类型交给模型。 模型看到的不再是崩溃,而是一句能照着改的错。

缺口的位置(读 host 源码确认,不是推测)

位置 事实
_dsh-tools.js:3321 const gate = await this.ctx.waterfall(carrier, "tools/pre-execute", exec, () => ({ kind: "allow" })) —— 唯一的入参关卡
_dsh-tools.js:3345 拒绝理由原样变成模型看到的 Error: <reason>
_dsh-tools.js:3091 / 3107 get(name, scope) / resolveExecution(name, scope, nested) 拿得到定义,定义上带 parameters
输出侧 output.schema 有强制校验,会抛 ToolOutputError

也就是说:schema 写给模型看,但没人照着检查。 每个插件作者只能自己手写 typeof 守卫,而手写的总会漏——上面 47 次里没有一次是"作者知道但选择不防"。

它做什么

注册一个 tools/pre-execute 处理器,对每次工具调用:

{"dir":123}                      → {"kind":"deny","reason":"publish_gate.dir: expected string, got number (123)"}
{"mode":"fix"}                   → {"kind":"deny","reason":"publish_gate.dir: required but missing"}
{"dir":"E:/p","mode":"slow"}     → {"kind":"deny","reason":"publish_gate.mode: expected one of \"check\", \"fix\", got string (\"slow\")"}
{"dir":"E:/p","extra":1}         → {"kind":"deny","reason":"publish_gate.extra: unexpected property (allowed: dir, mode)"}
{"dir":"E:/p","mode":"fix"}      → {"kind":"allow"}

(上面是真实输出,用 publish_gate 的 schema 驱动。)

拒绝理由的格式固定为 <工具名>.<JSON 路径>: expected <类型>, got <类型> (<值>), 根级错误省掉点号:publish_gate: expected object, got string ("…")。

安装

dsh plugin --profile desktop add @bushizhanghan/dsh-arg-guard

重启 DSH 后生效。只读:不写磁盘、不发网络请求,计数器只在内存里。

配置

- id: arg-guard
  name: "@bushizhanghan/dsh-arg-guard"
  config:
    enabled: true        # 总开关,默认 true
    mode: deny           # deny = 拦截;warn = 只记录、放行
    skip: []             # 不检查的工具名,例如 [bash]

上线顺序建议:先 mode: warn 跑一段时间,用 arg_guard_status 看 violations 里有没有误报(工具声明的 schema 比真实契约更严时会误报), 确认干净再切 deny。

Agent 工具

工具 作用
arg_guard_status hook 是否挂上、mode、skip、计数器(checked/allowed/denied/warned/skipped/errors)、最近 10 条违规
arg_guard_check {tool, args} 干跑:返回和真实 hook 完全一致的 verdict 与理由,不执行、不计数

arg_guard_check 的典型用法:某次调用被拒了,把当时的参数丢进去看为什么; 或者发请求前先自检一遍,省一次往返。

校验哪些规则

规则 例
原始类型 type: string / number / integer / boolean / null
类型联合 type: ["string","null"]
必填 required: ["dir"](传 undefined 等同于没传)
枚举 / 常量 enum、const
嵌套对象 properties 递归,路径用点号连起来
数组元素 items(对象或元组形式)
封闭对象 additionalProperties: false(patternProperties 命中的键放行)
变体 oneOf / anyOf / allOf

不校验什么(明确的边界)

  • 不做类型强转:schema 说 integer,"3" 就是错的。守卫的职责是让模型改, 不是替它猜。
  • 不认识的 JSON Schema 关键字一律忽略:$ref、if/then/else、format、 dependencies、自定义关键字——看不懂就不判定,因为看不懂不等于调用是错的。
  • 不校验输出:host 已经在做了。
  • 不做跨进程:只作用于注册在同一个 host 里的工具。

为什么它不会把工具调用搞坏

这是这个插件的第一原则:守卫弄坏的调用,比没有守卫更糟。

  • 整个处理器包在 try/catch 里,任何异常都 fall through 到 allow;
  • 解析不到定义(工具没注册、被 scope 限制、resolveExecution 抛错)→ allow;
  • 工具没声明 parameters.properties → allow(没有契约就不存在违约);
  • 类型名不认识 → 不判定;
  • schema 本身畸形(不是对象、是数组)→ allow;
  • 有 skip 名单,随时能放行某个工具;
  • 有 mode: warn,可以先只观测。

validateArguments 本身也是纯函数 + 全 try/catch:它是 38 个测试里唯一被直接 断言的对象,包括"定义查询抛错仍然放行"这条。

开发

npm test        # node --test,38 个用例

lib/engine.js 是纯函数(validateArguments(parameters, args) → null 或一句理由), lib/index.js 只负责挂 hook、查定义、记账、注册两个只读工具。

License

MIT

—/ 5

No ratings yet

Verified DSH bundle

Commit e0d928a952ab

Community comments

No comments yet. Be the first to write one.

DSH HUB

A community index for DSH plugins. Not an official GitHub or DeepSeek AI product.

CommunityResourcesAPIAbout