Skip to content

fix: 接受截止时间前发起的 dispatch readiness 成功结果 - #28

Merged
lanyue-llk merged 3 commits into
lex-mainfrom
codex/fix-dispatch-readiness-deadline
Sep 4, 2026
Merged

fix: 接受截止时间前发起的 dispatch readiness 成功结果#28
lanyue-llk merged 3 commits into
lex-mainfrom
codex/fix-dispatch-readiness-deadline

Conversation

@why-tomato

Copy link
Copy Markdown

背景

dispatch readiness 查询可能在 deadline 前发起,但在查询返回时已经越过 deadline。

原实现会先判断 deadline,再检查查询结果,导致查询已经返回 ready Agent 和 room_video_input 时仍被判定为超时,最终 /api/session/dispatch 返回 502,前端恢复逻辑随后断开已经工作的会话。

修改

  • 保留查询前的 deadline 检查,deadline 到期后不再发起新查询。
  • 查询返回 ready participant 时,保留取消检查并接受成功结果,即使返回时刚刚越过 deadline。
  • 查询返回 not-ready 且已越过 deadline 时,正常超时,不再 sleep 或继续轮询。
  • 未修改默认 timeout、轮询间隔、取消、dispatch 去重和清理语义。

回归测试

新增两个确定性行为测试:

  • deadline 前发起查询,deadline 后返回 ready:dispatch 成功。
  • deadline 前发起查询,deadline 后返回 not-ready:正常超时,并确认不再查询或 sleep。

修改前 ready 用例稳定失败;修改后两条用例均通过。

验证

  • session dispatch、prewarm、取消、registry 和 stop 相关测试:97/97 通过
  • tsc --noEmit:通过
  • ESLint:通过
  • Prettier:通过
  • git diff --check:通过

@github-actions

github-actions Bot commented Sep 1, 2026

Copy link
Copy Markdown

Claude finished @why-tomato's task in 2m 29s —— View job


任务清单

  • 获取 PR 上下文
  • 拉取 diff 与相关代码
  • 审查改动(session-dispatch-service.ts 逻辑 + 新增测试的模拟时序)
  • 输出 review 结论

Review 结论

通过

问题及建议

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

  • app/api/session/session-dispatch-service.ts:180-217waitForRequestedRoomSessionReadiness)在其 readiness 轮询路径上没有 try/catch,若 roomClient.listParticipants 在查询过程中抛出网络异常会直接冒泡、不会重试;这是既有行为,本 PR 未涉及,但因为本次改动进一步鼓励“晚返回也接受”的语义,建议后续关注该路径的异常处理一致性。
  • 新增的两个测试(tests/session-prewarm.test.mjs:661-777)通过模拟 Date.now() 精确验证了“deadline 前发起、deadline 后返回 ready/not-ready”的边界行为,且断言了 sleep/deleteDispatch 调用次数,覆盖到位;核对 session-dispatch-service.ts:641-673 的改动后顺序(先查询结果判断 participant,再判断 deadline)确认与 PR 描述一致,未引入死循环或漏判取消的风险。

改动范围克制(仅调整判断顺序 3 行 + 新增回归测试),未发现无关改动或 secret/权限相关问题。

@github-actions

github-actions Bot commented Sep 1, 2026

Copy link
Copy Markdown

Claude finished @why-tomato's task in 6m 11s —— View job


任务清单

  • 获取 PR 上下文
  • 拉取 diff 与相关代码
  • 审查改动
  • 输出 review 结论

Review 结论

有条件通过

问题及建议

  • [P1] app/api/session/session-dispatch-service.ts:516createAgentDispatchWithRetry 中新增的 throwIfDeadlineExpired(getDeadline(), 'agent dispatch readiness') 被放在 waitForReusableAgentParticipant(...) 返回值之后、if (agentParticipant) 判断之前且无条件执行。若该调用(readiness = {},即"agent 已加入房间"这一步)在越过 deadline 后才返回一个有效 participant,这一行会直接抛出 agent dispatch readiness deadline expired,把刚拿到的成功结果又丢弃掉,走到 catch 分支、退出重试循环并 deleteDispatchQuietly,最终仍然对调用方返回失败——这正是本 PR 想要修复的那类"越过 deadline 但结果已就绪"问题,只是发生在 createAgentDispatchWithRetrydispatchRoomSession 的第一段共享 dispatch,被 app/api/session/dispatch/route.ts 直接、无 prewarm 外层 abandon 包裹地同步等待)而不是 waitForRequestedRoomSessionReadiness。新增的两个回归测试只覆盖了 waitForRequestedRoomSessionReadiness(video-readiness)路径,未覆盖这里;新增的第三个测试(prewarm 场景)验证的是"外层 prewarm 已经超时放弃后台台完成再清理"的语义,不等价于这里的"仍在被同步等待的调用方"场景。建议将这行 throwIfDeadlineExpired 移到 if (agentParticipant) {...return...} 分支之后(即只在 participant 仍为空时才用它替代/补充 lastError),与 waitForReusableAgentParticipant 内部已经做的重排序保持一致,确保"刚好卡在 deadline 上的成功结果"在这条路径上也能被接受。Fix this →

其余改动(waitForReusableAgentParticipant 内部判断顺序调整、两个新增回归测试)符合 PR 描述且逻辑自洽,未发现其他阻塞性问题(无 secret 泄露、无 React/Next.js 边界或无关改动)。
· branch codex/fix-dispatch-readiness-deadline

@lanyue-llk

Copy link
Copy Markdown

整体审查结论:当前 HEAD 仍有 1 个 P1

这个 PR 是 Xunfei 切换链路的 dispatch readiness 辅助修复,改动范围本身很小;但当前 f271c71 仍保留此前 review 已指出的 deadline race,因此还不能认为修复完整。

[P1] 外层无条件 deadline 检查仍会丢弃已经拿到的成功 participant

app/api/session/session-dispatch-service.ts:516waitForReusableAgentParticipant(...) 返回后、if (agentParticipant) 成功分支之前,无条件执行:

throwIfDeadlineExpired(getDeadline(), 'agent dispatch readiness');

如果查询在 deadline 前发起、deadline 后返回一个有效 participant,这里会先抛错,成功结果永远进不了下一行的 success branch。也就是说,waitForReusableAgentParticipant 内部刚修好的“先接受结果、再检查 deadline”语义,被外层重新抵消了。

建议把 deadline check 移到 agentParticipant 为空的路径,只在没有拿到成功结果时抛错;并增加 createAgentDispatchWithRetry 基础 readiness 的精确回归测试。现有新增测试覆盖 requested video readiness 和 prewarm 清理,不覆盖这条被同步等待的 shared dispatch 成功路径。

除这项外,没有发现与本 PR 范围有关的新阻塞问题。它能修复切换时序,但不替代 lex-voice livekit-examples#271 / lex-reflex #5 的 owner 退役和能力等价工作。

@github-actions

github-actions Bot commented Sep 1, 2026

Copy link
Copy Markdown

Claude finished @why-tomato's task in 2m 41s —— View job


任务清单

  • 获取 PR 上下文
  • 拉取 diff 与相关代码(对比此前两轮 review 及最新 3 个 commit)
  • 审查改动,重点核实 lanyue-llk 与此前 Claude review 指出的 P1(createAgentDispatchWithRetrythrowIfDeadlineExpired 丢弃刚到手的成功 participant)是否已修复
  • 输出 review 结论

Review 结论

通过

问题及建议

未发现需要阻塞合并的问题。此前两轮 review(含 lanyue-llkf271c71 上指出的 P1)在最新 commit 148df08 中已修复并补充了回归测试,核实如下:

  • app/api/session/session-dispatch-service.ts:532,547,574createAgentDispatchWithRetrythrowIfDeadlineExpired('agent dispatch') 已从「waitForReusableAgentParticipant 返回后、if (agentParticipant) 判断前」移除,现在仅在循环起始处和 alreadyJoined/agentParticipant 成功分支之后(即下一轮循环前)触发;agentParticipant 命中后直接 return,不再有无条件 deadline 检查抢先丢弃刚拿到的成功结果,与 waitForReusableAgentParticipant 内部语义一致。
  • tests/session-prewarm.test.mjs:新增 shared dispatch accepts a readiness query started before the deadline...dispatch reuses an existing participant returned after the deadline 两个用例,直接覆盖了此前被指出「未覆盖 createAgentDispatchWithRetry/共享 dispatch 首段同步等待路径」的缺口。
  • 148df08 额外引入 DispatchCaller/Set<DispatchCaller>DispatchCallerAbandonedError 机制,用于「prewarm 放弃等待」与「仍有活跃常规 caller」并存时的正确 cleanup 归属(cleanupAbandonedDispatch 仅在 !inFlight.accepted && !hasActiveDispatchCaller(...) 时才删除共享 dispatch),并有对应测试 abandoned prewarm does not cancel a shared dispatch with an active regular caller 覆盖,逻辑自洽,未发现死锁或误删风险。

残余风险(非本 PR 引入,基线代码已有,仅供后续关注):

  • dispatchRoomSessioncatch 分支仅在 error instanceof DispatchCallerAbandonedError 时才调用 cleanupAbandonedDispatch;如果某个 caller 的共享 dispatch 已成功、但该 caller 自身额外的 readiness 等待(如 requireRoomVideoInputReady)超时抛出普通 Error 且它是最后一个 caller,共享 dispatch 不会被 deleteDispatchQuietly 清理。这一行为在 base 分支(origin/lex-main)中同样存在,本 PR 未改变该路径,不属于本次改动范围。

因未获得 Bash 工具执行权限,本次未能实际运行 node --test/tsc/eslint;已通过静态阅读 diff 与全文交叉核对确认修复逻辑正确,PR 描述中给出的 97/97 测试通过等结果未做二次验证。
· branch codex/fix-dispatch-readiness-deadline

@lanyue-llk

Copy link
Copy Markdown

审查结论:PR 28 本身通过,但不能作为 Xunfei 迁移完成的依据

当前 HEAD 148df088 只修改 dispatch readiness 的截止时间与清理逻辑,不承载 Xunfei 端侧迁移。我对本 PR 运行了 266 个测试,并检查了 TypeScript、ESLint、Prettier 和 git diff --check,均通过;当前两处改动没有发现阻塞问题。

按这个 PR 描述的迁移目标,我同时对照检查了 lex-voice#271lex-reflex#5。把设备连接、原始音视频和 AIUI 下沉到端侧,把业务识别留在云端,这个方向合理;但迁移本身仍有以下问题。

[P1] lex-voice 的旧 Xunfei owner 仍然公开且可运行

lexvoice/room_input/__init__.py 仍公开导出 XunfeiInputSourceAdapterlexvoice/room_input/session.py 仍保留 create_xunfei_room_input_session()lexvoice/room_input/sources/xunfei.pyaudio_publishers.py 仍能创建旧的 9080/9090/19199 音视频链路。PR 只在 lexvoice/edge_media/runtime.py 的一个入口增加了拒绝 Xunfei 的 guard。

这不是完整的 owner 迁移。库调用方仍能绕开该 guard 启动旧链路,使 lex-voice 与 lex-reflex 同时成为设备 owner,产生重复连接、端口冲突或双重发布。最小修复是删除或取消导出旧 Xunfei capture、AIUI、room-input session 入口及其旧测试,只保留云端 decoder、projector、识别和交互逻辑。

[P1] 两仓协议样例已经漂移,并且 person_attributes 能力回退

两个仓库同名的 tests/fixtures/xunfei-static-endpoint-wire-v1.json 内容不同。可执行集合比较结果为:

lex-voice:  face_presence, face_candidate, person_attributes
lex-reflex: face_presence

两边 CI 只验证各自的本地 fixture,所以可以同时为绿,但不能证明 producer 与 consumer 兼容。lex-reflex 当前生产实现也只发布 face_presence

迁移前,Xunfei 的 person_attributes pipeline 在 CLOTHING_GREETING_BACKEND=yoloe 时会实际运行;迁移后,lex-voice 的 Xunfei start request 把该字段设为 false,lex-reflex 又不生产 attributes,导致这个已支持配置静默失效。最小修复是明确唯一 owner,并保留能力:由云端在校验后的当前帧和 bbox 上运行 yoloe attributes;同时只保留一份契约源,或在 CI 中固定 checkout 对端提交并执行真实 producer-to-consumer contract test。

[P2] lex-reflex#5 混入无关修改

.ai/skills/agentic-collaboration/scripts/collaboration_guards.pytests/test_collaboration_runtime.py 的 provenance guard 修改与 Xunfei runtime 无关,增加了迁移 PR 的审查和回滚范围,建议拆分。

验证记录

  • agent-starter-react PR 28:266 tests passed;tsc --noEmit、ESLint、Prettier、git diff --check 通过。
  • lex-voice#271、lex-reflex#5:相关 Python 模块使用 Python 3.12 编译通过,git diff --check 通过。
  • 两仓 fixture 等价断言失败,差异即上述 face_candidateperson_attributes
  • 未进行真实硬件、跨主机 LiveKit、Baidu/VLM 的端到端验证,相关风险仍需在合并前覆盖。

因此,PR 28 可以按自身 dispatch 修复独立判断;如果它被用作 Xunfei 迁移验收入口,则迁移尚未完成,关联 PR 的两个 P1 需要先解决。

@lanyue-llk
lanyue-llk merged commit a887615 into lex-main Sep 4, 2026
2 checks passed
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.

2 participants