Skip to content

fix: stabilize session readiness and chat transcription history - #22

Open
lanyue-llk wants to merge 12 commits into
lex-mainfrom
fix/session-input-readiness
Open

fix: stabilize session readiness and chat transcription history#22
lanyue-llk wants to merge 12 commits into
lex-mainfrom
fix/session-input-readiness

Conversation

@lanyue-llk

@lanyue-llk lanyue-llk commented Aug 21, 2026

Copy link
Copy Markdown

Summary

修复 Browser 会话在输入尚未就绪时提前开放交互,以及工具过场话在最终答复到达后从聊天历史中消失的问题。

Changes

1. 以完整输入状态开放会话

  • managed input dispatch 同时等待 Agent session-ready 与对应 room input participant。
  • 需要视觉输入的会话继续等待 video input ready,不使用固定延时猜测就绪。

2. 保留同一轮的不同转写流

  • 按 LiveKit text stream id 累积过场话与最终答复,不再让共享 speech segment id 覆盖前一条消息。
  • 同一 stream 的增量文本仍原位更新;重连瞬时空快照保留历史,真正切换房间时清空。

Impact

  • 前端只在 Agent 和所需媒体都可用后进入交互态。
  • 模型实际生成并播放的工具过场话会与最终答复一起显示,不重复增量文本,也不跨房间残留。

Verification

  • pnpm test

    ✅ passed: 249 tests

  • pnpm lint

    ✅ passed

  • pnpm format:check

    ✅ passed

  • pnpm build

    ✅ passed: production build completed; only existing onnxruntime warnings remain

@github-actions

github-actions Bot commented Aug 21, 2026

Copy link
Copy Markdown

Claude finished @lanyue-llk's task in 1m 58s —— View job


任务清单

  • 获取 PR diff 与相关文件
  • 阅读仓库约定(无根级 CLAUDE.md)
  • 审查 LiveKit room/track 生命周期、React hook 清理等
  • 输出 review 结论

Review 结论

有条件通过

问题及建议

  • [P1] hooks/useRoom.ts:222-224 + lib/session-dispatch-readiness.ts:47-58requireRoomInputParticipantsReady 直接绑定到 usesManagedRoomInput(即 appConfig.usesServerRoomInput),但 usesServerRoomInputinputSource: 'mixed' 场景下只要音频或视觉任一使用 server room input 就为 true(见 app-config.ts:123-125)。而 hasReadyRoomInputParticipantslib/session-dispatch-readiness.ts:111-114)无条件要求 room_audio_inputroom_video_input 两个参与者同时就绪。当 mixed 模式下 audio 使用 xunfei/generic(server room input)而 vision 使用 browser(本地摄像头,非 server room input,requiresRoomVideoInputReadyfalse)时,room_video_input 参与者永远不会加入房间,findReusableAgentParticipant 会一直返回 null,导致 dispatch 卡在 "Starting..." 直至超时失败。建议:requireRoomInputParticipantsReady 的判定应像 requiresRoomVideoInputReady 一样按实际使用的 audio/vision 设备分别判断,或者让 hasReadyRoomInputParticipants 接受"仅要求实际启用的输入侧就绪"的选项。

  • [P2] hooks/useRoom.ts:214setIsSessionActive(true) 被移到 try 块末尾(第 314 行),但在 usesSandboxConcurrentStartup 分支中,dispatchAgentSession() 已经在 Promise.allSettled 内被 await 过;后续未见对该并发路径下"部分就绪"竞态的专门测试(仅测试了非并发路径的顺序断言)。建议为 usesSandboxConcurrentStartup === true 路径补充一个类似的时序断言,避免未来重构改变并发分支时静默倒退。

  • [P2] 测试覆盖:tests/session-start-dispatch.test.mjs 通过字符串匹配 (assert.match(useRoomSource, ...)) 校验新增字段传递,未对 mixed 音视频分离场景(P1 提到的组合)做行为级用例(类似 session-dispatch-readiness.test.mjs 里对 hasReadyRoomInputParticipants 的组合测试)。建议补一条覆盖"audio=server room input, vision=browser"组合的用例,能直接暴露上面的 P1 问题。

未发现 secret 泄露、Next.js 客户端/服务端边界或类型问题。

Branch: fix/session-input-readiness

@github-actions

github-actions Bot commented Aug 21, 2026

Copy link
Copy Markdown

Claude finished @lanyue-llk's task in 1m 56s —— View job


任务清单

  • 获取 PR diff 与相关文件
  • 阅读仓库约定
  • 审查 LiveKit room/track 生命周期、React hook 清理等
  • 输出 review 结论

Review 结论

有条件通过

新提交 deda8fa(fix: wait for configured session inputs)已修复上一轮 review 指出的 P1 问题:hooks/useRoom.ts:226 现通过 usesBothServerRoomInputParticipants(appConfig.audioInputDevice, appConfig.visionInputDevice) 按实际启用的音频/视觉设备分别判断是否需要等待 room_audio_input/room_video_input 参与者,不再直接绑定到笼统的 usesServerRoomInputtests/local-dispatch-config.test.mjs:141-146 已补充 mixed(audio=server, vision=browser)组合用例,覆盖此前风险场景。上一轮 P2(并发路径时序断言)也已通过 tests/session-start-dispatch.test.mjs:224-230lastIndexOf 顺序断言补齐。

问题及建议

  • [P2] app/api/session/session-dispatch-service.ts:304-305prewarmRoomSession 中仍无条件设置 requireRoomInputParticipantsReady: true(未按 audioInputDevice/visionInputDevice 拆分),若 mixed 场景(如 audio=xunfei/generic、vision=browser)走预热路径,room_video_input 参与者永远不会入会,可能导致预热在 45s 超时前一直等待。该代码不在本次 diff 改动范围内,但与本 PR 修复的问题同源,建议后续跟进对齐。
  • [P2] app/api/session/session-dispatch-service.ts:78DEFAULT_AGENT_DISPATCH_TIMEOUT_MS 从 8s 提升到 30s,属合理调整(新增等待 agent/room 输入就绪后耗时变长),但未见 PR 描述中说明该改动动机,建议在 PR 描述中补充一句说明,便于后续排查超时相关问题时追溯。

未发现会阻塞合并的问题。残余风险:上述两条均为 P2,可在后续 PR 中处理。

@github-actions

github-actions Bot commented Aug 21, 2026

Copy link
Copy Markdown

任务清单

  • 获取 PR diff 与相关文件
  • 阅读仓库约定
  • 审查 LiveKit room/track 生命周期、React hook 清理等
  • 输出 review 结论

@github-actions

github-actions Bot commented Aug 21, 2026

Copy link
Copy Markdown

Claude finished @lanyue-llk's task in 2m 19s —— View job


任务清单

  • 获取 PR diff 与相关文件
  • 阅读仓库约定
  • 审查 LiveKit room/track 生命周期、React hook 清理等
  • 输出 review 结论

Review 结论

有条件通过

新提交 18db439(fix: keep video readiness out of voice startup)将就绪判定简化为单一 requireAgentSessionReadyhooks/useRoom.ts:210-217app/api/session/dispatch/route.ts:23-24,60-61),不再依赖 room_audio_input/room_video_input 参与者组合判断。此前 review 指出的 P1(mixed 音视频设备场景下 dispatch 卡死)已通过此重构从根本消除——因为新的就绪门槛完全交由 agent 自身的 liveavatar.agent.session_ready 属性决定,不再依赖前端猜测应等待哪个 room-input identity。setIsSessionActive(true)hooks/useRoom.ts:305)在并发与非并发两条启动路径下均保持在 dispatch 完成之后,测试 tests/session-start-dispatch.test.mjs:212-216lastIndexOf 顺序断言覆盖了这一点。

问题及建议

  • [P2] app/api/session/session-dispatch-service.ts:304-305prewarmRoomSession 仍无条件设置 requireRoomInputParticipantsReady: true(未按实际启用的 audio/vision 设备拆分)。若 mixed 场景(如 audio=xunfei/generic、vision=browser)走预热路径,room_video_input 参与者永远不会入会,预热可能一直等到 45s 超时。与本 PR 修复的问题同源,建议后续对齐(不阻塞本次合并)。
  • [P2] tests/session-prewarm.test.mjs:334:测试名 'regular dispatch keeps its 8s timeout ...' 与本次改动后的断言值 30_000app/api/session/session-dispatch-service.ts:78)不一致,建议同步更新测试描述文案,避免误导后续读者。
  • [P2] DEFAULT_AGENT_DISPATCH_TIMEOUT_MS 由 8s 提升到 30s(app/api/session/session-dispatch-service.ts:78)是合理调整(等待 agent session ready 后耗时变长),但 PR 描述中仍未说明该改动动机,建议补充一句,便于后续排查超时问题时追溯。

未发现会阻塞合并的问题。残余风险:上述三条均为 P2,可在后续处理。

@github-actions

github-actions Bot commented Aug 21, 2026

Copy link
Copy Markdown

Claude finished @lanyue-llk's task in 1m 0s —— View job


任务清单

  • 获取 PR diff 与相关文件
  • 阅读仓库约定
  • 审查 LiveKit room/track 生命周期、React hook 清理等
  • 输出 review 结论

Review 结论

有条件通过

新提交 5ac7bad(fix: recognize server serialized readiness attributes)仅改动 lib/session-dispatch-readiness.ts 与其测试,为 isAgentSessionReadylib/session-dispatch-readiness.ts:130-136)增加了对 camelCase 属性 liveavatarAgentSessionReady 的兼容判断,逻辑本身正确且有配套测试(tests/session-dispatch-readiness.test.mjs:65-81)覆盖。

问题及建议

  • [P2] lib/session-dispatch-readiness.ts:18-19:新增第二个就绪属性 key liveavatarAgentSessionReady 缺少注释说明来源(例如某个 LiveKit server SDK 版本会把点号 key 序列化为 camelCase),建议补一行注释,避免后续开发者误以为是冗余/遗留代码而删除。
  • [P2] app/api/session/session-dispatch-service.ts:304-305prewarmRoomSession 仍无条件设置 requireRoomInputParticipantsReady: true,未按实际启用的 audio/vision 设备拆分(同 P1 已在主流程通过 requireAgentSessionReady 重构规避,但预热路径未跟进)。mixed 场景下预热可能一直等到超时,建议后续对齐。
  • [P2] tests/session-prewarm.test.mjs:334:测试名 'regular dispatch keeps its 8s timeout ...' 与实际断言值 30_000app/api/session/session-dispatch-service.ts:78)不一致,建议同步更新描述文案。

未发现会阻塞合并的新增问题。上述均为既有 P2 遗留项,可在后续 PR 处理。

@github-actions

github-actions Bot commented Aug 21, 2026

Copy link
Copy Markdown

Claude finished @lanyue-llk's task in 1m 21s —— View job


任务清单

  • 获取 PR diff 与相关文件
  • 阅读仓库约定
  • 审查 LiveKit room/track 生命周期、React hook 清理等
  • 输出 review 结论

Review 结论

有条件通过

新提交 5e4c87c(fix: gate prewarm on authoritative session readiness)已修复上一轮 review 指出的 P2:app/api/session/session-dispatch-service.ts:303-305prewarmRoomSession 现在只设置 requireAgentSessionReady: true,不再无条件附加 requireRoomInputParticipantsReady: true,与主 dispatch 路径(hooks/useRoom.ts:215app/api/session/dispatch/route.ts:60-61)保持一致,mixed audio/vision 设备组合下预热不会再卡到超时。配套测试 tests/session-prewarm.test.mjs:334,387,1395-1398 已同步更新断言(30s 超时、visionParticipantReady: false)。lib/session-dispatch-readiness.ts:18-20 的 camelCase 属性兼容也补了来源注释,回应了上一轮建议。

问题及建议

  • [P2] lib/session-dispatch-readiness.ts:14-15,40-60 + app/api/session/session-dispatch-service.ts:190-191requireRoomVideoInputReady/requireRoomInputParticipantsReady 及其对应的 hasReadyRoomVideoInput/hasReadyRoomInputParticipants 分支现在已无任何生产调用方(dispatch/route.tsprewarmRoomSession 均已全部切换为 requireAgentSessionReady),仅剩测试在直接调用 findReusableAgentParticipant/waitForRequestedRoomSessionReadiness 时使用。建议后续 PR 清理这部分死代码,避免以后误用旧的、已被证明有竞态风险的就绪判定路径。
  • [P2] app/api/session/session-dispatch-service.ts:78DEFAULT_AGENT_DISPATCH_TIMEOUT_MS 由 8s 提升到 30s 的动机(等待 agent session ready 后单次 dispatch 耗时变长)仍未体现在 PR 描述中,建议补一句说明便于后续排查超时问题。

未发现会阻塞合并的问题。残余风险:上述均为 P2,可在后续 PR 处理。

@github-actions

github-actions Bot commented Aug 26, 2026

Copy link
Copy Markdown

Claude finished @lanyue-llk's task in 2m 28s —— View job


任务清单

  • 获取 PR diff 与相关文件
  • 阅读仓库约定
  • 审查 LiveKit room/track 生命周期、React hook 清理等
  • 输出 review 结论

本轮新增提交 8f64cf6(fix: preserve tool preambles in chat history)改动 hooks/useChatMessages.ts、新增 lib/transcription-history.ts。此前各轮已审查的会话就绪相关改动(hooks/useRoom.tsapp/api/session/dispatch/route.tssession-dispatch-service.tssession-dispatch-readiness.ts 等)在本次未发生变化。

Review 结论

有条件通过

问题及建议

  • [P1] lib/transcription-history.ts:12if (current.length === 0) return [];):该分支会在 useTranscriptions() 返回空数组时无条件清空已合并的历史记录(hooks/useChatMessages.ts:82-84previous 被整体丢弃)。useTranscriptions() 在网络重连、track 重新发布等场景下可能瞬时返回空数组,而这正是本 PR 系列要加固的“会话/track 生命周期”场景;一旦触发,刚被本提交保留下来的 tool preamble/历史转录会被整体清空,与提交目的相悖。建议仅在明确的“新会话/房间切换”信号下清空历史(例如监听 room 切换或显式 reset 调用),而不是用 current.length === 0 作为代理判断;current 为空时更安全的默认行为是直接返回 previous
    Fix this →
  • [P1] tests/chat-message-filter.test.mjs:未覆盖 mergeTranscriptionHistory(previous非空, current为空) 的场景,上述清空历史的行为未被测试捕获,建议补充用例。
  • [P2](历史遗留,非本次新增)lib/session-dispatch-readiness.ts:14-60requireRoomVideoInputReady/requireRoomInputParticipantsReady 相关分支仍无生产调用方,建议后续 PR 清理死代码。
  • [P2](历史遗留)app/api/session/session-dispatch-service.ts:78DEFAULT_AGENT_DISPATCH_TIMEOUT_MS 由 8s 调整为 30s 的动机建议补充到 PR 描述中,便于后续排查超时问题。

未发现 secret 泄露、Next.js 客户端/服务端边界问题。上述 P1 与本次“保留 tool preamble”改动目标直接冲突,建议合并前修复;P2 为历史遗留项,可后续处理。

Branch: fix/session-input-readiness

@github-actions

github-actions Bot commented Aug 26, 2026

Copy link
Copy Markdown

Claude finished @lanyue-llk's task in 1m 17s —— View job


任务清单

  • 获取 PR diff 与相关文件
  • 阅读仓库约定
  • 审查最新提交(1197d4a)是否修复此前 P1 问题
  • 输出 review 结论

本轮新增提交 1197d4a(fix: retain transcription history across reconnects)已修复上一轮 review 指出的 P1:lib/transcription-history.ts:15mergeTranscriptionHistorycurrent 为空时改为返回 previous 而非 [],不再因 useTranscriptions() 瞬时返回空数组(重连、track 重新发布等)而清空已保留的 tool preamble/历史转录;改为在 hooks/useChatMessages.ts:82-84 新增 useEffect(() => setTranscriptionHistory([]), [room.name]),仅在 room.name 变化(新会话/新房间)时显式清空历史,语义上与"重连不丢历史,新会话才重置"的预期一致。配套测试 tests/chat-message-filter.test.mjs:59-65mergeTranscriptionHistory(prevWithEntries, []) → 保留 previous)已补齐,与上一轮建议一致。

Review 结论

通过

问题及建议

未发现需要阻塞合并的问题。残余风险:

  • [P2](历史遗留,非本次新增)lib/session-dispatch-readiness.ts:14-60requireRoomVideoInputReady/requireRoomInputParticipantsReady 相关分支仍无生产调用方,建议后续 PR 清理死代码。
  • [P2](历史遗留)app/api/session/session-dispatch-service.ts:78DEFAULT_AGENT_DISPATCH_TIMEOUT_MS 由 8s 调整为 30s 的动机建议补充到 PR 描述中,便于后续排查超时问题。
  • [P2] hooks/useChatMessages.ts:82-84room.name 重置逻辑仅有源码字符串匹配式测试覆盖(同文件其他用例风格),未见对该 useEffect 的行为级测试(如 room 切换后 history 清空、reconnect 后不清空),可后续补充。

Branch: fix/session-input-readiness

@lanyue-llk lanyue-llk changed the title fix: Wait for managed input before activating sessions fix: stabilize session readiness and chat transcription history Aug 26, 2026
@github-actions

github-actions Bot commented Aug 26, 2026

Copy link
Copy Markdown

Claude finished @lanyue-llk's task in 58s —— View job


任务清单

  • 获取 PR diff 与相关文件
  • 阅读仓库约定(无根级 CLAUDE.md)
  • 审查最新提交(revert 后的状态)
  • 输出 review 结论

本轮新增提交 40a51d5/aec6ac6 完整撤销了此前的 1197d4a(保留转写历史)与 8f64cf6(保留工具过场话)改动,lib/transcription-history.ts 已删除,hooks/useChatMessages.ts 及相关测试均恢复到改动前状态,未见残留引用。撤销后当前 diff(origin/lex-main...HEAD)与此前已审查通过的会话就绪改动(commit 5e4c87c)完全一致:hooks/useRoom.ts 用单一 requireAgentSessionReady 门槛替代旧的 room-input 参与者组合判断,setIsSessionActive(true) 在并发/非并发两条启动路径下均保持在 dispatch 完成之后,lib/session-dispatch-readiness.ts 对 camelCase 就绪属性的兼容判断也在。

Review 结论

通过

问题及建议

未发现需要阻塞合并的问题。残余风险(历史遗留,非本次新增):

  • [P2] lib/session-dispatch-readiness.ts:14-60requireRoomVideoInputReady/requireRoomInputParticipantsReady 相关分支已无生产调用方(dispatch/route.tsprewarmRoomSession 均已切换为 requireAgentSessionReady),建议后续 PR 清理死代码。
  • [P2] app/api/session/session-dispatch-service.ts:78DEFAULT_AGENT_DISPATCH_TIMEOUT_MS 由 8s 调整为 30s 的动机建议补充到 PR 描述中,便于后续排查超时问题。

注:本次撤销的“保留工具过场话/转写历史”功能已不在本 PR 范围内,如仍需该能力,建议在单独 PR 中重新提出并修复此前 review 指出的 mergeTranscriptionHistory 空快照清空历史的问题。

Branch: fix/session-input-readiness

@github-actions

github-actions Bot commented Aug 26, 2026

Copy link
Copy Markdown

Claude finished @lanyue-llk's task in 1m 15s —— View job


任务清单

  • 获取 PR diff 与相关文件
  • 阅读仓库约定
  • 审查最新提交(5fe07cf/fed9950,撤销此前的撤销,恢复"保留转写历史/工具过场话"改动)
  • 输出 review 结论

本轮新增提交 5fe07cffed9950 撤销了此前的撤销提交(aec6ac640a51d5),使当前 diff(origin/lex-main...HEAD)恢复到与此前两轮已分别审查通过的状态完全一致:

  • 会话就绪部分(hooks/useRoom.tsapp/api/session/dispatch/route.tssession-dispatch-service.tslib/session-dispatch-client.tslib/session-dispatch-readiness.ts)与已通过审查的 5e4c87c 状态逐行一致:统一以 requireAgentSessionReady 作为就绪门槛,setIsSessionActive(true)hooks/useRoom.ts:305)在并发/非并发两条路径下均保持在 dispatch 完成之后。
  • 转写历史部分(lib/transcription-history.tshooks/useChatMessages.ts)与已通过审查的 1197d4a 状态一致:mergeTranscriptionHistorylib/transcription-history.ts:15)在 current 为空时返回 previous 而非清空历史,仅在 room.name 变化时(hooks/useChatMessages.ts:82-84)显式重置。此前指出的 P1(瞬时空快照清空历史)问题的回归测试 tests/chat-message-filter.test.mjstranscription history survives a transient empty snapshot)已恢复保留。

Review 结论

通过

问题及建议

未发现需要阻塞合并的问题。残余风险(历史遗留,非本次新增):

  • [P2] lib/session-dispatch-readiness.ts:14-60requireRoomVideoInputReady/requireRoomInputParticipantsReady 相关分支仍无生产调用方,建议后续 PR 清理死代码。
  • [P2] app/api/session/session-dispatch-service.ts:78DEFAULT_AGENT_DISPATCH_TIMEOUT_MS 由 8s 调整为 30s 的动机建议补充到 PR 描述中,便于后续排查超时问题。
  • [P2] hooks/useChatMessages.ts:82-84room.name 重置逻辑仍未见行为级测试(如 room 切换后 history 清空、reconnect 后不清空),可后续补充。

Branch: fix/session-input-readiness

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant