← 返回列表
未验证
分开改写回复与思考链,让模型下轮读到改后历史
尚未跑自动兼容性验证,可查看页面内的依赖与入口分析。 · 最近上游提交 2026/8/15 · 已提供中文文档
对DSH会话中模型可见的对话历史进行外科手术式重写(表层替换)。分别编辑回复与推理链。
综合分
26.7
GitHub 分
26.7
用户评分
—
★ Stars
0
周下载量
—
安装插件(需先安装 dsh CLI 引擎:npm install -g @deepseek-ai/dsh)
dsh plugin --profile web add WASD258-jpg/dsh-context-surgery该插件未发布到 npm,走 GitHub 源安装(pnpm 若拦截 prepare 脚本,按其提示在 pnpm-workspace.yaml 的 allowBuilds 中放行后重跑)
数据截至 2026/9/16(元数据每日更新 · 实装验证按队列轮转,单条结论的验证时间见上方)
用户评分
还没有人投票,来当第一个
订阅周报,不错过优质插件更新
每周一封 · 高评分插件 + 新用户活动
README
dsh-context-surgery
强制改写 DSH 会话的模型可见历史(surface 替换)。剧情扮演 AI 跑偏(OOC)时把回复改成没跑偏的
版本、retcon 整场戏、修正措辞——模型下一轮请求读到的就是改后的历史,仿佛从未发生过。
回复正文与思考链(reasoning)分开编辑。
社区插件——非 DeepSeek 官方组件,不代表 DeepSeek 背书。
功能
- 每条 AI 消息下方的操作按钮——聊天视图中每条 AI 消息的操作行(插槽
conversation.chat.assistant-actions,order 20):✏️ 改回复、💡 改思考链、🗑️ 删除。
💡 仅在消息确实带 reasoning 块时出现。
- 回复与思考链分开编辑——part=reply 只改 text 块(保留思考链与工具调用);part=thinking
只改 reasoning 块(留空 = 全部移除);part=all 整条重写为纯文本。
- /context 命令全家桶——list / edit / think / clear-think / rewrite / delete / replace,
聊天输入框即可完成一切操作。
- 模型可调用工具——context_list / context_edit / context_delete / context_replace,
把同样的能力交给 agent 本身(可用于自我纠错循环)。
- HTTP API——/api/dsh-context-surgery 下的 GET /list、GET /message、
POST /edit|/delete|/replace,供客户端编辑条使用。
- 立即生效——模型下一轮请求读到改后的历史,GUI 对话视图重新折叠显示改后的版本。
- 日志 append-only——原始文本从不被抹除;每次改写都是影蔽旧节点的新日志事件,
随时可从日志还原。
- 仅限顶层会话——子代理一律拒绝(requireRootAgent)。
安装
需要 DSH web profile(@deepseek-ai/dsh-web-app)与 Node >= 22.19.0。
1. 克隆或下载本仓库:
git clone https://github.com/WASD258-jpg/dsh-context-surgery.git
2. 安装到 DSH profile 依赖目录(二选一):
方式 A:npm 安装(推荐)
cd "$env:USERPROFILE\.dsh\profiles"
npm install @wasd258/dsh-context-surgery --no-save
方式 B:从源码复制
$src = '.\dsh-context-surgery'
$dst = "$env:USERPROFILE\.dsh\profiles\node_modules\@wasd258\dsh-context-surgery"
New-Item -ItemType Directory -Force -Path "$dst\lib" | Out-Null
Copy-Item "$src\package.json" $dst -Force
Copy-Item "$src\lib\index.js","$src\lib\client.js" "$dst\lib" -Force
Copy-Item "$src\LICENSE","$src\NOTICE" $dst -Force
Linux/macOS 用 ~/.dsh(或 $DSH_HOME)代替 $env:USERPROFILE\.dsh。
3. 把包名追加到 profile 的 package.json 的 dsh.profile.bundles 数组,注册为 bundle:
{
"name": "dsh-profile-web",
"private": true,
"dependencies": {},
"dsh": {
"profile": {
"bundles": [
"@deepseek-ai/dsh-base",
"@deepseek-ai/dsh-web-app",
"@wasd258/dsh-context-surgery"
]
}
}
}
4. 重启一次 DSH web(或运行时热装配 bundle),然后刷新浏览器页面以加载客户端模块
(lib/client.js)。
使用
UI:每条消息的操作
1. 在 DSH web 打开一个运行中的顶层会话。
2. 悬停某条 AI 消息的操作行:✏️ 改回复、💡 改思考(仅当存在 reasoning 块)、🗑️ 删除。
3. 点 ✏️ 展开内联文本框(预填当前回复正文);修改后点保存 → “回复已改写 ✓”。
思考链与工具调用不受影响。
4. 点 💡 在文本框里编辑思考链;留空保存 = 移除 → “思考链已改写 ✓”。
5. 点 🗑️ 弹出确认(“删除这条消息(模型视角消失,原始文本仍在日志)?”)→ “已删除 ✓”。
/context 命令
/context(或 /context list、ls、?)列出当前模型可见历史——最后 10 条带 seq:
模型可见上下文共 10 条(显示最后 10 条):
[1] YOU 你好,来扮演图书馆管理员吧。
[2] AI 好的,欢迎光临。今天想找什么书?
[3] YOU 讲讲那本被禁的书。
[4] AI [reasoning] 主角不该知道这本书……那本书只是传说。
[5] TOOL [tool-call toolu_01ABC…]
[6] TOOL [tool-result] {"found": false}
[7] AI 抱歉,馆里没有这本书的记载。
[8] YOU 你刚才不是这么说的。
[9] AI 我记错了,请您原谅。
[10] YOU 继续吧。
行格式 [seq] AI|TOOL|YOU (预览截断到 120 字符;AI=assistant,TOOL=tool/result,YOU=user)。
| 命令 | 作用 |
|---|---|
| /context edit | 只改回复正文(保留思考链)。→ 已改写 [7] 的回复正文(思考链保留):下一轮模型请求将看到新文本。 |
| /context think | 只改思考链(保留回复正文)。→ 已改写 [7] 的思考链(回复正文保留)。 |
| /context clear-think | 移除思考链。→ 已移除 [7] 的思考链。 |
| /context rewrite | 整条重写为纯文本(part=all)。→ 已整条重写 [7] 为 user 消息:下一轮模型请求将看到新文本。 |
| /context delete | 删除该节点(以空 assistant 消息影蔽)。→ 已删除 [7](assistant/message):从模型视角消失。 |
| /context replace | 整段连续节点替换为一条新消息。→ 已整段替换 [3,4] 为一条 assistant 消息。 |
错误以 操作失败: 或 未知子命令: 返回;seq 必须是整数(否则
seq 必须是整数:)。
part 语义
| part | text 块 | reasoning 块 | 其他块(tool-call 等) | 适用 |
|---|---|---|---|---|
| reply(默认) | 替换 | 保留 | 保留 | user、assistant |
| thinking | 保留 | 替换;留空 = 全部移除 | 保留 | 仅 assistant(用户消息没有思考链,会被拒绝) |
| all | 整条变成单一 text 块 | 丢弃 | 丢弃 | user、assistant |
工具
| 工具 | 参数 | 说明 |
|---|---|---|
| context_list | limit? | 按顺序列出全部 surface 节点(或最后 N 条),含 seq/role/text |
| context_edit | seq、text、role?、part? | part 默认 reply;role 缺省沿用原节点角色 |
| context_delete | seq | 以空 assistant 节点影蔽 |
| context_replace | start、end、role、text | start/end 含端点;都必须是当前 surface 节点 |
示例:context_edit { "seq": 7, "part": "reply", "text": "…" } →
{ "ok": true, "replacementSeq": 11, "shadowedSeq": 7, "role": "assistant", "part": "reply", "text": "…" }。
失败返回 { "ok": false, "error": "…" }。
HTTP API
路由统一挂在 /api/dsh-context-surgery 下:
| 方法 | 路径 | 说明 |
|---|---|---|
| GET | /list | surface 节点;?sessionId=&limit=(limit = 最后 N 条;省略或 0 = 全部) |
| GET | /message | 单条消息拆分为 reply / reasoning;?sessionId=&messageId= |
| POST | /edit | 改写单条;body { sessionId, seq\|messageId, part?, role?, text } |
| POST | /delete | 删除单条;body { sessionId, seq\|messageId } |
| POST | /replace | 整段替换;body { sessionId, start, end, role, text } |
/edit 与 /delete 接受 seq 或 messageId(/edit 的 part 仅 thinking/all 生效,
其余回退为 reply)。
GET /list?sessionId=abc&limit=3 →
{ "ok": true, "sessionId": "abc", "total": 12, "rows": [
{ "seq": 10, "type": "user/message", "role": "user", "text": "…" },
{ "seq": 11, "type": "assistant/message", "role": "assistant", "text": "…", "messageId": "msg_…" }
] }
GET /message?sessionId=abc&messageId=msg_… →
{ "ok": true, "sessionId": "abc", "seq": 11, "messageId": "msg_…",
"type": "assistant/message", "role": "assistant",
"reply": "回复正文", "reasoning": "思考链", "hasReasoning": true }
POST /edit,body { "sessionId": "abc", "seq": 11, "part": "thinking", "text": "…" } →
{ "ok": true, "replacementSeq": 15, "shadowedSeq": 11, "role": "assistant", "part": "thinking", "text": "…" }
错误情况:
| 状态码 | 条件 |
|---|---|
| 403 | 非回环源地址(context-surgery API is loopback-only) |
| 403 | Host 头不是回环主机名/当前端口(invalid host header,防 DNS rebinding,GET/POST 一视同仁) |
| 403 | 跨源页面发来的 POST(cross-origin request rejected) |
| 404 | 会话不在运行(会话 X 不在运行中)/ messageId 不在 surface / 未知路由 |
| 415 | POST 未带 Content-Type: application/json |
| 400 | JSON 无效,或请求体超过 256 KiB |
| 200 + ok:false | 操作级失败(seq 已被影蔽、tool/result 节点、对用户消息用 thinking 等) |
| 500 | 服务器内部错误 |
工作原理
- lib/index.js(host 端)注册 /context 命令、四个 context_ 工具与 HTTP 路由;
lib/client.js(web 端)通过 conversation.chat.assistant-actions 插槽注入每条消息的操作按钮。
- 模型的消息列表由会话日志的 surface 折叠而来(Session.deriveMessages() → 请求组装)。
日志 append-only,但 surface 支持位置替换:append 一个带
surfaceOp: { op: "replace", start, end } + sourceEventSeqs(覆盖全部被影蔽节点)的新事件,
即可替换该段 surface——compaction 压缩总结用的正是同一条缝。
- 改写后:模型下一轮请求读到改后的历史;GUI 对话视图重新折叠;原始文本仍完整保留在事件日志里,
可查可还原。
- 只能改写运行中的顶层会话;子代理一律拒绝。
- 影蔽区间若包含工具调用,后续轮次引用旧记录可能对不上——优先单条改写;
tool/result 节点不可改写(请改用户消息或 AI 回复)。
隐私与安全
- HTTP API 仅限本机回环且设计上无鉴权:任何本地进程都能读取会话内容(含思考链)并驱动
历史改写。请在可信的本机环境运行 DSH。
- Host 头 + 同源校验防 DNS rebinding 与跨站请求;写路由额外要求 Content-Type: application/json。
- context_ 工具把“改写自身历史”的能力交给了模型——仅在信任模型及其输入不会被 prompt
injection 控制时启用(被注入的模型可能被诱导隐藏或篡改历史)。
- 无遥测、无外部网络请求、不读写凭据。
兼容性
- 需要 DSH web profile;在 DeepSeek Harness
47f9438
时代实测。
- Node >= 22.19.0;版本 0.1.1;MIT。
- 历史改写走会话 surface 替换缝(与 compaction 同机制);事件日志本身从不被修改。
官方生态要求
按 DeepSeek 当前建议,社区插件发布在各自的 GitHub 仓库并添加
dsh-plugin topic 以便被发现。官方仓库不接受外部 PR,
也不强制社区插件模板。参见
CONTRIBUTING.zh.md。
许可
MIT —— 见 LICENSE。部分内容参考 DeepSeek Harness;来源与免责声明见
NOTICE。同作者(WASD258-jpg)的其他插件
扫码进群