Summary
在多轮对话的长会话中,使用鼠标向上滚动查看历史消息时,会话视图会突然自动刷新并跳回最底部(最新消息位置),导致之前滚动定位的历史内容丢失,需要重新手动翻找。
Area
Web UI / Flow Chat / VirtualMessageList
Environment
- BitFun 版本:0.2.11
- 操作系统:Windows 11 x64
- 模型:DeepSeek V4-Pro
Reproduction
- 在一个已有较多轮次对话的会话中(10 轮以上效果更明显)
- 使用鼠标滚轮向上滚动,查看较早轮次的内容
- 持续向上翻阅一段时间(期间可能有新的 tool event 产生、token 统计更新、或 Agent 仍在后台执行任务)
- 实际结果: 会话视图突然刷新,滚动位置被重置到最底部(最新消息处),之前翻阅到的位置丢失
- 期望结果: 滚动位置保持稳定,不受后台数据更新影响;仅当用户主动滚动到底部或点击"回到底部"按钮时才回到最新消息
Observed Behavior Details
- 问题并非每次必现,但在长会话中触发频率较高
- 跳回底部时没有明显的加载动画或提示,表现为"闪回"
- 左右箭头按钮的逐轮跳转可以正常工作(说明底层 turn 定位能力存在)
- 跳回后需要重新手动向上翻找,体验极差
Likely Root Cause
推测与 VirtualMessageList 的 scroll position 管理有关,可能的触发路径:
1. Re-render 导致 virtual list state 丢失
// ModernFlowChatContainer.tsx 中,以下状态变化可能触发 VirtualMessageList 重新渲染:
// - dialogTurns 数组更新(新 turn 产生)
// - turnSummaries 更新(轮次摘要重新计算)
// - tool event 到达(工具卡片状态变化)
// - token usage 更新(用量统计刷新)
VirtualMessageList 使用虚拟滚动(react-virtuoso 或自研),当 items 数组引用变化时可能触发 scrollToIndex(0) 或重置 scrollTop。在用户手动滚动到历史位置时,新事件的到达会导致 items 重新计算,可能意外触发滚动重置。
2. Auto-scroll-to-bottom 缺少"用户正在查看历史"的判断
// 推测存在类似逻辑:
// 新消息到达 → 自动滚动到底部(这是正确的默认行为)
// 但缺少检查:用户当前是否正在手动浏览历史?
// 如果用户 scrollTop 距离底部超过一定阈值,不应强制滚动
3. 与 #1281 的共同根因
VirtualMessageList.pinTurnToTop() 在 #1281 中暴露了"列表不完全就绪时返回 false"的问题。同一个组件可能在以下场景中同样不稳定:
- items 重建时 scroll position 保持
- 异步更新期间的 scroll 状态一致性
scrollToIndex / scrollTo 在 reconcile 期间的可靠性
Relevant Code
src/web-ui/src/flow_chat/components/modern/VirtualMessageList.tsx — 虚拟滚动核心,pinTurnToTop、scroll position 管理
src/web-ui/src/flow_chat/components/modern/ModernFlowChatContainer.tsx — handleJumpToTurn、状态管理和重渲染触发
src/web-ui/src/flow_chat/components/modern/FlowChatHeader.tsx — turn 导航入口
src/web-ui/src/flow_chat/components/modern/useFlowChatNavigation.ts — 导航事件流
Suggested Fix Direction
- 判断用户是否在浏览历史:在
VirtualMessageList 或 ModernFlowChatContainer 中追踪 isUserViewingHistory 状态——当 scrollTop 距离底部超过一定阈值(如 200px)时设为 true,仅当用户主动回到底部或点击"回到底部"按钮时才清除
- 新消息到达时:如果
isUserViewingHistory === true,显示一个浮动的"新消息 ↓"按钮,而不是强制滚动
- items 更新时保持 scroll position:在
VirtualMessageList 的 items 重建逻辑中,保存并恢复 scrollTop 或目标 turn 的锚点位置
- 增加回归测试:在
FlowChatHeader.test.tsx 或 container 测试中补充 scroll position 保持的场景
Relation
可能与 #1281(轮次列表导航)共享 VirtualMessageList 的 scroll 状态管理根因。PR #1294 修复了 turn list 的面板关闭和 header 状态问题,但底层 pinTurnToTop 的滚动执行仍不稳定。
Summary
在多轮对话的长会话中,使用鼠标向上滚动查看历史消息时,会话视图会突然自动刷新并跳回最底部(最新消息位置),导致之前滚动定位的历史内容丢失,需要重新手动翻找。
Area
Web UI / Flow Chat / VirtualMessageList
Environment
Reproduction
Observed Behavior Details
Likely Root Cause
推测与
VirtualMessageList的 scroll position 管理有关,可能的触发路径:1. Re-render 导致 virtual list state 丢失
VirtualMessageList使用虚拟滚动(react-virtuoso 或自研),当 items 数组引用变化时可能触发scrollToIndex(0)或重置scrollTop。在用户手动滚动到历史位置时,新事件的到达会导致 items 重新计算,可能意外触发滚动重置。2. Auto-scroll-to-bottom 缺少"用户正在查看历史"的判断
3. 与 #1281 的共同根因
VirtualMessageList.pinTurnToTop()在 #1281 中暴露了"列表不完全就绪时返回 false"的问题。同一个组件可能在以下场景中同样不稳定:scrollToIndex/scrollTo在 reconcile 期间的可靠性Relevant Code
src/web-ui/src/flow_chat/components/modern/VirtualMessageList.tsx— 虚拟滚动核心,pinTurnToTop、scroll position 管理src/web-ui/src/flow_chat/components/modern/ModernFlowChatContainer.tsx—handleJumpToTurn、状态管理和重渲染触发src/web-ui/src/flow_chat/components/modern/FlowChatHeader.tsx— turn 导航入口src/web-ui/src/flow_chat/components/modern/useFlowChatNavigation.ts— 导航事件流Suggested Fix Direction
VirtualMessageList或ModernFlowChatContainer中追踪isUserViewingHistory状态——当 scrollTop 距离底部超过一定阈值(如 200px)时设为 true,仅当用户主动回到底部或点击"回到底部"按钮时才清除isUserViewingHistory === true,显示一个浮动的"新消息 ↓"按钮,而不是强制滚动VirtualMessageList的 items 重建逻辑中,保存并恢复scrollTop或目标 turn 的锚点位置FlowChatHeader.test.tsx或 container 测试中补充 scroll position 保持的场景Relation
可能与 #1281(轮次列表导航)共享
VirtualMessageList的 scroll 状态管理根因。PR #1294 修复了 turn list 的面板关闭和 header 状态问题,但底层pinTurnToTop的滚动执行仍不稳定。