DSH 长会话分页失效
DeepSeek Harness 长会话分页:Load Earlier 与 Trajectory 失效
- 作者
- DeepSeekAgent.io 编辑部
- 发布
- 更新
长会话不能一次把全部历史送进浏览器,DeepSeek Harness 会按页加载较早事件。社区在 DSH Desktop 0.2.1-rc.3 中复现了一条稳定故障链:第一次点击 Load Earlier 正常,第二次点击后 Chat 不再追加历史,Trajectory 也无法打开,刷新页面后才恢复。
服务端分页请求仍然返回 HTTP 200。故障发生在客户端把历史事件重新物化为 Chat 节点的阶段,因此“接口成功”并不代表页面已经接受了这一页。
复现边界
出现问题的 Session 约有 122 个 Turn、约 1.3 万条持久事件,并经历过多次上下文压缩和继承历史。相同数据在全新的 Chromium / Playwright 客户端中也能复现,说明故障不依赖 Electron 容器。
第二次分页后,控制台抛出:
conversation Definition "system-message" withdrew materialized target "chat";
return the same key with hidden visibility instead
此后事件订阅器停止继续处理,页面不再 prepend 更早的 Chat 历史,Trajectory 面板也无法读取完整的物化状态。重新加载会重建客户端状态,所以功能暂时恢复。
问题发生在哪一层
关键路径位于 buildTargetUpserts 一类物化逻辑:某个节点曾经以固定 key 生成 Chat target,历史页加入后,同一节点的 builder 却返回了 null。运行时把这解释为“已经物化的 target 被撤回”,于是触发不变量错误。
system-message 在追加模式、替换模式和当前窗口可见性不同的情况下,可能无法在本次窗口中生成目标。对于实时追加,这种严格检查有助于发现状态错乱;对于历史 prepend,同一事件可能只是暂时不在可见窗口中,直接撤回会让整条订阅链失败。
为什么 Chat 和 Trajectory 会一起失效
Chat 与 Trajectory 看起来是两个入口,底层却共享 Session 事件和客户端物化状态。一旦分页事件使订阅器抛错,Chat 无法继续构建历史,Trajectory 也拿不到一致快照。它不是两个独立 bug,也不应分别用“重载 Chat”和“重载 Trajectory”掩盖。
排查时应同时记录:
/api/session/page的游标、事件数量与 HTTP 状态;- 每次 Load Earlier 前后的首尾事件 ID;
- 抛错的 Definition、target key 与可见性;
- Chat 和 Trajectory 订阅器是否共享同一个失败边界。
修复方向
更安全的处理有三层:
- 当同 key 节点暂时不应显示时,返回带隐藏可见性的同一 target,不要返回
null; - 历史 prepend 允许节点从当前可见窗口退出,但不能破坏已经物化的身份;
- 增加跨页
system-message回归样本,覆盖第二页、第三页、压缩边界与继承历史。
测试不能只断言分页接口返回 200,还要断言第二次和第三次加载后 Chat 条数增长、Trajectory 可打开,并且刷新前后事件顺序一致。
当前恢复方法
页面已经进入错误状态时,刷新可重建订阅器;需要查看 Trajectory 时,先在触发第二次 Load Earlier 前打开。新建 Session 可以避免继续扩大故障,但不能替代旧历史恢复。
长期 Session 还应配合上下文压缩与工具结果剪枝使用。如果问题表现为 Session 列表为空或 Workspace 记录不一致,可再看Session 列表恢复指南。分页失效、上下文压缩与 Session Registry 属于不同层,不宜混为一个“长会话太大”。