Repository navigation
fix(runtime): align heartbeat admission, context and correction - #6483
Conversation
Signed-off-by: song <liusongstep@gmail.com>
Signed-off-by: song <liusongstep@gmail.com>
…artbeat-boundaries-20261015 Signed-off-by: song <liusongstep@gmail.com>
…artbeat-boundaries-20261015 Signed-off-by: song <liusongstep@gmail.com>
Signed-off-by: song <liusongstep@gmail.com>
Signed-off-by: song <liusongstep@gmail.com>
…artbeat-boundaries-20261015 Signed-off-by: song <liusongstep@gmail.com>
…artbeat-boundaries-20261015 Signed-off-by: song <liusongstep@gmail.com>
Signed-off-by: song <liusongstep@gmail.com>
Signed-off-by: song <liusongstep@gmail.com>
…artbeat-boundaries-20261015 Signed-off-by: song <liusongstep@gmail.com>
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=xhigh
Reviewed exact head: 6483@84e00bac1717cd07f25eafffbf60053bd1b46e5a.
动机
在 Codex、Pi、OpenCode 与外部定时器上运行长期 Goal 的用户。 用户暂停或 Core 拒绝工作后,旧检查或普通聊天原先仍可能恢复宿主、发送初始任务;新路径先检查当前准入并隔离暂停前结果,停止未确认则保留失败。 本头的受控宿主、文件绑定、CLI 与真实 Chat controller/store 测试支持停止隔离、恢复再准入和未发送任务恢复。 真实宿主停止延迟与 App 下发前拦截仍未资格化;模型纠偏采用和收益仍归原 Stride 后续验收。 不证明已安装厂商宿主、模型实际采纳、在途取消延迟、App 模型唤醒归零或长期纠偏收益;已提交效果仍需原结算。
改动思路
复用 Core 的当前准入和 replan owner,各适配器只负责自有传输、binding、计时器及结果隔离。修复落在已有状态与效果边界,验证直接覆盖旧竞态;无需新增通用框架。当前交付范围是源码中的状态发布/宿主派发不变量;安装态和长期收益仍保留原验收。通用决定继续属于 TypeScript owner;既有 Python/JS 宿主桥接不构成第二份决策规则。
| 原触发路径 | 本头行为 | 仍不代表 |
|---|---|---|
| 旧 quota 结果在暂停→恢复后返回 | 代次失效,下一次需新准入 | 已提交工具被取消 |
| 普通聊天或 OpenCode2 首次任务 | 不能绕过当前 Core 检查 | 宿主可自行解除 Goal 停止 |
| Codex 暂停只收到 ACK | 再读状态,未确认则关闭自有传输并失败 | App 的周期任务已停 |
| 心跳累计几次无进展 | 遵循 Core,不再另设两次阈值/自行暂停 | 决定回执证明模型采用或收益 |
具体改动
loopx/chat_codex_goal.py:115的pause先设置停止标志,再与激活互斥;active→paused 后重新读回,仍 active、消失或不可用则失败并关闭自有连接。第 261 行观察循环与迟到 start 事件路径不再投递排队输入/resume context;原 controller/store 接收失败事实。goal-bridge-runtime.mjs:343复用每 session 串行写入与本地 revision;普通聊天不解除显式暂停,原生 resume 先经过 Core。pi-goal-loop-runtime.mjs:788递增原 generation,旧 timer callback 不能消费替代 timer。opencode2-goal-worker.mjs:580把首次正文也放到准入后,保留未下发目标,终态退出;exclusive worker 的私有写入不被当作通用暂停 API。external_scheduler_worker.py:99仅接受布尔准入,local stop 优先。生成器各模式共享一次暂停/确认/未确认即结束条款;typed context 与 replan 明确 unknown、局部修正、到期复核可维持路线以及后续采用/结果核验。文档明确终态不再五分钟待机和去掉旧计数规则;这些是行为变更,不是默认关闭功能的隔离声明。
基于变更前 docs/architecture/rfcs/agent-session-execution-modes-v0.md; docs/architecture/rfcs/hierarchical-agent-stride-control-v0.md,不可变版本 3e611660af8e27aa8a97a8364606dad92e91ae7b,验收点 §5、§7.3、§7.5。模式与原权限绑定、Todo/replan owner 和长期观察的提案边界仍保留;本 PR 新写的 RFC 检查点只作为待验证主张,不能反过来自证。相邻未来重构检查:共享 stop 文案已收敛到一个 owner;跨 provider IO 的进一步统一并无当前收益证据,不增加框架。
149 项 Python、103 项宿主适配 Node、21 项 typed replan 均通过且无 skip,control-plane 类型检查、生成心跳和热路径预算 smoke 通过。包括真实本地 Chat controller/store 冷恢复;厂商宿主边界仍受控。另把同一组新测试指向不可变基线适配器,7 项全部产生旧错误,完整本头套件覆盖相应通过结果。风险 canary 5 个直接检查通过,19 个选中检查中 18 个通过、1 个失败;显式关闭 Node compile cache,不声称默认缓存问题已解决,也没有查询远程 CI。
对主干的风险
[P2] 补齐 compact Markdown 的现有回归预算资格化。 loopx/control_plane/testing/cli_output_budget.py:541 仍给 heartbeat_prompt_compact 的 Markdown 11,500 字符上限。当前必需 cli-output-budget-regression-smoke.py 因输出 11,530 失败。同一原生 mode fixture 的不可变基线为 11,315,本头增加 215 字符;行数均 145,JSON 为 12,658→12,873,仍在 13,500 内。这是此头生成文案增长暴露的现有约束遗漏,不能归为远程 CI、路径噪声或已知旧失败。
最小修复是保留停止对象、单次尝试、确认失败、Core 局部纠偏与原结算等有用语义,为同一 compact Markdown 工作负载补上消费者价值、真实冗余判断与合理余量,并使对应预算及文档一致;也可以删除确实可推导的冗余,不能为了过线删义务。本次扩大了 thin/正文预算,但没有解决这处独立 Markdown 上限。复验 uv run --extra test python examples/control_plane/cli-output-budget-regression-smoke.py,再执行同基线风险 canary;不要改变夹具或放松语义锚点。
真实宿主在途取消、已安装 App 停调度、模型实际消费与长期纠偏收益仍未验证,不能把受控恢复和 prompt 条款说成上述结果。作者此前的 budget/壁钟/ambient 路由及 work-map 失败未被本评审宣称修复;当前独立通过证据只覆盖所改不变量,当前 compact 检查失败则保留为明确阻塞。
我的整体评价
当前精确头 REQUEST_CHANGES,阻塞点是已复现的 compact Markdown 预算遗漏,不是否定暂停/恢复修复。生产机制对原问题基本合适,未发现需新增调度器或改写权限模型的理由。请以测量支持完整文本及合理上限后再提交新头;安装态、真实模型和长期验收仍由原 owner 继续,源码评审不替代合并授权。
English verdict: REQUEST_CHANGES. The stop/admission fixes pass focused counterexamples, but the required compact Markdown matrix regresses from 11,315 to 11,530 characters against an unchanged 11,500 ceiling. Reconcile that presentation budget with evidence while preserving the complete obligations, then rerun the native matrix.
Signed-off-by: song <liusongstep@gmail.com>
Follow-up: compact absolute budget repaired; merge holds remain已推送
本次是可独立回退的绝对展示预算修正。较广的增长规则和浏览器行为分别属于不同验证边界,保持明确失败,避免将局部修正包装成整个 PR 就绪。既有 REQUEST_CHANGES 保留;未批准、未合并。新头需要完整复验与 exact-head review。 |
Signed-off-by: song <liusongstep@gmail.com>
Signed-off-by: song <liusongstep@gmail.com>
songoow
left a comment
There was a problem hiding this comment.
Reviewer: model_agent; gpt-6-astra; OpenAI; runtime_reported; reasoning_effort=xhigh
Approval conclusion (author-owned PR; GitHub blocks formal self-approval)
评审对象:#6483,完整 head 8647d7ad866aa4d2345d834e515e5f10347fd200。本次按 capability policy 21 重新检查整个 PR,包含原有改动和三次修复;源码判断通过,合并状态另行判断。
动机
使用 Goal Chat、Pi、OpenCode 或外部调度器持续工作的用户,会在暂停、权限拒绝和重新恢复时遇到自动续跑边界。例如,用户在一次配额查询尚未返回时点击暂停,旧结果仍可能再发出一轮模型请求;现在暂停先使本地续跑失效,显式恢复后必须重新取得当前准入。已验证的改善是阻止暂停后的新派发、保留恢复所需的原始任务,并让续跑指令先读取当前工作和纠偏来源。
旧路径的实际代价是用户已经要求停止,却又产生模型请求或重复空唤醒;首轮被拒绝后重启还可能丢失原任务。此次验收覆盖持续运行中的暂停、重复事件、重启和显式恢复,不能只看一次成功调用。本次不承诺取消已经提交的工具、跨进程强制终止、零 App 首次唤醒,也不证明真实模型已采用纠偏。剩余的真实供应商停止延迟、已安装 App 调度关闭及长期模型收益,继续由现有 Session Execution Modes 和 Stride 验收负责。
独立依据是基线 3e611660af8e27aa8a97a8364606dad92e91ae7b 的 docs/architecture/rfcs/agent-session-execution-modes-v0.md §5,并对照同一基线的 Stride §7.3/§7.5 与 roadmap S7。没有用本 PR 新写的检查点反过来证明旧验收已满足;现有供应商资格和长期收益检查点仍然开放。
改动思路
保留现有 Core 准入与 TypeScript 指令 owner;Python 和 ESM 仅承担各自宿主的停止、读回及持久绑定,不另建统一运行时或第二套调度策略。本 PR 交付暂停、恢复、首轮准入和当前上下文的完整适配器修复;真实供应商与 App 安装态验收仍留在原有 RFC 检查点。
| 触发与路径 | 旧行为 | 当前行为与边界 |
|---|---|---|
| 本地暂停与待返回准入相交 | 旧结果可能继续派发;OpenCode 等 native ACK 后才解除续跑 | 先取消 timer、推进 binding revision 并持久关闭 autoResume,再等待 native IO;旧结果无权发送 |
| 普通消息、run_now 或 forceResume | 个别路径能绕过暂停或否定准入 | 不能代替当前 Core should_run;显式恢复仍重新查询 |
| OpenCode2 首轮或重启 | 首轮可能先调用模型;拒绝后的原任务不稳定 | 先保存原任务、再准入;重启继续同一任务 |
| 继续工作与纠偏 | 上下文可能陈旧,文本自行追加 wake-count 阈值 | 从现有 typed owner 读取当前来源,保持 Core cadence,区分指令、执行和结果 |
表格是源码流程说明,执行证据见后文。权限范围仍是已绑定会话和已有 Goal;安装插件、发现命令、普通输入都不会授予其他会话新的控制权。统一 provider 框架会增加无用维护面,本次只把重复停止顺序集中到现有 pauseBinding,这是已应用的有界重构。
具体改动
- Codex / Goal Chat:
CodexGoalDriver.pause先设置本地停止,再串行读取和更新 native Goal,确认状态后中断;拒绝、离线或无法确认时关闭自己拥有的 transport 并抛出错误。生产 controller/store 的停止和冷恢复路径一起覆盖,现有前端操作不增加设置或重复确认。 - Pi / OpenCode / OpenCode2:复用 session revision、CAS、timer、lease 和现有文件状态;Pi 不再把 run_now 当作越过否定准入的依据。OpenCode 普通消息不能解除硬暂停,resume 必须有成功宿主响应。OpenCode2 对第一条任务也准入,保留 private taskBody,forceResume 不能越过 Core 暂停。外部 scheduler
parse_tick拒绝非 boolean 和明确失败的准入,producer stop directive 的优先级保留。 - 当前上下文与纠偏:
interaction_contract.ts、replan_semantics.ts和现有 heartbeat renderer 共用当前来源,去掉自行发明的 wake-count replan/self-pause 阈值。完整、简短、紧凑和薄模式保持一次停止尝试、核实结果、未解决不冒充成功、停止新工作/花费以及不借 retry/RRULE 复活等义务;full/brief 把停止置于 wait/safe-bypass 之前。文档与 managed skill 同步披露,机器准入与 Agent 指令分别表述。 - 本次修复的输出预算问题:原 compact Markdown 11,500 上限确实失败。相同基线/头工作负载为 11,315 → 11,530 字符、均145行;仅该展示上限改为11,750,JSON仍13,500。完整 growth gate 还暴露 context/replan/heartbeat 文本增长,因此在原有测试 owner 中按完整 old→new 子句分别限定 +224/+384/+224 的迁移额度,错误 surface、缺失子句、已升级状态和再次超额均不能借用。没有缩短停止义务、改变执行配额或缩小原矩阵。
- 本次新发现并修复的竞态:4个 native stop 延迟场景在修复前全部失败,旧准入能在宿主停止尚未完成时转发1个事件。
8647d7ad8将 canonical pause/block、legacy pause 和 command pause 的本地 fence 移到 native IO 之前,4个场景全部通过;宿主抛错时继续暴露错误,本地仍保持关闭。新增 native-error 例覆盖此边界。 - 整个 diff 的其他部分:既有 Python/Node/TS 测试、三个现有 smoke/probe、provider README、heartbeat/Goal Chat/replan/interface-budget 文档,以及英中文 Session Modes、Stride、roadmap 检查点和 managed skill 均已读过。共41个 tracked 文件,+1361/-342;无生成锁文件、原始日志、私有状态或无调用方的新模块。
对主干的风险
- 核心正向与失败证据:149个 Python 用例通过;最终 head 的108个适配器用例、134个输出差异用例通过;37个 TypeScript 用例与 control-plane typecheck 通过。基线真实 adapter 模块运行相同选定测试时7个原缺陷全部失败,新增延迟停止场景在修复前4个全部失败。实际文件绑定、worker restart、不同 session、旧 activation 结果、拒绝准入、明确恢复和 host 错误都有覆盖;host/quota 外部响应采用可控 seam,不能当作真实模型试验。
- 项目原生检查:最终冻结提交的标准 canary 19/19 通过,无失败、跳过、超时或 tracked side effect;另有 diff/编译/maintainability 直接检查,semantic drift 与 advisory 通过。advisory 没有发现受支持的新词汇载体,但不覆盖所有 ESM 构造或证明语义等价。完整真实 CLI base/head growth matrix 通过。使用支持的 Node22.22.3 与显式禁用 compile cache;早先 Node25 runtime 失败没有被宣称修复。执行中途编辑造成的一次 canary side-effect 失败已作废,保留记录,以冻结源码运行替代。
- 产品入口:打包 dashboard/chat 构建与既有
loopx-mode浏览器交互通过(控制 API seam),生产 controller/store/native RPC 错误与恢复另有测试。没有 layout、首屏、Lark 或新增配置变更。没有 PostgreSQL authority 路由/schema 修改,因此不把未改动存储架构迁移验收强加到此 PR。 - 仍为红色的独立检查:打包
work-map在goal-work-map.mjs:178关闭详情后 selected-node locator 超时;workspace在goal-workspace-m2.mjs:82得到 showcase-reconcile 而期望 showcase-map-columns。在不可变基线独立安装、构建后执行同命令,两者的失败身份和细节与当前 head 一致;相关 UI、场景及 fixture 路径未改动。判为 pre_existing_unrelated,保留红色,不能声称 CI 全绿或以此跳过合并门禁。 - 未验证与兼容边界:真实供应商模型、已安装 App 调度关闭、首个 wake 成本、跨进程/已提交工具取消未执行。原有 legacy OpenCode 命令及持久文件读取仍有真实调用方,保留且覆盖;没有借兼容新增平行决策 owner。所有新默认行为在上述文档披露,通用错误和义务保持领域中立。
我的整体评价
此次实现给已有用户带来了可观察的暂停、首轮准入与恢复改善,修复后未发现需要继续阻塞该源码批次的实质问题。更严的准入没有删掉合法恢复:显式 resume 后重新准入、重启保留任务、普通原生未绑定路径与会话隔离均已验证。预算增加有同工作负载数据和完整子句约束,属于展示回归预算调整,不是放宽执行成本或牺牲 Agent 义务。
因此对当前精确 head 给出批准结论。这个结论仅针对已验证的适配器/指令批次,不关闭整个 RFC、不证明长期模型收益,也不授权合并。发布时远端部分构建仍在运行或排队,旧 REQUEST_CHANGES 尚需按项目流程核对;独立 browser 红项和实际 GitHub merge readiness 必须单独报告。
English verdict: APPROVE - 8647d7a; full-PR review completed, bounded output-growth qualification and the pre-native-stop admission race repaired. 149 Python, 108 adapter, 37 TypeScript and 134 differential tests plus 19 canary checks pass. Two independently reproduced baseline browser failures, pending CI and live-provider qualification remain separate holds; no merge authorized.
Verified resolution at 8647d7a, following the requested PR review and repair. The sole blocking finding was the compact Markdown presentation budget: the unchanged fixture measures base11,315 vs head11,530 characters at145 lines, now qualified under11,750 while JSON remains capped at13,500. Complete stop and correction obligations are retained. The full native output matrix,134 differential cases and final frozen19/19 premerge canary pass. Full exact-head review5530175890 is published and read back; unrelated baseline browser failures and live-provider gaps remain explicitly recorded. This dismisses only the resolved budget blocker, preserves the discussion and does not authorize merge.
Goal And Delivered Outcome
Long-running work must wake only under current admission, consume current requirements, and correct the affected work without inventing a new replan or pause policy. This change connects that chain to the existing pause/resume boundaries in Codex Goal Chat, Codex App heartbeat instructions, the external CLI scheduler and Pi/OpenCode/OpenCode 2. It adds no scheduler, summary store or parallel Goal state.
"false"as admissionFive managed-adapter counterexamples plus five Codex pause/recovery cases and four generated-prompt obligation checks failed before their respective repairs and passed after them. Core denial cannot be overridden by a runnable scheduling hint. Original in-flight effects and settlement remain the original operation's responsibility.
mainat3e611660a(release/manual-only advance after thea59aed703source audit).Author Declaration
agent-session-execution-modes-v0.md§5 andhierarchical-agent-stride-control-v0.md§7.5, rechecked ata59aed703; the paired RFC refinements specify pause precedence, scope, recovery and evidence boundaries. The current three-stage refinement also audits roadmap S4/S7, Stride §7.3–7.6, the Goal Vision planning contract, existing typed interaction/replan owners and current PR overlap. feat(checkpoint): expose ordinary Goal capture and evidence continuation #6486 owns Explore review knowledge, feat(chat): interact with bound Codex App conversations #6482 attached conversations, and fix(dashboard): surface host activity delivery windows #6465 activity-window presentation; none is reimplemented here.Scope And Continuation
Complete for the named dispatch, Codex pause-confirmation and current-context/correction instruction defects and corresponding RFC alignment. Existing ESM adapters and Python Codex transport/prompt renderers retain their provider responsibility; no parallel Python admission owner is introduced. They consume existing Core decisions; shared work-context and replan instructions remain in the existing TypeScript owners. No new shared policy owner or vocabulary is introduced. The semantic advisory does not analyze these JavaScript carriers, so its empty result is not semantic equivalence proof.
The bounded companion refactor centralizes the stop clause so prompt compaction cannot drop its obligations, serializes OpenCode binding updates so an old snapshot cannot overwrite pause/resume, and removes obsolete automatic standby behavior. Private worker state gains an optional initial task body; legacy unstarted bindings can supply the original task explicitly. The objective remains private and is not a new Core authority.
Behavior change: activated OpenCode 1/2 adapters stop on validated terminal no-follow-up instead of standby polling; OpenCode permission rejection and host errors require explicit re-arming. Initial OpenCode 2 task dispatch is now gated. Codex Stop/recovery now fails closed when pause cannot be read back, and generated heartbeat modes retain the complete stop contract. The external scheduler now rejects malformed or failed admission. Full/compact/thin templates and the managed project skill no longer invent wake-count replan/self-pause thresholds; brief guidance uses the same Core ownership rule. Configured Core review cadence remains intact. Inactive/unbound sessions retain their existing route. Existing host commands and Goal/quota settings remain the controls; no new frontend or Lark configuration is needed.
Working briefs are Agent instructions over current sources, not deterministic summary generation or evidence that a model adopted the correction. A due review can retain a path; only relevant goal/path/dependency/acceptance evidence warrants wider change. Receipt, subsequent work and independently verified outcome remain separate. The existing Stride provider-result wake and live-utility qualifications remain open.
App-owned heartbeats still require the host's existing stop action and confirmed readback. Without a host pre-dispatch hook, the first wake may already invoke a model. This PR does not promise zero App model wakes, live vendor adoption, arbitrary cross-process cancellation, or cancellation of submitted tools. OpenCode 2 inactivity hold is an observation of an outstanding turn, not evidence of an explicit user pause. Those limits are recorded in the existing RFC rather than another tracking framework.
Prompt Size And Semantic Review
Clause-by-clause review preserves the current heartbeat target, single attempt, verified stop, unresolved outcome, no new work/spend, no retry/RRULE fallback, and the existing notification/settlement boundaries. Stop handling precedes wait/safe-bypass instructions in full and brief bodies. No task prose is treated as a new machine-enforced lifecycle owner.
The same scoped Agent projection grows from 3,182 to 3,299 JSON characters; its 5,400 ceiling is unchanged. Bound envelope fixtures now measure the shipped projection, as the contract already requires, instead of generator diagnostics. Compact scoped body: 7,086 → 7,213 including fixed optional headroom, against the old 7,140 ceiling. Thin real CLI with the supported 320-character scope: 2,992 → 3,109, against 3,000. Only these presentation allowances rise: compact 6,500 → 6,700; thin 3,000 → 3,200. Execution/token quotas, other body limits and key-count caps remain unchanged. The broader full-scoped fixture was already oversized and remains an overflow diagnostic; it is not reclassified as passed.
The current refinement reuses instruction carriers instead of adding fields or model calls. Matched ordinary generated bodies change by full −215 / compact +88 / brief +46 / thin +37 characters, with no further body-ceiling increase. Across the same small/crowded/multi-Agent real CLI fixtures, main → pause-only → final thin outputs measure 3,070/4,998 → 3,187/5,115 → 3,224/5,152 characters (JSON/Markdown), all 65 Markdown lines. The old 5,100 Markdown diagnostic ceiling already failed on the pause-only head; only that human-output ceiling becomes 5,250. The 3,400 JSON ceiling and line/key/compute limits stay unchanged. Replan advice adds 363 text bytes for local scope and followthrough: its bounded advice allocation rises from 1,500 to 1,800 while the 8 KiB envelope warning and existing overflow evidence remain unchanged.
Validation
8647d7ad866aa4d2345d834e515e5f10347fd200.Earlier evidence is not erased: the a9472bb full growth gate failed before bounded semantic qualification; earlier Node25 runtime errors are not claimed fixed by this PR; a canary run overlapped tracked edits and was invalidated, then superseded by the frozen-head19/19 run. An older broad run also hit a2-second wall-time assertion; its later isolated pass is not presented as a timeout fix. The current source checks above establish the affected invariants. Original Core settlement, in-flight tool cancellation and cross-process host cancellation are unchanged and not newly qualified.
Frontend / Visual Evidence
Type of Change
LoopX Area
Technical Direction
Boundary Checklist