Files
claude-code-best ba74e0976c feat: fork-agent-redesign — 新增 AgentTool fork 参数与 spec 设计文档
为 AgentTool 引入 fork 布尔参数,支持子代理从父对话上下文中 fork 出独立分支,
继承完整历史、系统提示和模型配置。重构 inputSchema 条件逻辑以适配 fork 模式。

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-02 23:39:43 +08:00

5.8 KiB
Raw Permalink Blame History

Feature: 20260502_F001 - fork-agent-redesign

需求背景

当前 FORK_SUBAGENT feature flag 是一个"一刀切"开关,启用时同时强制三件事:

  1. 所有省略 subagent_type 的 agent 调用隐式走 fork 路径(继承父级完整上下文和模型)
  2. 所有 agent spawn 强制异步(forceAsync 绑定在 isForkSubagentEnabled() 上)
  3. prompt 引导模型优先省略 subagent_type,导致大部分 agent 都用同等级模型(贵)

这导致探索任务被迫使用与父级相同的模型(而非 haikutoken 消耗大增。因此该 flag 在 defines.ts 中被注释禁用。

目标

  • 将 fork 从隐式行为改为显式参数触发fork: true
  • FORK_SUBAGENT flag 只控制 fork 能力的可用性,不再影响 forceAsync 等其他行为
  • 模型始终继承父级(保持现有行为)
  • 完全向后兼容——不传 fork 参数时行为与当前flag 关闭时)一致

方案设计

Schema 变更

Agent tool 参数新增 fork?: boolean,仅在 FORK_SUBAGENT flag 启用时可见schema 动态裁剪,复用现有的 schema memo 模式)。

// inputSchema 中新增
fork: z.boolean().optional().describe(
  'Set to true to fork from the parent conversation context. '
  'The child inherits full history, system prompt, and model. '
  'Requires FORK_SUBAGENT feature flag.'
)

flag 关闭时schema 通过 .omit({ fork: true }) 裁剪掉该字段(与当前 run_in_background 的裁剪方式一致)。

路由逻辑重构

AgentTool.tsx call() 中的路由从当前的隐式判断:

// 旧行为:省略 subagent_type → forkflag 开启时)
const effectiveType = subagent_type ?? (isForkSubagentEnabled() ? undefined : GENERAL_PURPOSE_AGENT.agentType);
const isForkPath = effectiveType === undefined;

改为显式参数触发:

// 新行为:显式 fork 参数触发fork 优先级高于 subagent_type
const isForkPath = input.fork === true && isForkSubagentEnabled();
const effectiveType = subagent_type ?? GENERAL_PURPOSE_AGENT.agentType;

决策表

fork subagent_type flag 开 结果
true 有值 fork 路径,忽略 subagent_type
true 省略 fork 路径(继承上下文)
true * 忽略 fork走 subagent_type 或 general-purpose
false/省略 有值 * 走指定 agent 类型(原有行为)
false/省略 省略 * 走 general-purpose原有行为

核心原则:fork: true 是最高优先级(当 flag 开启时),但 flag 关闭时静默降级,不影响原有行为。

后台运行由参数决定

fork agent 是否后台运行由 run_in_background 参数决定,与普通 agent 一致。forceAsync 不再绑定 isForkSubagentEnabled()

// forceAsync 不再受 isForkSubagentEnabled() 影响
const forceAsync = /* 其他条件coordinator, assistant mode 等)*/;

fork agent 与普通 agent 使用相同的 run_in_background 参数判断逻辑:

  • run_in_background: true → 后台异步运行
  • run_in_background: false / 省略 → 同步阻塞运行

prompt 调整

移除引导模型"省略 subagent_type 以触发 fork"的 prompt 文本。改为说明 fork: true 的适用场景:

When you need to delegate work that benefits from full conversation context (e.g., continuing a multi-file refactor where the child needs the same system prompt and history), use fork: true. For most tasks, prefer specialized agent types (Explore, Plan, general-purpose).

isForkSubagentEnabled() 精简

函数签名和行为保持不变,但调用方语义改变:从"隐式路由判断"变为"参数校验门控"。

export function isForkSubagentEnabled(): boolean {
  if (!feature('FORK_SUBAGENT')) return false;
  if (isCoordinatorMode()) return false;
  if (getIsNonInteractiveSession()) return false;
  return true;
}

不变的部分

以下保持不变,无需修改:

  • buildForkedMessages() — fork 消息构建逻辑
  • isInForkChild() — 递归 fork 防护
  • FORK_AGENT — fork agent 定义model: 'inherit', permissionMode: 'bubble'
  • buildChildMessage() — fork 子 agent 指令模板
  • buildWorktreeNotice() — worktree 隔离通知

实现要点

  1. Schema 动态裁剪inputSchema memo 中根据 isForkSubagentEnabled() 决定是否 .omit({ fork: true })flag 关闭时字段不存在于 schema
  2. 省略 subagent_type 恢复原有行为:不再隐式走 fork恢复为 GENERAL_PURPOSE_AGENT
  3. defines.ts 注释更新FORK_SUBAGENT 保持注释状态,但描述更新为新行为(显式参数触发,不影响探索任务模型选择)
  4. 递归 fork 防护:保持现有 isInForkChild() + querySource 双重检测

涉及文件

文件 改动
packages/builtin-tools/src/tools/AgentTool/AgentTool.tsx 新增 fork 参数解析路由逻辑重构forceAsync 解耦
packages/builtin-tools/src/tools/AgentTool/prompt.ts 移除隐式 fork 引导,新增 fork: true 使用场景说明
scripts/defines.ts 更新 FORK_SUBAGENT 注释描述

验收标准

  • fork: true + FORK_SUBAGENT 启用 → 走 fork 路径,继承父级上下文和模型
  • fork: true + subagent_type 有值 + flag 开 → fork 路径,忽略 subagent_type
  • fork: true + FORK_SUBAGENT 关闭 → 忽略 fork走普通 agent 路径
  • 不传 fork 参数 → 行为与当前 flag 关闭时完全一致(走 general-purpose 或指定 subagent_type
  • forceAsync 不再因 isForkSubagentEnabled() 而全局生效
  • fork 子 agent 的后台/同步行为由 run_in_background 参数控制,与普通 agent 一致
  • bun run precheck 零错误通过