🎁 福利专区全网大模型免费应用 + 新用户福利 + 注册活动入口,低成本玩转 AI

思考剥离 miao-pa-si-wutao/dsh-think-strip

DeepSeek Harness
miao-pa-si-wutao11 天前有提交已提供中文文档扫描:含敏感能力

剥离历史思考与超长工具输出,原文归档可查

30/100
综合分
0
GitHub 星标
—
npm 周下载
—/5
用户评分

数据截至 2026/10/24 · 周下载取自 npm 全网(含 CI / 镜像),非本站安装数;综合分由星标、活跃度与兼容性检查合成。

安装命令 · 需先装 dsh CLI 引擎
dsh plugin --profile web add miao-pa-si-wutao/dsh-think-strip
该包不可直接 npm 安装,改从 GitHub 源安装(明细见下方安装检查)

状态速览

判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态
信任档位:仅索引
是什么
dsh 原生插件 · chat
装得上吗
本站尚未做安装检查
安全吗
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
还在维护吗
活跃:最近一次提交在 11 天前
档位由哪些信号合成

本站实装验证(真实安装 L4 覆盖全站;L5 为运行时冒烟或实机截图,覆盖范围小于 L4) · 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。 下方各区块是它的证据明细。

验证判据与等级说明 →
社区实装还没有人打卡 · 装过的第一个就是你
安全扫描自动 · 静态分析源码
v2.7.0
🔵 扫描:含敏感能力尚无人工评估
展开查看扫描说明与证据 ↓

静态扫描发现插件具备触达本地系统的能力:执行外部命令、读写/删除本地文件、读取剪贴板或密钥类环境变量(至少其一)。这是能力清单,不是危险判定——具体能力项与证据见下方,安装前请自行判断是否需要。

读写/删除本地文件发起外部网络请求
查看扫描证据(共 12 处,展示前 12 条)
  • 写入本地文件
    lib/index.js:153
    await mkdir(root, { recursive: true });
  • 写入本地文件
    lib/index.js:154
    await appendFile(
  • 写入本地文件
    lib/index.js:185
    await mkdir(dir, { recursive: true });
  • 读取本地文件
    lib/index.js:190
    await access(full);
  • 写入本地文件
    lib/index.js:195
    await writeFile(full, `${JSON.stringify(record, null, 2)}\n`, 'utf8');
  • 写入本地文件
    lib/index.js:196
    await appendFile(path.join(root, 'index.jsonl'), `${JSON.stringify(entry)}\n`, 'utf8');
  • 写入本地文件
    lib/index.js:222
    await appendFile(path.join(root, 'plugin.log'), `${new Date().toISOString()} ${line}\n`, 'utf8');
  • 发起网络请求
    client.js:93
    fetch(API + '?sessionId=' + encodeURIComponent(sessionId), {
  • 发起网络请求
    client.js:128
    fetch(API + '?sessionId=' + encodeURIComponent(sessionId), {
  • 读取本地文件
    lib/pure.js:152
    const raw = await readFile(file, 'utf8');
  • 写入本地文件
    lib/pure.js:171
    await mkdir(root, { recursive: true });
  • 写入本地文件
    lib/pure.js:172
    await writeFile(file, `${JSON.stringify(store, null, 2)}\n`, 'utf8');
扫描于 2026/11/4(0 天前) · 范围 入口闭包 + 发布文件清单 · 来源 GitHub 仓库

静态扫描只反映源码中出现的调用,不构成安全背书;人工评估与自动扫描相互独立、互不覆盖。

依赖的 DSH / Cordis 模块
@deepseek-ai/cordis@deepseek-ai/dsh-session@deepseek-ai/schemastery
给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个

让 DeepSeek Harness 会话撑过几百轮:从上下文里剥掉历史推理块和过大的工具输出,把原件归档到磁盘,只留一行占位。按会话开关。

README

由 DeepSeek 最新模型翻译生成
dsh-think-strip English · 中文 把历史里的思考(reasoning)块和过长的工具输出从模型上下文中剥离,原文按时间戳归档到磁盘并建可检索索引:思考每处留一行摘要,工具结果留「头 1200 字 + 尾 400 字」预览 + 归档路径。 聊天输入框左侧有两个开关(思考 / 工具),按会话独立,互不影响;新会话走默认值。 它解决什么 DeepSeek Harness 每次请求都会把历史 assistant 消息里的 reasoning 块原样回传(dsh-llm-deepseek/lib/index.js 的 assistant() 里 case "reasoning" 没有任何过滤),工具结果也整段回传。
展开完整文档(README 剩余 1 节)
dsh-think-strip

English · 中文

把历史里的思考(reasoning)块和过长的工具输出从模型上下文中剥离,原文按时间戳归档到磁盘并建可检索索引:思考每处留一行摘要,工具结果留「头 1200 字 + 尾 400 字」预览 + 归档路径。

聊天输入框左侧有两个开关(思考 / 工具),按会话独立,互不影响;新会话走默认值。

它解决什么

DeepSeek Harness 每次请求都会把历史 assistant 消息里的 reasoning 块原样回传(dsh-llm-deepseek/lib/index.js 的 assistant() 里 case "reasoning" 没有任何过滤),工具结果也整段回传。在真实会话 session-f0b74f94(1101 条工具结果 / 1118 条 assistant 消息)上实测:

| 项目 | 数值 |
| 工具输出总字符 | 2,163,722 |
| 其中 ≥4000 字符的 | 128 条,合计 1,426,922 字符(66%) |
| 思考块 | 776 块,合计 1,078,446 字符 |
| tool/result 的 content 形状 | text × 1069、text,image × 32 |

也就是说:压缩 128 条长工具输出可省约 122 万字符,剥离思考可省约 108 万字符,两项都是百万字符级。

同时保证:

- 不改写 append-only 会话日志。原文永远在 session.v4.jsonl.zstd 里,fork / resume / replay 不受影响。
- KV cache 前缀不受损。剥离散布在历史中段,但一旦剥离完成,后续每步的消息序列保持字节一致,前缀缓存照常命中。
- 原文可查。每条被剥离的内容写成独立 JSON 文件,索引汇总在 index.jsonl;工具输出的替换文本里直接写了归档绝对路径。

工作原理

两条通道配合,都不碰日志原文:

1. appendPluginRecord(session, 'plugin:think-strip', { targets, indexed }) —— 写一条 ignorable: true 的插件记录。它不进 surface nodes、不改 contentGeneration 之外的任何状态,DSH 重启后仍能重放。
2. ctx.sessions.registerMessageProjection({ type: 'plugin:think-strip', project }) —— 注册同类型名的投影。fold 时把记录点名的 seq 换成冻结副本(message.id 保留不变)。

targets 每项是 { seq, kind, summary?, replacement? },kind 为 'reasoning' 或 'tool'。没有 kind 的旧记录按 'reasoning' 解释,所以 v0.1 写的记录继续有效,老会话不会因为升级而失效。

时序:监听 agent/turn-stopping(回合即将关闭,模型不再欠回复)→ 回扫全部历史 → 先归档原文 → 再提交一条记录覆盖全部目标 seq。

回扫全部历史而不是只扫本轮,是因为插件启用前、或开关打开前的回合也积压着原文,只处理当轮会让它们永远留在上下文里。已处理过的消息经 session.deriveEventMessage(event) 读出来时已经不含原文(投影已应用),所以天然幂等跳过。同时会用 session.surface.nodes 作白名单,跳过已被压缩遮蔽的旧消息。

为什么不是别的做法

| 候选 | 为什么不行 |
| agent/pre-step 改写 messages | 该数组只是本步新认领的 user 批次,历史不在其中(dsh-agent-loop/lib/index.js:902-927 的 this.inbox.claim(...)) |
| surface replace 写 assistant/message | 源码硬拦:assistant/message embeds its source stream and cannot carry sourceEventSeqs |
| llm/stream waterfall 改 options.messages | 请求是 deep-frozen 的,「listeners read it, never rewrite it」 |
| agent/request waterfall | 官方明示「this waterfall cannot mutate messages」 |
| 直接 session.append() 自定义类型 | 普通 append 无法设置 ignorable,会话重开会拒绝未知事件 |
| 内置 tool-result-pruner | 本机这版 DSH 上它是坏的:读 event.data.message.content[0].content(假设嵌套结构),而实际是扁平 ContentBlock[] → pruneContent(undefined) 抛错。而且 cordis.yml:321 本来就是 disabled: true |

两个会话级开关

输入框左侧两个 role="switch" 的小按钮:

- 思考 —— 本会话是否剥离历史思考内容
- 工具 —— 本会话是否压缩历史里过长的工具输出

状态按 sessionId 存在 <archiveDir>/switches.json:

{
"defaults": { "reasoning": true, "tools": false },
"sessions": { "session-f0b74f94": { "reasoning": false } }
}

优先级:会话覆盖 > defaults > Config。开关只决定「这一轮要不要提交新的剥离记录」,已经提交的记录永远继续生效(日志不可改写,这是设计使然)。想撤销某个会话的剥离,只能归档该会话或接受它继续被投影。

查询 / 修改(只接受 loopback):

读 Invoke-RestMethod 'http://127.0.0.1:<DSH_WEB_PORT>/think-strip/state?sessionId=session-f0b74f94'

关掉该会话的思考剥离;tools:null 表示清除覆盖、回落到默认 Invoke-RestMethod 'http://127.0.0.1:<DSH_WEB_PORT>/think-strip/state?sessionId=session-f0b74f94' -Method Post -ContentType 'application/json' -Body '{"reasoning":false}'

归档布局

<archiveDir>/
├── switches.json # 会话级开关 ├── index.jsonl # 每行一条索引 ├── plugin.log # 启动标记(排查 apply 有没有跑) └── <sessionId>/ ├── 2026-10-20T10-33-24-123Z-t3-s1-q42.json # 思考 └── 2026-10-20T10-33-24-456Z-tool-97.json # 工具输出

单条归档文件内容(思考):

{
"kind": "reasoning",
"time": 1760950000000,
"sessionId": "session-f0b74f94",
"turn": 3,
"step": 1,
"seq": 42,
"model": "deepseek-v4.1-flash",
"chars": 2514,
"summary": "用户要算 1+1。", "reasoning": "(完整思考原文)", "text": "(该条回复的正文)" }

单条归档文件内容(工具输出):

{
"kind": "tool",
"time": 1760950000000,
"sessionId": "session-f0b74f94",
"turn": 3,
"step": 1,
"seq": 97,
"toolName": "pwsh",
"chars": 49932,
"summary": "pwsh 输出 49932 字符", "text": "(工具输出全文)" }

索引行:

{"time":1760950000000,"sessionId":"session-f0b74f94","kind":"tool","turn":3,"step":1,"seq":97,"toolName":"pwsh","chars":49932,"summary":"pwsh 输出 49932 字符","file":"session-f0b74f94/2026-10-20T10-33-24-456Z-tool-97.json"}

检索示例(PowerShell):

按关键词找 Select-String -Path "$env:USERPROFILE\.dsh\think-archive\index.jsonl" -Pattern "关键词"

只看工具输出、按字符数排 Get-Content "$env:USERPROFILE\.dsh\think-archive\index.jsonl" |
ForEach-Object { $_ | ConvertFrom-Json } |
Where-Object { $_.kind -eq 'tool' } |
Sort-Object chars -Descending |
Select-Object -First 20

模型在上下文里看到的工具结果是:

(头部若干字)
…[工具输出已归档]…
(原文 49932 字符已归档:<DSH_HOME>\think-archive\session-xxx\2026-….json;可用 read 或 grep 读取)…(尾部若干字)

需要细节时它会自己去读那个文件 —— 省掉的是「无差别塞进上下文」,不是信息本身。

配置

写在 profile 的 cordis.patch.yml 里,按 id 覆盖:

- id: dsh-think-strip
config:
enabled: true
archiveDir: ''
archive: true
summaryMode: first-line
summaryMaxChars: 100
minReasoningChars: 0
keepSummary: true
reasoningDefault: true
toolsDefault: true
toolStripChars: 4000
toolHeadChars: 1200
toolTailChars: 400
trace: true

| 字段 | 默认 | 说明 |
| enabled | true | 总开关。关掉后两个功能都不再处理新回合,已提交的记录仍生效 |
| archiveDir | '' | 归档根目录;空 = <DSH_HOME>/think-archive |
| archive | true | 是否写盘。关掉则只剥离不留档(不建议:归档失败的内容不会被投影) |
| summaryMode | first-line | first-line 取思考首行;none 只留 [思考已归档] 占位 |
| summaryMaxChars | 100 | 摘要最大字符数 |
| minReasoningChars | 0 | 思考短于此值不剥离 |
| keepSummary | true | 是否在剥离位置插一行摘要正文 |
| reasoningDefault | true | 没单独设置过的会话,默认是否隔离思考 |
| toolsDefault | true | 没单独设置过的会话,默认是否隔离工具输出 |
| toolStripChars | 4000 | 工具结果纯文本超过此长度才压缩;0 = 全部压缩 |
| toolHeadChars | 1200 | 压缩后保留的头部字符数 |
| toolTailChars | 400 | 压缩后保留的尾部字符数 |
| trace | true | 每回合往 plugin.log 写一行工作记录(排查「为什么没生效」时看它) |

注意

- 投影注册在插件里。卸载插件会让用过它投影的会话拒绝继续派生(session message projection "plugin:think-strip" was removed or replaced)。要卸载,先把这些会话归档或接受它们不能再打开。
- 每轮一条记录,不是每步一条。一轮里多个 step 的内容会被同一条记录覆盖。
- 工具输出只处理「全部是 text 块」的结果。含图片 / 文件 / 结构化块的(实测 32/1101 条是 text,image)整条跳过 —— 拆图片块的风险大于收益。
- 归档失败的内容不会被投影。原文落盘失败的 seq 会留在上下文里并打一条警告 —— 宁可不省 token,也不让原文丢失。
- 压缩(compaction)把历史整段替换成摘要后,被遮蔽的 seq 不再在 surface 上,投影会静默跳过。
- 插件记录里不能出现 undefined 值。Session.append 用 snapshotJsonValue 校验,只接受 boolean / string / 有限 number / plain object / plain array,碰到 undefined 直接抛 session event "…" carries non-JSON-serializable data,投影就提交不上(归档照写,但上下文不变)。所以提交前一律过一遍 toJsonSafe()(lib/pure.js),它用 JSON 往返削掉 undefined 键。
- 改插件源码必须重启 DSH。node_modules 下的模块不参与 HMR,只改配置才会热生效。
- 启停标记:<archiveDir>/plugin.log 里每次 apply 写一行;trace 打开时每个回合再写一行 turn=N sid=… sw=r1t1 ev=事件数 sf=surface节点数 targets=命中数 committed|targets=0|FAILED,用来区分「插件没起来」「起来了但没触发」「触发了但没命中」「命中了但提交失败」。

测试

纯逻辑层(lib/pure.js)可以脱离 Harness 跑:

cd dsh-think-strip
node --test test/pure.test.mjs

安装

在 DSH 里: plugin_manager action=install_bundle target=<本包绝对路径>

或手动在 profile 的 cordis.patch.yml 里加:

- insert:
- id: dsh-think-strip
name: 'dsh-think-strip'

Client 半部由 package.json 的 dsh.client.platform = "web" + exports["./client"] 声明,Host 会自动把它注入 Web UI。

许可

MIT
预览分享卡片长什么样 ↓miao-pa-si-wutao/dsh-think-strip
分享 · DeepSeek Harness Hub
miao-pa-si-wutao/dsh-think-strip

剥离历史思考与超长工具输出,原文归档可查

这是你的仓库?认领条目

回到顶部