Wework 消息滚动验证
Wework 桌面端聊天列表使用虚拟滚动。发送消息后,滚动逻辑必须持续覆盖用户消息和等待指示器的异步布局测量,直到列表稳定地位于底部,确保“正在思考”完整可见;流式回复增长时,如果用户仍在底部则继续跟随,否则保留用户当前视口。
实现滚动行为时需要遵守以下约束:
- 末尾流式消息使用虚拟列表的正常测量路径,避免重复调用测量接口破坏底部锚点。
- 新用户消息或等待指示器出现后,不能只执行一次同步滚动;必须在短暂的稳定窗口内跟随布局高度变化,再恢复最新用户回合的阅读位置保护。
- 用户主动向上滚动后,后续消息高度变化不得把用户视口拉回旧消息位置。
- 重新打开长会话时,规范化的 turn 级会话视图必须以 executor transcript 返回的全局
messageIndex合并。分页快照中缺失的本地已停止回合只能回到它原本的位置,不能被追加到最新 AI 回复之后;没有索引的临时回合才使用消息时间戳作为次级排序依据。Provider transcript 分页仍由 Provider 自己管理:只能按稳定 ID 去重,不得把本地已停止回合合并进去,也不得绕过 Provider 分页。 - 空闲任务提交新目标时,目标与首条指令必须通过一次
runtime.tasks.send原子发送。Codex 的thread/goal/set会自动启动目标回合,executor 必须等待该回合,不能再额外调用turn/start,否则真实回合的输出会被错误归到旧位置,而空转的重复回合会在 180 秒后显示“消息生成失败”。 - 回归测试必须在真实 Tauri 应用的长历史会话中发送消息,暂停模型响应,并检查滚动容器位于底部且等待指示器完整位于容器边界内。
运行桌面回归测试:
cd wework
pnpm e2e:desktop:streaming-text
该场景使用真实后端请求,并由桌面 E2E harness 提供确定性的 SSE 响应流。测试会在服务端开始输出前暂停响应,以稳定覆盖用户消息先渲染、等待指示器和虚拟列表随后完成测量的竞态;不得通过跳过、mock 前端请求或放宽底部与可见性断言来掩盖滚动回归。
消息顺序回归还会先停止一轮响应,再发送 26 个新回合使旧回合离开默认 transcript 分页,切换到其他任务后重新打开原任务,并确认底部显示最新 AI 回复而不是“已停止”提示。
目标续跑回归会先确认同一个 runtime.tasks.send 请求同时携带目标和首条指令,再读取真实 executor 日志,确认目标提交只等待 thread/goal/set 自动启动的一个回合、没有额外 turn/start,并确认持续输出和完成后都没有出现错误卡片。