[Bug] Headless 正常结束时关闭子会话,终态通知在 shutdown 期间再次启动模型请求 #2082
Replies: 1 comment
|
Investigated this report and produced a candidate fix, validated on a fork of this repository. Root cause, fix and validation from the working notes:
Diff: awhite0030/prime-agent@main...fix-headless-shutdown-new-request-5249490025362446185 The change passes |
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
1. 现象
Prime Agent 0.7.3 的
--mode json -p主会话正常结束后,CLI 关闭仍有子会话的 worker。子会话的取消又注入rlm_child_terminal_notice,主会话在关闭过程中发出新的模型请求,然后立即取消。已转发的请求没有终态 usage,评测无法完整计量。两个真实运行都出现此顺序。时间为 2026-09-06 UTC:
stop写入 transcriptcompleted_without_reply通知另外四条在 shutdown 前已发出的子会话请求也被取消。两条尚未取得上游流对象,bridge 写 499;两条已经取得流对象,写
stream-failed: CancelledError/ 502。六条客户端响应均为aborted;两格 agent 执行均为 38 秒量级,实际启动参数为--agent-timeout-sec 1200 --trial-wall-cap-sec 3600,没有到点。后续 campaign 停止发生在 19:10:02.111505,晚于上述全部取消。这里的 499/502 是 bridge 计量分类,客户端最初收到的 HTTP 响应为 200。没有 Azure 服务端连接终止时间,不能声称重建了服务端的完整网络时序。
2. 固定源码
复现版本为 61131b2d195ba7a67a4ce8ac60bb10cecae07b67,即 v0.7.3。
packages/coding-agent/src/modes/print-mode.ts:121,165:等待主会话完成,然后 dispose connection。packages/coding-agent/src/modes/agent-connection/daemon-agent-connection.ts:1330:owned session 的 dispose 发complete_owned_session。packages/coding-agent/src/modes/daemon/daemon-supervisor.ts:1537,4789:结束 owned session 调用 stopWorker,向 worker 发 shutdown。packages/coding-agent/src/modes/daemon/daemon-mode.ts:6344,6373:先 await closeChildSessions,之后才 abort 父会话;父会话此时尚未进入 dispose。packages/coding-agent/src/core/agent-session.ts:9858,9989:子会话结束通知可走_promptInjectedMessage,唤醒父会话。packages/coding-agent/src/core/agent-session.ts:6578与modes/headless-completion.ts:78:主会话 idle 不代表子会话已结束。3. 免费复现
没有调用真实 provider。使用项目既有
AgentSession、Agent和假streamFn,执行实际waitForHeadlessCompletion与AgentDaemon.closeSessionOnce。仅用 fake daemon 状态提供容器、UI 与文件保存依赖;子会话和父会话都是真实 AgentSession。可在
test/agent-session-recursion.test.ts的createSession基础上构造:stop;创建一个等待 AbortSignal 的子会话。waitForHeadlessCompletion(root),观察它在子会话仍 active 时返回。closeSessionOnce(..., "shutdown", true, true, ...);子会话 abort 时让假 stream 返回stopReason=aborted。实测事件顺序,测试通过:
另用真实
streamAzureOpenAIResponses连接 loopback bridge,bridge 的 LiteLLM 上游替换为受控异步流:这说明真实批里的 502 不足以判断上游先断,也说明仅修改 bridge 的 499/502 分类不会消除关闭阶段新增请求。
4. 建议边界与验收
建议先明确两个独立合同:headless 是否必须等待子会话结束;worker 已决定 shutdown 后,子会话通知只能落盘,不能再启动父会话模型请求。后一项不应靠延长超时处理。
可复用后续版本已有的 RLM quiescence 能力,但需要决定 print 路径是否消费它。截至本次读取的 915c78f42c248b08238dd27fcd4bcab32c60beab,
print-mode.ts仍不传waitForRlmQuiescence。本次未动态验证最新版,复现结论仅覆盖 0.7.3,没有提交补丁。验收应覆盖:父结束但子仍在流中、子取消通知、关闭期零新增模型调用、普通运行时通知仍能唤醒父会话、显式取消与非 Azure provider。已转发请求仍需保留未知用量,不能改写为免费或未发生。
5. 去重
已查 Issues、PRs 与 Discussions 的 shutdown、headless、subagent、completed_without_reply。Discussion 1670 是长时间无输出后由外部 deadline 杀进程;Discussion 1566 是 SIGTERM 后恢复卡住;Discussion 2026 是忙内核泄漏。本例为正常主会话完成后的主动关闭,以及关闭期新请求。
PR 1253 处理 kernel host 消失后的子任务取消,PR 506 改 worker 所有权,PR 1239 处理 ACP 终态;未验证它们解决本例。bridge 侧未知 usage 已在 EvoMap/model-bridge 的 Issue 69 跟踪,不在本条重复要求估算计量。
All reactions