DeepSeek Harness Hub
← 返回列表

静默失败拦截器Rhymer-Lcy/dsh-plugin-loud-failure

DeepSeek Harnessspec-screened在 GitHub 查看 ↗
未验证

识别成功输出中的警告,阻断或提示工具静默失败

尚未跑自动兼容性验证,可查看页面内的依赖与入口分析。 · 最近上游提交 2026/8/17 · 已提供中文文档

DeepSeek Harness 插件,将静默的工具失败变为显式失败:一个 tools/post-execute 策略,匹配成功工具输出中的警告特征,并阻止结果或附加通知

综合分
27.7
GitHub 分
27.7
用户评分
★ Stars
1
周下载量
安装插件(需先安装 dsh CLI 引擎:npm install -g @deepseek-ai/dsh)
dsh plugin --profile web add Rhymer-Lcy/dsh-plugin-loud-failure
该插件未发布到 npm,走 GitHub 源安装(pnpm 若拦截 prepare 脚本,按其提示在 pnpm-workspace.yaml 的 allowBuilds 中放行后重跑)
数据截至 2026/9/16(元数据每日更新 · 实装验证按队列轮转,单条结论的验证时间见上方)
依赖的 DSH / Cordis 模块
@deepseek-ai/cordis@deepseek-ai/dsh-llm@deepseek-ai/dsh-session@deepseek-ai/dsh-system-prompt@deepseek-ai/dsh-tools@deepseek-ai/schemastery
用户评分
还没有人投票,来当第一个
订阅周报,不错过优质插件更新
每周一封 · 高评分插件 + 新用户活动

README

dsh-plugin-loud-failure

ci
license: MIT

一个 DeepSeek Harness 插件,将静默的工具失败转变为显式的失败。

一次工具调用可能以退出码 0 结束,但仍然失败了。pandoc 丢弃一个字形却只发出警告;管道吞掉一个 Python traceback;; 链隐藏了 command not found;NumPy 打印一个 RuntimeWarning 并返回 nan。退出码显示成功,模型读到成功,错误便向下游传播。这个插件就是一个 tools/post-execute 瀑布监听器:它将工具返回的文本与规则表进行匹配,命中时要么阻断结果(结果变为一个 isError 结果,其内容以解释开头并保留原始输出),要么附加一条提示,该提示会出现在模型的下一次请求中。它不改变任何工具,也不改变任何循环:它参与有序的 post-execute 瀑布(仅上下文的匹配会委托并保留下游决策;阻断匹配则有意短路),并能干净地卸载。

目录

- 为什么
- 工作原理
- 安装
- 配置
- 内置规则
- 模型看到的内容
- 验证
- 设计说明
- 模型体验
- 已知限制与推迟的工作
- 开发
- 许可证

为什么

每条内置规则都来自一次被观察到隐藏在成功退出码背后的失败:

| 观察到的情况 | 模型看到的内容 | 实际发生的事 |
|---|---|---|
| pandoc ... --pdf-engine=xelatex 打印 Missing character: There is no ₂ in font ... | 写出了一个 PDF,退出码 0 | SpO₂ 中的下标被静默地从 PDF 中丢弃 |
| python script.py \| tail -n 20 | 最后 20 行,退出码 0 | 一个 traceback 滚了过去;tail 提供了退出状态 |
| pandocc in.md -o out.pdf; ls -l out.pdf | bash: pandocc: command not found 后跟一个列表,退出码 0 | 什么都没构建;ls 提供了退出状态 |
| python calc.py 打印 RuntimeWarning: invalid value encountered in divide | 一个数组,退出码 0 | 该数组包含 nan |
| 一条使用 2>&1 运行的 PowerShell 5.1 命令 | NativeCommandError,$? 为 false | 程序已以 0 退出;PowerShell 包装了它的 stderr |
| 一个打印 ��� 的 Windows 控制台 | 文本,退出码 0 | GBK/UTF-8 代码页不匹配;文本已损坏 |

harness 已经记录了模型看到的一切,并允许任何插件在模型看到工具结果之前重写它。这个插件正是利用这个接缝,在失败发生的那一刻让它可见,而不是三步之后。

工作原理

flowchart LR
call["tool/call"] --> pre["tools/pre-execute"] --> exec["tools/execute"] --> post["tools/post-execute(this plugin)"] --> result["tool/result"]
post -->|"error rule matched"| block["block: isError resultheader + original output"]
post -->|"context rule matched"| notice["accept + additionalContextsplugin-sourced notice"]
post -->|"no match"| next["next()"]

1. 加载时,插件会将内置规则与配置的规则合并(具有内置 id 的用户规则会替换它),并编译每个模式。不可用的表(无效的正则表达式、重复的 id、有状态标志、空消息)会以违规的规则 id 拒绝插件加载,因此损坏的配置会在启动时失败,而不是在第一次工具调用时失败。
2. 在每次 tools/post-execute 时,结果的文本块(可选地还包括成功规范值的 JSON)会与 when 和 tools 过滤器适用的规则进行匹配。当结果为 isError 或其文本带有随附 shell 工具自身追加的失败标记时,该结果对 when 过滤器而言算作失败:一行 N != 0 的 [exit code: N]、一个带有非零退出码的 [status: ...] 尾部标记,或一条 [sandbox: file access denied ...] 通知。模型已经看到这些;它们并非静默,因此 when: success 规则保持安静。
3. 如果任何匹配的规则具有 action: error,监听器会返回 { kind: 'block' },其反馈以一个标题开头,标题列出每个匹配的规则及其消息,随后是未更改的原始内容块;工具主体延迟的上下文会携带在决策上,因此 block 不会将其丢弃。注册表会将其转换为 isError 结果:规范值消失,因此 Code Mode 程序也无法消费被污染的值。
4. 否则(仅 context 匹配),监听器通过 next() 委托,并向决策的 additionalContexts 追加一个 UserMessage。其来源为 { kind: 'plugin', plugin: 'loud-failure', form: 'notice', summary },因此 Web UI 会显示一个折叠的单行行,会话日志会准确记录模型被告知的内容。
5. 无匹配:next()。具有 action: off 的规则永不运行。

因为监听器通过 ctx.on 注册,它会随插件一起拆除;配置更改会重新加载插件并注册一个新的监听器。

安装

需要 DeepSeek Harness 0.1.0-rc.6(@deepseek-ai/dsh-tools 和 @deepseek-ai/dsh-llm 为 0.1.0-rc.6)以及 Node.js 20+。这是该插件唯一测试过的版本;该 harness 是开发者预览版,可能会破坏兼容性,因此 peer 范围被固定并随每个版本提升。dsh plugin add 会为 @deepseek-ai/ 打印 peer 依赖警告:这是预期行为,因为 profile 从 harness 安装中解析这些包,而不是将它们安装在插件旁边。

从发布 tarball 安装(无需构建步骤,无需构建授权):

sh
dsh plugin --profile web add https://github.com/Rhymer-Lcy/dsh-plugin-loud-failure/releases/download/v0.1.1/dsh-plugin-loud-failure-0.1.1.tgz
dsh --profile web --dump-config   # 显示一个 "# == dsh-plugin-loud-failure" 层

从 GitHub 的固定提交安装: git 安装会获取源代码,因此必须允许 pnpm 运行此包的 prepare 脚本(它会运行 tsc)。第一次 add 会失败并打印出需要允许的确切键(对于固定提交,该键包含 codeload URL);将其追加到该 profile 的 pnpm-workspace.yaml,然后重新运行:
sh
dsh plugin --profile web add github:Rhymer-Lcy/dsh-plugin-loud-failure#
yaml
$DSH_HOME/profiles/web/pnpm-workspace.yaml(键从 pnpm 的消息中复制)
allowBuilds:
"dsh-plugin-loud-failure@https://codeload.github.com/Rhymer-Lcy/dsh-plugin-loud-failure/tar.gz/": true

请如实看待该授权:来自此仓库的代码会在安装时在你的机器上运行,处于任何 agent 沙箱之外。请固定提交。

从源代码检出运行,无需安装:
sh
git clone https://github.com/Rhymer-Lcy/dsh-plugin-loud-failure.git
cd dsh-plugin-loud-failure && pnpm install && pnpm run build
yaml
overlay.yml
- insert:
- id: loud-failure
name: /absolute/path/to/dsh-plugin-loud-failure/lib/index.js
sh
dsh web --patch ./overlay.yml

使用 dsh plugin --profile web remove dsh-plugin-loud-failure 卸载。

配置

该 bundle 插入一行,id: loud-failure,并重述了 schema 默认值。补丁会替换某一行的整个 config,因此你 profile 的 cordis.patch.yml 中的覆盖必须重述它保留的每一个键。

| 键 | 类型 | 默认值 | 含义 |
|---|---|---|---|
| builtinRules | boolean | true | 在用户规则之前加载内置规则表。 |
| rules | Rule[] | [] | 用户规则。与内置规则共享的 id 会就地替换该规则;新 id 按顺序追加;两个具有相同 id 的用户规则会导致加载失败。 |
| shellTools | string[] | [bash, pwsh, job_output] | 由省略 tools 的规则检查的工具。在此处添加其他类似 shell 的工具(例如来自另一个 bundle 的终端读取工具)。 |
| excerptChars | natural | 240 | 向模型显示的匹配摘录的最大字符数。 |
| scanValue | boolean | false | 同时扫描成功规范值的 JSON,用于文本投影隐藏 stderr 的工具。注意:这会在匹配之前对整个值执行 JSON.stringify,并且匹配会向模型和会话日志显示该原本隐藏值的最多 excerptChars 个字符。 |

一条规则:

| 字段 | 类型 | 含义 |
|---|---|---|
| id | string,必填 | 稳定标识符。 |
| pattern | string,必填 | JavaScript 正则表达式源。 |
| flags | string | i、m、s、u 中的任意一个。g 和 y 会被拒绝,因为它们会在调用之间携带状态。 |
| tools | string[] | 规则适用的工具。省略或为空:shellTools。['']:所有工具。 |
| when | success \| error \| any | 规则检查哪些结果。默认为 success,因此已经失败的结果不会被重复修饰。 |
| action | error \| context \| off,必填 | error 阻止,context 附加通知,off 禁用该规则。 |
| message | string,必填 | 该特征的含义以及模型接下来应该做什么。它会原样展示给模型。 |

禁用一个内置规则并添加一个你自己的规则:
yaml
$DSH_HOME/profiles/web/cordis.patch.yml
- id: loud-failure
config:
builtinRules: true
rules:
- id: no-such-file-with-success
pattern: unused
action: off
message: unused
- id: cuda-oom
pattern: 'CUDA out of memory|torch\.OutOfMemoryError'
tools: [bash, pwsh, job_output]
action: error
message: 'The GPU ran out of memory; whatever this run was supposed to produce is incomplete. Reduce the batch size or free VRAM, then rerun.'
shellTools: [bash, pwsh, job_output]
excerptChars: 240
scanValue: false

内置规则

所有内置规则都使用 when: success 并适用于 shellTools。

| id | action | 触发条件 |
|---|---|---|
| pandoc-missing-character | error | 以 Missing character: There is no  或 [WARNING] Missing character: There is no  开头的行(通过 pandoc 调用 xelatex/lualatex;PDF 缺少字形) |
| python-traceback-with-success | error | 在报告成功的结果中,以 Traceback (most recent call last): 开头的行(允许前导空白或 ANSI 颜色代码) |
| shell-command-not-found | error | bash: [line N:] name: command not found 和 sh: N: name: not found 行 |
| windows-command-not-recognized | error | 形如 'name' is not recognized as an internal or external command 或 [prefix: ][The term ]'name' is not recognized as a/the name of a cmdlet 的行 |
| fatal-signal-with-success | error | shell 崩溃行:Segmentation fault(带或不带 (core dumped)),或带 (core dumped) 的 Bus error / Aborted,可选前缀为 bash: line N: PID |
| numpy-runtime-warning | context | RuntimeWarning: invalid value encountered / divide by zero encountered / overflow encountered |
| powershell-native-command-error | context | NativeCommandError |
| latex-undefined-references | context | LaTeX Warning: There were undefined references / Citation ... undefined / Reference ... undefined |
| latex-rerun-needed | context | Rerun to get cross-references right、Rerun to get outlines right、rerunfilecheck Warning |
| pandoc-could-not-fetch-resource | context | [WARNING] Could not fetch resource |
| no-such-file-with-success | context | No such file or directory |
| permission-denied-with-success | context | Permission denied |
| unicode-replacement-character | context | 输出中的任何 U+FFFD 替换字符 |

error 规则按行锚定到工具实际打印的形态,这排除了常见的引用子串提及(grep -r "command not found" logs/,一个引用 pandoc 警告的 README);逐字回显真实日志行的文件仍会匹配,这是已知的局限。context 规则有意更宽泛,因为通知成本很低,而模型会保留原始结果。

模型看到的内容

一个被阻止的结果,完全按渲染后的样子呈现(第二个内容块是未经改动的原始输出):
text
[loud-failure] Tool "bash" reported success, but its output matched a rule (pandoc-missing-character) that indicates a silent failure. dsh-plugin-loud-failure marked this result as an error; do not treat the call as successful.

- pandoc-missing-character (error): pandoc/xelatex dropped one or more glyphs; the produced PDF is missing characters even though the exit code was 0. Rewrite the character (for example write SpO2 instead of a subscript digit) or switch to a font that has it, then rebuild and re-check for this warning.
excerpt: "pandoc thesis.md -o thesis.pdf --pdf-engine=xelatex\n[WARNING] Missing character: There is no ₂ in font Microsoft YaHei/OT!\n[exit code: 0]"

The original tool output follows unchanged.

附加到成功结果上的通知(结果本身未改动;它以 user 角色消息到达,来源为 {"kind":"plugin","plugin":"loud-failure","form":"notice","summary":"loud-failure: bash output matched numpy-runtime-warning"}):
text
[loud-failure] Notice for tool "bash": its output matched a rule (numpy-runtime-warning) that often means a silent failure. Verify before relying on this result.

- numpy-runtime-warning (context): NumPy raised a RuntimeWarning about NaN, division by zero, or overflow. Downstream numbers may be NaN or inf while the exit code stays 0. Check the affected arrays before using the result.
excerpt: "python calc.py\ncalc.py:12: RuntimeWarning: invalid value encountered in divide\n[0.5 nan 0.25]"

验证

pnpm run check 运行类型检查、测试、构建和打包 dry-run;CI 在 Ubuntu 和 Windows 上使用 Node 20 和 22 运行它。总共 87 个测试。

- tests/rules.test.ts 覆盖合并(包括重复用户 id 拒绝)、编译失败(每个都带其消息)、过滤器、无状态性、摘录边界、失败标记检测器,以及每条内置规则针对真实签名和负面用例(干净输出、非 shell 工具、已失败的结果、引用提及、作为普通单词的 Aborted)。
- tests/plugin.test.ts 将插件挂载到真实的 ToolRuntime 旁边,并通过完整流水线驱动工具调用:保留原始输出的 block、带插件来源的 notice、error 优先于 context、工具与 when 过滤器、带有 [exit code: N] / 作业状态 / 沙箱标记的结果不被 success 规则触碰、when: any 仍会作用于它们、被 block 后延迟的工具上下文仍然保留、内置覆盖、省略了 tools 的用户规则、scanValue、与下游 tools/post-execute 监听器的组合、干净卸载,以及在错误规则表上大声失败。
- 该 bundle 还在 Windows 上针对 @deepseek-ai/dsh@0.1.0-rc.6 进行了演练:从检出目录执行 dsh plugin add、从 v0.1.0 发布 tarball URL 执行,以及从 github:...#(带 allowBuilds 键)执行,都能正常组合,并且 --dump-config 会显示该层;使用注入无效规则的 overlay 启动 dsh --profile web 会在启动时失败,并从已安装插件的 apply 抛出 RuleConfigError: rule "bad": invalid pattern,而使用随附配置启动则会提供 Web UI。

设计说明

- 使用 tools/post-execute,而不是 tools/result。 tools/result 只能观察冻结后的结果;这里的重点是改变模型看到的内容,而这正是 post-execute 的用途(替换内容、带反馈地 block、附加 context)。
- Block 会保留原始输出和延迟的 context。 否则,被 block 的结果会抹掉模型修复问题所需的证据。header 放在最前面,这样模型会先读到判定,再看到噪声;原始 blocks 原样跟随其后,而工具主体延迟的 context 会随决策一起传递,而不是被丢弃。
- 两种严重级别,没有第三种。 error 用于表示工作没有发生的签名;context 用于表示“先检查再信任”的签名。比这更软的任何东西都不值得一个 token。
- 使用正则表达式,而不是模型。 这些签名是工具发出的字面字符串;正则表达式是确定性的、廉价的、可测试的,并且可以在配置转储中审计。语义属于模型,模型会获得规则消息和摘录。
- 加载时大声失败。 规则表是配置;错误的规则表应该带着规则 id 停止启动,而不是退化成永远不会触发的监听器。
- 瀑布式礼仪。 阻塞性决策会短路,正如拥有决策权的策略监听器应该做的那样;context 决策会先委托,再丰富返回的任何内容,因此下游替换会保留下来。在此监听器之前注册的监听器会包裹它,并且仍然可以覆盖任一结果。

模型体验

请求上下文与条件

模型看到的内容
仅在规则匹配时生效。对于 error 匹配:工具结果变为 isError: true,其内容为一个文本块,渲染方式如模型所见中所述,后跟原始内容块。对于仅 context 匹配:工具结果保持不变,并在该批次记录的工具结果之后追加一条 user 角色的通知消息,来源为 { kind: 'plugin', plugin: 'loud-failure', form: 'notice', summary }。规则消息属于配置,按原样显示;摘录受 excerptChars 限制。

Token 影响

有条件的。无匹配时为零。匹配时:头部加上每条匹配规则的消息以及最多 excerptChars 个字符的摘录。一个块只添加该头部;随后的原始块与模型本来就会收到的字节相同。

KV 缓存影响

仅追加。该插件不贡献系统提示部分,也从不重写更早的历史;一个块在首次记录之前更改当前工具结果的内容,而通知则在该批次的工具结果之后追加。两者都不会使任何先前可复用的前缀失效。

已知限制与待办工作

- 仅限文本。 监听器检查文本块(以及在使用 scanValue 时,检查成功值的 JSON)。如果失败在输出中未留下任何痕迹,例如某个库返回了负状态码而脚本从未打印它,则无法在此处捕获;针对这类情况的模式是打印该值,并让规则捕获它。
- 正则表达式可能误报。 context 规则在设计上较为宽泛;如果它在你的工作负载中过于嘈杂,可用 action: off 禁用某条规则。被阻止的结果仍携带原始输出,因此一次误报的 error 只会让模型多花一步纠正,而不会丢失信息。
- 仅识别三种失败标记。 [exit code: N]、带有非零退出码的 [status: ...] 尾部标记,以及沙箱拒绝通知。shell 工具以文本形式报告失败的其他方式(信号名称、超时)尚未被视为失败结果,因此 success 规则仍可能对它们触发。
- 全文扫描。 非常大的工具输出会按每条规则扫描一次;随附的 shell 工具已经会截断长输出,因此这在实践中尚未成为成本问题,但目前还没有大小上限。
- run_code 聚合输出。 Code Mode 子分派的每一轮都会经过 post-execute 并单独检查;当 run_code 被列入 shellTools 时,外层 run_code 结果(程序日志和返回值)会作为普通文本检查,而默认情况下它并不在列表中。
- 无按代理作用域。 监听器注册在插件上下文上,会看到每个代理的调用。将其作用域限定到子代理预设是 Cordis 层面的工作,此处未尝试。

开发
sh
pnpm install
pnpm run check          # typecheck + test + build + pack dry-run
pnpm run test:watch

源代码位于 src/(rules.ts 是纯函数且经过单元测试;index.ts 是 Cordis 适配器);测试位于 tests/;lib/ 是由 tsc 以及 git 安装时的 prepare 脚本生成的构建输出。

许可证

MIT

上游仓库有新提交时邮件通知你(每天最多一封,无更新不打扰),随时一键退订。

💬 加入 DPharness 群聊

插件用法、部署报错、新插件第一时间同步——群里问,比一个人翻文档快。

点击加入 QQ 群
DPharness 群聊二维码,手机 QQ 扫码进群
扫码进群