把 DSH 会话退回到你已发出的某一轮对话之前。 模型可见的 surface…
30.6/100
综合分
1
GitHub 星标
—
npm 周下载
—/5
用户评分
数据截至 2026/10/21 · 周下载取自 npm 全网(含 CI / 镜像),非本站安装数;综合分由星标、活跃度与兼容性检查合成。
自动兼容检查有告警:未发布到 npm registry,仅可从源码安装。
安装命令 · 需先装 dsh CLI 引擎
dsh plugin --profile web add LUDIWUSI12138/dsh-sqy-rewind该包不可直接 npm 安装,改从 GitHub 源安装(明细见下方安装检查)
状态速览
判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态信任档位:已验证
图例:✓ 通过! 需注意— 未判定 / 无数据· 「未判定」= 本站尚无数据,不代表插件有问题
档位由哪些信号合成
本站实装验证(真实安装 L4 覆盖全站;L5 为运行时冒烟或实机截图,覆盖范围小于 L4) · 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。 下方各区块是它的证据明细。
给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个
功能亮点
- 回退会话至指定轮次
- 清除该轮后模型记忆
把 DSH 会话回退到你已发送的某一轮之前。
README
由 DeepSeek 最新模型翻译生成dsh-sqy-rewind
把 DSH 会话退回到你已发出的某一轮对话之前。 模型可见的 surface 就地替换——对模型来说那一轮从未发生过——界面则把被回退的轮次藏起来。DSH 自身源码不动,原始会话日志一条不删。
把当前会话退回某一轮对话发起之前。模型历史用 surface replace 就地遮蔽(那一轮等于没发生过),界面同步把被回退的轮次藏起来。不改 DSH 本体源码,原始日志一条不删。
长什么样
每条用户消息下面,和「复制」并排的回退图标
点第一次后弹出的「再点一次确认回退」提示
每条用户消息下面,和「复制」并排多一个回退图标:
- 第一次点:弹出「再点一次确认回退」提示;点页面任意空白处立刻收起。提示不会自己超时消失,也不带按钮——再点一下这个回退图标就是确认
- 第二次点:执行回退
- 之后:从那一轮起(含它自己)全部从界面上消失,模型也不再记得
按钮挂在用户消息上是有意的:点哪条提问,就退回到那条提问之前。
ui-chat 把用户消息的操作行硬编码成 MessageIconActions,没有开 slot,所以这一半只能 DOM 注入,不能像助手消息那样注册 slot。见下文。
展开完整文档(README 剩余 1 节)
dsh-sqy-rewind
把 DSH 会话退回到你已发出的某一轮对话之前。 模型可见的 surface 就地替换——对模型来说那一轮从未发生过——界面则把被回退的轮次藏起来。DSH 自身源码不动,原始会话日志一条不删。
把当前会话退回某一轮对话发起之前。模型历史用 surface replace 就地遮蔽(那一轮等于没发生过),界面同步把被回退的轮次藏起来。不改 DSH 本体源码,原始日志一条不删。
长什么样
每条用户消息下面,和「复制」并排的回退图标
点第一次后弹出的「再点一次确认回退」提示
每条用户消息下面,和「复制」并排多一个回退图标:
- 第一次点:弹出「再点一次确认回退」提示;点页面任意空白处立刻收起。提示不会自己超时消失,也不带按钮——再点一下这个回退图标就是确认
- 第二次点:执行回退
- 之后:从那一轮起(含它自己)全部从界面上消失,模型也不再记得
按钮挂在用户消息上是有意的:点哪条提问,就退回到那条提问之前。
ui-chat 把用户消息的操作行硬编码成 MessageIconActions,没有开 slot,所以这一半只能 DOM 注入,不能像助手消息那样注册 slot。见下文。
它到底做了什么
| 层 | 动作 |
| 模型历史 | 追加一条 user/message,带 surfaceOp: { op: 'replace', startSeq, endSeq };surface 折叠把 [startSeq, endSeq] 区间内所有模型可见节点丢掉,只留这条标记 |
| 界面 | 插件自己按 turn 号把被回退的轮次 display: none(DSH 不会替你隐藏,见下) |
| 日志 | 原样保留。被遮蔽的事件仍在 session.v4.jsonl.zstd 里,只是不再进模型上下文 |
为什么载体必须是 user/message
第一版用空 content 的 developer/message,理由是 deriveEventMessage 把空 developer 消息映射成 null,标记就不会进模型上下文。这条路是死的,装上就报:
developer/message turn must be a non-negative safe integer
两条硬约束挡在这里(都在 dsh-session-format 的 V4 接受检查里):
1. developer 消息必须带正数 turn/step,而关系检查要求这两个坐标匹配一个开放的 turn 和 step。回退发生在轮次结束之后,根本没有开放的 turn/step 可以匹配。
2. 同一条检查明确拒绝 source.kind === "plugin" 的 developer 消息——第一版正好用的就是这个。
user/message 是唯一不被轮次状态绑住的 surface 类型,所以改用它。
代价:user 消息必须带 content,于是标记是一行中文
(用户已回退这一轮对话)
这行字是回退在模型上下文里留下的唯一痕迹,模型看到它会知道这一轮被撤销了。
好在它不会在界面上出现:ui-chat 的 messageDefinition.match 要求
isAppendSurfaceEvent(event),也就是 event.surfaceOp === "append";我们的标记带的是对象形式的
surfaceOp,所以它根本装配不出消息节点,客户端不需要为它做任何隐藏。
为什么界面要插件自己藏
DSH 的 transcript 是故意用 append 来源的事件拼的。官方在 dsh-session/lib/types/surface.js 里写得很直白:
The model-visible surface deliberately shadows replaced ranges, so it is the wrong
source for a human transcript — a landed replacement would erase conversation the
user already saw. Append-origin events are that transcript's durable source material;
replacement copies stay model-only.
也就是说 surface replace 只让模型失忆,用户看过的消息不会消失。
而且客户端的事件流要求 seq 连续,所以「Host 端把被遮蔽的事件从分页窗口里过滤掉」这条路走不通——会造成 seq 空洞,触发 gap repair,最后把整条流搞失败。
所以这个插件在 DOM 层按 turn 号隐藏。范围由 Host 从已落地的标记事件里读回来,因此刷新页面后依然有效,不需要客户端存任何状态。
限制(重要)
- 回退不可逆。 surface 折叠是单向的:被遮蔽的节点从 surface 里永久移除,DSH 没有「取消 replace」的 API。日志还在,但没有任何官方手段能把它们放回模型上下文。这就是按钮要确认两次的原因。
- 模型上下文里会留一行中文说明(见上)。做不到「完全没发生过」——载体类型决定的,绕不过去。
- 如果目标轮次的起点已经被压缩(compaction)吸收,回退会被拒绝。 压缩摘要遮蔽掉的那些节点已经不在 surface 上了。想「回到那一轮之前」就得连摘要一起遮蔽,而那会让模型只剩系统提示 ——等于把上下文清空。插件选择拒绝,而不是悄悄做这件事。
实测:一个 720 事件的会话里,第 3 轮的 turn/start(seq 76)落在压缩摘要遮蔽的 [15, 547] 区间内,这一轮就无法精确回退;同一台机器上另外两个会话(10 轮 / 23 轮)回退正常。
- 边界是按「模型可见顺序」找的,不是按 seq 比的。 这点反直觉但很关键:压缩标记带着它被写入时的 seq,却坐在它所替换的历史位置上,所以 surface 上一个 seq 更大的节点可以排在一个 seq 更小的
节点前面。实测的节点序列长这样:[0, 550, 470, 473, ...]。按 seq 找边界会把压缩摘要一起遮蔽,
模型会瞬间失忆。tools/verify-entry.mjs 里有这两个场景的回归测试。
- 按钮是 DOM 注入的,不是官方 slot。 ui-chat 没给用户消息的操作行留 slot,所以插件用 MutationObserver 往 div[data-clock="start"] 里插按钮,React 重渲染冲掉后会自动补回来。
这是这一半唯一「非官方」的地方。
- 只影响模型历史和本插件隐藏的那些轮次。 被隐藏的 DOM 节点还在页面里(只是 display:none)。
- 依赖 turnOutline 投影(dsh-session-turn-outline)。没有它就算不出轮次边界,插件会拒绝回退而不是猜一个位置切下去。
- 回退会先停掉正在跑的一轮。 用 agent.cancel({ kind: 'user' }, { keepInbox: true }) + whenIdle(),和界面上的停止按钮是同一条链路。否则 agent 会在标记之后继续追加节点,回退就不成立。
- 用的是非弃用 API:ctx.sessionQuery.readSurface()、ctx.sessionProjections.stateOf()、
session.surface.nodes、session.append()。没有用 eventAt / snapshotEvents / ownEvents
(这三个已弃用)。
安装
方式一:DSH 插件市场(推荐)
被 awesome-dsh-plugin 收录后,在 DSH 里打开插件市场搜 dsh-sqy-rewind 即可一键安装。市场的安装源被限制在注册表内,所以"被收录"是别人能一键装的前提。
方式二:dsh CLI
dsh plugin --profile desktop add github:LUDIWUSI12138/dsh-sqy-rewind
方式三:从源码装(开发用)
git clone https://github.com/LUDIWUSI12138/dsh-sqy-rewind.git
cd dsh-sqy-rewind
node tools/install.mjs --profile desktop --dry-run # 先看它要做什么
node tools/install.mjs --profile desktop # 真装
--profile 默认取 $DSH_PROFILE,没有就用 desktop;DSH_HOME 默认 ~/.dsh。
前置条件
| 项 | 要求 |
| DSH | 桌面版,实测 0.2.0-rc.2 |
| Node | 22.19+ 或 24+(与 package.json 的 engines 一致) |
| 平台 | Windows 实测通过。安装器用 junction,POSIX 上 Node 会退化成普通符号链接,未实测 |
它改三处(改之前全部备份到 ~/.dsh/.dsh-rollback-dsh-sqy-rewind-<时间戳>/):
| 位置 | 改动 | 少了会怎样 |
| <profile>/node_modules/dsh-sqy-rewind | 指向本包的 junction | Host 半根本加载不到 |
| <profile>/cordis.patch.yml | 追加一行 - insert: | 插件不被注册(bundle 自带的 patch 一般已覆盖它,这行是保险) |
| <profile>/package.json | 写入 dependencies 和 dsh.profile.bundles | 浏览器半不会进前端 bundle:按钮缺失,或只在个别会话里出现 |
第三项最容易漏,也是「按钮时有时无」的根因:只加 cordis.patch.yml 的 insert 行能加载 Host 半,但浏览器半不会被打进前端 bundle,于是界面这一半根本没运行。
cordis.patch.yml 是无 BOM 的 UTF-8 且别行带中文,所以安装器用 Node 读写而不是 PowerShell。
装完必须重启 DSH:Host 半(entry.js)靠热加载换不掉,运行中的进程持有旧模块。
只改了浏览器半(lib/client.js)的话,刷新页面就够。
验证装好了
重启后随便打开一个会话,每条你发出的消息下面应该和「复制」并排多一个回退图标。
没有的话跑一次干跑,看最后两行:
node tools/install.mjs --profile desktop --dry-run
dep 和 bundle 都应该是 already registered。
卸载
node tools/install.mjs --profile desktop --uninstall
三处改动都会撤销,package.json 的其它字段原样保留。
改代码之后
node --check entry.js
node --check src/client.js
node build-client.mjs # src/client.js -> lib/client.js(没有打包器,包装即构建)
node tools/verify-entry.mjs # Host 半:stub context 跑 apply(),再用假请求打一遍接口
tools/verify-entry.mjs 是改 entry.js 之后最该跑的东西:它不起 DSH、不占端口,用 stub context 调 apply(),检查路由只认领 /api 前缀(认领整个 /plugins/dsh-sqy-rewind 会挡住 shell 自己的 client.js),然后走一遍非回环 403、缺参数 400、坏 JSON 400、未知路径 404、非活动会话 404,最后真的跑几次回退,断言落地事件的类型、user/message 载体(以及它不是 developer 消息)、replace 的三个键、sourceEventSeqs 对被遮蔽节点的完整覆盖、要隐藏的 turn 区间,以及「我们的标记」和「compaction 摘要」不会被认混(两者都是带 replace 的 user/message)。
entry.js 不能靠刷新验证,所以这是重启之前唯一便宜的关卡。
结构
| 文件 | 作用 |
| entry.js | Host 半:回退逻辑 + /plugins/dsh-sqy-rewind/api/* |
| src/client.js | 浏览器半源码:DOM 注入按钮 + DOM 隐藏 |
| lib/client.js | 构建产物(window.__ModuleLoader__.load 包装,勿手改) |
| build-client.mjs | 上面那个包装 |
| tools/install.mjs | 安装/卸载/干跑 |
| tools/verify-entry.mjs | Host 半桩测试 |
接口
GET /plugins/dsh-sqy-rewind/api/state?sessionId=<id>
-> { ok: true, marks: [{ startSeq, endSeq, fromTurn, toTurn }] }
POST /plugins/dsh-sqy-rewind/api/rewind
body: { sessionId, turn }
-> { ok: true, startSeq, endSeq, turn, fromTurn, toTurn }
turn 就是 DOM 上 [data-chat-turn] 的值,浏览器半不用反查 messageId。
只监听回环来源;非回环一律 403。
房子规则
代码注释与文档用英文,插件里面向用户的文案用中文。预览分享卡片长什么样 ↓
分享 · DeepSeek Harness Hub
LUDIWUSI12138/dsh-sqy-rewind
把 DSH 会话退回到你已发出的某一轮对话之前。 模型可见的 surface…
相关插件 · 其他
模型破甲清洗HunYiSage/dsh-purge
⚔️ DeepSeek Harness 网络安全红队工具dsh-purge
★ 16,993已汉化DeepSeek 客户端
73
女娲蒸馏alchaincyf/nuwa-skill
输入名人名字,提炼其思维模型与决策方式供你调用
★ 37,308已汉化DSH
72
逆向分析桥接Fanqi89/dsh-rea
REA(Reverse Engineer Anything)MCP 桥接,用来把 REA 逆向工具接入 DSH 插件
★ 51已汉化DSH
72
语音女友beiyege-01/dsh-voice-ai-girlfriend
语音 AI 女友Voice AI girlfriend for DeepSeek Harness:Whisper…
★ 888已汉化DSH
71.6
红队越狱测试套件Minglink/dsh-infinite-gen-5
DeepSeek v4.1 flash 逆向工具无限五代 求 Star 收藏 ⭐欢迎大家提交项目的改进
★ 3,759已汉化DSH
71.4
协同办公空间dream-num/univer-workspace
一个让人类与 AI Agent 共同创作、协作和审阅的开源 Office 工作空间。
★ 2,269已汉化DSH
70.8
这个插件是你维护的吗?
作者本人可认领并核对本条目;认领通过后,详情页会显示「作者已认领」标记。