| 1 | # 自动工作流 |
| 2 | |
| 3 | > 英文原文:[AUTOMATIC_WORKFLOWS.md](../AUTOMATIC_WORKFLOWS.md)。 |
| 4 | > 最后与英文同步日期(last synced with English revision):2026-09-29。 |
| 5 | |
| 6 | 要协调多个智能体(agent),你**不需要**自己写 `.workflow.js` 文件。小而紧耦合的工作 |
| 7 | 由 Operate 直接处理。多步委派从一份紧凑的工作流(workflow)计划开始:具名步骤、 |
| 8 | 依赖关系、有界范围,以及完成检查。工作流运行的就是 Fleet 所配置和管理的那批子智能体 |
| 9 | (sub-agent),并在相互依赖的步骤之间传递结果与证据。一个独立且边界清晰的任务 |
| 10 | 可以直接用一个后台智能体;后续工作应当用 `followup` 复用那个智能体。Act/Agent |
| 11 | 仍然可以使用下面描述的可选软自动策略。 |
| 12 | |
| 13 | 相关文档: |
| 14 | |
| 15 | - [工作流编写](WORKFLOW_AUTHORING.md) — 签入的脚本与 IR |
| 16 | - [Fleet + Workflow 教程](FLEET_WORKFLOW_TUTORIAL.md) — 手动的 Fleet 路径 |
| 17 | - [配置](CONFIGURATION.md) — `[workflow]` 开关 |
| 18 | - [沙箱](SANDBOX.md) — 工作流 VM 做不到的事情 |
| 19 | |
| 20 | ## Act/Agent 中的软自动 |
| 21 | |
| 22 | 1. **你用自然语言提要求**——“审计每个 crate 里的 unsafe”,“先侦察再实现”, |
| 23 | “并行比较这两个提供商(provider)”。 |
| 24 | 2. **由 Codewhale 在 Act/Agent 中判断**——范围大、相互独立或分阶段的工作可以触发 |
| 25 | 工作流;单文件编辑、简单命令和纯问答不会触发。 |
| 26 | 3. **它会先告诉你**——例如“这看起来适合用工作流——三个侦察智能体,再一个验证者。” |
| 27 | 4. **可选的前置确认**——如果有一两个事实会改变计划(只读还是写入、范围、子项数量), |
| 28 | 它会打开 **`request_user_input`** 模态框(结构化单选/多选,而不是冗长的自由问答)。 |
| 29 | 5. **启动**——结构化的 `plan` JSON(goal / phases / children),或一段简短的内联脚本。 |
| 30 | 并行分支使用 `parallel()` 的部分成功语义。 |
| 31 | |
| 32 | 在 Operate 里,同样的诉求只要需要多个委派步骤,就会改用一份紧凑的工作流计划。 |
| 33 | 这份计划把并行工作、依赖交接,以及完成所需的证据一起摆到明面上。小而紧耦合的工作 |
| 34 | 可以留在父级,按当前生效的工具(tool)与审批(approval)策略执行;一个独立且边界清晰的任务 |
| 35 | 可以直接用一个智能体。任务没变时,用 `followup` 继续已有的智能体。你随时可以输入 |
| 36 | `/workflow` 显式请求编排。 |
| 37 | |
| 38 | ## 只读自动启动与写入审批 |
| 39 | |
| 40 | `[workflow]` 配置(见 `config.example.toml`): |
| 41 | |
| 42 | | 开关 | 默认值 | 含义 | |
| 43 | |------|---------|---------| |
| 44 | | `automatic` | `true` | 软自动编排已启用 | |
| 45 | | `auto_start_read_only` | `true` | 只读计划可以不带写入审批卡片直接启动 | |
| 46 | | `require_approval_for_writes` | `true` | 写入/提权启动前必须经过的计划审批卡片 | |
| 47 | | `max_children` / `max_concurrent` / `max_depth` | `1000` / `16` / `5` | 任务数量、并发子项数量,以及计划结构(IR 形状,而不是派生深度)的上限。运行时(runtime)的子级委派预算(默认 3,硬上限 8)是一个名字相近但彼此独立的量;见 `docs/SUBAGENTS.md`。 | |
| 48 | | `default_token_budget` | `0` | 一次运行及其子项共享的准入上限;`0` = 不设上限——把它设上,或在调用时传 `token_budget`,以限制开销 | |
| 49 | |
| 50 | 提权(elevated)工作(写入、只读之外的 shell、网络、机密、worktree、高预算) |
| 51 | 在启动之前会给出审批卡片,上面写着目标、子项摘要、能力标志和预算(#4126)—— |
| 52 | 前提是 `require_approval_for_writes` 处于开启状态。这个标志只管这张卡片。 |
| 53 | 会话(session)级自动批准(YOLO / Full Access(完全访问)/ `bypass`)仍会跳过它, |
| 54 | 和其他普通的 `Required` 工具一样。运行中的 VM `task()` 步骤内部的写入属于 |
| 55 | VM 运行时契约(沙箱、`writeAuthority`、父级工具策略)——这个标志不会为每次 |
| 56 | 子项写入重新询问。 |
| 57 | |
| 58 | worktree 隔离与写入归属是两回事。具备写入能力的 `task()` |
| 59 | (`type: "implementer"`,或 `writeAuthority: "workspace_write"` / |
| 60 | `"worktree_write"`)可以声明仓库相对路径的 `writeRoots`、`exactFiles` 或 |
| 61 | `coordinationContracts`;什么都不声明时,派生边界会认领它的 `deliverables`, |
| 62 | 否则就认领工作区根目录(`.`),与普通的 Agent 派生完全一致。协调账本会拒绝 |
| 63 | 第二个存活写入者与之重叠的认领,所以当脚本在同一个检出目录里扇出并行写入者时, |
| 64 | 应当给每个写入者不相交的 `writeRoots` 或 `exactFiles`。只读角色不能声明写入权限。 |
| 65 | `worktree: true` 只是选择隔离,不会悄悄授予改动权限。纯提示词(prompt)的普通任务 |
| 66 | 是只读的。`dependencies` 和 `acceptance` 承载有界的、子项专属的前置条件与 |
| 67 | 可观察的完成检查;它们不是父级转录(transcript)的副本。 |
| 68 | |
| 69 | 当一个工作流从包含多个仓库的工作区运行时,需要 shell 或文件访问的子项必须把 `cwd` |
| 70 | 设成它应当使用的、相对仓库的目录。宿主(host)在派发之前会校验该目录确实存在于 |
| 71 | 父工作区内。隔离写入请用 `worktree: true`;`cwd` 只是选中一个已有的检出, |
| 72 | 本身不授予写入权限,也不提供隔离。 |
| 73 | |
| 74 | ## 控制一次运行 |
| 75 | |
| 76 | `/workflow status [run_id]`、`/workflow cancel [run_id]` 和 |
| 77 | `/workflow settings` 由 Codewhale 自己根据运行日志和实时运行状态作答—— |
| 78 | 它们绝不消耗模型回合(turn),所以查状态是免费的,取消操作甚至在模型正忙时也能落地。 |
| 79 | 不带 id 的 `/workflow cancel` 会停掉当前唯一在跑的工作流。 |
| 80 | |
| 81 | 开始工作走的是“先复审”的路子。`/workflow <objective>` 和裸 `/workflow` |
| 82 | 会让模型给出一份有界、不调用工具的提案;`/workflow run |
| 83 | <path/to/x.workflow.js>` 则为那份确切的签入源码准备一次复审。这两种形式都不执行 |
| 84 | 任何东西。复审完提案之后,运行 `/workflow confirm` 启动最近一次复审过的草稿。 |
| 85 | 上文 `[workflow]` 表里的设置,在每次启动决策时(自动启动、写入审批卡片、子项上限) |
| 86 | 都从你的 `config.toml` 读取;`/workflow settings` 会打印当前生效的值以及每一项的 |
| 87 | 作用。重新加载 `config.toml` 会刷新该表,对设置和工作流工具同时生效。 |
| 88 | |
| 89 | `/workflows` 打开运行面板:本工作区的日志为这个会话保留的每一次运行—— |
| 90 | 正在跑的和已完成的——最新的排在最前。每一行显示状态标记、运行标签、已用时间、 |
| 91 | 子项数量和最新进度;`Enter` 打开详情面板(运行 id、阶段、带每子项状态的子项名册、 |
| 92 | 近期进度,以及错误/结果摘要)。`x` 通过与 `/workflow cancel` 相同的宿主路径 |
| 93 | 取消选中的运行,`r` 重新读取日志,`Esc` 关闭。这个面板从不启动任何东西—— |
| 94 | 编排权力仍然留在 `/workflow` 手里。 |
| 95 | |
| 96 | ## 运行期间你能看到什么 |
| 97 | |
| 98 | - **工作流面板**——阶段、子项、状态、预算 |
| 99 | - **紧凑历史卡片**——一行平静的记录,展开看细节 |
| 100 | - **每个委派单元一个工件(artifact)**——不重复出现“委派卡片 + 工具卡片” |
| 101 | - **带类型的子项身份**——标签/角色;默认界面里不会出现“未知子项” |
| 102 | |
| 103 | 取消会停掉该次运行和它的子智能体。已完成的活动可以跨会话留存 |
| 104 | (配置之后也能跨重启留存)。 |
| 105 | |
| 106 | ## 沙箱(sandbox)保证 |
| 107 | |
| 108 | 工作流 JS VM **没有**文件系统、shell、网络、环境变量、import、时钟或随机数。 |
| 109 | 允许的宿主调用:`task`、`parallel`、`pipeline`、`phase`、`log`、 |
| 110 | `budget`、`args`。真正的工作发生在子智能体/Fleet 里,遵守常规的工具与审批策略。 |
| 111 | 见[沙箱](SANDBOX.md)。 |
| 112 | |
| 113 | ## 汇总与兼容性 |
| 114 | |
| 115 | - 必须返回结构化字段的子项,请优先用 `responseSchema`。 |
| 116 | - 普通的并行槽位失败会变成 `null`(部分成功);在汇总成一份面向操作者的总结之前, |
| 117 | 先把它们过滤掉。`responseSchema` 不匹配属于契约失败,会故意让整次运行失败, |
| 118 | 而不是被悄悄转成 `null`。 |
| 119 | - `null` 槽位不再匿名。`parallel()` 和 `pipeline()` 会给结果附加一个不可枚举的 |
| 120 | `errors` 数组——`[{ index, kind, message }]`,按 index 排序——这样汇总者就能说出 |
| 121 | 某个槽位*为什么*缺失。数组自身的内容和 JSON 编码保持不变。 |
| 122 | - `kind` 取值为 `admission`、`budget`、`cancelled`、`agent`、`schema`、 |
| 123 | `driver`(由故障所在的宿主赋值)或 `script`(脚本自己抛出的)。请从抛出的 |
| 124 | `Error` 的 `.kind` 读取;它从不依据消息文本推断,所以子项自己的措辞无法伪造 kind。 |
| 125 | - `opts.mode` 选择契约:`settled`(默认——今天的行为)、 |
| 126 | `fail-fast`(以第一个非致命槽位错误拒绝整个扇出), |
| 127 | 或 `partial`(把每个非取消失败都解析为 |
| 128 | `{ __taskError: { index, kind, message } }`)。无法识别的模式会抛错, |
| 129 | 而不是悄悄按 `settled` 处理。 |
| 130 | - 所有任务都失败的一次运行会被记为 **failed**,而不是部分成功, |
| 131 | 即使脚本本身返回了值。 |
| 132 | - 工作流的 token 预算管的是准入和总量核算。预算耗尽后,它会拒绝后续或 |
| 133 | 后代派生的发生,但已经在并行运行的子项可能把总用量对账到提示的上限之上, |
| 134 | 因为提供商(provider)只在响应边界报告用量。 |
| 135 | - 兼容路径仍然保留:`script`、`source_path`(签入的 |
| 136 | `.workflow.js` / `.workflow.ts`),以及结构化的 `plan`。 |
| 137 | |
| 138 | ## 什么时候不自动启动 |
| 139 | |
| 140 | 下列情况会抑制自动工作流: |
| 141 | |
| 142 | - 单文件编辑和极小的单步请求 |
| 143 | - 简单命令/事实性问题 |
| 144 | - 高度交互的设计讨论 |
| 145 | - 没有清晰分解方式的风险型写入 |
| 146 | - 会超出 `max_children` / `max_depth` 的计划(在启动前就被拒绝) |
| 147 | |
| 148 | 在这些情况下,Codewhale 改用直接调用工具,或只用一个 `agent`。 |
| 149 | |
| 150 | ## 示例场景(#4131) |
| 151 | |
| 152 | 签入的示例工作流覆盖四个自动工作流场景: |
| 153 | |
| 154 | 1. 只读仓库审计 |
| 155 | 2. 分阶段的缺陷修复,配 worktree 实现者 + 验证者 |
| 156 | 3. 部分失败与汇总 |
| 157 | 4. 运行中途取消 |
| 158 | |
| 159 | 夹具:[`docs/examples/dogfood-automatic/`](../examples/dogfood-automatic/)。 |
| 160 | 面板回归测试在 `crates/tui/src/tui/widgets/workflow_panel.rs` 中使用 |
| 161 | `dogfood_` 前缀。 |
| 162 |