diff --git a/Friends.md b/Friends.md deleted file mode 100644 index 612ff65e3..000000000 --- a/Friends.md +++ /dev/null @@ -1,38 +0,0 @@ -# 社区项目 & Blog 合集 - -> 每日更新,欢迎自荐! - -## 工具 & 应用 - -| 项目 | 描述 | 作者 | -|------|------|------| -| [4qtask.vercel.app](https://4qtask.vercel.app/) | 免费四象限时间管理工具 | @kevinhuky | -| [kaying.studio](https://kaying.studio/) | 个人 AI 工具箱 | @kayingai | -| [supsub.ai](https://supsub.ai/) | 高效阅读工具 | @hidumou | -| [x-video-download.net](https://x-video-download.net/) | 视频下载工具 | @syakadou | -| [1openapi.com](https://1openapi.com/) | API 中转站 | @thinker007 | -| [claw-z.com](https://claw-z.com/) | 一键部署 OpenClaw AI Agent(场景驱动、全面管理) | @uhhc | -| [gemini-watermark-remover.net](https://gemini-watermark-remover.net/) | Gemini 水印移除工具 | @syakadou | - -## GitHub 开源项目 - -| 项目 | 描述 | 作者 | -|------|------|------| -| [VersperClaw](https://github.com/versperai/VersperClaw) | 全自动科研流 | @versperai | -| [claude-reviews-claude](https://github.com/openedclaude/claude-reviews-claude) | 原汤化原食——Claude 如何看待眼中的老己 | @openedclaude | -| [agentica](https://github.com/shibing624/agentica) | 自研 Agent 框架,借鉴 claude-code 多 Agent 处理 | @shibing624 | -| [macman](https://github.com/tonngw/macman) | Mac 从 0 到 1 保姆级配置教程 | @tonngw | -| [SuperSpec](https://github.com/asasugar/SuperSpec) | SDD / Spec-Driven Development | @asasugar | -| [adnify](https://github.com/adnaan-worker/adnify) | 高颜值高定制化 AI 编辑器 | @adnaan-worker | -| [another-rule-engine](https://github.com/eatmoreduck/another-rule-engine) | 基于 Groovy 的开源多功能决策引擎 | @eatmoreduck | -| [creative_master](https://github.com/chatabc/creative_master) | AI 驱动的创意灵感管理工具 | @chatabc | -| [RapidDoc](https://github.com/RapidAI/RapidDoc) | Office 文件解析工具转 Markdown(支持 PDF/Image/Word/PPT/Excel) | @hzkitt | -| [token-share](https://github.com/leemysw/token-share) | macOS 原生菜单栏 LLM API 网关,支持 OpenAI 与 Anthropic 协议间的实时互译与流式转发 | @leemysw | -| [feishu-docx](https://github.com/leemysw/feishu-docx) | 飞书知识库导出、写入与云空间管理工具(支持 Markdown、公众号导入、CLI、TUI) | @leemysw | -| [web-search-fast](https://github.com/uk0/web-search-fast) | 快速网页搜索 | @uk0 | - -## Blog - -| 链接 | 作者 | -|------|------| -| [blog.xiaohuangyu.space](https://blog.xiaohuangyu.space/) | @eatmoreduck | diff --git a/spec/feature_20260502_F001_fork-agent-redesign/spec-design.md b/spec/feature_20260502_F001_fork-agent-redesign/spec-design.md deleted file mode 100644 index 83ab4dd46..000000000 --- a/spec/feature_20260502_F001_fork-agent-redesign/spec-design.md +++ /dev/null @@ -1,132 +0,0 @@ -# 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` 零错误通过 diff --git a/spec/feature_20260502_F001_fork-agent-redesign/spec-human-verify.md b/spec/feature_20260502_F001_fork-agent-redesign/spec-human-verify.md deleted file mode 100644 index dc0c1720a..000000000 --- a/spec/feature_20260502_F001_fork-agent-redesign/spec-human-verify.md +++ /dev/null @@ -1,170 +0,0 @@ -# Fork Agent 显式参数触发重构 人工验收清单 - -**生成时间:** 2026-05-02 -**关联计划:** spec/feature_20260502_F001_fork-agent-redesign/spec-plan.md -**关联设计:** spec/feature_20260502_F001_fork-agent-redesign/spec-design.md - ---- - -## 验收前准备 - -### 环境要求 -- [ ] [AUTO] 检查 Bun 版本: `bun --version` -- [ ] [AUTO] 安装依赖: `bun install` - ---- - -## 验收项目 - -### 场景 1:Schema 与类型变更 - -#### - [x] 1.1 fork 字段已添加到 baseInputSchema -- **来源:** spec-plan.md Task 1 / spec-design.md §Schema 变更 -- **目的:** 确认 fork 参数在基础 schema 中声明 -- **操作步骤:** - 1. [A] `grep -n 'fork:' packages/builtin-tools/src/tools/AgentTool/AgentTool.tsx | head -5` → 期望包含: `fork: z`(schema 定义)和 `fork?: boolean`(类型声明) - -#### - [x] 1.2 fork 字段在 flag 关闭时被 schema 裁剪 -- **来源:** spec-plan.md Task 1 / spec-design.md §Schema 变更 -- **目的:** 确认 FORK_SUBAGENT 关闭时 fork 字段不可见 -- **操作步骤:** - 1. [A] `grep -n 'omit.*fork' packages/builtin-tools/src/tools/AgentTool/AgentTool.tsx` → 期望包含: `schema.omit({ fork: true })` - -#### - [x] 1.3 AgentToolInput 类型包含 fork 字段 -- **来源:** spec-plan.md Task 1 -- **目的:** 确认类型声明与 schema 一致 -- **操作步骤:** - 1. [A] `grep -n 'fork' packages/builtin-tools/src/tools/AgentTool/AgentTool.tsx | grep 'AgentToolInput\|fork?:'` → 期望包含: `fork?: boolean` - ---- - -### 场景 2:路由逻辑重构 - -#### - [x] 2.1 isForkPath 使用显式 fork 参数判断 -- **来源:** spec-plan.md Task 1 / spec-design.md §路由逻辑重构 -- **目的:** 确认 fork 路径由 fork=true 显式触发 -- **操作步骤:** - 1. [A] `grep -n 'isForkPath' packages/builtin-tools/src/tools/AgentTool/AgentTool.tsx` → 期望包含: `fork === true && isForkSubagentEnabled()` - -#### - [x] 2.2 forceAsync 已完全移除 -- **来源:** spec-plan.md Task 1 / spec-design.md §后台运行由参数决定 -- **目的:** 确认 forceAsync 不再绑定 isForkSubagentEnabled() -- **操作步骤:** - 1. [A] `grep -c 'forceAsync' packages/builtin-tools/src/tools/AgentTool/AgentTool.tsx` → 期望精确: `0` - -#### - [x] 2.3 isForkSubagentEnabled() 仅用于 schema 裁剪和路由判断 -- **来源:** spec-plan.md Task 1 -- **目的:** 确认 isForkSubagentEnabled() 不再影响 forceAsync/shouldRunAsync -- **操作步骤:** - 1. [A] `grep -n 'isForkSubagentEnabled' packages/builtin-tools/src/tools/AgentTool/AgentTool.tsx` → 期望包含: 仅出现在 inputSchema 裁剪和 isForkPath 路由判断中 - -#### - [x] 2.4 shouldRunAsync 由 run_in_background 控制 -- **来源:** spec-plan.md Task 1 / spec-design.md §后台运行由参数决定 -- **目的:** 确认异步行为与普通 agent 一致 -- **操作步骤:** - 1. [A] `grep -n 'run_in_background' packages/builtin-tools/src/tools/AgentTool/AgentTool.tsx | head -5` → 期望包含: `shouldRunAsync` 计算中含 `run_in_background === true`,无 `forceAsync` - -#### - [x] 2.5 enableSummarization 使用 isForkPath 而非 isForkSubagentEnabled() -- **来源:** spec-plan.md Task 1 -- **目的:** 确认摘要仅在当前调用实际走 fork 路径时启用 -- **操作步骤:** - 1. [A] `grep -n 'enableSummarization' packages/builtin-tools/src/tools/AgentTool/AgentTool.tsx` → 期望包含: `isForkPath`,不包含 `isForkSubagentEnabled()` - ---- - -### 场景 3:Prompt 文本更新 - -#### - [x] 3.1 不再包含 "omit subagent_type" 引导文本 -- **来源:** spec-plan.md Task 2 / spec-design.md §prompt 调整 -- **目的:** 确认隐式 fork 触发引导已移除 -- **操作步骤:** - 1. [A] `grep -c 'omit' packages/builtin-tools/src/tools/AgentTool/prompt.ts` → 期望精确: `0` - -#### - [x] 3.2 包含 "fork: true" 显式参数说明 -- **来源:** spec-plan.md Task 2 / spec-design.md §prompt 调整 -- **目的:** 确认新的显式 fork 使用说明已写入 -- **操作步骤:** - 1. [A] `grep -c 'fork: true' packages/builtin-tools/src/tools/AgentTool/prompt.ts` → 期望包含: >= 3(shared section + whenToForkSection + forkExamples) - -#### - [x] 3.3 背景任务说明条件不再含 !forkEnabled -- **来源:** spec-plan.md Task 2 -- **目的:** 确认 fork 解耦后背景任务说明在 fork 启用时也显示 -- **操作步骤:** - 1. [A] `grep -n 'forkEnabled' packages/builtin-tools/src/tools/AgentTool/prompt.ts` → 期望包含: 所有匹配行均为 `forkEnabled ?` 形式,不包含 `!forkEnabled` - -#### - [x] 3.4 术语从 "fresh agent" 更新为 "non-fork" -- **来源:** spec-plan.md Task 2 -- **目的:** 确认 prompt 术语与新的显式 fork 逻辑一致 -- **操作步骤:** - 1. [A] `grep -c 'non-fork' packages/builtin-tools/src/tools/AgentTool/prompt.ts` → 期望包含: >= 2 - ---- - -### 场景 4:边界与回归(决策表验证) - -#### - [x] 4.1 fork=true + subagent_type + flag 开 → fork 路径,忽略 subagent_type -- **来源:** spec-design.md §决策表 + spec-plan.md Task 3 -- **目的:** 确认 fork 优先级高于 subagent_type -- **操作步骤:** - 1. [A] `grep -A2 'isForkPath = fork === true' packages/builtin-tools/src/tools/AgentTool/AgentTool.tsx` → 期望包含: `effectiveType = subagent_type ?? GENERAL_PURPOSE_AGENT.agentType`(fork 生效时 effectiveType 被 isForkPath 覆盖,subagent_type 不影响路由) - -#### - [x] 4.2 fork=true + flag 关闭 → 忽略 fork,走普通 agent 路径 -- **来源:** spec-design.md §决策表 -- **目的:** 确认 flag 关闭时 fork 静默降级 -- **操作步骤:** - 1. [A] `grep 'isForkPath = fork === true && isForkSubagentEnabled' packages/builtin-tools/src/tools/AgentTool/AgentTool.tsx` → 期望包含: `&& isForkSubagentEnabled()`(双条件确保 flag 关闭时 isForkPath 为 false) - -#### - [x] 4.3 fork 省略 → 走 general-purpose 或指定 subagent_type -- **来源:** spec-design.md §决策表 -- **目的:** 确认向后兼容 -- **操作步骤:** - 1. [A] `grep 'effectiveType = subagent_type ??' packages/builtin-tools/src/tools/AgentTool/AgentTool.tsx` → 期望包含: `GENERAL_PURPOSE_AGENT.agentType` - ---- - -### 场景 5:defines.ts 注释与构建验证 - -#### - [x] 5.1 FORK_SUBAGENT 注释已更新为新行为描述 -- **来源:** spec-plan.md Task 1 / spec-design.md §实现要点 -- **目的:** 确认注释反映显式参数触发设计 -- **操作步骤:** - 1. [A] `grep 'FORK_SUBAGENT' scripts/defines.ts` → 期望包含: `显式 \`fork: true\` 参数触发` - -#### - [x] 5.2 单元测试全部通过 -- **来源:** spec-plan.md Task 1 + Task 2 -- **目的:** 确认路由逻辑和 prompt 文本测试通过 -- **操作步骤:** - 1. [A] `bun test packages/builtin-tools/src/tools/AgentTool/__tests__/ 2>&1 | tail -10` → 期望包含: `0 fail` - -#### - [x] 5.3 precheck 零错误通过 -- **来源:** spec-plan.md Task 3 / spec-design.md §验收标准 -- **目的:** 确认 typecheck + lint + test 无回归 -- **操作步骤:** - 1. [A] `bun run precheck` → 期望包含: 零错误退出 - ---- - -## 验收结果汇总 - -| 场景 | 序号 | 验收项 | [A] | [H] | 结果 | -|------|------|--------|-----|-----|------| -| 场景 1 | 1.1 | fork 字段已添加到 baseInputSchema | 1 | 0 | ✅ | -| 场景 1 | 1.2 | fork 字段在 flag 关闭时被 schema 裁剪 | 1 | 0 | ✅ | -| 场景 1 | 1.3 | AgentToolInput 类型包含 fork 字段 | 1 | 0 | ✅ | -| 场景 2 | 2.1 | isForkPath 使用显式 fork 参数判断 | 1 | 0 | ✅ | -| 场景 2 | 2.2 | forceAsync 已完全移除 | 1 | 0 | ✅ | -| 场景 2 | 2.3 | isForkSubagentEnabled() 仅用于 schema 裁剪和路由判断 | 1 | 0 | ✅ | -| 场景 2 | 2.4 | shouldRunAsync 由 run_in_background 控制 | 1 | 0 | ✅ | -| 场景 2 | 2.5 | enableSummarization 使用 isForkPath | 1 | 0 | ✅ | -| 场景 3 | 3.1 | 不再包含 "omit subagent_type" 引导文本 | 1 | 0 | ✅ | -| 场景 3 | 3.2 | 包含 "fork: true" 显式参数说明 | 1 | 0 | ✅ | -| 场景 3 | 3.3 | 背景任务条件不再含 !forkEnabled | 1 | 0 | ✅ | -| 场景 3 | 3.4 | 术语更新为 "non-fork" | 1 | 0 | ✅ | -| 场景 4 | 4.1 | fork=true + subagent_type + flag 开 → fork 路径 | 1 | 0 | ✅ | -| 场景 4 | 4.2 | fork=true + flag 关闭 → 忽略 fork | 1 | 0 | ✅ | -| 场景 4 | 4.3 | fork 省略 → general-purpose(向后兼容) | 1 | 0 | ✅ | -| 场景 5 | 5.1 | FORK_SUBAGENT 注释已更新 | 1 | 0 | ✅ | -| 场景 5 | 5.2 | 单元测试全部通过 | 1 | 0 | ✅ | -| 场景 5 | 5.3 | precheck 零错误通过 | 1 | 0 | ✅ | - -**验收结论:** ✅ 全部通过 / ⬜ 存在问题 diff --git a/spec/feature_20260502_F001_fork-agent-redesign/spec-plan.md b/spec/feature_20260502_F001_fork-agent-redesign/spec-plan.md deleted file mode 100644 index 7181f577a..000000000 --- a/spec/feature_20260502_F001_fork-agent-redesign/spec-plan.md +++ /dev/null @@ -1,317 +0,0 @@ -# Fork Agent 显式参数触发重构 执行计划 - -**目标:** 将 FORK_SUBAGENT 从隐式行为改为显式 `fork: true` 参数触发,解耦 forceAsync,保持向后兼容 - -**技术栈:** TypeScript, Zod schema, Bun test, React/Ink (prompt UI) - -**设计文档:** spec/feature_20260502_F001_fork-agent-redesign/spec-design.md - -## 改动总览 - -- 本次改动涉及 3 个修改文件:`AgentTool.tsx`(Schema + 路由 + forceAsync 解耦)、`prompt.ts`(引导文本)、`defines.ts`(注释更新)。新建 1 个测试文件 `prompt.test.ts`。 -- Task 1 是 Task 2 的前置:Task 1 完成 Schema 变更和路由重构后,Task 2 才能安全地调整 prompt 文本(prompt 行为描述必须与代码实际行为一致)。 -- 关键设计决策:fork 参数添加到 `baseInputSchema` 而非 `fullInputSchema`,因为 fork 是基础 agent 能力而非 multi-agent 特有能力。 - ---- - -### Task 0: 环境准备 - -**背景:** -确保构建和测试工具链在当前开发环境中可用,避免后续 Task 因环境问题阻塞。 - -**执行步骤:** -- [x] 验证构建工具可用 - - `bun --version` - - 确认输出 Bun 版本号 -- [x] 验证测试工具可用 - - `bun test --help 2>&1 | head -3` - - 确认输出包含 test 相关帮助信息 - -**检查步骤:** -- [x] 构建命令执行成功 - - `bun run build 2>&1 | tail -5` - - 预期: 构建成功,输出包含 dist/cli.js -- [x] 现有测试通过 - - `bun test packages/builtin-tools/src/tools/AgentTool/__tests__/ 2>&1 | tail -10` - - 预期: 所有现有测试通过,无失败 - ---- - -### Task 1: 核心路由重构 - -**背景:** -[业务语境] — 当前 `FORK_SUBAGENT` flag 启用时,所有省略 `subagent_type` 的 agent 调用隐式走 fork 路径,导致探索任务被迫使用父级同等级模型,token 消耗大增。本次重构将 fork 从隐式行为改为显式 `fork: true` 参数触发。 -[修改原因] — `AgentTool.tsx` 中路由逻辑(`effectiveType` / `isForkPath`)通过 `subagent_type` 是否省略来判断 fork 路径,需改为通过 `fork` 布尔参数显式触发。同时 `forceAsync` 变量绑定在 `isForkSubagentEnabled()` 上,导致 fork flag 开启时所有 agent 强制异步,需解耦。 -[上下游影响] — 本 Task 的输出(`fork` 参数、新路由逻辑)被 Task 2(prompt 文本调整)依赖。本 Task 无前置依赖。 - -**涉及文件:** -- 修改: `packages/builtin-tools/src/tools/AgentTool/AgentTool.tsx` -- 修改: `scripts/defines.ts` - -**执行步骤:** -- [x] 在 baseInputSchema 中新增 `fork` 字段 - - 位置: `packages/builtin-tools/src/tools/AgentTool/AgentTool.tsx:baseInputSchema()` (~L136-152),在 `run_in_background` 字段之后 - - 在 `run_in_background` 字段的闭合 `),` 之后,闭合 `})` 之前,新增: - ```ts - 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.', - ), - ``` - - 原因: fork 参数需要在基础 schema 中声明,与 `subagent_type`、`run_in_background` 同级,因为它是所有 agent 调用的可选参数,不限于 multi-agent 场景。 - -- [x] 重构 inputSchema memo 的裁剪逻辑 - - 位置: `packages/builtin-tools/src/tools/AgentTool/AgentTool.tsx:inputSchema()` (~L193-204) - - 将 L194-203 替换为: - ```ts - let schema = feature('KAIROS') ? fullInputSchema() : fullInputSchema().omit({ cwd: true }); - if (isBackgroundTasksDisabled) { - schema = schema.omit({ run_in_background: true }); - } - if (!isForkSubagentEnabled()) { - schema = schema.omit({ fork: true }); - } - return schema; - ``` - - 同时删除 L196-202 的 GrowthBook 注释块(该注释描述的是旧 `forceAsync` 行为,已不适用)。 - - 原因: fork 字段仅在 `FORK_SUBAGENT` flag 启用时可见;`run_in_background` 不再受 `isForkSubagentEnabled()` 影响,两者独立裁剪。 - -- [x] 更新 AgentToolInput 类型声明 - - 位置: `packages/builtin-tools/src/tools/AgentTool/AgentTool.tsx` (~L211-217),`AgentToolInput` type 定义 - - 在 `z.infer> & {` 的下一行(`name?: string;` 之前),新增 `fork?: boolean;` - - 原因: 类型声明必须包含 `fork` 字段,确保 `call()` 解构时有正确的类型推断。 - -- [x] 更新 inputSchema 附近的 fork gate 注释 - - 位置: `packages/builtin-tools/src/tools/AgentTool/AgentTool.tsx` (~L207-210),`AgentToolInput` 上方的注释 - - 将 L209-210 的注释: - ```ts - // subagent_type is optional; call() defaults it to general-purpose when the - // fork gate is off, or routes to the fork path when the gate is on. - ``` - - 替换为: - ```ts - // subagent_type is optional; call() defaults it to general-purpose. - // fork is gated by FORK_SUBAGENT flag; when omitted or flag is off, no fork. - ``` - - 原因: 旧行为描述与新的显式 fork 触发逻辑不一致,需要更新。 - -- [x] 在 call() 解构中新增 `fork` 参数 - - 位置: `packages/builtin-tools/src/tools/AgentTool/AgentTool.tsx:call()` (~L322-333),参数解构 - - 在 `subagent_type,` 之后(L324),新增 `fork,` - - 原因: `call()` 需要从输入中提取 `fork` 值用于路由判断。 - -- [x] 重构路由逻辑为显式 fork 触发 - - 位置: `packages/builtin-tools/src/tools/AgentTool/AgentTool.tsx:call()` (~L409-414) - - 将 L409-414 替换为: - ```ts - // Fork routing: explicit `fork: true` parameter triggers the fork path - // (inherits parent context and model). Requires FORK_SUBAGENT flag. - // subagent_type is ignored when fork takes effect. - const isForkPath = fork === true && isForkSubagentEnabled(); - const effectiveType = subagent_type ?? GENERAL_PURPOSE_AGENT.agentType; - ``` - - 原因: 将隐式路由(省略 `subagent_type` 触发 fork)改为显式参数触发(`fork: true`),同时保持 `subagent_type` 省略时走 general-purpose 的原有行为。 - -- [x] 删除 forceAsync 变量及其注释 - - 位置: `packages/builtin-tools/src/tools/AgentTool/AgentTool.tsx:call()` (~L695-697) - - 删除 L695-697(注释 + `const forceAsync = isForkSubagentEnabled();`) - - 原因: `forceAsync` 不再绑定 `isForkSubagentEnabled()`,fork agent 的异步行为由 `run_in_background` 参数控制,与普通 agent 一致。 - -- [x] 从 shouldRunAsync 中移除 forceAsync 条件 - - 位置: `packages/builtin-tools/src/tools/AgentTool/AgentTool.tsx:call()` (~L708-715) - - 将 L708-715 的 `shouldRunAsync` 计算中的 `forceAsync ||` 移除: - ```ts - const shouldRunAsync = - (run_in_background === true || - selectedAgent.background === true || - isCoordinator || - assistantForceAsync || - (proactiveModule?.isProactiveActive() ?? false)) && - !isBackgroundTasksDisabled; - ``` - - 原因: `forceAsync` 变量已删除,fork agent 不再全局强制异步。 - -- [x] 更新 enableSummarization 使用 isForkPath 替代 isForkSubagentEnabled() - - 位置: `packages/builtin-tools/src/tools/AgentTool/AgentTool.tsx:call()` (~L892) - - 将: - ```ts - enableSummarization: isCoordinator || isForkSubagentEnabled() || getSdkAgentProgressSummariesEnabled(), - ``` - - 替换为: - ```ts - enableSummarization: isCoordinator || isForkPath || getSdkAgentProgressSummariesEnabled(), - ``` - - 原因: `enableSummarization` 应仅在当前调用实际走 fork 路径时启用,而非 flag 全局启用。`isForkPath` 是当前调用的运行时判断结果。 - -- [x] 更新 defines.ts 中 FORK_SUBAGENT 的注释 - - 位置: `scripts/defines.ts` (~L55) - - 将: - ```ts - // 'FORK_SUBAGENT', // 已禁用:启用后 prompt 引导模型用 fork(继承父模型)替代 Explore(haiku),导致探索任务使用同等级模型 - ``` - - 替换为: - ```ts - // 'FORK_SUBAGENT', // 已禁用:显式 `fork: true` 参数触发 fork 路径(继承父级上下文和模型),不影响 forceAsync 和探索任务模型选择 - ``` - - 原因: 旧注释描述的是隐式 fork 行为的问题,新注释描述的是当前显式参数触发的设计。 - -- [x] 为路由逻辑重构编写单元测试 - - 测试文件: `packages/builtin-tools/src/tools/AgentTool/__tests__/agentToolUtils.test.ts` - - 测试场景(通过导出路由判断辅助函数或验证 inputSchema 裁剪行为): - - `isForkSubagentEnabled() 返回 false 时`: `inputSchema()` 不包含 `fork` 字段(通过 `.omit({ fork: true })` 裁剪) - - `isBackgroundTasksDisabled 为 true 时`: `inputSchema()` 不包含 `run_in_background` 字段,但仍包含 `fork` 字段 - - 两个条件同时满足时: `inputSchema()` 同时 omit `run_in_background` 和 `fork` - - 运行命令: `bun test packages/builtin-tools/src/tools/AgentTool/__tests__/agentToolUtils.test.ts` - - 预期: 所有测试通过 - -**检查步骤:** -- [x] 验证 `fork` 字段已添加到 baseInputSchema - - `grep -n 'fork:' packages/builtin-tools/src/tools/AgentTool/AgentTool.tsx | head -5` - - 预期: 输出至少包含 1 行 schema 定义中的 `fork:` 和 1 行类型中的 `fork?:` - -- [x] 验证 forceAsync 已完全移除 - - `grep -n 'forceAsync' packages/builtin-tools/src/tools/AgentTool/AgentTool.tsx` - - 预期: 无输出(grep 返回非零退出码) - -- [x] 验证 isForkSubagentEnabled() 在 call() 中仅用于路由判断 - - `grep -n 'isForkSubagentEnabled' packages/builtin-tools/src/tools/AgentTool/AgentTool.tsx` - - 预期: 仅出现在 `inputSchema()` 的 `!isForkSubagentEnabled()` 裁剪条件和路由的 `fork === true && isForkSubagentEnabled()` 中,不出现在 shouldRunAsync 或 enableSummarization 中 - -- [x] 验证 defines.ts 注释已更新 - - `grep 'FORK_SUBAGENT' scripts/defines.ts` - - 预期: 输出行包含 "显式 `fork: true` 参数触发" - -- [x] 运行 precheck 确认无类型/lint/测试错误 - - `bun run precheck` - - 预期: 零错误通过 - ---- - -### Task 2: Prompt 文本调整 - -**背景:** -[业务语境] — Task 1 将 fork 从隐式行为(省略 `subagent_type` 触发)改为显式参数(`fork: true`),prompt.ts 中的引导文本必须同步更新,否则模型仍会尝试用旧方式触发 fork。 -[修改原因] — 当前 prompt.ts 引导模型"省略 `subagent_type` 以触发 fork"(~L85 `omit \`subagent_type\``),且 forkExamples 中省略了 `subagent_type`(隐式触发)。这些文本与 Task 1 的新路由逻辑矛盾。此外,背景任务说明的显示条件 `!forkEnabled` 不再正确——Task 1 已解耦 forceAsync,fork agent 不再强制异步,背景任务说明应在 fork 启用时也显示。 -[上下游影响] — 本 Task 依赖 Task 1 完成(Task 1 重构了路由逻辑,本 Task 更新对应的 prompt 文本)。本 Task 仅修改 prompt 文本,不影响运行时逻辑。 - -**涉及文件:** -- 修改: `packages/builtin-tools/src/tools/AgentTool/prompt.ts` - -**执行步骤:** - -- [x] 替换 `whenToForkSection` 中的 fork 触发说明 - - 位置: `packages/builtin-tools/src/tools/AgentTool/prompt.ts` `getPrompt()` 函数内 `whenToForkSection` 模板字面量(~L80-97) - - 将 `## When to fork` 标题下的第一段文本(从 "Fork yourself (omit..." 到 "...Do research before jumping to implementation.")替换为: - ``` - 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). - ``` - - "Don't peek."、"Don't race."、"Writing a fork prompt." 段落保持不变 - - 原因: 移除"省略 subagent_type"的引导,改为说明 `fork: true` 的适用场景 - -- [x] 更新 `writingThePromptSection` 中的术语 - - 位置: `packages/builtin-tools/src/tools/AgentTool/prompt.ts` `getPrompt()` 函数内 `writingThePromptSection` 模板字面量(~L99-113) - - 将 ~L103 的条件文本从 `'When spawning a fresh agent (with a `subagent_type`), it starts with zero context. '` 替换为 `'When spawning an agent without `fork: true`, it starts with zero context. '` - - 将 ~L110 的条件文本从 `'For fresh agents, terse'` 替换为 `'For non-fork agents, terse'` - - 原因: fork 通过 `fork: true` 显式触发,"fresh agent"与"fork"的对立不再准确,改为"non-fork agents" - -- [x] 替换 `shared` section 中的 fork 使用说明 - - 位置: `packages/builtin-tools/src/tools/AgentTool/prompt.ts` `getPrompt()` 函数内 `shared` 模板字面量(~L208-212) - - 将整个条件分支(`forkEnabled ? ... : ...`)替换为统一文本: - ``` - When using the ${AGENT_TOOL_NAME} tool, specify a subagent_type parameter to select which agent type to use. If omitted, the general-purpose agent is used.${forkEnabled ? ` Set \`fork: true\` to fork from the parent conversation context, inheriting full history and model.` : ''} - ``` - - 原因: 省略 `subagent_type` 现在总是走 general-purpose,统一两分支为基础文本 + fork 追加说明 - -- [x] 移除背景任务说明的 `!forkEnabled` 条件 - - 位置: `packages/builtin-tools/src/tools/AgentTool/prompt.ts` `getPrompt()` 函数内背景任务说明的条件判断(~L259-261) - - 将条件从 `!isEnvTruthy(process.env.CLAUDE_CODE_DISABLE_BACKGROUND_TASKS) && !isInProcessTeammate() && !forkEnabled` 改为 `!isEnvTruthy(process.env.CLAUDE_CODE_DISABLE_BACKGROUND_TASKS) && !isInProcessTeammate()` - - 原因: Task 1 已解耦 forceAsync,fork agent 不再强制异步,背景任务说明应在 fork 启用时也显示 - -- [x] 更新 continue agent note 中的术语 - - 位置: `packages/builtin-tools/src/tools/AgentTool/prompt.ts` `getPrompt()` 函数内 continue agent 说明(~L267) - - 将条件文本从 `'Each fresh Agent invocation with a subagent_type starts without context — provide a complete task description.'` 替换为 `'Each non-fork Agent invocation starts without context — provide a complete task description.'` - - 原因: 与 writingThePromptSection 保持术语一致 - -- [x] 更新 `forkExamples` 中第一个示例调用,添加 `fork: true` 参数 - - 位置: `packages/builtin-tools/src/tools/AgentTool/prompt.ts` `getPrompt()` 函数内 `forkExamples` 模板字面量(~L120-124) - - 在 `Agent({...})` 调用中 `description:` 行之后添加 `fork: true,` 行 - - 第二个示例(~L133-139)是"mid-wait"场景无工具调用,保持不变;第三个示例(~L141-154)有 `subagent_type: "code-reviewer"` 是 fresh agent 场景,保持不变 - - 原因: 第一个示例展示 fork 用法,需要显式传入 `fork: true` - -- [x] 为 prompt.ts 的 fork 相关文本变更编写单元测试 - - 测试文件: `packages/builtin-tools/src/tools/AgentTool/__tests__/prompt.test.ts` - - 测试场景: - - `forkEnabled = true` 时: prompt 不包含 "omit `subagent_type`" 文本,包含 "`fork: true`" 文本 - - `forkEnabled = true` 时: prompt 包含 "non-fork" 术语(替代 "fresh agent") - - `forkEnabled = true` 时: prompt 包含 "Set `fork: true` to fork from the parent" 说明 - - `forkEnabled = true` 时: prompt 包含背景任务说明(`run_in_background`) - - `forkEnabled = false` 时: prompt 不包含 "`fork: true`" 文本,不包含 "When to fork" section - - `forkEnabled = false` 时: prompt 包含 "general-purpose agent" 回退说明 - - Mock 列表: `isForkSubagentEnabled`(返回 true/false)、`getFeatureValue_CACHED_MAY_BE_STALE`(返回 false)、`shouldInjectAgentListInMessages`(返回 false)、`isInProcessTeammate`(返回 false)、`isTeammate`(返回 false)、`getSubscriptionType`(返回 'pro')、`hasEmbeddedSearchTools`(返回 false)、环境变量 `CLAUDE_CODE_DISABLE_BACKGROUND_TASKS` 未定义 - - 运行命令: `bun test packages/builtin-tools/src/tools/AgentTool/__tests__/prompt.test.ts` - - 预期: 所有测试通过 - -**检查步骤:** -- [x] 验证 prompt 中不再包含 "omit `subagent_type`" 引导文本 - - `grep -n "omit" packages/builtin-tools/src/tools/AgentTool/prompt.ts` - - 预期: 无输出 - -- [x] 验证 prompt 中包含 "`fork: true`" 文本 - - `grep -c "fork: true" packages/builtin-tools/src/tools/AgentTool/prompt.ts` - - 预期: 输出 >= 3(shared section + whenToForkSection + forkExamples) - -- [x] 验证背景任务条件中不再包含 `!forkEnabled` - - `grep -n "forkEnabled" packages/builtin-tools/src/tools/AgentTool/prompt.ts` - - 预期: 所有匹配行均为 `forkEnabled ?` 形式的三元表达式条件,不包含 `!forkEnabled` - -- [x] 运行 prompt 单元测试 - - `bun test packages/builtin-tools/src/tools/AgentTool/__tests__/prompt.test.ts` - - 预期: 所有测试通过 - -- [x] 运行 precheck 确保无回归 - - `bun run precheck` - - 预期: 零错误通过(typecheck + lint + test) - ---- - -### Task 3: Fork Agent 显式参数触发 验收 - -**前置条件:** -- 启动命令: `bun run dev`(开发模式) -- 环境变量: `FEATURE_FORK_SUBAGENT=1` 启用 fork 功能 - -**端到端验证:** - -1. 运行完整测试套件确保无回归 - - `bun run precheck` - - 预期: typecheck + lint + test 全部通过,零错误 - - 失败排查: 检查 Task 1(AgentTool.tsx 路由逻辑)和 Task 2(prompt.ts 文本)的修改 - -2. 验证 `fork: true` + flag 启用时走 fork 路径 - - `grep -n 'isForkPath = fork === true' packages/builtin-tools/src/tools/AgentTool/AgentTool.tsx` - - 预期: 找到路由逻辑行,确认 `fork === true && isForkSubagentEnabled()` 条件 - - 失败排查: 检查 Task 1 路由逻辑步骤 - -3. 验证 `fork` 参数在 flag 关闭时不在 schema 中 - - `grep -n 'omit.*fork' packages/builtin-tools/src/tools/AgentTool/AgentTool.tsx` - - 预期: 找到 `schema.omit({ fork: true })` 行 - - 失败排查: 检查 Task 1 inputSchema 裁剪逻辑 - -4. 验证 `forceAsync` 已完全移除,不再绑定 `isForkSubagentEnabled()` - - `grep -c 'forceAsync' packages/builtin-tools/src/tools/AgentTool/AgentTool.tsx` - - 预期: 0(无匹配) - - 失败排查: 检查 Task 1 forceAsync 删除步骤 - -5. 验证 prompt 中不再引导"省略 subagent_type 触发 fork" - - `grep -c 'omit.*subagent_type' packages/builtin-tools/src/tools/AgentTool/prompt.ts` - - 预期: 0(无匹配) - - `grep -c 'fork: true' packages/builtin-tools/src/tools/AgentTool/prompt.ts` - - 预期: >= 3(shared section + whenToForkSection + forkExamples) - - 失败排查: 检查 Task 2 prompt 文本替换步骤 - -6. 验证后台/同步行为由 `run_in_background` 参数控制 - - `grep -n 'run_in_background' packages/builtin-tools/src/tools/AgentTool/AgentTool.tsx | head -5` - - 预期: `shouldRunAsync` 计算中包含 `run_in_background === true` 条件,无 `forceAsync` 条件 - - 失败排查: 检查 Task 1 shouldRunAsync 修改步骤