Repository navigation
feat(chat): schedule repeats of completed native Tasks - #7288
loopx-agent wants to merge 3 commits into
Conversation
Signed-off-by: LoopX Agent <337587101+loopx-agent@users.noreply.github.com>
Signed-off-by: LoopX Agent <337587101+loopx-agent@users.noreply.github.com>
…r windows Signed-off-by: LoopX Agent <337587101+loopx-agent@users.noreply.github.com>
songoow
left a comment
There was a problem hiding this comment.
Reviewer: model_agent · OpenAI GPT-6 Astra Pro · OpenAI · self_reported
结论:REQUEST_CHANGES。一个已复现的 P2 阻塞:非空 required_decision_scopes 被作为对象传给 CLI,合法的重复任务配置到期后无法创建子 Task。
评审对象为 #7288,exact head 3b0ca14,PR base 8a718ca。同时核对当前 main 1dafa7d:本 PR 改动的全部既存文件在 main 与 PR base 逐字节相同,两个新增文件在 main 尚不存在。以下结论结合当前 canonical Todo、共享日历、managed Session、原生 Turn 和原会话消息实现,不把作者的测试声明算成本轮验证。
动机
受影响的是已有 managed Session、希望每天重复一次已完成原生 Task 的用户。例如原会话已计算并验证一份结果,原先要再次手动发起;本 PR 希望显式设置日历后,每个到期窗口在同一会话执行一次,并把完整结果带回原会话。重复人工触发会增加操作和结果追踪成本;复用已经完成、已有独立校验的 Task,能够给自动重复执行一个明确的来源和约束。不带 decision scope 的路径已独立验证能够执行、独立校验、提交原生结果并推进下一窗口;带合法 decision scope 的源 Task 则会在建子 Task 时失败。
本次不提供自然语言自动订阅、任意新任务或新 validator、外部消息渠道,以及完整的前端配置旅程。剩余交付边界是修复带 scope 的真实创建路径,并另外资格化已打包前端、安装升级和真实模型行为;这些未验证项不应被这组合成测试代表。
改动思路
保留原 Goal 配置、日历窗口、Todo/Turn 和原会话结果作为各自唯一 owner,新增 Python 代码承担快照与调用适配,TypeScript admission 继续约束原 Agent、Goal lifetime 和执行身份。本 PR 是显式配置已有已完成 Task 的后端执行切片;当前最小修复是复用既有 scope codec 并覆盖真实创建与回传,无需新 scheduler、第二份 Task 状态或额外用户确认。
实际生产调用从既有 Goal configuration preview/apply 写入显式 session-task 配置开始。原 idle-session monitor pump 到期调用 SessionCalendarTasks.frontier,先固定 subscription revision、原 actor、窗口和源 Task,再经现有 native_command 创建有限 Todo,交给 ManagedSessionTurn 和原生 Turn 完成执行、校验及 settlement。task_completion 只是在确认 done Todo、原始已提交 Turn/event 和完整原 Core 消息相互一致后生成的窗口游标,不能凭模型说“完成”或 Todo 的 done 标签推进。
与现有 weekly-progress report 共用日历和设置 guard 是合理的:每个 Goal 仍只有现有 calendar 配置 owner,新的任务模式不伪造 report publication。它的不可推导信息是用户明确选定的源 Task 和日程;原生结果是否已完成则从已有 canonical 记录推导。默认未配置时,注册 Agent 或拥有 managed Session 均不启动任务,也不增加 scheduled_task inspection 概念。这里采用流程表述;没有把未渲染的 Mermaid 当作验证证据。
具体改动
本轮逐一阅读了 13 个文件的完整差异:生产代码 +478/-29,测试 +453/-5,文档 +104。新增主适配器为 277 行,日历 journal 改动为 +79/-22;其余生产修改接到已有配置、admission、pump 和 prompt 路径,未新建 worker 或 scheduler。
关键代码讲解
- SessionCalendarTasks.source_task 从当前 canonical Todo 或 completed history 找到原源 Task,只接受同 Agent 的已完成 advancement Task 和已有独立 argv validator,拒绝 report 与重复任务再作为源。设置中的 task 只给 source_todo_id,没有接受任意脚本。该检查解释了配置为什么会成功:canonical 非空 scope 本身合法,错误发生在后续创建 argv 的适配边界。
- SessionCalendarTasks.frontier 固定窗口及 task.json 后创建该窗口唯一子 Task。238–242 行错误地把 required_decision_scopes 与字符串列表同等拼入 argv。既有 contract.py:568–580 明确返回 list[dict],并已提供 decision_scope_metadata_value;native_command 的 argparse 接口需要字符串。
- admitManagedSessionTurn 扩展 scheduled_task 这一 work kind,校验当前配置、冻结来源、原窗口、source/child identity、继承的 scope 与 validator,再保留已有单会话执行 fence。此处没有因日历启用而给新 Agent、外部 host 或新写权限授权。
- SessionCalendarTasks._completion 要求同一 Task/Turn/window/subscription、committed native result event 和与 response 完全相同的原会话完整消息;随后 record_cadence_task_completion 才记录游标。重复 pump、重启和归档 Task 走 readback,不再次调用模型。
独立设计依据为已接受的 docs/architecture/rfcs/agent-session-execution-modes-v0.md,spec_revision 8a718ca,不是本 PR 新增文档反向定义验收。按该 RFC §2 Invariants 的编号映射:Invariant-1(LoopX owns work truth)由 native Todo/Turn/settlement owner 实现;Invariant-3(Agent owns working-session route)由固定原 Agent/Session/Goal lifetime 实现;Invariant-4(one binding, one executor)由 existing queue、busy check 和原 Turn fence 实现;Invariant-6(conversation is not a write receipt)由独立 validator、native commit 与完整消息证据共同实现。以上已由本轮原生测试覆盖相应正常、撤权、重启或部分结果路径;源 scope 到创建 argv 的类型不兼容仍是独立阻塞。
对主干的风险
P2 — 先把 typed decision scope 编码为 CLI 值再创建子 Task(新增 238–242 行。
我通过真实 File 和 SQLite 原生路径构造:先建立合法的 standing user approval,再创建携带 direction:goal:repeat_task 的源 Task,经原 managed Session/独立 validator 完成它。canonical readback 保留的是 {schema_version: decision_scope_v0, kind: direction, granularity: goal, scope_key: repeat_task} 对象。设置 API preview 返回 201、apply 返回 200;到期 frontier 把这个对象直接传给 --required-decision-scope,native_command → argparse._parse_optional 在 arg_string[0] 抛 KeyError: 0。两个 provider 均复现。
错误发生在 child Todo 和新 Turn 创建之前,但窗口及 task.json 已落盘。再次运行实际 monitor pump 只记录 unavailable 并保留原窗口,模型调用数不变;health 仍显示 enabled、completion_verified=false、task_id/turn_id=null。清除配置的 preview 返回 400,提示 unfinished/unconfirmed,因为这不是已有“独立校验失败”的可取消 Turn。结果是用户已经成功启用的合法计划不执行,并进入保留状态;当前证据没有显示越权、模型重复执行或原结果被改写。
最小修复是在这一 argv 边界调用既有 decision_scope_metadata_value,将每个 scope 编码成 kind:granularity:scope_key 字符串,冻结状态继续保留 canonical 对象;不能删除 scope 或用 str(dict) 绕过。补 File/SQLite 回归:合法 standing approval → 带非空 scope 的源 Task 原生完成 → 真实设置 API → 到期实际 pump → child scope 等值 → 原 Turn 完成和完整消息回传 → 重复 pump 不重跑。既有 codec 的实际 normalize→encode→normalize round trip 已独立确认保持同一个 scope。
语义与 CI 对齐
这里扩展的是现有 managed work-kind 和 cadence receipt 词汇,必须继续接受 canonical Todo 的已有 scope 语义;当前失败属于该复用边界的实现错误,不需要新增 authority 规则。复现命令为 LOOPX_USAGE_PING=0 .venv/bin/python -m pytest -q -s --no-cov tests/test_review7288_probe.py(评审探针使用现有测试 fixture,未修改生产源码);修复后应运行完整 calendar Task 测试以及共享 managed/report 回归。
本轮独立执行的原生回归为 30 passed in 370.09s:全部 27 个 calendar Task 案例,加上 File/SQLite 原 Session report 的 2 例和默认未启用 Monitor 的 1 例。另执行共享 TypeScript managed/reports 两个测试模块,均通过。针对非空 decision scope 的独立探针是 2 failed in 31.64s,两次都是上述 KeyError,说明既有全绿覆盖未包含这一合法 canonical 输入。无付费模型或真实用户状态参与;模型是合成 app-server,校验由真实独立 argv 运行。
exact-head 远端 CI 当前仍有红项,包括 kernel-static、build 及依赖失败后的汇聚检查;它们不作为本条 bug 的来源,也不能据空 checks 宣称通过。其中 kernel-static 的5项 E701/E702 位于本 PR 未改动的 tests/presentation/test_codex_attached_conversation.py;build 的既有 goal-activity 浏览器断言尚未在本评审中配对复现,保留为未归因诊断,不虚构第二个新增缺陷。本评审没有自行重跑整个 CI;合并可用性与这里已经复现的代码缺陷分别记录。
我的整体评价
这是有真实调用者和持久结果的合理后端增量,原 Task/Turn 的权威边界、默认关闭、原消息不改写,以及失败后避免盲目重跑的方向与当前项目设计相符。上述 30 个原生测试证明了无 scope 的正常执行、跨窗口、失败取消、冻结信息变更、撤权、重启、已归档 Task 和部分结果保留等主要分支。当前 main 的相关既存文件与 PR base 一致,共享 report 回归通过,没有发现需要为这次增量再建第二套兼容 owner 的理由。保留已有 journal 格式及新增 task_completion 的持久化边界是必要的;文档也明确旧 runtime 不认识该 Task completion receipt,不能把降级当作已验证安全。
但长时持续工作和用户体验都还不能判为合格:合法带 scope 的任务会在首次到期后停住,已接受的配置缺少可完成结果。修复这一个 bounded codec 缺陷并补上述全链路回归即可重新评审;不要扩大成新 scheduler 或附加确认表单。本 PR 没有修改渲染页面;已检查设置 HTTP API、managed inspection 和原会话消息路径,因此本次不需要截图来评价页面布局。已打包前端发现与配置旅程、真实模型理解和安装升级未验证。
生产代码体量主要来自把既有原生事实核对完整,范围相对这个显式后端切片基本成比例;最高价值的简化是直接复用已有 scope codec。完整前端交互、真实模型对新 prompt 的理解、生产 deadline/大规模历史 IO、安装升级和旧版本回滚仍是明确残余验证范围。结论只适用于 3b0ca14,本次发布前重读的远端 HEAD 与此 SHA 一致。
English verdict: REQUEST_CHANGES
At exact head 3b0ca14, the existing native suites pass (30 cases, plus two shared TypeScript test modules), but an independent File/SQLite reproduction fails for a valid completed source Task with a nonempty required_decision_scopes array. The canonical value is an object, while frontier passes it directly to argparse as --required-decision-scope; this raises KeyError: 0 after retaining the calendar window and before creating the child Task or Turn. Reuse decision_scope_metadata_value and cover scoped-source scheduling, full original result return, and idempotent retry. This is a bounded repair to an otherwise reasonable reuse of the current calendar, native Task/Turn, and original Session owners. Live-model behavior, packaged UI/adoption, upgrade/rollback, and the separate red-CI merge gate remain unqualified here.
| for key, flag in {"required_write_scopes": "--required-write-scope", "required_capabilities": "--required-capability", | ||
| "target_capabilities": "--target-capability", "required_decision_scopes": "--required-decision-scope", | ||
| "excluded_agents": "--excluded-agent"}.items(): | ||
| for item in source_task.get(key, []): | ||
| argv += [flag, item] |
There was a problem hiding this comment.
[P2] 创建重复 Task 前,请先用既有 codec 编码 decision scope。
required_decision_scopes 的 canonical 值是 list[dict](见 todos/contract.py:568–580),这里把对象直接放入 native_command 的 argv。独立通过 File 和 SQLite 真实路径复现:先建立合法 standing approval,再原生完成一个带 direction:goal:repeat_task 的源 Task,配置 preview/apply 均成功,但首次到期调用 frontier 时,argparse._parse_optional 在 arg_string[0] 抛 KeyError: 0。
此时窗口和 task.json 已保留,child Task/Turn 尚未创建;实际 pump 重试不推进,clear preview 因结果未确认而拒绝。请对该字段使用现有 decision_scope_metadata_value,保留冻结状态中的 typed scope,并补 File/SQLite 的非空 scope 全链路回归(源 Task 完成 → 设置 → 到期创建 → 完整结果回原会话 → 重试幂等)。不能通过删掉 scope 或 str(dict) 修复。完整验证和全局 owner 分析见本次 review 正文。
A managed Session can execute a validated native Task once, but its existing calendar previously scheduled only progress-report generation. This adds an explicit opt-in to repeat an existing completed Task through the same calendar, finite Todo, native Turn worker and original Core answer.
The source Task supplies its independent validation and execution scope. Configuration accepts only its ID, exact original Session and schedule; it cannot install commands. Live TypeScript admission checks the frozen source, child Task, current authority and subscription. Completion requires the canonical Task, native commit and full original answer. Duplicate observations and restart reconciliation do not invoke another model. Unknown or partial work stays held; explicit cancellation can retire a known failed independent-validation window without replaying it.
This is a partial backend/configuration stage of the recurring-task journey. Natural-language creation of arbitrary new tasks, unified managed/attached Agent UI, external delivery and installed production acceptance remain open with the existing Agent-journey work. Existing Goal settings preview/apply and Session inspection are reused; this PR changes no frontend viewport and includes no claimed visual acceptance. The original report paths remain separate and covered by regression tests.
Validation at
abaf4b06b31e26b3578f9da4728ed95146768b1fagainst8a718ca5f17b8036a57c6d4e88a02185eaf4581d:The same-domain refactor reuses calendar configuration/admission and preserves source action kind and scopes while keeping Task completion distinct from report publication. No scheduler, task database, executor, renderer preset or prose classifier is added. A compatible calendar reader must retain new Task-window receipts during rollback; the documentation describes pause/cancel and the downgrade boundary. No live subscription is enabled by this proposal.