人工审批
在任意步骤加 manual_approval 门控:App 内、邮件、API 三条通道批复,数值可编辑,超时自动拒绝。
manual_approval 把"等某个人确认再继续"编码成步骤修饰符:执行到达配置了它的步骤时暂停,批准后才运行步骤本体。批准之前,系统不会执行该步骤及其下游的任何动作。
配置
- step: apply_changes
agent: executor
input: "把已审核的变更应用到线上"
manual_approval:
enabled: true
approvers: # 平台用户 ID;留空 = 发起人 / 有执行权限者可批
- "usr_team_lead"
timeout: 86400 # 秒;24 小时无人批复自动拒绝
approval_message: |
请确认是否应用本轮变更。
拒绝或超时不会做任何线上修改。它可以挂在任意步骤上(agent、code、sub_workflow 等),也常用于一个只打印状态的轻量 code 步骤,作为纯粹的"人工闸门"。
参数
| 字段 | 类型 | 默认 | 说明 |
|---|---|---|---|
enabled | boolean | — | 是否启用审批门控(必填) |
approvers | string[] | [] | 指定审批人(平台用户 ID)。非空时只有名单内的用户和管理员能批复——执行发起人也不行,天然满足职责分离;留空时执行发起人或对该工作流有执行权限的协作者都可批复 |
timeout | long | 3600 | 超时秒数。到点无人批复则自动拒绝,状态标 TIMED_OUT |
approval_message | string | null | 展示给审批人的说明,出现在审批卡片和通知邮件里 |
reviewable_actions | array | [] | 可编辑审批表分组,审批人可勾选子集、编辑数值后再批准(见下文) |
审批流程
- 执行到达配置了 manual_approval 的步骤时暂停,执行状态变为 AWAITING_APPROVAL
- 创建审批记录并开始超时计时;控制台通过 WebSocket 收到 approval_request 实时提醒,审批人可同时收到通知邮件
- 审批人从三条通道之一批复:App 内审批列表、消息里的一键链接、API
- 批准 → 步骤继续;拒绝 → 步骤按失败处理(可用 on_failure 接通知分支);超时 → 自动拒绝
通道一:App 内审批列表
控制台的审批管理页面列出你可见的全部审批,支持卡片/表格两种视图和状态筛选。批准或拒绝时可附备注,备注会保存在审批记录里。配置了 reviewable_actions 的审批会展开为可勾选、可编辑的表格。
通道二:邮件通知与一键链接
开启邮件通知后,审批人(未指定 approvers 时为执行发起人)账号邮箱会收到邮件,内容包括:工作流与步骤名、执行 ID、可审核动作数量、超时提示("约 N 小时后自动拒绝")、approval_message 的说明文字,以及进入审批列表的链接。
邮件、Slack、Telegram 这类无法自定义请求头的消息里,还可以嵌入一键批复链接:
GET https://braidrun.com/api/webhook-trigger/approval/{approvalId}/approve?api_key=dyk_...
GET https://braidrun.com/api/webhook-trigger/approval/{approvalId}/reject?api_key=dyk_...链接用 API Key 鉴权(APPROVAL_RESPOND 范围),Key 放在 api_key 查询参数里。为防止链接预览机器人(Slack 展开、邮件客户端预抓取)误触,第一次打开只渲染确认页、不执行任何动作;点击确认按钮后带 confirm=1 再次请求才真正批复。页面带 no-store 与 noindex 头,避免缓存或搜索引擎重放。
通道三:API
v1 开放 API 提供 5 个审批端点,全部要求 APPROVAL_RESPOND 权限范围:
| 端点 | 作用 |
|---|---|
GET /api/v1/approvals | 审批列表,可按 status 筛选 |
GET /api/v1/approvals/{id} | 审批详情 |
GET /api/v1/approvals/execution/{executionId} | 查某次执行关联的审批 |
POST /api/v1/approvals/{id}/approve | 批准;body 可带 comment 与 editedItems |
POST /api/v1/approvals/{id}/reject | 拒绝;body 可带 comment |
# 批准(可附备注)
curl -X POST https://braidrun.com/api/v1/approvals/<approval-id>/approve \
-H "Authorization: Bearer dyk_..." \
-H "Content-Type: application/json" \
-d '{"comment": "确认执行"}'
# 拒绝
curl -X POST https://braidrun.com/api/v1/approvals/<approval-id>/reject \
-H "Authorization: Bearer dyk_..." \
-H "Content-Type: application/json" \
-d '{"comment": "本轮预算已用完"}'editedItems 按分组名提交勾选/编辑后的子集,结构与下节的可编辑审批表对应;不传则视为原样全部批准。
可编辑审批表(reviewable_actions)
有些审批的粒度落在单条建议上:一批建议里只执行其中一部分,个别行还要改数值。reviewable_actions 把这类审批做成表格——审批人勾选要执行的行,直接编辑标了 editable: true 的列(例如改出价),然后再点批准。
manual_approval:
enabled: true
timeout: 86400
approval_message: |
请审核本轮调价建议:可勾选要执行的行,并直接修改建议出价。
reviewable_actions:
- name: raise_bid
title: 加价建议
source_var: raise_bid_file # 变量值 = 建议清单 JSON 数组文件路径
output_var: raise_bid_approved_file # 批准后 = 勾选/编辑后的子集文件路径
key_field: item_id
columns:
- { key: item_name, label: 名称, editable: false }
- { key: current_bid, label: 当前出价, type: number, editable: false }
- { key: proposed_bid, label: 建议出价, type: number, editable: true }
- { key: reason, label: 理由, editable: false }name— 分组内部名,同时用作输出文件前缀(批准后引擎写出 reviewed_<name>.json)source_var— 指向一个变量,变量值是上游步骤生成的建议清单(JSON 数组文件路径)output_var— 批准后设置的变量,值为勾选/编辑后的子集文件路径;下游执行步骤改读它,就只会处理被批准的行key_field— 行身份字段,编辑后按它对齐;缺省按数组下标对齐columns— 表格列定义;editable: true 的列审批人可改,type: number 渲染为数字输入
提交的子集会在服务端校验:不属于任何分组的数据被过滤;定义了 key_field 时,每行必须能在原清单里找到对应项,拼一行不存在的数据无法绕过;editable: false 的列以原值为准,改了也无效。某个分组一行都没勾选时会写出空数组,下游步骤按"全空跳过"处理。
拒绝与超时:零改动
审批门控的核心承诺是:批准之前系统不执行任何动作。拒绝或超时时——
- 步骤本体不运行,依赖它的下游步骤也不会触发
- 可用 on_failure 分支接一个"审批被拒"的通知或归档步骤
- 超时由系统自动拒绝,决策人记为 system;每次审批决定(含决策人、时间、备注)都会写入审计日志
审批记录持久化存储。服务重启后,待处理的审批原样恢复,超时计时按原始截止时间继续,审批人照常批复即可。