DSH 会话接力插件
> 仓库名:dsh-session-handoff
English | 中文
聊到上下文快满了?一条 /handoff,把几十轮对话压成一页交接文档,开个干净的新会话接着干——旧会话一字不动。
DSH 的会话越聊越长:加载变慢、上下文吃紧、模型开始忘事。官方有"压缩"和"分叉",但没有
"把该记的记住,然后换一个干净会话继续"。这个插件补的就是这一步。
它会在上下文或会话体积到点时先问你一句;你确认后,它把 用户需求 / 方案梗概 / 已完成 /
涉及文件与产物 / 接下来做什么 整理成交接文档,在同一工作区开一个新会话、把文档作为第一条消息注入,
并自动打开。你回来时,新会话已经知道要做什么,不用从头解释。
和"压缩"、"分叉"有什么不一样
/compact 压缩 |
fork 分叉 | 本插件 | |
|---|---|---|---|
| 旧会话 | 原会话被压缩 | 原会话保留 | 原会话原样保留,标题留回链 |
| 新会话的负担 | 还是同一个会话 | 复制全量历史 | 只有一页交接文档 |
| 谁来接着干 | 还是自己 | 还是自己 | 全新会话 + 干净上下文 |
| 什么时候换 | 到阈值自动压 | 手动 | 到点先问你,也可全自动 |
一句话:压缩是"把旧包袱打包",分叉是"把旧包袱复制一份",这个插件是"把旧包袱写成一页交接单,轻装出发"。
特性
- 手动——
/handoff [|all],想切就切;不填轮数就用配置里的turns(默认 50 轮用户消息) - 自动——按策略到点触发,三档模式:替代(抢在原生压缩前切)/ 混合(会话过重时切)/ 原生(不自动切)
- 先问你——默认弹窗确认,可改成「只提醒」或「全自动」;点过「先不接力」后,触发量再涨 50% 才会重问
- 健康度行——输入框上方常驻「上下文 xx% | 会话 xxMB | 还能撑约 N 轮」,点开看明细,心里有数
- 干净的接力——新会话继承原会话的工作区、模型路由与 agent preset(系统提示 / 工具 / 技能),不带旧上下文
- 结构化交接文档——并在磁盘留一份,设置页可翻历次记录、直接打开目录
- 自动打开——客户端等新会话就绪后自动跳过去(每个子会话只跳一次,历史回放不会反复跳)
- 决策留痕——每次判定都记一条决策日志(选了哪个动作、为什么),出问题能复盘
- 新会话可预设——新会话用哪个模型、多强推理、什么工作权限,三项都可选「跟随原会话」
- 零核心改动——只插入一行
dsh.bundle.patch,全部走宿主公开服务
安装
要求:DSH 桌面版或 CLI,Node ^22.19.0 || >=24。
已在下列内核上实测可用:0.1.0-rc.5–rc.8、0.1.1-rc.2、0.2.0-rc.2、0.2.1-rc.2。
插件是标准的 DSH bundle 包,核心只有两件事:放进你正在用的 profile 的 node_modules,
并在该 profile 里登记。以桌面版(desktop profile)为例:
# 1) 把仓库放到任意目录(或直接解压 Release 里的 dsh-session-handoff-0.3.1.tgz)
git clone https://github.com/MountBatten718/dsh-session-handoff.git ~/dsh-session-handoff
# 2) 软链进 desktop profile 的 node_modules
ln -s ~/dsh-session-handoff ~/.dsh/profiles/desktop/node_modules/dsh-session-handoff
然后在 profile 的 package.json 里登记依赖:
{
"dependencies": {
"dsh-session-handoff": "link:/Users/you/dsh-session-handoff"
}
}
并把 dsh-session-handoff 加进该 profile 的 dsh.profile.bundles。重启 DSH 后生效。
> 桌面版的 desktop profile 由 Electron 独占,CLI 会拒绝对它执行 plugin add / --dump-config;
> 想只读验证组合结果,可以做一个换个名字的软链指向同一目录再 --dump-config。
> 如果你用的是普通 CLI profile,也可以按该 profile 的常规插件安装方式装入本目录。
使用
在任意会话输入框敲:
/handoff # 用配置里的轮数(默认 50 轮用户消息)
/handoff 20 # 总结最近 20 轮
/handoff all # 总结全部用户消息
执行后:命令卡片显示"正在总结…" → LLM 生成交接文档 → 新会话自动打开,原会话原样保留并回链。
> ⚠️ 隐私提示:所选窗口内的对话文本(用户 + 助手消息)会发送给配置的模型用于生成摘要。
配置
大多数选项在 DSH 设置 → 插件 → 会话接力 里就能改(即时生效)。profile patch 里可写的完整键:
- id: handoff
name: dsh-session-handoff
config:
# —— 自动接力 ——
autoMode: hybrid # replace(替代)/ hybrid(混合,默认)/ native(原生,不自动切)
autoPromptLevel: confirm # confirm(弹窗确认,默认)/ notify(只提醒)/ auto(全自动)
sessionVolumeBytes: 8388608 # 会话体积阈值(默认 8 MB)
compactionCountTrigger: null # 每压缩 N 次就切;null/留空 = 不启用
confirmTimeoutMs: 120000 # 确认弹窗超时(自有硬兜底,不依赖宿主)
# —— 新会话形态(留空 = 跟随原会话;设置页里可直接选)——
provider: '' # 新会话固定用的供应商
model: '' # 新会话固定用的模型(与 provider 成对)
childReasoningEffort: '' # 新会话的推理强度(与摘要调用的 reasoningEffort 不是同一个键)
childPermissionPreset: '' # 新会话的工作权限:read-only / workspace-write / danger-full-access
childPlanFirst: true # 新会话读完交接文档先给计划、等确认再动手(默认开)
subagentDrainTimeoutMin: 10 # 换会话前等子代理交卷的最长时间(分钟,1–60)
askRearmPercent: 50 # 点过「先不接力」后,触发量再涨这么多百分点才重问(10~500)
decisionLogEnabled: true # 决策日志开关
# —— 交接文档落盘 ——
handoffDocPersist: true # 默认开;落盘目录 = DSH 数据目录
handoffDocDir: '' # 留空用默认;只接受绝对路径
# —— 摘要调用 ——
turns: 50 # 取多少轮(1–200)
maxInputChars: 200000 # 输入字节上限(超限保留头 + 尾)
maxTokens: 8000 # 输出 token 上限(推理模型会先把预算花在思考上)
reasoningEffort: inherit # inherit(默认,跟随会话)| off | high | max
# ⚠️ 别默认写 off:部分模型会直接拒绝该参数
timeoutMs: 120000 # 摘要调用超时
未配 provider / model 时,自动使用当前会话最近一次请求的模型路由。
原理
- 宿主侧(
index.mjs+lib/*.mjs,纯 ESM):只消费宿主公开服务——commands(/handoff)、llm、
agents(会话与 agent 一起建,经agentPresets.mount继承 cwd / 模型路由 / preset)、
workspaceRegistry.attachSession、sessionTitle.rename、userQuestions(原生问答弹窗)。
自动接力挂agent/pre-step瀑布(步骤边界 = 安全点);客户端经 Typert RPC 读健康度、改配置、手工换会话。 - 客户端侧(
src/client/→scripts/build-client.mjs→lib/client.js):健康度行 + 设置面板 +
会话接力卡片;命中成功事件后自动打开子会话(轮询等待可寻址,localStorage 去重)。 - 黑匣子:每次接力把阶段与结果写进
/session-handoff-docs/handoff-trace.jsonl,
长文本脱敏成[omitted N chars],文件超 5 MiB 自动轮转。
构建
客户端半区产物 lib/client.js 已随仓库提供;改了 src/client/** 之后需要重建:
node scripts/build-client.mjs # 重建 lib/client.js
node scripts/build-client.mjs --check # 校验产物与源码逐字节一致
构建脚本只依赖 Node 内建的 TypeScript 类型剥离,不需要安装任何依赖。
已知限制
- 支持 DSH
0.1.0-rc.5至rc.8、0.1.1-rc.2、0.2.0-rc.2,以及0.2.1-rc.1/rc.2
(2026-10-20 在 0.2.1-rc.2 上实测:插件加载、健康度行、设置页、统计接口均正常);
0.1.2-alpha.1拆分了会话 UI / 服务,需要单独迁移客户端半区。 session.snapshotEvents()已被宿主标注@deprecated(宿主内部仍在使用);未来内核换入口时需要跟改。- 链路状态(第几棒 / 已交接)只存内存:重启后靠旧会话标题上的标记恢复"已交接",链序号会退化为 1(仅影响展示)。
- 自动接力失败后不会自动重试(避免重复创建会话),可在会话里手工「换会话」。
- 自动跳转依赖客户端轮询时序,真实浏览器下的极端时序仍需按你的 DSH 版本自测。
致谢
本项目基于 WeiYe6/dsh-session-handoff(MIT)扩展而来。
上游提供了 /handoff 命令与交接文档的基础实现;本仓库在此基础上增加了自动接力、健康度行、设置面板、
交接文档落盘、决策日志与子代理收尾等待等能力。
License
MIT