dsh-web
zhu1090093659/dsh-webDeepSeek Harness(DSH)Web 插件聚合生态包 · 一切皆插件,创意工坊分发(dsh-market.com)
DSH 宿主插件:每轮对话结束后,把该轮的原始工具结果归档(tool result)到会话目录(tool-result-logs),并从上下文中清除,减少 Token 消耗;模型可用 read_tool_result_log 工具按轮次或时间自主读取归档数据。
[⚠️已废弃]
DSH 宿主插件:在工具结果进入上下文之前做准入过滤。超过阈值的纯文本结果全文落盘到会话目录,模型只收到「收据 + 有界预览 + 绝对路径」;需要原文时 read 归档路径(分页)或 grep 检索取回,也可用插件提供的 read_tool_result_log 按轮/步/时间取回。
当前版本:0.8.6。
tools/post-execute waterfall({ prepend: true }),在结果 materialize 之前决定它的形态。result.content,不受同一条瀑布上其它监听者(如 spill-policy)对模型可见内容的改写影响。isError),只写一条 warning。dsh plugin --profile web add dsh-clear-tool-results
包内的 cordis.patch.yml 通过 package.json 的 dsh.bundle.patch 声明,安装时由宿主注入(id: clear-tool-results-host),无需手工编辑 profile 的 patch 层。安装或升级后需重启 dsh GUI:进程内已 import 的模块不会热替换,不重启则仍在跑旧构建。
| 命令 | 效果 |
|---|---|
/clear-tool-results on | 启用:超过阈值的纯文本工具结果落盘,模型侧只留收据与预览 |
/clear-tool-results off | 停用:工具结果原样进入上下文 |
/clear-tool-results status | 显示启用状态、准入阈值、豁免工具与插件版本 |
$DSH_HOME/clear-tool-results.json(DSH_HOME 未设置时回退 ~/.dsh),内容为 { "enabled": true };旧状态文件里的 mode 字段会被忽略。read_tool_result_log 无条件注册:停用后仍可读取此前落盘的归档,只是不再产生新的落盘。对每条工具结果依次判断,命中任一条即原样放行;全部不命中且是超过 1024 字节的纯文本时才落盘 + 收据:
| 条件 | 处理 |
|---|---|
决策不是 accept,或带 value(结构化输出) | 原样 |
嵌套调用 exec.parent(PTC 子调用,不进模型上下文) | 原样 |
工具是 read_tool_result_log | 原样(它本身就是取回通道) |
read 的目标路径落在任何会话的 tool-result-logs/ 下 | 原样(这是收据指定的取回路径,跨会话也放行;解开了 read → 收据 → read 死锁) |
read 的同一路径第二次起 | 原样(重复读说明真的需要,不再让它多跑一轮) |
read 其余情况(首次读某个大文件) | 与普通工具同规则(>阈值 ⇒ 落盘 + 收据) |
result.isError === true | 原样(报错内容是排障必需) |
| 结果含任何非 text block | 原样(准入策略只认纯文本) |
| 纯文本,≤ 1024 字节 | 原样 |
| 纯文本,> 1024 字节 | 落盘 + 收据 |
取不到 session 上下文时也原样放行。
[bash · npm test · 84,231 字节 / 2,104 行 → 全文已落盘,此处是尾部 30 行]
路径:/Users/…/sessions/…/tool-result-logs/results/t0001-s0003-01-bash-call_00_ab12.txt
取全文:read 该路径(可用 offset/limit 分页),或 grep 该路径检索。
……(中间省略 2,074 行,共 2,104 行)
<尾部 30 行原文>
command/file_path/path/pattern/query/description/prompt/url 的顺序取第一个非空字段。bash/run_code 取尾部(最终状态与错误),其余工具取开头(命中列表与正文开头)。取尾部时省略提示在预览之前,取开头时在预览之后。DSH_HOME 才会触发)。准入过滤永不把上下文变大。read(分页)或 grep(检索),不需要学新工具。grep 不在豁免名单,其结果超过阈值时同样会被收据化。稳定的取回通道是 read——读归档路径始终豁免(见「准入规则」里的三条 read 规则)。<session>/tool-result-logs/
index.json # schemaVersion 3
results/t0001-s0003-01-bash-call_00_ab12.txt
t<turn 4位>-s<step 4位>-<同轮同步序号 2位>-<工具名≤16>-<callId≤12>.txt。turn/step 取自 session/event 维护的每会话游标,取不到时为 0000。index.json:{ schemaVersion: 3, sessionId, workspace, updatedAt, results[] };每条为 { turn, step, callId, tool, hint, file, relFile, bytes, lines, time },其中 file 是绝对路径。callId 只落一份,重放或重试不会重复归档。但 callId 缺失(非字符串)时该机制失效——索引里存 null、查找用 undefined 永不匹配,于是每次调用都会新落一份,且文件名里 callId 段为空(…-bash-.txt,因为 safeSegment 用 ?? '')。index.json 读写竞争。sessionPersistence.locate() 解析;不可用时回退默认布局 $DSH_HOME/sessions/<projectKey>/<encoded-session-id>/tool-result-logs,编码规则与 dsh-session-persistence-jsonl 一致。read_tool_result_log 工具收据里已直接给出单条路径,多数情况直接 read 即可;这个工具用于按轮/步/时间取回。
| 参数 | 说明 |
|---|---|
turn | 轮次编号(1 起),读取该轮全部归档 |
step | 可选,配合 turn 精确到某一步 |
time | ISO 8601 时间或毫秒时间戳,取该时刻(±30 分钟)所在的轮 |
offset / limit | 可选,按行窗口取回;对每条结果各自生效 |
| 都不传 | 归档清单:按轮汇总 + 最近 40 条的坐标与路径,不返回正文 |
纯数字字符串会被归一化成数字(turn: "3" 等价 turn: 3)。
返回体是紧凑纯文本,每条是一段以 --- 开头、以 --- 收尾的区块:
--- turn 3 step 5 · bash · npm test · 第 1-2104 行 / 共 2104 行 · 84231 字节
路径:/Users/…/tool-result-logs/results/t0003-s0005-01-bash-call_00_ab12.txt ---
<正文>
整份载荷受 48000 字节预算约束,超预算的条目会被跳过并提示缩小 turn+step 范围或直接 read 路径。
都不传时是清单模式:不返回正文,每条的头行只给真实尺寸(10,238 字节 / 82 行)与路径,没有行窗口(正文里那行「(清单模式不返回正文)…」只是占位)。
turn 不是正整数时报错「轮次编号必须为正整数」;该轮无归档时报错并列出已归档轮次;time 无法解析时报错。
旧归档可读:0.7.0 写的 round-NNNN.json 仍可按轮取回(正文从旧事件的 tool-result block 中提取);旧版 index.json(只有 rounds、没有 results)按空结果集处理,由旧文件兜底。
| 常量 | 值 | 作用 |
|---|---|---|
INLINE_MAX_BYTES | 1024 | 准入阈值(UTF-8 字节) |
PREVIEW_BYTES | 300 | 收据预览预算(字节) |
RENDER_BUDGET_BYTES | 48000 | 取回渲染总预算,留在 harness 的 50000 字节截断线以内 |
apply() 注册四件事:/clear-tool-results 命令、session/event 监听、tools/post-execute 监听(prepend: true)、read_tool_result_log 工具。session/event 中凡带数字 turn/step 的事件都更新该会话的游标,供落盘时标注坐标。tools/post-execute 里先 await next(),再按准入规则判断;命中落盘条件时用 result.content 写文件并登记 index.json,返回 { kind: 'accept', content: [收据] }(保留上游的 additionalContexts)。warn() 后原样返回上游决策,绝不把成功调用变成错误。warning 同时交给 ctx.logger 并追加到 $DSH_HOME/clear-tool-results.log——只有异常路径写,正常路径零 I/O。read_tool_result_log 从调用方会话目录读 index.json 与落盘文件,返回原文。tools/post-execute waterfall(本机 0.1.5-rc.1 核心验证通过)。不使用 surface 改写,因此不需要按核心代数切换 op 键名,也不需要任何核心补丁。compaction、spill-policy 共存。register() 用 prepend ? 'unshift' : 'push';dsh-tools 的 postExecute 把同一个 result 对象交给每个监听者,只用最外层活下来的 decision.content 覆盖结果。本插件用 {prepend:true} ⇒ 最外层;spill-policy / dsh-tool-fs-search / dsh-repeat-tool-reminder 都不带选项 ⇒ 内层。两个后果:①本插件读到的是原始 result.content,与顺序无关;②模型看到的是本插件收据(指向会话目录里持久的全文),spill 的预览被覆盖——代价是 >50000 字节的结果会被 spill 重复落一份(已知冗余,未处理)。inject: ['commands', 'tools', 'sessionPersistence']。npm test(node --test "test/*.test.mjs")跑 95 个用例,mock ctx 直驱 tools/post-execute 与取回工具。所有 fixture 的字节数由阈值派生(harness.mjs 从源码读 INLINE_MAX_BYTES,并提供 overThreshold()),并有 A0 断言"脚手架阈值 == 实现阈值"——避免阈值变动后测试静默失真(文本不再超阈值 ⇒ 断言可能因为错误的原因变绿)。覆盖:准入判定 22(阈值边界、按字节不按字符、多 text block 无分隔符拼接、read 三条路径规则与跨会话归档豁免、isError/嵌套/非纯文本/value 原样)、收据与预览 12(头行格式、取端规则、300 字节硬上限、单行裁切不切坏码点、收据恒短于原文、无「已清除/已删除」)、落盘与索引 17(文件名与截断、幂等、ordinal、并发、索引损坏重建、路径编码、locate 与回退、无收益时不落盘)、取回 15(清单 / turn / step / time、逐条 offset·limit、48000 预算跳过、报错分支、旧 round-NNNN.json 回读)、旧数据回读 4、状态与命令 6、宿主共存 9(waterfall 顺序、内层改写被丢弃、反序时收据被覆盖但全文已落盘、读归档仍豁免、读普通大文件被收据化、additionalContexts 透传)、失败路径 10(不可写、日志不可写、DSH_HOME 不存在、非 ASCII cwd)。用例走隔离的临时 DSH_HOME,每条一份全新模块实例(DSH_HOME 与 stateCache 都在 import 时定型)。web_fetch 这类结果大小不可预处理的工具(bash 不行——模型会主动把大输出重定向掉)。用隔离的 DSH_HOME 起 headless 会话,抓一个超过 1024 字节的页面:DSH_HOME=<隔离的 DSH_HOME> dsh --profile headless \
--patch <path>/plugin-patch.yml "抓取 <url>,告诉我 <需要看正文细节的问题>"
预期:工具结果被换成收据;模型用 read <收据里的绝对路径> 取回全文;落盘文件出现在 <session>/tool-result-logs/results/。
ls "$DSH_HOME"/sessions/*/*/tool-result-logs/results/
cat "$DSH_HOME"/sessions/*/*/tool-result-logs/index.json
dsh plugin --profile web remove dsh-clear-tool-results;$DSH_HOME/clear-tool-results.json、$DSH_HOME/clear-tool-results.log 与各会话的 tool-result-logs/ 目录。MIT