Description
先看这里:这条 Issue 在解决什么
现在的“最长运行时间”更像一个提醒,而不是闹钟。Agent 只会在一轮工作开始或结束时看一眼时间;如果它正在等待模型、工具或用户授权,即使已经超时,也不会马上停止。
举个例子
用户把任务上限设为 10 秒。第 8 秒时 Agent 发起了一个可能等待 120 秒的工具调用,最终任务可能两分钟后才结束。对用户来说,“10 秒上限”就失去了意义。
修改后应该是什么样
任务开始时确定一个统一的截止时刻。模型调用、工具、权限等待、子 Agent 和最后的总结都只能使用剩余时间;时间用完后立即进入清理流程,不再开始新的模型请求。
第一次看代码,从哪里开始
先看 ExecutionContext.wall_clock_exceeded() 如何记录运行时间,再沿着 AgentLoop.run() 中的模型请求和 invoke_tool() 的固定超时向下追踪。核心思路是“传递剩余时间”,而不是到处增加新的计时器。
下面是实现时需要参考的技术细节和验收标准。
问题
ExecutionContext.wall_clock_exceeded() 目前只在 Agent Loop 的若干检查点调用(src/sztu_code/core/loop.py:120、341)。正在进行的 LLM 请求不受剩余预算约束,工具调用又在 src/sztu_code/core/tools/invocation.py:207 使用固定 120 秒超时;wrap-up/conclude 阶段也可能在预算耗尽后继续请求模型。
因此配置 10 秒的 max_wall_clock_s,实际运行仍可能被一次慢 Provider、工具、权限等待或收尾请求拖到数分钟。
目标
把墙钟预算实现为贯穿整个 run 的单调时钟 deadline,而不是轮次之间的软检查。
实现范围
- 在 run 开始时基于
time.monotonic()计算 deadline,并提供remaining_s()。 - LLM 请求、工具执行、权限等待、后台子代理等待、压缩收尾和 wrap-up 都使用
min(自身超时, remaining_s)。 - deadline 到达时取消底层 await,并等待必要的进程/任务清理,避免孤儿进程和后台写入。
- 所有路径使用一致、可观测的终止原因,例如
max_wall_clock_exceeded,且只能发布一次最终事件。 - deadline 耗尽后禁止再发起 wrap-up/conclude 模型请求。
- 明确同步不可取消操作的处理方式,并在 Trace 记录超时层级和清理结果。
验收标准
- 使用可取消的 slow fake provider/tool 时,run 在预算后 200 ms 内结束。
- 工具固定 120 秒超时不会覆盖更短的 run 剩余预算。
- 权限等待和后台子代理等待也会被父 deadline 截断。
- 超时后不存在仍运行的子任务或测试进程。
RunFinishedEvent只有一个,状态和 reason 在 provider/tool/wrap-up 超时路径上一致。- 增加
tests/unit/test_loop.py、tests/unit/test_runner.py中的确定性 fake-clock/slow-await 测试。
非目标
不要求强行终止 Python 无法取消的任意同步第三方代码;此类情况需要被明确标记和隔离。
Activity
[-][Agent Core] ????????? LLM??????????????[/-][+][Agent Core] 让墙钟预算成为覆盖 LLM、工具与收尾阶段的硬截止时间[/+][-][Agent Core] 让墙钟预算成为覆盖 LLM、工具与收尾阶段的硬截止时间[/-][+][Agent Core] 任务设置了 10 秒却可能跑几分钟:为 Agent 增加真正的截止时间[/+]z2Ace0107 commentedon Sep 10, 2026
你好,我希望持续参与 #69,而不是只做一次性的局部修复。
这个 Issue 同时涉及 LLM、工具、权限等待、Subagent、上下文压缩、清理和 Trace。如果一次性修改,改动面会较大,也不利于逐步 Review。因此我准备按依赖关系拆成多个可独立 Review 的 PR:
PR-01:Python Run Deadline Foundation
PR-02:AgentLoop LLM Hard Cutoff
PR-03:Provider Timeout and Retry Boundary
min(provider_timeout, run_remaining_time);
后续独立 PR:
目前 PR-01 已在本地完成并提交为 commit 6662090,PR-02 也已完成本地实现但尚未提交。PR-02 的 focused tests 为 123 passed,Ruff、mypy 和 diff check 均通过。
PR-02 暂不声称完整解决 #69;工具、权限、Subagent、Provider 内部 retry 以及完整清理会分别在后续 PR 中处理。预计在拆分确认后先提交 PR-01,随后提交依赖它的 PR-02;后续阶段根据 Review 结果继续推进。
如果这个拆分或 PR 依赖关系需要调整,请告诉我。我会先按维护者意见修改范围,避免与其他贡献者重复工作。
rojim666 commentedon Sep 10, 2026
fix: 让上下文压缩请求遵守 Run 截止时间并有界清理后台任务
fix: 让子 Agent 继承父 Run 的截止时间与终止语义
z2Ace0107 commentedon Oct 23, 2026
进展同步:PR-01 至 PR-08 已全部合并(#159 / #161 / #162 / #164 / #165 / #166 / #167 / #168 / #169),覆盖 Run Deadline 基础、LLM hard cutoff、Provider timeout/retry、工具取消清理、权限 deadline、压缩边界、Subagent 继承与 Trace 可观测性。
接下来按原拆分计划做最后一项:全生命周期集成测试——一次 Run 撞 wall-clock deadline 时,LLM / 工具 / 权限 / 子 Agent / 压缩五类等待都能有界收尾,只发布一次 RunFinishedEvent,且 Trace 中有一条带阶段与清理结果的 deadline 记录,对应 ADR 0004 的「超时状态、原因、清理结果和终态事件可以被一致验证」。
预计以新增集成测试为主,不改生产行为;如果实测发现需要改代码才能让断言成立,我会先说明再调整范围。完成前不关闭本 Issue。
test: 补 Run deadline 全生命周期一致性集成测试
z2Ace0107 commentedon Oct 24, 2026
进展汇总:原拆分计划的 9 个 PR 已全部合并。
remaining_s())其中 #175 在补测试的过程中抓到一个真 bug:
cancel_descendants()只回报它动手取消的后代,继承父 deadline 后自行命中的子 Agent 不被计入,导致 trace 把
cleanup误报成completed。已修复。就本 Issue 的 Python runtime 范围而言,模型请求、工具、权限、后台子 Agent、压缩和
Trace 都已接入同一个 Run deadline。仍未覆盖的项(当初都列在非目标里,这里明确列出
以免误解为已完成):
ToolExecutionState.UNKNOWN/cleanup: unknown层面体现,没有跨工具的统一编排);SubagentFinishedEvent没有 reason 字段,子的具体终止原因只能经agent_result观察;这些是否需要继续做、以及本 Issue 现在能否关闭,由你判断。如果需要,我可以按同样的
拆分方式继续。
rojim666 commentedon Nov 10, 2026
完成状态复核(main
bbbe73f):deadline 主路径已有多轮合并,但暂不关闭。当前回归可复现:在py-runtime执行pytest tests/unit/test_subagent_cancellation.py::test_child_cancel_reason_inherits_parent_deadline_reason -q,子任务terminal_detail实际为cancelled,预期为max_wall_clock_exceeded(该组测试合计 124 passed / 1 failed)。这与本 issue 的一致终止原因要求仍有差距。另 deadline lifecycle/foundation/trace 等针对性测试通过,不能据此认定所有终止分支已满足。rojim666 commentedon Nov 11, 2026
2026-11-11 更新(复核当前 main
e3fdb9e):上一条复核 中的取消原因失败已由合并的 #183 修复,不再是当前阻塞项。已在该 main 的独立快照重新运行原失败用例所在的 subagent cancellation、runner、loop、deadline foundation/lifecycle/trace 测试,共 145 passed;另 invocation 与 permission manager 共 55 passed。感谢 @z2Ace0107 此前完成 #159 至 #175 的 deadline 系列实现和集成验证;#183 是其基础上的父取消原因竞态修复,不应把此前主体工作归于这次补丁。
这次验证确认原失败已消除,但不把这项补丁等同于整个 issue 全部验收完成:当前生命周期集成测试直接覆盖 provider 终态/Trace、子任务清理及 provider 的预算 + 200 ms,尚需逐项补齐或明确映射 slow tool、权限、compaction、wrap-up 的端到端终态一致性与时间边界证据。暂保留开放;这里不是声称这些路径仍有已复现故障,也不声明全仓 CI 全绿。