dsh-web
zhu1090093659/dsh-webDeepSeek Harness(DSH)Web 插件聚合生态包 · 一切皆插件,创意工坊分发(dsh-market.com)
Durable failure journal for dsh tool calls: every abnormal exit appended to JSONL on disk, folded by error signature, readable back by the agent.
同一个错误犯五次,是一行记录 —— 在它滚出上下文之前就已经落盘。
一个 DeepSeek Harness 宿主插件:把每一次异常退出的工具调用追加到磁盘上的
JSONL 日志,把近似相同的失败折叠成带计数的签名,并通过一个工具
failure_journal 交还给 agent。
English · 简体中文
编程 agent 不只是会出错,它会以同样的方式反复出错,而证据在任何人能看出模式之前 就已经离开了上下文窗口:工具结果被折叠、被压缩,或者干脆被后面四次尝试埋掉。
宿主确实有一份会话日志 —— 但会话日志就是模型的上下文。它会被重写、折叠、裁剪。 它不可能是失败历史该待的地方。
所以这个插件维护了第二份记录,在上下文窗口之外,用一种比进程活得更久的格式。
只挂一个 tools/result 监听器 —— 那是宿主对一次调用的最终通知,在
pre-policy、guards、工具本体、post-policy、输出校验全部走完之后才发出。
这一个钩子就覆盖了:
一个钩子顶四个,而且不需要轮询。
每条记录自带上下文,因为一条记录必须在它所属的会话消失之后依然有用:
{"v":1,"at":"2026-09-11T00:31:07.412Z","sessionId":"session-c9a2…","callId":"call_00_…",
"turn":12,"step":3,"tool":"pwsh","aborted":false,"errorCode":"COMMAND_NOT_FOUND",
"message":"'lake' is not recognized as an error…","messageHead":"…","argsChars":41,
"args":"{\"command\":\"lake build\"}","content":"…","signature":"9f2c1ab73e04",
"tag":"failure","recurrence":3,"recurring":true,"firstSeenAt":"2026-09-11T00:28:51.003Z",
"remediation":["The binary is not on PATH for this shell; …"]}
签名(signature)。 每个失败都会被哈希成一个稳定 id,由工具名、错误码和一条 归一化后的消息组成 —— 路径、时间戳、UUID、长数字都被替换成占位符。 四十次近似相同的失败折叠成一行带计数,这才是人能据以行动的单位。
regression: true。 一个在本次会话中先成功过、之后又失败的工具会被标记。
这是日志里最强的信号:本来能用的东西坏了,它指向期间发生的任何改动。
aborted 不算 failure。 被撤回的调用单独打标,永远不计为缺陷。把取消算作失败
会污染复发统计 —— 而复发统计正是这份日志值得读的原因。
内置修复提示。 对成因明确的那几类 —— EDIT_NO_MATCH、EDIT_NOT_UNIQUE、
COMMAND_NOT_FOUND、TIMEOUT、PERMISSION_DENIED、SYNTAX、BAD_ARGS ——
记录里直接带上成因,以及与刚才那次不同的下一步动作。
| action | 回答什么问题 |
|---|---|
stats | 什么在反复坏,按签名折叠。先看这个。 |
list | 最近失败了什么,最新在前 |
show | 某个签名的全部出现记录(支持前缀) |
sessions | 磁盘上有哪些日志文件、多大 |
clear | 归档当前页,重新开始 |
selftest | 证明观察器已挂载、目录可写 |
stats 是真正改变行为的那个。"同一个错误犯了五次"以
count=5, recurring=true 一行呈现,和五段独立的堆栈,对读者来说是两条不同的指令。
本插件和其他所有 dsh 插件一样,作为包安装进一个 dsh profile。
dsh plugin 会在 profile 目录里转发给 pnpm,所以 pnpm 接受的任何 spec 都可以用。
# 从 GitHub 安装(这是公开发布形式)
dsh plugin --profile web add github:catsenior507/dsh-tool-failure-journal
# 本地检出安装(开发时用)
dsh plugin --profile web add /absolute/path/to/dsh-tool-failure-journal
web 是自带 GUI 的 profile;可以换成 headless、sdk、acp 或你自己的 profile 名。
Windows 上路径请用正斜杠,或给路径加引号。
装完重启宿主让 profile 重新组装,然后用这条确认:
failure_journal action=selftest
selftest 会报告观察器是否已挂载,并往日志目录写一个探测文件以证明可写。
dist,没有打包器,
也没有 prepare 脚本,所以安装时不会执行任何东西。dependencies 和 peerDependencies 都是空的;插件只需要它被加载进的
那个宿主。cordis 由宿主在运行时提供。需要 Node.js 20 或更新版本 —— 因为宿主本身就有这个要求。
<DSH_HOME>/failure-journal/sessions/<sessionId>.jsonl,每个会话一个文件,
按大小轮转(maxBytes 默认 4 MiB,保留 maxRotated 代)。
轮转后的旧文件是保留而不是删除:一个会话把同一个错误循环五十次, 正是事后值得读的情形,而在这个文件刚变得有意思的时刻把它截断就本末倒置了。
dsh plugin add 已经替你插入了插件行。要改默认值,编辑 profile 的
cordis.patch.yml 里那一行的 config:
- insert:
- id: tool-failure-journal
name: '@dsh-external/dsh-tool-failure-journal'
config:
maxBytes: 4194304
clusterThreshold: 3
excludeTools: ['todo_write']
recordSuccesses: false
exposeTool: true
recordSuccesses: true 会把成功的调用也记下来 —— 用于回答"这条命令到底干了什么"。
注意:用于 regression 信号的成功追踪无论如何都在跑,这个开关只决定什么写进磁盘。
selftest 报告写入、丢弃、轮转的条数,
所以一份停止工作的日志会自己说出来。npm test # 31 个测试,含真实 cordis 挂载与真实事件
npm test 需要 @deepseek-ai/cordis 可解析 —— 它随 dsh 安装而来。如果你是从检出目录
而不是已安装的包运行,把 node_modules 指向 profile 里的那份;Windows 上目录 junction 即可。
挂载测试在真实的 cordis Context 上注册一个假的 tools 服务,发出真实的
tools/result 事件,再通过工具把日志文件读回来 —— 因为"inject 声明写错了导致
观察器根本没挂上"这一类故障,恰恰是手搓假 context 抓不到的。
| 文件 | 职责 |
|---|---|
lib/index.js | cordis 插件:解析配置、挂载、注册 |
lib/observer.js | tools/result 与 session/event 监听器 |
lib/store.js | JSONL 存储、轮转、归档 |
lib/signature.js | 失败身份、归一化、修复提示目录 |
lib/tool.js | failure_journal 工具 |
MIT