Repository navigation
fix(chat): bind managed conversations to registered Agents - #7255
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>
loopx-agent
left a comment
There was a problem hiding this comment.
Reviewer: model_agent · gpt-6.1-sol · OpenAI · runtime_reported · max
Approval conclusion (author-owned PR; GitHub blocks formal self-approval)
动机
同一 Goal 中有多个已注册 Agent 的本地会话调用者,需要分别延续各自的工作和历史。
以前调用者选择的工作 Agent 只属于单次请求,普通 Goal 会话没有这个持久归属;现在显式选择 Agent 创建独立会话,恢复时保留原归属,并在注册撤销后拒绝新任务。
真实 HTTP/Core 验收读回了不同 Agent 的独立会话和持久身份,同一 Agent 恢复原会话,撤销注册后不接收新任务。
本 PR 不完成 Agent 工作台界面、自然语言任务配置或周期任务组合,也不改造原私聊 Bot 的身份和回传链路。
Agent 页面仍需把 managed 与 attached 会话并列展示,完整自然语言及周期任务验收仍未完成。
没有发现阻塞当前切口的问题。原来的“给 Goal 聊天再加 Agent 选择器”不能建立持久归属;同一执行端下两个 Agent 会混淆历史和后续执行者。本次把这个必要约束贯穿真实创建、持久化、继续执行和恢复入口,能够作为后续界面的独立可用前置能力。它不是整个周期任务产品的完成声明。
改动思路
身份约束由现有 TypeScript 决策层拥有,注册信息读取与会话恢复由现有原生聊天适配层拥有,持久化继续使用 Core;不增加任务库、调度器或模型执行者。
当前切口通过既有 HTTP 创建入口交付可执行、可恢复的 Agent 会话身份;界面与周期任务由既有后续产品工作接续。
显式选择是不可从模型或执行端推断的用户意图;工作目录和 Goal 生命周期则取自当前原生注册信息,不接受浏览器任意配置。Core 路由仍由 Goal、执行端和 channel 共同标识,派生的 agent.<id> 不需要把长 Goal 名拼进另一个字段。后续普通消息、恢复和原生执行均重新观察身份,而不是只在序列化时写一个字段。原始私聊管家继续使用自己的外部来源入口。
下表描述精确版本 27bdd0e67be4a5b293a697daeb04e4bbca8619a0 的源代码行为,属于解释性对照;执行证据另列在验证段。
| 请求 | 之前 | 当前 |
|---|---|---|
| 未指定工作 Agent | 原 Goal 聊天 | 保留原会话及历史,不自动认领 |
| 显式指定已注册 Agent | HTTP 不支持该字段 | 独立 Core 会话,恢复原身份与线程 |
| 注册撤销后继续 | 缺少持久工作归属检查 | 在新任务进入 Core 前拒绝 |
| 已接受但结果未知的旧操作 | 原操作记录 | 继续读回原记录,不重放 |
具体改动
关键代码讲解
prepare_managed_session_route由chat_server.py→chat_session_open.py→ChatRuntimeController.open_session的真实创建路径调用。没有工作身份时保持旧路由;显式身份只允许本地 Goal 的 managed Codex host,经过当前注册观察后确定 channel、生命周期和目录。project、steward、manager 或其他执行端不能通过参数替换混入此入口。require_managed_agent_session在普通提交、steer、resume、adapter 恢复前重新核对工作目录、Goal 生命周期、channel 和注册。它只观察与拒绝,不拥有调度或业务执行;实际效果仍属于原 Core worker。codex_context.py接回原有 home/upstream-mode 辅助逻辑,分支保持不变。admitManagedSessionTurn把请求 actor 与 Core 中不可变的managed_agent_id对齐,同时保留原执行端、目录、队列、原生验证等约束。conversation_scope.ts和 Python transport 一起传递并分类这些结构化字段;内部 handler 在既有 owner 注册,没有第二个权限源。ChatSessionStore.create_session在创建目录前核验本地 channel,保存身份和私有目录见证;后续更新不能更换 Agent 或 Goal。public projection 只为已绑定会话增加 Agent/生命周期,隐藏目录;旧记录无需迁移。两个测试文件覆盖 HTTP、Core、原生 Task 和类型决策,产品文档明确剩余工作。
规范基准:docs/product/periodic-reports.md,不可变版本 c10d8c2b4a20747e6eb77a188fd8e870b3be19de 的 Managed Agent execution boundary(基准正文)。该节没有编号,以下用其原文短语作为 criterion_id,未从本次改写后的文档倒推要求:registered Agent 和 original Session 已实现;managed and attached 的完整 Agent 界面留给既有后续产品工作;second scheduler 对应禁止增加第二套调度/任务库/模型 worker,已满足;recurring task composition 在基准中明确尚未完成,仍在本 PR 范围外。
对主干的风险
最大的回归风险是只检查“新建”而漏掉普通消息和恢复。独立 HTTP 验收在同一临时注册/真实 Core 后端上运行基准和当前版本:省略字段均得到 201、重复恢复同一会话且没有 Agent 字段;显式有效 Agent 从基准的 400 unknown field 变为当前 201 并独立读回;新增 peer 不继承原历史;撤销注册后当前普通请求返回 400,并且 Core 没有接受对应 client Turn。故意将提交前检查替换为空操作后,真实 HTTP 返回 202,独立断言失败,说明验收能识别这个绕过。模型、app-server 与消息 provider 是合成实现,HTTP、Core、注册及 File/SQLite 原生 Task authority 是真实路径;这不等于生产消息已补办。
兼容性有两个明确变化:显式 null 新字段按省略处理;空字符串仍拒绝且错误目前较泛化。旧 Goal 聊天可以继续普通对话,但不能再靠请求时选择另一个 Agent 来启动新的原生工作;已接受的旧 unknown operation 继续幂等读回,不能重放。这个限制来自既有 Agent 归属规范,不能笼统称为所有旧原生输入完全不变。private steward、普通 project 和 attached 入口未转换,新增能力也不因安装、注册或执行端可用就自行激活。最小修复不能只增加 UI selector,必须覆盖这些持续执行路径;额外维护成本是两个可选持久事实和共享类型操作,没有新服务。
验证:精确版本 Python 107 passed(95.54s),类型测试 17 passed,控制面类型检查通过,打包前端兼容构建通过;premerge 6 项直接检查和 11 项选中检查全部通过,0 自动失败、0 人工 hold。此前 chat_runtime.py 的 2350 > 2312 失败保留,重构后恢复 2312 行,没有提高基线。对照审计最初错误预期了普通 bad-request 的 409,源码和实际路径是 400;保留该失败并修正测试预期后,两版本重跑通过。故障注入仍按预期失败。wait_for_ci=false,未查询、轮询或等待远端 CI;广域 registry 的无关历史健康缺口没有被称为通过。
语义与 CI 对齐
本次扩展既有 managed Session 身份字段,复用原 ConversationScope、actor、Turn 和验证语义,不创建新的业务状态。共享纯分类器/运输字段在同一切口更新;语义 advisory 的有界扫描没有新词汇载体候选,这不是穷尽性证明。维护性、双语 RFC、编译、canary 和公开边界检查均通过,扫描范围及预算未缩减。新增错误是强制拒绝,文档中的后续 UI/周期工作是未完成说明,两者没有混称“建议”。
我的整体评价
APPROVE,属于 justified_increment。long_horizon 为 improved:多 Agent 重复恢复、原线程延续、unknown 只读回以及独立验证后的原生工作均有覆盖;user_experience 为 improved,仅指现有 API 少了歧义,不声称用户界面已完成。已检查 chat_server.py、chat_session_open.py 和共享 conversation_scope.ts:本次没有改变渲染组件、样式或界面入口。
未验收 Agent 工作台的新界面、手机展示或真实模型对自然语言周期任务的理解。
没有渲染改动,因此没有新增截图或页面质量结论。现有页面构建只是兼容证据。用户已提供选择及授权时,本 API 不增加确认轮次;后续自然语言工作仍要通过原有受管执行及权限边界。
残余风险是非法空 Agent 的泛化错误、真实模型/生产恢复未由本合成旅程证明,以及后续界面尚未消费新身份。兼容逻辑保留的是实际历史和操作记录,不保留随意切换业务 actor;维护性最高价值简化已经落实到既有适配层。此结论仅针对 27bdd0e67be4a5b293a697daeb04e4bbca8619a0,没有授予合并、部署或其他受众消息权限;合并前仍需当前精确 head 的独立 readiness 读回。
English verdict: APPROVE 27bdd0e67be4a5b293a697daeb04e4bbca8619a0 as a bounded managed-Agent identity increment. No blocking finding. Real HTTP/Core baseline-head and mutation checks plus 107 Python tests, 17 typed tests and local premerge qualification pass. Full Agent UI, real-model adoption and recurring-task acceptance remain unfinished; no production message replay is claimed.
Managed Goal conversations now bind the explicitly selected registered work Agent independently of executor/model, retain their original Core Session and upstream thread, and revalidate registration, lifetime and workspace before continued execution. Legacy Goal history stays unassigned; prior unknown operations remain readback-only. This delivers the existing API/host lifecycle slice; Agent workspace UI, natural-language configuration and recurring task composition remain unfinished.
Validation: 107 Python tests; 17 TypeScript tests; control-plane typecheck and packaged frontend build; real HTTP/Core baseline-head and deliberate guard-bypass counterfactuals. Local premerge: 6 direct and 11 selected checks pass, zero automated failures/manual holds. Runtime stays at the existing 2312-line ceiling. Model/provider boundaries are synthetic; no production message recovery or completed UI claim.