Files
goodbuddy/docs/features/chat-history-navigation/progress.md
T
mesalogo b22be5146b feat(settings): add a scrollbar minimap switch under Appearance
chatMinimapEnabled defaults to on; turning it off restores the native message scrollbar while keeping continuous history and DOM windowing.
2026-10-12 21:26:39 +08:00

10 KiB
Raw Blame History

实施进度

2026-10-08

  • 已确认 80 条限制由 ChatHistoryPane 的 messageRenderBatchSize 和 revealEarlierMessages 驱动。
  • 已确认消息窗口化仍以高度占位和最多约 60 条挂载消息为上限。
  • 已建立基线、本阶段和 minimap 阶段的对比测试计划。
  • 已将生产会话接线改为直接使用当前已加载消息总数,保留 DOM 窗口化。
  • ChatHistoryPane 与 ChatTimeline 定向测试通过:58/58。
  • 改动文件定向 web 类型检查和 lint 通过。
  • npm run build:bundle 通过。
  • npm run perf:app 通过。本次 B 组测量中,长会话打开交互延迟为 86.9 ms,长会话滚动帧间隔 p95 为 16.9 ms、无长任务;流式输入场景帧间隔 p95 为 16.9 ms,输入延迟 p95 为 17.1 ms。
  • B 组第二次运行仍通过:长会话打开交互延迟为 46.9 ms,长会话滚动帧间隔 p95 为 16.8 ms、无长任务;流式输入场景输入延迟 p95 为 19.1 ms。
  • App 测试通过 341/349;剩余 8 个失败集中在既有图片附件异步场景,未出现聊天历史窗口相关失败。
  • 全局 npm run typecheck 仍被既有 src/main/desktop-storage-electron-fixture.ts:215-217 类型错误阻断;全局 lint 仍包含生成的 VitePress cache 错误。
  • A 组临时恢复后连续两次在 composer 初始化阶段超时,未进入性能场景,因此没有有效 A 组数据,不能据此推导 A/B 数值差异。B 组代码已恢复并重新完成 bundle、定向类型检查、定向 lint 和 58/58 聊天窗口测试。

2026-10-11

  • 已确认工作区干净,生产代码保持 47917094 的 A 组:向上滚动仍按 80 条揭示,DOM 窗口化仍保留。
  • 当前聊天窗口和时间线定向测试:59/59 通过,包含 2,000 条消息连续滚动、实际挂载数量上限、锚点稳定、状态恢复和 80 条历史揭示。
  • App 单元测试:342/350 通过;8 个失败均为等待状态圆点的既有异步断言,失败位置不涉及历史窗口逻辑。
  • npm run build:bundle:通过。
  • 当前 A 组首次可重复的 npm run perf:app:通过。长会话打开交互延迟 54.4 ms;长会话滚动无长任务,帧间隔 p95 8.5 ms;流式输入延迟 p95 10.0 ms;流式输入场景无长任务。
  • 性能基准内存回收:24 次切换后 mounted panes 保持 6,DOM 从 24,746 降至约 2,446,堆从 50.5 MB 回收至约 22 MB,后半段增长约 0.1 MB。
  • 之前记录的“A 组 composer 初始化超时”未在当前回退后的基线复现;现在已经取得有效 A 组数据,后续可在同一 bundle 和环境下重新接线 B 组做严格交替 A/B。
  • minimap 尚未实现;在 B 组完成交替测量前不进入 minimap 性能对比。
  • B 组已重新接线:ConversationHistorySlot 对完整会话传入 conversation.messages.length,App 层不再维护 80 条可见数量状态;摘要会话仍走原有历史加载流程。
  • B 组 App 历史回归:4/4 通过,覆盖无历史闸门、长会话有界提交、暖切换位置和展开状态、超过 500 条历史保留。
  • B 组 npm run build:bundle:通过;改动文件 web 类型检查和 lint:通过。
  • B 组 npm run perf:app:通过。长会话打开交互延迟 46.8 ms,长会话滚动无长任务、帧间隔 p95 8.5 ms;流式输入延迟 p95 9.5 ms,无长任务。
  • A/B 基准对比:B 组 DOM 在长会话滚动后约 2,644、24 次切换回收后约 2,446;A 组对应约 2,632 和 2,446。B 组 24 次切换后的堆约 22.9 MB,后半段增长约 0.1 MB;A 组约 22.0 MB,后半段增长约 0.1 MB。当前没有观察到明显滚动、流式或内存回收回归。
  • 全量 App 测试:B 组 341/350 通过;剩余 9 个中 1 个为已迁移历史测试前的旧断言结果,8 个仍为既有等待状态圆点异步断言。迁移后的历史相关测试已单独通过。
  • B 组尚未提交;下一步继续做多轮交替 A/B 和低端机模拟,再决定是否进入 minimap。

2026-10-12

  • C 组已实现 minimap:使用单个 canvas 绘制用户、助手、工具/待处理和错误消息色带,不为每条消息增加 DOM 节点。
  • minimap 显示当前滚动视口,支持点击、指针拖动、Home、End、PageUp 和 PageDown;使用现有滚动容器和消息高度估算定位。
  • 新增 ChatMinimap.test.tsx,覆盖颜色分类、坐标边界、跳转和键盘操作;minimap、历史窗口和时间线定向测试共 62/62 通过。
  • C 组 App 历史相关回归 4/4 通过;改动文件 lint、web 类型检查和 npm run build:bundle 通过。
  • C 组 npm run perf:app:通过。长会话打开交互延迟 46.4 ms;长会话滚动帧间隔 p95 8.5 ms、无长任务;流式输入延迟 p95 9.6 ms、无长任务。
  • B/C 单次对比:滚动 p95 均为 8.5 ms 且无长任务;B 组流式输入 p95 9.5 ms,C 组 9.6 ms;B 组 24 次切换后 DOM/堆约 2,446/22.9 MB,C 组约 2,449/23.1 MB,后半段堆增长均约 0.1 MB。
  • C 组尚未做多轮交替和低端机模拟;当前结果支持继续保留实现并进入更广泛验证,不能单凭单次数据宣称最终性能结论。

2026-10-12 交互修订

评审发现初版 minimap 是悬浮在中部的 220 px 小条,视口指示经 requestAnimationFrame + React 状态更新而滞后于滚动,且没有悬停放大。已修订:

  • minimap 替代消息滚动区的原生滚动条:.chat-history-pane > .chat 隐藏原生滚动条,minimap 高度与滚动区 clientHeight 一致并贴合右侧。
  • 视口滑块在 scroll 事件和 ResizeObserver 回调中同步写入 transform,不经过 React 提交或下一帧;滚动区尺寸不变时只写 transform,不读布局。
  • canvas 仅在消息变化、行高测量变化、尺寸变化或展开/收起时重绘;普通滚动不重绘。
  • 悬停时展开为 96 px(窄屏 64 px)的缩略长图:用户消息靠右、助手消息靠左并按内容长度给出线宽;拖动中离开不收起。
  • 点击轨道将滑块中心移到指针处,拖动滑块保持抓取偏移;滚轮转发给消息区;保留 Home/End/PageUp/PageDown;无障碍角色为 scrollbar,文案使用 i18n chat.minimap。
  • 验证:minimap、历史窗口和时间线定向测试 65/65;web 类型检查和改动文件 lint 通过;App.test.tsx 342/350,8 个失败与此前相同(等待状态圆点异步断言);npm run build:bundle 通过。
  • npm run perf:app 通过:长会话打开帧 p95 8.6 ms、无长任务;长会话滚动帧 p95 8.6 ms、无长任务;stream-seeded/stream-and-type 无长任务、帧 p95 8.5 ms;24 次切换后 DOM 2,449、堆 23 MB,后半段增长 0.1 MB。
  • 未验证:真实鼠标悬停/拖动的视觉效果仍需在桌面端人工确认;多轮交替与低端机模拟仍未做。

2026-10-12 第二次交互修订

  • minimap 只覆盖阅读区:顶部从 --chat-context-height(任务条)开始,毛玻璃模式下再让出 58 px 标题栏;滑块轨道高度取 rail 实际高度,rail 自身尺寸变化由独立 ResizeObserver 触发重算。
  • 展开宽度调为 120 px(后续按反馈改为 80 px)。展开视图改为逐行描线:minimapLines 按约 72 列折行(CJK 按两列计)、保留空行、代码块缩进并降低不透明度,每条消息最多取 600 行;消息块高度装不下时按行均匀抽样。行剖面按消息对象缓存在 WeakMap,流式更新产生新对象时才重算。
  • 验证:定向测试 67/67(新增折行剖面和逐行绘制用例);web 类型检查与 lint 通过;npm run build:bundle 通过。
  • npm run perf:app 通过,各场景帧 p95 8.5–8.6 ms;长会话打开、长会话滚动、两个流式场景均无长任务;内存回收与上一轮一致。运行中出现的 renderer error 为网络更新检查 AbortError,与本功能无关。

2026-10-12 第三次交互修订

  • 展开宽度改为 80 px(窄屏仍为 64 px)。
  • 已取消的回复在缩略图中改为助手灰色,与正文状态行一致;只有失败的回复显示红色(复用 isCancelledMessage)。
  • 修正滚动时缩略图密度变化:此前每条消息的色块高度取 MessageRowHeights.size(),未测量行使用“已测行平均高度”估算;滚动挂载新行后估算值和实测值变化,每次提交都会按新高度重画整张图。现改为双轴:
    • 绘制轴:minimapMessageWeight(折行数 + 3 行头部 + 每个工具 2 行),只依赖消息内容;画布只在消息数组变化(新消息、流式输出)或尺寸、展开状态变化时重画,行测量不再触发重画。
    • 滚动轴:行高前缀和,仅在 scrollHeight 变化时重建。滑块位置和高度按行在两轴之间分段线性映射,覆盖视口内消息在缩略图上的实际区段(最小 16 px);点击和拖动走反向映射。
  • 验证:minimap、历史窗口、时间线定向测试 69/69(新增“行测量不��发重画”和“滑块对齐可见行的概览区段”用例);web 类型检查与 lint 通过;npm run build:bundle 通过。
  • npm run perf:app 连续两次通过。第二次结果:长会话打开、长会话滚动、stream-seeded、stream-and-type 均无长任务,帧 p95 8.5 ms;24 次切换后 DOM 2,449、堆 23.2 MB,后半段增长 0.2 MB。第一次运行中长会话滚动帧 p95 为 16.6 ms,stream-seeded 有 1 个 62 ms 长任务,第二次未复现,按单次噪声记录。
  • 未验证:真实桌面端滚动时的视觉稳定性需人工确认。

2026-10-12 外观设置开关

  • 新增应用设置 chatMinimapEnabled(z.boolean().default(true)),旧设置文件缺省时读为开启,无需升级设置版本;application.update 配置工具复用同一更新 schema,自动接受该字段。
  • 设置 › 外观新增开关“滚动条缩略图”/“Scrollbar minimap”,位于“透明磨砂特效”之后,保存后立即生效。
  • 关闭时 ChatHistoryPane 不挂载 ChatMinimap,也不再设置 data-minimap,原生滚动条随之恢复;历史窗口(完整已加载消息)和约 60 条 DOM 窗口不变。
  • 验证:设置存储(缺省默认、两种取值的持久化与重载、非法值拒绝)、外观开关(中英文)、窗格开关切换用例均通过;相关 8 个测试文件 410 项中修正配置快照夹具后全部通过;App.test.tsx 342/350,8 个失败与此前相同;web/node 类型检查(除既有 desktop-storage-electron-fixture.ts)与改动文件 lint 通过。