跳转到主要内容
文档运行人工审批

人工审批

在任意步骤加 manual_approval 门控:App 内、邮件、API 三条通道批复,数值可编辑,超时自动拒绝。

manual_approval 把"等某个人确认再继续"编码成步骤修饰符:执行到达配置了它的步骤时暂停,批准后才运行步骤本体。批准之前,系统不会执行该步骤及其下游的任何动作。

配置

yaml
  - 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 步骤,作为纯粹的"人工闸门"。

参数

字段类型默认说明
enabledboolean是否启用审批门控(必填)
approversstring[][]指定审批人(平台用户 ID)。非空时只有名单内的用户和管理员能批复——执行发起人也不行,天然满足职责分离;留空时执行发起人或对该工作流有执行权限的协作者都可批复
timeoutlong3600超时秒数。到点无人批复则自动拒绝,状态标 TIMED_OUT
approval_messagestringnull展示给审批人的说明,出现在审批卡片和通知邮件里
reviewable_actionsarray[]可编辑审批表分组,审批人可勾选子集、编辑数值后再批准(见下文)

审批流程

  1. 执行到达配置了 manual_approval 的步骤时暂停,执行状态变为 AWAITING_APPROVAL
  2. 创建审批记录并开始超时计时;控制台通过 WebSocket 收到 approval_request 实时提醒,审批人可同时收到通知邮件
  3. 审批人从三条通道之一批复:App 内审批列表、消息里的一键链接、API
  4. 批准 → 步骤继续;拒绝 → 步骤按失败处理(可用 on_failure 接通知分支);超时 → 自动拒绝

通道一:App 内审批列表

控制台的审批管理页面列出你可见的全部审批,支持卡片/表格两种视图和状态筛选。批准或拒绝时可附备注,备注会保存在审批记录里。配置了 reviewable_actions 的审批会展开为可勾选、可编辑的表格。

通道二:邮件通知与一键链接

开启邮件通知后,审批人(未指定 approvers 时为执行发起人)账号邮箱会收到邮件,内容包括:工作流与步骤名、执行 ID、可审核动作数量、超时提示("约 N 小时后自动拒绝")、approval_message 的说明文字,以及进入审批列表的链接。

邮件、Slack、Telegram 这类无法自定义请求头的消息里,还可以嵌入一键批复链接:

text
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
bash
# 批准(可附备注)
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 的列(例如改出价),然后再点批准。

yaml
    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;每次审批决定(含决策人、时间、备注)都会写入审计日志
服务重启时

审批记录持久化存储。服务重启后,待处理的审批原样恢复,超时计时按原始截止时间继续,审批人照常批复即可。

相关页面