Repository navigation
fix(pi): trigger fresh continuation checks on idle resume - #7637
Conversation
Evaluate fresh quota admission when an idle session is explicitly resumed. Detach any fenced pre-pause evaluation so it cannot suppress the new check, while retaining busy-host, cancellation, and Core stop behavior. Signed-off-by: Jim-jimu <3230103159@zju.edu.cn>
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
loopx-agent
left a comment
There was a problem hiding this comment.
Reviewer: model_agent · gpt-6.1-sol · OpenAI · runtime_reported · reasoning_effort=max
APPROVE — 8fb12547122fdab3989e27365ccfa71fe4a8284a。未发现阻塞问题。 已独立复现旧代码缺少 idle resume 准入,再验证源码和实际安装出的入口;这项批准限于当前恢复控制流,不代表已验证真实模型、所有 Pi SDK 行为或获得合并权限。
动机 / Motivation
受影响的是在 Pi 中暂停或中止 LoopX 任务后,使用 /loopx resume 继续工作的用户。
旧实现已经把会话写成可继续,却只等下一次 agent_settled 事件;如果 Pi 当时已经 idle,就可能一直不再检查,用户还要额外发消息才能唤醒。
本提交让一次显式 resume 在 idle 时立即重新询问 LoopX 准入;只有允许继续才发送任务,忙碌、暂停、拒绝和依赖等待仍由原有边界处理。
本次只修复现有 Pi 会话的恢复路径,不增加启用策略、持久化格式、权限、跨会话接管或新的模型执行方式。
这解决了一个可复现的停滞,而不是用更多自动运行换取表面活跃。原有明确恢复意图已经存在,因此不应要求用户再输入一条无关提示。召回的用户旅程建议在本轮通过真实 adapter/存储和同输入反事实验证,没有继承历史评审结论或推断记忆收益。
改动思路 / Approach
保留现有 resume owner:先建立新的本地撤销 fence、持久化递增 generation 和恢复状态,再移除旧的在途 evaluation 缓存,调用原 evaluateIdle。这里的移除只解除旧 Promise 对新准入的合并,不取消已有工具或原 settlement,也不把旧 quota 结果变成新授权。
evaluateIdleOnce 继续检查当前会话、idle、autoResume、generation、Goal 与 Core 结果;已有 input fence、epoch 和 store CAS 在每个异步边界之后保留拒绝迟到副作用的能力。旧 evaluation 的 finally 只有仍持有同一 Promise 时才删除缓存,所以不能清掉新检查。忙碌会话直接保留到后续 settle,不产生抢跑或新增计时器。
当前局部 owner 和两条执行语句已经足够,没有引入新状态、轮询器、兼容分支或配置来解决这次停滞。再抽 helper 或重写调度反而扩大回滚范围,当前无需额外重构。
当前交付范围是现有 Pi 会话的显式 idle 恢复;存储、Core 准入与 host 权限继续归原有 owner。
对 exact head 的实际比较如下;表格是运行观察,不是根据实现反推的验收:
| 场景 | 旧生产代码+同一组当前测试 | 当前源码 / 安装文件 |
|---|---|---|
| idle、持久化暂停后显式 resume | 不产生新准入,相关断言失败 | 无需另一个 settle 即重新准入并派发 |
| pre-pause probe 尚未返回 | 没有独立的新检查 | 新检查立即进行,旧结果不能派发或移除新缓存 |
| busy、input/shutdown、Core deny/stop/wait | 依赖既有防护 | 对应正反例通过,等待保持有界 |
具体改动 / Changes
完整 diff 是4个文件、+159/-22。生产 runtime 只增加5行,其中两条执行操作;README 更新恢复语义;两份已有测试增加 idle、restart、并发与撤销覆盖,并调整原有测试对“必须再 settle”的旧期待。没有新模块、导出、依赖、CLI 参数或持久化字段。
spec_ref loopx/pi_goal_mode/README.md,spec_revision 0a9a3a3884490e7af2c2f27c2f2136ae738460db。审查的是改动前已接受的恢复/权限边界,并用独立复现的停滞说明为何要让当前 idle 检查立即发生,没有拿本 PR 的文档修改自证正确性:
- PI-RESUME — implemented:显式恢复重新武装绑定,idle 无需额外用户事件;真实注册 adapter 和持久化 restart 回归通过。
- PI-ADMISSION — implemented:每次继续需新 quota 允许;deny 加 run_now 提示仍不派发,Core stop 会再次暂停。
- PI-INPUT — implemented:interactive/RPC、queued/image/text-identical 输入仍撤销后续任务,已有任务不被取消;等待旧 re-arm 写入后保存暂停。
- PI-GENERATION — implemented:暂停/恢复递增 generation,旧探针不能派发;旧 finally 也不能删除新的 evaluation。
- PI-WAIT — implemented:依赖等待及探针失败恢复有界检查,不调用模型来空等;原 stop/最终检查策略保持。
- PI-DISPOSE — implemented:shutdown/实例替换仍以 epoch 和 fence 拒绝迟到发送与重新调度。
关键代码讲解
createGoalLoop().resume沿现有写入队列及 CAS 完成恢复后,解除旧 evaluation 并立即调用评估器;缺绑定或拒绝写入的测试确认不会询问 quota。evaluateIdle/evaluateIdleOnce仍拥有并发合并和实际准入;身份相等的 finally 保护新 Promise。quota 之后重读 binding,Core 停止/等待/允许分别走原分支,防护没有复制进 resume。/loopxcommand handler 的既有 resume 分支确实调用这个 runtime,isIdle来自 Pi context,后续发送沿sendUserMessage(...triggerTurn)。安装器将同一 adapter/runtime 写入目标项目,入口并非只存在于测试 helper。
已检查合并的 #7401 与同 owner 的输入暂停规则;本修复保留其边界。#7568 的相关改动只在 Pi README 区分另一条 bounded OAR 路径,没有改这个在宿主内工作的 runtime。当前 main 的这些 Pi owner 与本 PR base 一致,没有发现需重复实现或等待的同域改动。
对主干的风险 / Risks
最强风险是恢复启动的新探针与旧探针或用户输入竞争,从而重复发任务、清掉新检查或越过暂停。已读完整评估/恢复/暂停路径,并运行对应交叉场景:旧探针迟到、并发 settle 合并、input/shutdown 在新 probe 等待期间撤销、旧 timer 被取消、存储 read/write/CAS 故障及文件存储 restart。断言同时检查发送次数、准入次数、计时器和 durable autoResume,而不是只看返回成功。
| 本轮独立验证 | 结果与边界 |
|---|---|
| 三份 Pi Node suites,当前精确 head | PASS:111 passed,零 fail/cancel/skip |
| 同一组111项测试、未修改的不可变 base 生产文件 | 77 pass /34 fail;失败对应缺少立即恢复准入,故旧代码确实不能满足新请求 |
| 实际 CLI 安装到隔离项目后检查并执行 | adapter/runtime 与源码逐字一致;安装出的入口通过同一111项测试 |
| 五个相关 Python 集成/安装/调度/模块边界模块 | PASS:103 passed;其中包含 Node wrapper,数量不作为独立用例相加 |
原生 premerge,对固定 target b201da8bab305d053866aa0d4516b97ba4a4499e |
PASS:4项 direct+15项选中检查,零 failure/hold;精确 scope 质量回执有效 |
| 语义 diff advisory 与实际源码核对 | advisory 成功;该扫描不覆盖 mjs,不以零候选代替语义审查。源码未新增 vocabulary/状态格式 |
安装、TypeScript adapter 注册、Node runtime 和 native 文件绑定是真实的;SDK/UI 及 CLI quota 响应为 synthetic,未声称完成真实 Pi TUI/provider 或完整 SDK typecheck。Python suite 的 scheduler parity 使用实际 typed scheduler owner,Core quota 决策语义本身没有变更。作者此前环境限制中的8个 Python 错误在本次所选103项里未再出现;这里只报告当前独立覆盖,不猜测旧环境根因,也不改写历史失败。
无新增 feature flag 或权限,恢复仍由既有明确命令触发;自动输入、目录可发现性和安装不会自行恢复。inspect/status 路径不变,Core deny 不因 run_now 被绕过。对 typed-state、domain-neutrality 和 guidance/obligation 的核对没有发现新规则混用:这次沿现有 boolean、generation、fence 和显式 Core 判定,不从提示文案推断准入。没有查询、轮询或等待远端 CI。
我的整体评价 / Verdict
APPROVE,未发现阻塞问题。 当前 bounded bug-fix 目标达到;long_horizon 为 improved,依据是跨暂停/重启可继续且无迟到重复效果的已测路径,未推及普遍长期收益。user_experience 为 improved:已明确授权恢复的 idle 用户无需额外提示或确认;忙碌、停止和失败恢复仍由原 owner 决定。关闭/非恢复路径以及既有权限、存储与定时器语义均在实际相关用例中保持。
当前四路径没有改变渲染布局;本次验证的是命令控制流、通知语义、实际注册入口和持久化回读,不要求新的页面或截图。
未验证范围:真实 Pi SDK/provider 的完整端到端会话、TUI 视觉、最低 Node/Windows 矩阵和全仓 pytest;这次局部控制流没有引入对应新依赖、语法或平台分支,所选真实入口与故障覆盖足以支持当前审查,不能据此声称这些未执行范围通过。
CQR 对应当前4文件精确 scope,未做 reviewer safe-fix。现有代码已经直接复用正确 owner,额外架构和兼容层没有必要。合并仍需维护者权限与当前 exact-head readiness;本评审未执行合并。
English verdict: APPROVE — 8fb1254. Idle resume now obtains fresh admission without another event; stale probes, concurrent settle, input revocation and bounded waits retain their guards. 111 source and installed-entry tests, 103 related Python tests, exact-scope quality and local premerge pass; live Pi/provider coverage remains unverified.
Goal And Delivered Outcome
/loopx resumere-armed the binding but waited for anotheragent_settledevent. An already-idle session could therefore remain stalled.loopx-project/loopx:main. Related to fix(pi): pause automatic continuation on interactive and RPC input #7401; this completes the idle-resume path after its input-pause work. No issue-closing claim.Author Declaration
Implemented against
createGoalLoop().resumeevaluateIdleguardScope And Continuation
Validation
8fb12547122fdab3989e27365ccfa71fe4a8284afor Node regression, installed-entrypoint and typecheck runs. Python, lint and premerge checks used the identical pre-commit diff over0a9a3a3884490e7af2c2f27c2f2136ae738460db.node --experimental-strip-types --test tests/pi_goal_adapter_authority.test.mjs tests/pi_goal_adapter_input.test.mjs tests/pi_goal_loop_runtime.test.mjs: 111 passed.python -m loopx.cli slash-commands --install --surface pi --pi-project <temporary-project>; installed adapter/runtime bytes matched source, and all 111 tests passed against the installed files. Adapter registration and native file stores are real; SDK/UI and CLI quota responses are synthetic.python -m mypy(17 files);npm run -s typecheck:control-plane; diff whitespace and bilingual-RFC checks. Control-plane typecheck does not establish full Pi SDK compatibility.python -m loopx.cli canary premerge --from-git-diff --git-diff-base upstream/main --format json: four direct checks passed; 12/15 selected checks passed. Semantic-vocabulary, issue-fix PR lifecycle and CLI-project lifecycle smokes failed with the same host-permission denial, also reproduced on baseline. Public-boundary scan passed for all four changed files.loopx checkcannot start the Effect runtime in this environment. The budget failure also reproduces on baseline.mcpis unavailable (four skips, one collection error). Offline test-extra installation also lacks the pinned Hypothesis package.tests/test_pi_goal_mode.py,tests/test_host_loop_runtime_parity.py,tests/test_slash_command_install.py,tests/test_agent_onboarding_pi_host.py, andtests/architecture/test_top_level_module_budget.py.Frontend / Visual Evidence
Type of Change
LoopX Area
Technical Direction
Shared-authority RFC fixture impact
N/A: no TypeScript migration or shared Goal Authority progress claimed; no schema, provider conformance, runtime routing or compatibility projection changes.
Boundary Checklist
Signed-off-bytrailer.