Skip to content

Architecture: 抽取 Delegated Agent Run 运行时构造,补全 delegated-* 模块族 #201

Closed
1 of 1 issue completed

Description

@suntianc

来源:#199 架构审查 grilling 后缓抽的独立加深项(2026-07-20)。本 issue 承接该共识,独立于 #199 推进。
依赖:建议在 #199(装配收拢)落地后再做。

背景

src/main/deepagent/runtime.ts 中 buildDeepAgentRuntime(约 line 633)内有一个 ~120 行的 delegatedRuntimeAdapter.run 闭包,它是 ADR-0061「每个 Delegated Agent Run 拥有隔离运行时」的实现本体——子 model / child graph / MemorySaver / 工具 scope 收窄 / 审批门控全在其中。

deepagent 已形成 8 个聚焦的 delegated-* 模块(configuration-snapshot / run-coordinator / run-repository / model-selection / run-failure / subagent-adapter / tool-action-repository / tool-approval-scheduler),此闭包是唯一仍陷在装配 god-file 里的委派逻辑。

为什么从 #199 缓抽(而非遗漏)

它是审批/工具门控的业务最高风险路径,承载:

  • ADR-0061 隔离运行时
  • ADR-0062 工具 scope 只收窄不扩大
  • ADR-0063 审批模式继承自父运行
  • Delegated Failure Isolation(失败隔离)

把它 relocation 捆进 #199 那种「行为保持」的结构重构,会使任何审批回归无法归因(结构改动 vs 逻辑改动)。它是可干净分离的独立加深,应单独做、先补测试再动结构。

方案

把闭包抽成显式工厂,补全 delegated-* 族:

createDelegatedRuntimeAdapter(parentContext): DelegatedRuntimeAdapter
  • DelegatedRuntimeAdapter 接口已存在(delegated-agent-run-coordinator.ts:69,单方法 run(request)),seam 非 hypothetical——coordinator 已依赖它。
  • 抽出后获得专属测试面:可单测「配置快照 + 父上下文 → 隔离运行时」,不必整体起一个 root run。

关键设计输入(动结构前需先解决)

  1. 父→子继承契约要收窄成刻意设计的窄接口。闭包当前隐式捕获约 10 项父级上下文:currentApprovalMode、builtInToolNames、allMcpServers、mcpServers、skillSnapshot、provider、project、overrides、sessionId、delegatedRunCoordinator。需甄别哪些是子运行真正需要继承的(对应 CONTEXT.md 的 Delegated Permission Context / Agent Tool Scope / Conversation Skill Snapshot 传播),哪些是偶然捕获,收进一个内聚的 parentContext,避免做成「把父运行内部全漏给委派模块」的浅 seam。
  2. 解开 coordinator ↔ adapter 循环:当前 adapter(633) 在闭包体内引用 coordinator(760),coordinator(760) 又持有 adapter,靠闭包延迟绑定。抽成独立模块后需改为 coordinator 以参数/thunk 注入。

前置 / 验收

  • Architecture review 01 — Collapse the Agent Run assembly god-file #199 装配收拢已落地、测试全绿。
  • 先为审批继承(ADR-0063)、工具 scope 收窄(ADR-0062)、失败隔离补专属单测。
  • 抽出后行为零变更,现有集成测试(parallel-delegated-runtime.deepagents.integration.test.ts、delegated-agent-run.deepagents-contract.integration.test.ts)全绿。

不做(domain-modeling 纪律)

  • 不更新 CONTEXT.md:用到的 Delegated Agent Run / Agent Tool Scope / Delegated Permission Context 均为既有领域词。
  • 不立 ADR:这是排序决策的承接项,非「拒绝且防重提」。

Spec(/to-spec 调研补充,2026-07-26)

调研结论:问题仍然存在,且前置已满足——#199 装配收拢已合入(装配模块已抽出),但 delegatedRuntimeAdapter 闭包原封未动仍在 runtime god-file 内(约 130 行),是 issue 预判的"唯一仍陷在装配文件里的委派逻辑"。
前置验收项的现状盘点:

  • Architecture review 01 — Collapse the Agent Run assembly god-file #199 落地 ✅;两个集成测试(parallel-delegated-runtime、delegated-agent-run contract)均存在。
  • 纯函数层已有专属单测 ✅:工具 scope 收窄(agent-tool-scope)、审批中断解析(shared-infra 的 interrupt 解析)、模型选择(delegated-model-selection)、配置快照、coordinator、审批调度器。
  • 缺口:闭包的组合行为(配置快照 + 父上下文 → 隔离运行时)没有任何单元级测试面,只能靠整跑集成测试覆盖;失败分类模块(delegated-run-failure)无专属测试。这正是本票要创造的测试面。
  • 循环确认:闭包体内引用 coordinator(审批中间件构造处),coordinator 又持有 adapter,靠闭包延迟绑定——与 issue 描述一致。
  • 闭包实际隐式捕获的父级上下文核对为:审批模式、父内建工具名集、父 MCP server 集与全量 MCP 目录、Conversation Skill Snapshot、provider、模型 overrides(含 allowedTools)、Project 与 Agent 文件根、Conversation 标识、coordinator(循环项)。与 issue 所列一致。

Problem Statement

Delegated Agent Run 的隔离运行时构造——业务上审批/工具门控风险最高的路径——是装配文件里一个约 130 行的匿名闭包。维护者无法单独测试"给定配置快照与父上下文,子运行时是否正确隔离、正确收窄、正确继承审批模式";任何审批回归都无法归因到结构改动还是逻辑改动;父→子的继承契约是隐式的闭包捕获,谁也说不清哪些捕获是刻意设计、哪些是偶然。

Solution

把闭包抽成显式工厂,补全 delegated-* 模块族:工厂接收一个刻意设计的窄父上下文接口,返回 coordinator 已依赖的既有 DelegatedRuntimeAdapter(单方法 run(request))。父→子继承项从隐式捕获升级为显式契约字段;coordinator ↔ adapter 的闭包延迟绑定改为显式注入(审批门控能力以延迟提供者注入 adapter,而非让 adapter 持有整个 coordinator)。行为零变更;装配文件只剩组合调用。

User Stories

  1. 作为 CDF 维护者,我想让"配置快照 + 父上下文 → 隔离运行时"可以脱离完整 root run 单独测试,以便审批/门控回归能在单元层被拦住。
  2. 作为 CDF 维护者,我想让父→子继承契约成为一个显式的窄接口,以便评审时能看出每个继承项对应哪条领域规则(Delegated Permission Context / Agent Tool Scope / Conversation Skill Snapshot 传播),而不是从闭包捕获里逆推。
  3. 作为 CDF 用户,每个 Delegated Agent Run 继续拥有隔离运行时:子模型、子图、内存 checkpointer、受限文件后端各自新建,父运行状态不被子运行污染(ADR-0061 行为不变)。
  4. 作为 CDF 用户,Delegated 工具 scope 继续只收窄不扩大:子运行可用工具永远是父可用集合经目标 Agent 配置与快照排除后的子集(ADR-0062 行为不变)。
  5. 作为 CDF 用户,Delegated 运行继续继承父 Conversation 的审批模式:父运行需要审批的工具类别,子运行同样进审批门控,不多不少(ADR-0063 行为不变)。
  6. 作为 CDF 用户,单个子运行失败继续被隔离为结构化失败结果,不拖垮父运行与并行批次中的其他子运行(Delegated Failure Isolation 行为不变)。
  7. 作为 CDF 用户,子运行的 Skill 预载继续只能从 Conversation Skill Snapshot 内选择,快照冻结语义不变。
  8. 作为 CDF 用户,单发与并行委派继续共享同一 coordinator 的并发窗口、持久身份与运行时工厂,进度与审批投影行为不变。
  9. 作为 CDF 维护者,我想让审批回归可归因:结构迁移提交不含逻辑改动,逻辑改动(若未来有)发生在有专属测试面的模块里。
  10. 作为 CDF 维护者,我想消除 coordinator ↔ adapter 的隐式循环,让依赖方向可从构造签名读出。
  11. 作为测试作者,我想用假的图执行器与假的 MCP 装载在 adapter 接缝上断言子运行时的组成(工具集合、门控集合、系统提示、模型选择、checkpointer 隔离),不真正调用模型。
  12. 作为 CDF 维护者,我想为失败分类补上专属单测,明确各类子运行失败(无效结构化输出、中断、超限、异常)映射到的结构化结果。

Implementation Decisions

  • 既有 seam 复用:不新增接口形状——工厂返回 coordinator 已依赖的 DelegatedRuntimeAdapter(单方法 run(request)),DelegatedRuntimeRequest 契约不变。全库新增 seam 数为一(工厂本身)。
  • 窄父上下文接口:显式字段限定为调研核对出的继承项——审批模式(ADR-0063)、父内建工具名集与父 MCP 标识(ADR-0062 收窄基线)、全量 MCP 目录(供快照排除后的子候选集)、Conversation Skill Snapshot、provider 标识与模型 overrides(委派模型选择输入)、Project 根与 Agent 文件根(文件系统限域)、Conversation 标识。不得把父运行其余内部状态漏进该接口。
  • 解循环:adapter 需要的审批门控能力(为门控工具构造审批中间件)以延迟提供者/回调注入,coordinator 构造后完成绑定;adapter 不再引用 coordinator 整体。
  • 模块归属:新工厂加入 delegated-* 模块族,与配置快照、run coordinator、模型选择、失败分类、审批调度器并列;装配文件(runtime)只做组合:构造父上下文 → 建工厂 → 建 coordinator → 注入门控提供者。
  • 可注入执行依赖:图构建(deepagents createDeepAgent)与 MCP 工具装载在工厂依赖中可注入,生产默认用真实实现——这是获得单元测试面的前提,不改变生产行为。
  • 行为零变更:子运行时组成、审批继承、scope 收窄、失败隔离、结构化结果解析、进度回调、并发窗口全部逐行为保持;本票不顺手修任何逻辑。
  • 提交纪律:先补测试(见下),后做纯结构迁移,两个提交独立可回滚。

Testing Decisions

  • 好的测试只验证外部行为:给定配置快照 + 父上下文 + 假执行依赖,断言子运行时的可观察组成与结果——子工具集合是父集合的收窄结果、门控集合等于按父审批模式解析的集合、Skill 预载 ⊆ 快照、模型选择输出、无效结构化输出降级为截断摘要成功结果、中断出现时报审批不可用错误;不断言闭包内部结构或调用次序。
  • 结构迁移前先在现有整体(经 coordinator + 假 adapter 或集成测试)补齐三条领域规则的行为锚点:审批继承(ADR-0063)、scope 只收窄(ADR-0062)、失败隔离——迁移后同样的断言在工厂接缝上重写为单元测试。
  • 为失败分类模块补专属单测(各失败形态 → 结构化结果字段),填补现有空白。
  • 先例:coordinator 测试的假 adapter 注入写法、delegated-model-selection 的纯函数测试写法、两个 deepagents 集成测试(迁移后必须全绿,作为零行为变更的最终判据)。
  • 验证:pnpm test 覆盖 deepagent 全簇;重点回归 parallel-delegated-runtime 与 delegated-agent-run contract 两个集成测试。

Out of Scope

Further Notes

Activity

  1. added
    needs-triageMaintainer needs to evaluate this issue
    architecture架构 deepening 候选(来自架构评审)
    ready-for-agentFully specified, ready for an AFK agent
    and removed
    needs-triageMaintainer needs to evaluate this issue
    on Jul 20, 2026
  2. suntianc commented on Jul 28, 2026

    @suntianc
    OwnerAuthor

    2026-07-28 code-review follow-up

    主体抽取与行为锚点已经落地;剩余的规格缺口已拆为原生子 Issue:

    #242 保持纯结构收窄,不修改 ADR-0061/0062/0063 行为。父票在 #242 完成、deepagent 相关单测与两个 delegated 集成测试通过后关闭。

  3. suntianc commented on Jul 29, 2026

    @suntianc
    OwnerAuthor

    已在 #245 完成实现并推送;Ubuntu、macOS、Windows CI 均通过。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    architecture架构 deepening 候选(来自架构评审)ready-for-agentFully specified, ready for an AFK agent

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions