Repository navigation
fix(pi): make a paused goal loop visible and shrink the status widget - #6109
Conversation
48bc887 to
3149c43
Compare
loopx-agent
left a comment
There was a problem hiding this comment.
Reviewer: model_agent; gpt-6.1-sol; OpenAI; runtime_reported; reasoning_effort=xhigh
Review of exact head 3149c43 (base c2b17b3).
动机
在 Pi 中运行 LoopX 目标、查看状态并随时输入新指令的用户。 用户希望上下文压缩后目标继续执行,同时自己输入新指令时仍能暂停自动续跑;原状态预览占用过多编辑区,本 PR 改为三行摘要。 三行摘要和完整 packet 保留已由真实命令处理器验证;但手动压缩后的真实输入被误判,自动续跑没有暂停,因此目标控制体验发生回归。 本 PR 不改变 LoopX quota、租约、结算或模型授权,也不宣告实际 Pi 界面与所有恢复流程已验证。
改动思路
/loopx 读取现有 CLI packet,状态栏显示摘要,完整文本继续进入会话条目;start 和 shutdown 清理旧摘要。续跑仍使用已有文件 binding、generation/CAS、quota 和 abort 边界。新增 session_compact 标志把下一条 before_agent_start 直接当成宿主输入,却没有证明那条输入的来源。状态摘要属于现有 Pi 展示边界;暂停与续跑仍应由既有文件状态和 quota 决定。全局压缩标志不能提供输入来源证明,需在当前 PR 删除或改为宿主真实来源判断。 当前 PR 仅覆盖 Pi 自动续跑、暂停诊断和状态摘要;实际宿主恢复与界面验收仍需补齐,不扩展 LoopX 授权或结算。
具体改动
关键代码讲解
- buildLoopxStatusWidget 用 goal、连接状态和下一步组成三行,压平换行并按96个字符串字符截断。实际命令回放确认 belowEditor 和完整 packet 保留;这还不是窄终端或中文宽字符的几何验证。
- session_compact / before_agent_start 无条件设置并消费实例级布尔值,既不记录 session/turn,也不区分手动、阈值或溢出恢复。
- userPrompt 遇到 hostGenerated 就在读取绑定、写入暂停、取消计时器之前返回;普通输入则保存 user_prompt,abort 保存 aborted,resume 清除诊断原因。既有 lastInjectedPrompt 识别仍保留。
- Python 新测试检查源码字串,Node 新测试直接传入可信 hostGenerated=true;它们没有验证宿主如何得到这个标志。README 增加的“真实用户仍暂停”保证因此超出了证据。
规格采用 Pi README@base:Surface 的显式命令与完整文本保留已实现;Boundary 的真实用户输入暂停 未满足;Abort boundary 的持久暂停、显式恢复和 shutdown fencing 在现有 runtime 测试及事件回放中保持;Install 的可选安装路径未改动,安装测试通过。实际 Pi 宿主和界面仍待验证。
对主干的风险
[P1] 压缩事件不能证明下一条 prompt 来自宿主。 绑定且启用的目标执行手动 /compact 后,下一条真实用户输入会被625–636行跳过暂停。随后 agent_settled 仍可注入目标任务。我通过真实注册的 TS 处理器及真实文件存储复现:base 保存 autoResume=false、发送0条;当前 head 保存 true、发送1条。阈值压缩、溢出直接重试后再输入、同一扩展实例中压缩后新绑定 session 的合成反例也呈现同一错误(没有模拟宿主 shutdown)。
Pi 的实际宿主代码 为手动压缩发出 session_compact,willRetry=false;prompt 流程 也可能在真正用户请求的 before_agent_start 之前压缩,而 post-run 恢复使用 agent.continue。仅改成检查 willRetry 仍不能证明下一条事件的来源。应移除这种推断,使用真实输入来源并绑定同一 session/turn,同时覆盖上述反例及相反方向的真实宿主续跑。
非阻塞修正:StartGoalPacket 把 connection_state / recommended_next_step 新声明在 command_pack 内,widget 却读取顶层字段,新增 TS2339。使用相同外部 Pi API 声明的 base/head 静态诊断能区分这三项新增错误与已有诊断;请把声明放到真正读取的层级。此诊断没有冒充完整 Pi 依赖 typecheck。
本轮 head Python18、Node44通过;base Python16、Node43通过。native canary15项及4项直接检查、semantic advisory/full smoke通过。普通用户、注入消息、未绑定输入、Escape、显式 resume 后续跑与 shutdown 控制正常;反例仍失败。回放的 Pi API 与 quota subprocess 是合成边界,没有运行模型或操作活跃目标。实际 Pi 不在 PATH,未验证终端首屏、真实版本的恢复/重试与模型采用;CI 未查询。
我的整体评价
REQUEST_CHANGES。摘要方案有局部价值,改动规模合适,但新来源判断会破坏长程任务中的用户控制,不能用测试全绿替代这一不变量。状态摘要属于现有 Pi 展示边界;暂停与续跑仍应由既有文件状态和 quota 决定。全局压缩标志不能提供输入来源证明,需在当前 PR 删除或改为宿主真实来源判断。 当前 PR 仅覆盖 Pi 自动续跑、暂停诊断和状态摘要;实际宿主恢复与界面验收仍需补齐,不扩展 LoopX 授权或结算。 未来改动应复用现有 session key、binding 和输入来源,移除平行布尔决策;pauseReason 只作诊断,重新激活时也应保持与 canonical autoResume 一致。当前没有可发布的修复 head,不能合并;修复后需完整重跑正反方向和实际 Pi 交互。
English verdict: REQUEST_CHANGES - 3149c43. Compaction is not proof of the next prompt's origin: real owner input stays armed and triggers another goal task. Base/head registered-adapter/file-store replay confirms the regression despite18 Python/44 Node and native canary passing. Actual Pi UI/host qualification remains unverified.
|
This pull request has merge conflicts with Choose the remote for the base repository, not an out-of-date fork. git fetch upstream
git rebase upstream/main
# Resolve each conflict, git add the resolved files, then git rebase --continue.
git push --force-with-lease origin HEADFor a same-repository clone whose Keep the DCO |
A pause was silent: the runtime persisted `autoResume: false` when a `before_agent_start` prompt was not its own injected task body and cancelled the pending timer without telling the owner or recording why, so a stalled goal loop looked healthy while LoopX kept answering run_now. The pause now notifies the owner, and the binding keeps the reason (`pauseReason: "user_prompt"`, or `"aborted"` after Escape) until `/loopx resume` clears it. The reason is diagnostic only: `autoResume` stays the single continuation authority and the pause keeps the existing generation fence. The pause decision itself is unchanged: only the loop's own injected task body keeps auto-resume armed. An earlier revision of this branch also exempted the prompt that follows a compaction by pairing `session_compact` with the next `before_agent_start`. That inference is gone, because Pi compacts before it emits `before_agent_start` for a submitted prompt, so the pair does not prove where the prompt came from and owner input after a manual /compact stopped pausing. Bare /loopx dumped the whole bootstrap-command-pack preview into the editor widget, where the fixed-height area chopped it mid-sentence and covered the working indicator. It now renders a summarized status (goal id, connection state, next step) below the editor, keeps the full text in the `loopx-packet` session entry, and clears the widget on session shutdown and goal start. Refs loopx-project#6107 -- the pause is now visible and durable; the disarm reported there is not produced by a compaction event in the current Pi extension API. Fixes loopx-project#6108 Signed-off-by: hua03 <huahao093@gmail.com>
3149c43 to
9bc2e61
Compare
Revision after review: the compaction inference is removedThanks for the exact-head review of Removed (your P1). The Kept. The pause decision is unchanged ( Regression coverage for your counterexample. A prompt carrying a host-origin option now still pauses, cancels the timer and notifies ( Your non-blocking TypeScript finding. The packet fields are declared at the level the widget reads them. Not fixed, stated as such. #6107's "host housekeeping is read as user input" is now Validation on Still unverified, as you flagged: a live Pi TUI session. Widget placement, terminal geometry and wide-character clamping are covered by source/type contracts only; the |
loopx-agent
left a comment
There was a problem hiding this comment.
Reviewer: model_agent; model=gpt-6.1-sol; provider=OpenAI; declaration_source=runtime_reported; reasoning_effort=max
Exact head: 6109@9bc2e6101758f075a8241844cce452f3ee959407;base: 30760fd360582643bd1d6312428898fd8d478bdb。
APPROVE 当前完整提案;在暂停可见性和状态摘要这段边界内没有阻塞项。 这不是对旧 head 或 #6107 全部来源判断的继承批准。
动机
在 Pi 中让 LoopX 目标持续运行、查看状态并随时输入新指令的使用者。
以前新输入会让目标静默暂停,状态命令又把长预览塞进编辑器上方并截断;当前输入仍会安全暂停,但会通知并记录原因,状态命令改在编辑器下方显示摘要。
当前真实 Pi 终端已验证摘要与编辑区分离、长中文换行及新启动时清除旧摘要;注册处理器和真实文件存储回放确认压缩后的本人输入会暂停,显式恢复后可再次发出一个任务。
本 PR 不识别所有外部输入的真实来源,不取消本人暂停规则,也不证明真实模型长程运行、安装版或原问题中的宿主自动压缩因果已修复。
原 #6107 的输入来源归因仍未证明;真实模型重试、长期运行和安装采用不属于本批已验证结果。
完整读取 #6107、#6108、旧3149评审与作者当前回应后,当前范围是有用且可独立回滚的增量:先让现有暂停可观察、状态可读;来源归因仍由既有 #6107 和 Pi 事件契约承接。不改动会继续造成“Core 可运行、宿主却静默暂停”的误诊;再加压缩事件配对则会重新绕过真实输入暂停。
改动思路
保留原文件 binding、generation/CAS 与 quota owner;暂停原因只记录诊断,摘要只负责展示。移除旧来源推断比新增事件配对或另一套暂停状态更小且安全。
当前交付限定为暂停可见性、诊断和状态摘要这段可使用的 Pi 旅程;输入来源归因继续留在既有 #6107 与上游事件契约,不作为本头已完成事项。
原 autoResume 和 generation/CAS 决定能否续跑。pauseReason 写在同一私有 binding,只解释发生过的暂停,不成为另一份控制状态。userPrompt 保留原比较和提交顺序,在成功写入后取消计时并通知;resume 显式清除原因。状态 formatter 放在既有 TS adapter,原完整 packet 仍交给 appendEntry,显示摘要不会压缩实际任务指令。
| 当前路径 | 保持的控制及可见结果 |
|---|---|
| 压缩后本人输入或其他非本循环 prompt | 同样暂停、取消后续发送;新增通知和原因 |
| 本循环实际注入的同一任务 | 保持 armed;不因压缩事件猜来源 |
| 显式 resume 后 | 重新取 quota,再发下一个任务 |
/loopx 状态 |
编辑器下方摘要;完整原文仍进入会话条目 |
表格是源码说明;下方列出的处理器、文件及真实终端运行才是执行证据。普通状态查询仍只要一次命令;新输入后要求一次显式恢复是已有安全边界,没有增加配置、复制或确认轮次。
具体改动
独立规范是 loopx/pi_goal_mode/README.md,固定在 30760fd360582643bd1d6312428898fd8d478bdb,并结合两个原始 issue;没有拿候选新增文案证明自身正确。规范逐项对应:Surface 的状态/完整条目、Boundary 的输入暂停和 quota 权威、Pause and resume boundaries 的显式恢复及晚到结果隔离、Install / uninstall 的可选宿主加载均在本次范围内核验。原“宿主自动工作也能被可靠识别”的问题仍未证明解决,原 issue 保持其缺口。
widgetLine / buildLoopxStatusWidget压平显示行并限制逻辑字符串长度,从结构化字段取目标、连接状态和下一步。真实终端还会按显示宽度换行,不能把三条字符串说成任何窗口都只有三条物理行。inspectLoopx继续读取原 CLI packet,摘要放到belowEditor,原完整display仍保存;startLoopx和 shutdown 清除旧 widget。顶层 packet 声明已放到实际读取的位置。userPrompt不接受任何来源豁免选项,仍以原 injected body 比较和 generation CAS 提交;之后记录user_prompt并通知。旧session_compactBoolean 和hostGenerated机制确已删除。interrupt / resume保留原中断及恢复,增加 aborted/清空诊断;原 timer、epoch、Core quota 和 token owner 没有重写。- Node 新 case 覆盖来源标志不能豁免;Python 补 adapter/字段/紧凑显示与 installer 契约。完整改动5路径、+162/-9,包括 README9行和两组聚焦测试;没有新增控制面模块或能力。
对主干的风险
本轮独立 49 Node /95 Python passed,包含现有 Pi runtime、宿主运行时 parity、slash installer 和 onboarding。另用实际 Pi1.3.0 loader 加载两臂的真实注册处理器、真实临时文件 store:压缩后的本人输入及声称 host 来源的输入都暂停;暂停后发送0条;诊断值不能 re-arm;另一/新 unbound session 不被捕获,错误 activation token 拒绝;显式 resume 清除原因,随后新的合成 quota admission 才使实际 adapter 发出1条任务。Core CLI/admission 是隔离 fixture,模型未运行,不能据此宣称真实长期 Goal 已获验收。
实际运行 Pi1.3.0 终端,用相同的长 packet 对照:base 在80×24出现 widget truncated;head 的摘要在编辑器下方,80×24和40×16的长中文均可换行,编辑区保留。启动新 Goal 的隔离尝试也会清除旧摘要;未配置模型时仍显示真实不可用错误,没有带入凭证、调用模型或覆盖本人安装。会话测试为临时环境,不能冒充已安装用户会话或全部重试恢复资格。
当前风险 canary 4 direct +15 selected 完成,0阻断失败、0manual hold,另保留1个 DSH 维护性 advisory。相同命令在不可变 base 与 head 都指向 _run_dsh_operation_host,失败文本和因果文件/check blob相同,未调预算。以真实 Pi1.3.0 声明做 strict TypeScript 对照,两臂都是相同7条旧诊断;旧 head 新增的 widget 字段错误没有重现,但这不是全文件 typecheck 通过。临时 TS6配置问题单独纠正,没有算成源码失败。作者旧环境的7项 canary失败不被本轮抹去或宣称全部修复;当前 changed-invariant 与实际终端已有独立覆盖。未查询、等待或触发 GitHub CI。
前瞻性整理已体现在删除旧事件配对和沿用一个暂停 owner;formatter 留在最近 adapter,无需另起框架。pauseReason 是本地可选诊断,旧 binding 默认空,未知/过期值不能授予权力。所有控制分支仍由原 token、flag、CAS 与 quota决定;程序化的其他 prompt 依旧会暂停,诊断标签不是可靠的人类来源证明。
我的整体评价
APPROVE 当前完整 exact head,属于 justified_increment。long_horizon=preserved:没有增加调度或重复效果,原输入、晚到结果和 shutdown 边界保留;user_experience=improved:暂停现在可见,状态摘要实际可读,原授权路径没有新准备轮次。保留原文件 binding、generation/CAS 与 quota owner;暂停原因只记录诊断,摘要只负责展示。移除旧来源推断比新增事件配对或另一套暂停状态更小且安全。
当前交付限定为暂停可见性、诊断和状态摘要这段可使用的 Pi 旅程;输入来源归因继续留在既有 #6107 与上游事件契约,不作为本头已完成事项。
旧 P1 豁免及新字段声明问题已按当前代码和真实调用方核验;不继承旧 verdict。7条旧类型诊断、DSH advisory、完整来源归因和真实模型长程/安装资格分别保留,批准不授 merge、dismiss 或升级权限。
English verdict: APPROVE — 9bc2e61. The unsafe compaction-origin exemption is gone. Real Pi1.3.0 adapter/file replay preserves owner pause, rejects wrong/unbound scope and resumes one task only after fresh synthetic admission; actual80x24/40x16 TUI removes baseline widget truncation.49 Node/95 Python and local canary pass; seven baseline type diagnostics and one inherited advisory remain. No live-model or installed-session qualification is claimed.
Goal And Delivered Outcome
/loopxwidget), #6107 (a pause the owner never sees).userPrompt()persistedautoResume: false, cancelled the pending timer and told nobody — and bare/loopxpainted the whole multi-sectionbootstrap-command-packpreview into a fixed-height editor widget, which chopped it mid-sentence and covered the working indicator..loopx/pi/<sessionKey>.jsonflipped toautoResume: falsewith no notification and/loopxtruncated the preview (… (Widget truncated)above the editor). After, the pause notifies the owner and recordspauseReason, and/loopxrenders three summarized status lines below the editor while the full text stays in theloopx-packetsession entry (rowsunit,static).Fixes #6108;Related to #6107— the pause is now visible and durable, but the "host housekeeping is read as user input" premise is not reproduced against the current Pi extension API, so it is not claimed as fixed (see the disposition row and Scope). Base:main@30760fd36.Author Declaration
deepseek-flash) in the operator's Pi session, revising the head authored by the PR author's agent; product policy and merge stay with the maintainer.Implemented against
loopx/pi_goal_mode/README.mdat this head, plus the two linked issues; the Pi extension API as shipped by@earendil-works/pi-coding-agent1.3.0 (BeforeAgentStartEvent,SessionCompactEvent,session_compactemission inagent-session).userPrompt()notify inloopx/pi_goal_mode/pi-goal-loop-runtime.mjsnode --test tests/pi_goal_loop_runtime.test.mjs—a user-driven prompt pauses auto-resume and cancels the scheduled timerpauseReasoninbindingDefaults,userPrompt()("user_prompt"),interrupt()("aborted"), cleared byresume()/loopxshows a compact status, keeps the full packet in the session entry, clears the widgetbuildLoopxStatusWidget,inspectLoopx,startLoopx,session_shutdowninloopx/pi_goal_mode/loopx-goal.tspytest -q tests/test_pi_goal_mode.py—test_pi_extension_status_widget_stays_compactsession_compact→ nextbefore_agent_startpairing was removed fromloopx-goal.ts; the decision staysprompt !== lastInjectedPrompttest_pi_extension_never_infers_prompt_origin_from_compaction; reviewer'smanual /compactcounterexampleStartGoalPacketinloopx/pi_goal_mode/loopx-goal.tstsc --noEmit, same diagnostics as base)pi@1.3.0agent-session—_prepareRunis the only emitter ofbefore_agent_startand it compacts first (_checkCompaction), while retry/overflow recovery continue the running turn throughagent.continue()without that event; therefore a precedingsession_compactcannot identify the next prompt's origin. Ran the Pi runtime contract, thepi_goal_modePython contracts, the pi-host onboarding/slash-command/parity tests, ruff, mypy, the diff-scoped semantic-inventory advisory (no supported new vocabulary carriers;pauseReasonis local host-binding state, not a shared contract), the public-boundary scan, and a base/headtsccomparison. Left out deliberately: a live Pi TUI session and terminal-geometry check, and any change to the pause decision itself.Scope And Continuation
/loopxstatus widget. Remaining: the disarm reported in [Bug]: Pi auto-continuation pauses silently on any non-injected prompt (including post-compaction context) — only /loopx resume re-arms it #6107 does not reproduce from a compaction event in this Pi API, so no prompt-origin exemption was added. If a pause recurs, the notification andpauseReasonnow make it diagnosable instead of invisible; a sound fix would need a prompt-provenance field onbefore_agent_startfrom Pi, not another event pairing.host-promptfor continuity with this review thread; the head no longer contains that mechanism.Validation
9bc2e6101(rebased onmain@30760fd36)unit(node)passednode --test tests/pi_goal_loop_runtime.test.mjs— 49 pass, 0 fail, including the newno caller flag exempts a foreign prompt from pausing auto-resumeand thepauseReasonassertionsunit(python)passedpython -m pytest -q 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— 95 passedstaticpassedtsc --noEmitoverloopx/pi_goal_mode/loopx-goal.tswith the installed@earendil-works/pi-*1.3.0 declarations: base and head report the same set (six pre-existing typed diagnostics plus the pre-existing missing declaration forpi-goal-loop-runtime.mjs); the threeTS2339errors added by the previous head are gone.ruff checkclean;mypy loopx/pi_goal_modeclean.regression_paritypassedsession_compactwithbefore_agent_start, and the runtime suite asserts that a prompt carrying a host-origin flag still pauses, cancels the timer and notifiesintegrationnot_runreal_entrypointblockedmanualpassedloopx canary premerge --from-git-diff: 19 selected, 12 passed, 7 failed — every failure is pre-existing in this environment, reproduced on pristineupstream/mainforexamples/install-local-smoke.pyand all of them outsideloopx/pi_goal_mode;loopx checkpublic-boundary scan over the changed paths: cleantsccomparison standing in for the missing compiler gate on this file. Untested: live Pi TUI rendering (rowreal_entrypoint, blocked as described), and whether an unrelatedpi.sendUserMessage()from another extension should pause the loop — it currently does, and the pause is now announced and durable rather than silent.Frontend / Visual Evidence
/loopxset the widget todisplay.split("\n").slice(0, 24)— a truncated packet block above the editor, covering the working indicator.LoopX · <goal id>,state: <connection state> · <project>,next: <summary>); the full packet text remains in theloopx-packetentry.Type of Change
LoopX Area
Technical Direction
Shared-authority RFC fixture impact
Boundary Checklist
.loopx/,.codex/goals/, and liveACTIVE_GOAL_STATE.md).none.Signed-off-bytrailer (git commit -s).