mateclaw/text.txt

78 lines
4.1 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

请基于以下已确认事实,分析并修复前端 Chat 会话串线问题。不要泛泛而谈,直接围绕时序、状态隔离、消息归属和可验证修复方案展开。
问题背景:
用户连续两次问了同一句话“你有记忆里有啥”,系统创建了两个不同的 conversationId并且后端日志显示这两个会话都是独立、正常完成的
1. 第一次会话:
- conversationId: conv_1775859743291_z9pav7
- SSE chat 建立时间2026-04-11 06:22:32
- user message 已落库
- assistant message 已落库
- done 已发送
- stream fully completed
2. 第二次会话:
- conversationId: conv_1775859773188_335bjk
- SSE chat 建立时间2026-04-11 06:22:55
- user message 已落库
- assistant message 已落库
- done 已发送
- stream fully completed
关键信号:
- 两次请求是两个不同 conversationId。
- 服务端日志没有显示 approval / awaiting_approval / interrupt / queued_input 相关链路。
- 第一个会话已经完成后,前端仍然发了一次 stop请求日志为 `stopped=false`,这说明 stop 到达时旧流已经结束,不是服务端还在跑旧流。
- 因此,这更像是前端本地状态污染、会话切换时序竞争、或 reconcile 逻辑把旧本地消息错误带入新会话,而不是后端把旧会话内容串到了新会话。
当前高优先级怀疑点:
1. 切换会话 / 新建会话时,只调用了 stopChatGeneration(),但没有等待旧 SSE 流和本地状态完全清理。
- 这会导致旧流晚到的事件delta / done / error在新会话已经创建 assistant 占位消息后,继续命中新会话的共享状态。
- useChat 内部当前使用共享的 `currentAssistantId`、`streamConversationId`、`messages`,如果不做 conversation 级别隔离,就有天然串线风险。
2. 审批占位 assistant message 在某些路径下创建后没有 conversationId。
- 当前 refresh / reconcile 的过滤逻辑对 `!conversationId` 的本地消息仍可能放行。
- 这类 orphan message 可能被错误并入后续任意会话。
3. reconcileMessages() 当前有“保留 fetched 中不存在的本地 assistant 消息”的策略。
- 这个策略本来是为了防止 lagging snapshot 丢刚完成的 rich message。
- 但如果 local 里混入了旧会话消息、orphan message、或者未彻底清理的占位消息就会把错误消息保留下来。
你的任务:
1. 先明确判断:
- 根因是否主要在前端状态管理,而非后端 conversation/message 落库。
- 哪一条最可能导致“上一轮消息出现在新会话”。
2. 给出修复方案,要求具体到代码层面:
- 会话切换 / 新建会话时,如何确保旧流彻底解绑。
- 如何避免旧流事件写入当前会话。
- `currentAssistantId` / `streamConversationId` 是否应该按 conversation 隔离,还是至少在事件处理时校验 conversationId。
- 所有本地新建 message 是否必须强制携带 conversationId。
- reconcileMessages() 是否应该完全禁止保留非当前 conversation 的本地消息。
- 对 `conversationId` 为空的本地消息,应该如何处理。
3. 给出建议的防御性约束:
- 每个 SSE 事件落地前必须校验所属 conversationId。
- onStreamEnd / reconnect / refreshCurrentConversationMessages 只能作用于当前会话。
- 新会话开始前,旧会话的 placeholder / generating message 必须被清理或隔离。
4. 输出格式要求:
- 先给“根因判断”。
- 再给“最小修复方案”。
- 再给“更稳妥的长期方案”。
- 最后给“如何验证修复有效”,至少覆盖:
- 连续快速新建会话并发送相同问题
- 旧会话刚结束时立刻切新会话
- refreshCurrentConversationMessages 在流结束后执行
- orphan assistant message / 空 conversationId message 不得污染新会话
补充要求:
- 不要只说“加锁”或“避免 race condition”要明确到状态变量、事件处理器、过滤条件和消息生命周期。
- 如果你认为某个现有修补不够,请直接指出为什么不够。
- 如果需要改 reconcileMessages请说明保留本地 assistant message 的边界条件。