前言¶
长 DSH 会话最终会达到一个大小,此时原生压缩停止工作。其机制值得精确说明,因为这是导致失败永久化的原因:
- 压缩会将整个被阴影覆盖的区域作为输入重放,提交给一次总结请求。
- 上游提供商对单个请求的提示强制执行硬上限。
- 一旦会话超过该上限,压缩请求本身就会超过上限。
- 因此,压缩每次都会失败,永远不会治愈溢出。
会话随后无法被压缩,无法被继续,并且——因为简单的交接实现以相同方式构建总结请求——也无法被交接。这就是死锁。/handoff 存在以打破它。
是什么¶
这是一个 DSH 插件,用于在旧会话变得不可用之前,将其记忆传递给新会话。
- 维护者:iuuuuuuuu
- 类别:记忆
- 许可证:MIT
- 核心价值:解决会话因上下文溢出而陷入死锁的问题,通过总结与传递实现记忆保全。
安装与启用¶
安装插件需要指定目标配置文件。
dsh plugin --profile <name> add /path/to/dsh-session-handoff
安装后必须重启 DSH 才能生效。DSH 的加载器缓存机制决定了这一点:如果不重启,修改插件源码或新增插件不会在运行中的宿主生效。
重启后,日志中应显示安装成功的标志:
[session-handoff] installed: /handoff registered, pressure monitor active (upstream limit 1048576)
核心功能¶
上下文压力监控¶
插件在每个回合边界测量会话的 token 压力,并与两个独立上限进行比对,取其中较紧者作为绑定上限:
- 模型上下文窗口:从会话使用的模型配置读取,代表模型本身接受的大小。
- 上游提示限制:配置项,代表提供者对单次请求的接受上限。
后者是导致会话崩溃的实际原因,且无法从前者推导得出。当压力越过策略阶梯时,插件会向会话注入通知,告知测量值、绑定上限以及退出路径。该通知是模型面向的上下文,不会自发开启新回合,且对增长和时间进行了限流。
自动会话交接¶
自动交接默认开启;自动归档默认关闭。
当会话因三种独立原因变得不可用时,会触发自动交接:
- 压力:测量压力达到阈值。
- 超时:会话持续时间过长。
- 会话死亡:上游服务返回错误。
交接运行在一个事务中:读取会话 -> 提取四层记忆 -> 有界总结 -> 创建继承路由与工作目录的新会话 -> 交付种子作为新会话的第一回合 -> 归档旧会话 -> 释放旧会话事件树。新会话会立即开始工作。
记忆保全¶
设计问题在于携带什么。插件提取四层记忆,按成本排序:
- 逐字事实:正则提取,精确,成本为零。
- 之前的检查点:会话已成功写入的
compaction/end总结,精确,成本为零。 - 近期转述:对话的尾部,逐字,精确,成本为零。
- 叙述总结:模型生成的总结,改写,需要一次处理。
前三层精确层永远不会被丢弃以腾出空间给改写层;只有改写层会被截断,且仅截断中间部分。逐字尾部获得种子预算的保留份额,而非与散文竞争。
凭证脱敏¶
逐字层是副本,会复制会话曾经回显的内容。为防止凭证泄露,插件在写入前会根据形状进行脱敏:移除 bearer tokens、sk- / ghp_ / github_pat_ / xox / AKIA 密钥、JWT、PEM 私钥、password= 赋值以及内联连接字符串密码。事实层也会被脱敏,因为路径可能包含密钥。
典型用法¶
使用以下命令进行手动操作:
/handoff hand this conversation off to a fresh session
/handoff-status show the measurement, the binding ceiling, and the trigger state
执行 /handoff 会打印一份报告:
Handed off `session-9ef22e43-…` to `session-e7d70ba3-…`.
- read: 32286 messages, 117541 events
- memory: 240 facts, 0 checkpoints
- summarize: 70 chunk(s), source=map-reduce, 18422 chars
- seed: 21544 chars (~5386 tokens)
- create: session-e7d70ba3-…
- archive: session-9ef22e43-…
The source session is archived; it stays readable in the sidebar.
注意:归档操作在最后执行,因此如果早期步骤失败,源会话仍然完整可用。
实现细节与注意事项¶
归档与释放的区别¶
归档是一种可见性变更:会话 ID 加入归档集,使其在侧边栏的默认视图中隐藏。其日志仍留在磁盘上,保持可读性,取消归档可恢复其确切位置。归档不删除任何内容,也不释放内存。
释放规则:会话只有在被归档后才能被释放。
释放调用 SessionStore.remove(id),执行存储的官方分离生命周期。这会从 ctx.sessions(会话事件树)中移除会话,但不会从 ctx.agents(Agent)中移除。Agent 注册表是纯 Map,没有公共移除方法,且由 Agent 循环调用,插件无法调用。因此,释放会话会移除事件树,但其 Agent 仍持有对树的引用,磁盘日志也保持不变。
适用场景与注意¶
该插件适合长对话场景,特别是上游提供商对单次请求有严格限制,而模型配置的上下文窗口远大于此限制的情况。
- 安装生效:安装后必须重启 DSH。
- 内存管理:理解归档仅改变可见性,释放仅移除会话树,Agent 仍持有引用。
- 权限:插件以当前 DSH 进程权限运行,安装前应检查源码与许可证。
结语¶
/handoff 插件通过主动的上下文压力监控与记忆保全机制,解决了 DSH 会话在上下文溢出时的死锁问题。它将“无法继续”的对话转化为可继承的种子,确保工作流不会因单次会话的膨胀而中断。
- 目录页:https://www.skillhub.cn/plugins/iuuuuuuuu/dsh-session-handoff
- GitHub 仓库:https://github.com/iuuuuuuuu/dsh-session-handoff