fix(multi-subagent): distinguish configured and live child capacity - #4768
Conversation
5916c03 to
3580711
Compare
|
Rebased this PR onto current Repair applied:
Local validation at this exact head:
The maintainability ratchet still reports Entry-point scope: this remains a shared agent-context/CLI + managed-Turn projection change. It adds no new user-editable setting or card surface, so the existing frontend/Lark consumers continue to consume the common typed projection rather than gaining a second source of truth. No self-merge; exact-head review remains required. |
Pull in the independently validated main-branch repairs for the module budget ratchet and time-dependent Lark context fixtures so this feature branch can exercise its own checks without duplicating the fixes. Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com>
|
CI repair update for exact head
Fresh GitHub checks are now queued. This PR remains review-required and is not self-merged. |
58c1c31 to
b0c05e8
Compare
Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com>
Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com>
Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com>
Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com>
5efb3a2 to
2acb4f8
Compare
huangruiteng
left a comment
There was a problem hiding this comment.
Request changes conclusion (author-owned PR; GitHub blocks formal self-review)
Exact head: 2acb4f86428efa38d967c60578a955db75932ef4
动机
这个 PR 解决的是一个真实的多子 Agent 协调缺口:Goal 的 max_children 是持久配置上限,并不等于原生宿主当前仍有多少可用槽位。旧的 v3 context 只投影 max_children,当 native spawn / followup 返回线程上限时,没有稳定、可脱敏、可跨 Python/TypeScript 使用的结果输入,协调者容易把配置误当实时容量并在同一 Turn 内重复尝试。
当前 exact head 已完成该功能目标:新增只读 typed observation,把 agent_thread_limit_reached 投影为 capacity_exhausted、retry_same_turn: false 以及继续 parent work / defer 未启动 child / 容量变化后再试的恢复动作;成功结果只表示 attempt_observed,不会声称仍有槽位或授权继续重试。
改动思路
实现复用了既有 loopx agent-context 与 multi_subagent provider,没有新建 capacity store 或第二套权限来源。Python CLI 只负责接收 spawn|followup、succeeded|agent_thread_limit_reached 和可选非负 count,并校验参数成对出现、只能用于 after_delegate_result。真正的语义、脱敏和恢复事实仍由 TypeScript subagent_context.ts 统一拥有。
正向链路是:native host 显式提交一次操作观察 → Python 适配到 generic observations → TypeScript 白名单/限幅 → v4 contribution 返回只读事实。负向链路覆盖了半组参数、错误 phase、负数/孤立 count、disabled policy、伪造 raw error 与 success outcome:它们不会生成额外 authority、不会写 registry,也不会把 success 解释成可重试容量。
default-off 边界经过 base/head 公共 CLI 对照:spawn_allowed=false 且未提交 observation 时,base 与 head 都返回 ok: true、agent_context: null,不出现 capacity 字段;disabled 状态下显式提交 observation 会直接拒绝,而不是静默返回成功。
具体改动
loopx/cli_commands/agent_context.py:增加三个 typed CLI 参数,校验 co-presence、phase、count 与 capability enablement;只在真实提交 observation 时输出host_capacity_observed。loopx/control_plane/subagent_context.ts:provider 升级到 v4;新增capacity_contract与boundedNativeCapacityObservation,过滤 raw/未知字段,count 上限为 10,000,并区分not_observed、attempt_observed、capacity_exhausted。- 三个 Python/TypeScript 测试文件:覆盖公共 CLI、成功/限额、disabled、raw-error 脱敏、turn-envelope budget 与 provider size boundary。
docs/integrations/codex-subagent-orchestration.md:补充中英文命令、恢复行为、权限与隐私边界。
关键代码讲解
register_agent_context通过 argparse choices 建立第一层 typed boundary,不读取或解析宿主原始错误文本。handle_agent_context保持命令 read-only,并在 supplied observation 被 disabled policy 吞掉时显式报错,避免“看似提交成功、实际没有投影”的假成功。subagentContextProvider是唯一恢复语义 owner:max_children明确标为 configured upper bound,只有 after-result observation 才能改变本次 projection 的 live status。boundedNativeCapacityObservation是第二层 defensive boundary:只接受版本化 schema 与固定 enum,剥离raw_error,且仅对 thread-limit 发出retry_same_turn: false。
提交历史也已清理并重新核对:origin/main..2acb4f86 只有 4 个 huangruiteng 的 DCO-signed commit;先前混入分支的 songoow commit 已从 PR 独有历史移除。当前可见的 songoow commit 只属于已合并的 main 基线,不会作为 #4768 的额外提交合入。
对主干的风险
功能侧最强风险是把一次成功调用误写成“仍有容量”,或把 typed observation 变成新的 spawn/session authority。当前实现避免了这两点:success 只产生 attempt_observed,没有 retry_same_turn;context 仍是 guidance_only / read_only,不删除、导入、恢复或 rebind Session,也不写 Todo、quota、journal 或 registry。
本 head 的 feature-local 验证通过:
- Python focused suites:29 passed;
- TypeScript provider:12 passed;
- TypeScript typecheck、Ruff、
py_compile、git diff --check:通过; - risk-based premerge canary:14 selected,0 failure,0 manual hold,public/private boundary 通过;
- base/head 公共 CLI probe:enabled no-input 的行为变化符合 v4 disclosure,disabled no-input 保持 parity,base 对新 typed flags 明确拒绝,head 正确返回 bounded observation。
当前 blocker 不在本 PR 的 feature diff,而在其 base:main@6e5d5409 的 semantic inventory 实际值已是 17/39/10,预算仍是 18/41/11,所以现有 test_live_inventory_ignores_missing_or_stale_reports 两个参数化 mutation 在 base 上均复现 DID NOT RAISE Drift。这意味着 #4768 目前无法形成 required exact-head CI 结论;跳过或 admin bypass 会把已知主干回归误当成本功能验证通过。
最小修复是先由 maintainer 合入对应 semantic ratchet 修复(#4806),随后把 #4768 rebase 到新主干,并重新执行 exact-head review 与 required checks。由于 head 会改变,本次 review 不能沿用为最终 merge approval。
语义与 CI 对齐
该 PR 扩展既有 multi_subagent agent-context vocabulary,而不是创建新的 capability 或 authority model。版本化 observation 名称准确限定为单次原生 child 操作观察;公开文档、provider revision、typed enum、disabled parity 与 negative coverage 对齐。当前 REQUEST_CHANGES 仅来自外部 base/CI 依赖,并非发现 feature 语义或实现缺陷。
我的整体评价
REQUEST_CHANGES(依赖阻塞,非功能代码否定)。设计所有权正确、范围完整、隐私与权限边界清晰,feature-local 证据支持代码层面的正面评价;相关 future-facing refactor 也已做到位:配置上限、一次性观察和执行 authority 分离,不需要再引入新模块或持久状态。
但仓库 policy revision 7 要求 required validation 绑定 exact head。当前 base 回归尚未进入主干,且 CLI/control-plane 行为本身也属于 maintainer-only surface,因此不能自合并。依赖落地并 rebase 后应重新生成 packet、重跑验证并发布新的 exact-head 结论。
English verdict: REQUEST_CHANGES - exact head 2acb4f8 has no identified feature-code defect and passes 29 Python tests, 12 TypeScript tests, typecheck, lint, compile, diff checks, and 14 canaries; merge remains blocked until the known main-branch semantic-ratchet regression is fixed, the PR is rebased, and exact-head required validation is rerun.
Summary
max_childrenas a configured upper bound instead of live native-host availabilityagent-context --phase after_delegate_resultobservation for successful dispatch oragent_thread_limit_reachedon native spawn/followupProduct boundary
This changes the coordinator CLI/managed context projection and bilingual operator documentation. No frontend or Lark control is added because native host capacity is an ephemeral per-attempt observation, while the existing settings UI continues to own the durable
max_childrenceiling. The interface is read-only and never deletes, imports, resumes, or rebinds sessions.Validation
uv run --extra test python -m pytest -q tests/capabilities/test_codex_subagent_host_capacity.py tests/control_plane/test_agent_context.py tests/control_plane/test_delegation_context.py— 29 passednode --no-warnings --experimental-strip-types --test tests/control_plane_ts/agent_context.test.ts— 12 passednpm run typecheck:control-plane— passeduv run ruff check loopx/cli_commands/agent_context.py tests/control_plane/test_agent_context.py— passeduv run --extra test loopx canary premerge --from-git-diff— passed, 14 checks, no failures or manual holdsgit diff --check— passedResidual boundary
LoopX still cannot transparently intercept arbitrary native host tools. The current host must submit the bounded typed outcome after a native call; raw error text and session identities are not accepted.