mirror of
https://github.com/claude-code-best/claude-code.git
synced 2026-06-18 22:35:51 +00:00
为 AgentTool 引入 fork 布尔参数,支持子代理从父对话上下文中 fork 出独立分支, 继承完整历史、系统提示和模型配置。重构 inputSchema 条件逻辑以适配 fork 模式。 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
133 lines
5.8 KiB
Markdown
133 lines
5.8 KiB
Markdown
# 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 都用同等级模型(贵)
|
||
|
||
这导致探索任务被迫使用与父级相同的模型(而非 haiku),token 消耗大增。因此该 flag 在 `defines.ts` 中被注释禁用。
|
||
|
||
## 目标
|
||
|
||
- 将 fork 从隐式行为改为**显式参数触发**(`fork: true`)
|
||
- FORK_SUBAGENT flag 只控制 fork 能力的可用性,**不再影响 `forceAsync` 等其他行为**
|
||
- 模型始终继承父级(保持现有行为)
|
||
- **完全向后兼容**——不传 `fork` 参数时行为与当前(flag 关闭时)一致
|
||
|
||
## 方案设计
|
||
|
||
### Schema 变更
|
||
|
||
Agent tool 参数新增 `fork?: boolean`,仅在 `FORK_SUBAGENT` flag 启用时可见(schema 动态裁剪,复用现有的 schema memo 模式)。
|
||
|
||
```ts
|
||
// 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() 中的路由从当前的隐式判断:
|
||
|
||
```ts
|
||
// 旧行为:省略 subagent_type → fork(flag 开启时)
|
||
const effectiveType = subagent_type ?? (isForkSubagentEnabled() ? undefined : GENERAL_PURPOSE_AGENT.agentType);
|
||
const isForkPath = effectiveType === undefined;
|
||
```
|
||
|
||
改为显式参数触发:
|
||
|
||
```ts
|
||
// 新行为:显式 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()`:
|
||
|
||
```ts
|
||
// 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() 精简
|
||
|
||
函数签名和行为保持不变,但调用方语义改变:从"隐式路由判断"变为"参数校验门控"。
|
||
|
||
```ts
|
||
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` 零错误通过
|