前言¶
在 DeepSeek Harness(dsh)的 TUI 里做长会话时,上下文压缩是常态:窗口满了会自动压,也可以手动 /compact。但 TUI 主界面里,自动压缩往往没有明显反馈;历史里压过几次也不直观;更常见的是 /new 开新会话后,刚压出来的全量摘要还在旧会话里,当前会话从空白重新开始。
社区插件 dsh-tui-compact-carry(维护者 sailoflight,分类:客户端)面向 仅 TUI 场景(@deepseek-harness-tui/dsh-tui):在状态行显示压缩次数与进行中进度,并在你手动 /compact 后缓存摘要,用 /carry 写入当前会话。Web / headless 没有 ctx.tuiStatus,装上不会报错但也没有状态行;命令本身两端都能跑,插件刻意只服务 TUI。
下面介绍它解决什么问题、怎么用,以及安装前需要知道的约束。
这是什么¶
dsh-tui-compact-carry 是零依赖的小插件(只用 Node 内置模块),通过监听 session/event 做三件事:
- 状态行显示已压缩次数(以及最近一次回收 token),压缩进行中显示「压缩中…(第 N 次 · Ns)」。
- 识别用户手动
/compact结束后的摘要,在进程内短期缓存,状态行提示「摘要待带出」。 - 提供
/carry等命令,把缓存摘要 append 到当前 agent 会话,并尽量用官方 checkpoint 标记,让 TUI 渲染成折叠的「压缩检查点」行。
它不触发压缩、不介入 /new 的切换事务;压缩仍由官方 /compact 完成,插件只「取现成的摘要 + 搬运」。
核心功能¶
状态行:次数与进度¶
| 能力 | 说明 |
|---|---|
| 压缩次数 | 监听 compaction/summary,经 ctx.tuiStatus.set('compact-carry', …) 更新状态行 |
| 进行中 | compaction/start 进入进度态,summary / end 退出;约 1 秒刷新,progressMaxMs 兜底防事件丢失 |
自动压缩在 TUI 主界面原本几乎无声;插件把 compaction/start|end 相关信号搬到状态行,便于确认「正在压」而不是界面卡住。
手动压缩后缓存与 /carry¶
手动 /compact 完成后,插件按事件签名(sourceCommandId === undefined && turn == null)在 compaction/end 时置 pending,并可通过 toast 提示使用 /carry(若 ctx.get('tuiToast') 不可用则静默跳过)。
常用命令(均在希望摘要落入的会话里执行,写的是 invocation.agent.session):
| 命令 | 作用 |
|---|---|
/carry |
默认 merged:带最后一条全量摘要(官方会把上一份 checkpoint 合并进新摘要) |
/carry show |
预览来源会话、回收量、正文前 400 字 |
/carry all |
按序拼接每一次压缩记录 |
/carry last |
只带最后一条(与默认 merged 语义相关,见 README) |
/carry now |
新建独立会话 carry-<uuid> 写入后 /resume 选择 |
/carry off |
清除待带出 pending,不删已有会话记录 |
/compactstats |
次数、累计回收、待带出/已带出状态 |
摘要缓存默认 30 分钟内有效(配置项 autoArmWindowMs);过期需重新 /compact。缓存是进程内的:压完未 /carry 就重启 TUI,需再压一次。没有可带摘要时 /carry 会报错,不会代替你执行压缩。
典型三步用法¶
README 给出的可复现流程:
/compact # ① 官方手动压缩一次(拿到含最近几轮的最新全量摘要)
/new # ② 起新会话 —— dsh-tui 原生行为,插件不参与
/carry # ③ 在新会话里:把刚缓存的摘要写进本会话
② 与 ③ 的顺序可以调换,关键是 ③ 必须在目标会话里敲。想先看内容用 /carry show;要带全部历史用 /carry all;改主意用 /carry off。
设计约束(使用与排错时有用)¶
- 不订阅 TUI 决策事件(如
tui/session-switched)。普通插件用裸ctx.on订阅会被决策守卫拒绝,表现为「状态行有更新、新会话却没写入」——本插件计数、进度、缓存全部走普通session/event。 - 绝不自己触发压缩。TUI 把手动压缩做成切换前必须结算的事务;插件若绕过会与
/new赛跑,可能出现输入栏无响应等问题。离线冒烟用engineCalls.length === 0断言插件不碰引擎。 - 不参与
/new 切换。可选autoCarryOnNew(默认关)仅监听session/created延迟写入,默认仍建议手动/carry。
与宿主 session format V4(插件版本 0.6.0)对齐:/carry 写入使用 kind: 'compact-checkpoint' 或 plugin:dsh-tui-compact-carry,避免 V3 时代的 kind: 'plugin' 被拒;历史读取改用 snapshotEvents() 而非已移除的 Session.events。
安装与启用¶
要求:Node.js ^22.19.0 || >=24.0.0,且 dsh 已在 PATH。
方式 A:按 bundle 安装(推荐)¶
package.json 声明了 dsh.bundle,安装命令为:
dsh plugin --profile dsh-tui add github:sailoflight/dsh-tui-compact-carry
装完后重启该 profile 才生效(manifest/包元数据不热更新;用户自己的 cordis.patch.yml 才可热重载)。
方式 B:绝对路径挂载¶
零外部依赖时,可将 index.js 放到本地目录,并在 $DSH_HOME/profiles/dsh-tui/cordis.patch.yml(默认 $DSH_HOME = ~/.dsh)中 insert 一行绝对路径。README 给出了 mkdir、cp 与 YAML 示例。方式 A 与 B 二选一,同一 id 重复挂载会报 duplicate loader entry id。
维护者提供离线冒烟:node smoke.mock.mjs 或 npm test(60 项断言,含引擎门、决策事件门、V4 消息源门、会话快照门)。升级 dsh / dsh-tui 后建议先跑一遍。
配置项(节选)¶
在 index.js 顶部 CONFIG 可调,例如:
| 键 | 默认 | 含义 |
|---|---|---|
carryMode |
'merged' |
'merged' 最后一条全量,'all' 按序全部 |
maxCarryChars |
0 |
注入正文上限,0 不截断 |
showProgress / progressMaxMs |
true / 900000 |
进度显示与兜底超时 |
useCheckpointMarker |
true |
true 用官方 compact-checkpoint 折叠行;false 改用插件 kind |
autoCarryOnNew |
默认关 | 新会话创建后延迟自动 carry |
完整表见 GitHub README。
适用场景与注意¶
适合:长期在 dsh-tui 里开发智能体、依赖压缩续聊,又需要在 /new 后把刚压好的摘要接到新会话的人。
务必知晓:
- 插件以当前 dsh 进程权限运行;安装前请阅读 GitHub 仓库 源码与 MIT 许可证,自行判断是否纳入 profile。
- 仅 TUI 有状态行体验;Web / headless 无
tuiStatus。 /carry now新建会话未 attach TUI workspace registry(仅meta.cwd),仍可能出现在同 cwd 的/resume列表;伪造的compactionId无对应compaction/summary时主要影响展示层。- DeepSeek Harness 生态强调「一切皆插件」;SkillHub 目录页 为社区收录,与 DeepSeek / 幻方无官方从属关系。
结尾¶
dsh-tui-compact-carry 不替代官方压缩,而是让 TUI 里「压了几次、正在压、压完怎么带到新会话」这三件事可看见、可操作:/compact → /new(可选)→ /carry。需要细节、配置与限制表时,以仓库 README 为准。
- 目录页:https://www.skillhub.cn/plugins/sailoflight/dsh-tui-compact-carry
- GitHub:https://github.com/sailoflight/dsh-tui-compact-carry