跳转到主要内容
当一条防火墙规则返回 pending_approval 判定时,该智能体的工具调用被挂起 而非派发——它现在在等待一名人工。本页面向审查者:如何从控制台批准智能体 工具调用挂起(或拒绝它们)、队列向你展示什么,以及 OrcaRouter 如何防止 两名审查者在同一个决策上相撞。 这是人工介入的解决那一半。关于一个调用为什么被挂起以及被挂起的智能体 之后如何重新提交,参见 判定 以及更深入的 审批参考。要从你自己的系统而非控制台解决, 参见 审批 webhook

1. 从审查者视角看被挂起调用的生命周期

一个被挂起的调用是一个简短的带外循环。你的工作是中间那一步:
1

该调用被挂起

一条规则解析为 pending_approval。中继返回 HTTP 400,带码 firewall_approval_pending 和一个审批 id;该调用从不到达工具。智能体 开始在那个 id 上轮询。
2

你解决它

你打开 Approvals 队列、读懂该调用为什么被挂起,并批准拒绝 它——本页的焦点。
3

智能体继续(或停止)

在批准时,智能体携带一个一次性 X-OrcaRouter-Firewall-Approval 头重新 提交原始调用,网关放它通过那一次。在拒绝时,该调用保持被拦截。
解决一个挂起被门控到 Developer+——与防火墙 Events 信息流相同的门。更低 角色可以读取防火墙策略、设置和 discovered tools,但只有 Developer 及以上 角色才能列出审批队列或批准/拒绝一个被挂起的工具调用。参见 角色与范围

2. 列出挂起队列

Approvals 标签读取 GET /api/workspace/firewall/approvals。无过滤时它返回 pending 队列,最旧优先——所以等待最久的调用位于顶部,你按顺序处理 积压。
GET /api/workspace/firewall/approvals?state=pending
state 是那个重要的过滤器。这些值映射到审批的生命周期:
state返回的审批
pending (默认)已挂起,等待一个决策——你的工作队列。
approved已放行。
rejected已拦截。
这是你会话上的一条控制台路由——从仪表盘配置和审查它,而非用一个 sk-orca-… 中继密钥。中继密钥用于 /v1/* 模型调用;防火墙管理在你的控制台 登录下运行。

3. 读懂该调用为什么被挂起

每一行携带审查者需要的决策输入——工具名tool_name)、一个参数 指纹args_hash,规范化调用参数的 SHA-256——原始参数值不存储在审批中)、 请求 id,以及一行点名触发的策略、规则和子句的朴素英文来源行:
匹配规则所属的命名策略,工作区限定地解析,这样一个陈旧的 id 永远无法 浮现另一个租户的策略名。
规则的标签和一行”为什么”描述符——例如 command contains rm -rf,或对 一条仅 glob 规则的 tool matches "http_fetch"。这渲染队列中的 “Held because…” 行。
当匹配规则在这个审批创建之时或之后被编辑时为 true。此时实时标签和 子句被抑制(它们可能不再反映实际挂起该调用的东西),而队列显示一个 “rule since changed” 提示而非陈旧的来源。工具名和参数——真正的决策输入 ——总是被显示。
rule_changed 是一个有意的诚实信号,而非一个错误。如果有人在一个调用坐在 队列里时编辑了防火墙规则,OrcaRouter 宁愿隐藏一个可能错误的原因,也不向你 显示一个不再匹配的来源。那种情况下,根据工具名和策略名(仍被显示) 决定。

4. 批准或拒绝

解决发送 PATCH /api/workspace/firewall/approvals/:id,带一个 approvedrejecteddecision 和一个可选的 reason。当你点击按钮时控制台为你 做这件事;其形态是:
PATCH /api/workspace/firewall/approvals/507f1f77bcf86cd799439011
Content-Type: application/json

{ "decision": "approved", "reason": "verified target host with the on-call" }
  • approved → 被挂起的调用可以继续。智能体携带一次性审批头的下一次 重新提交被放行一次。
  • rejected → 该调用保持被拦截。智能体看到这次拒绝,能另选一条路径、 询问用户,或停止。
decision 对照封闭的 {approved, rejected} 集合验证——其他任何东西都被 拒绝。reason 与该决策一起被记录,并连同行动者、工具名和请求 id 一起写入 防火墙审计日志。
每一次解决都写入一个工作区审计行,点名谁决定、决策以及原因。控制台 解决记录人类行动者;webhook 解决 记录一个系统行动者。解决来源绝不会被静默丢弃。

5. 首个写入者生效:没有双重解决

一个挂起审批可能被竞争——控制台里两名审查者,或一次控制台点击和一个 webhook 回调 一起到达。OrcaRouter 用一条单一的首个写入者生效规则解决它:
  • 该决策是一个原子的条件更新,只在该审批仍是 pending 时触发。第一个 写入者胜出并应用该决策。
  • 每个更晚的写入者观察到”已解决”,并被当作一个幂等空操作——它得到 HTTP 200,带已解决的文档,而非一个错误。
响应告诉你你在哪一侧:
{
  "resolved": false,
  "already_resolved": true,
  "approval": { "state": "approved", "decision": "approved", "...": "..." }
}
resolved: true 意味着你的调用应用了该决策;already_resolved: true 意味着某人(或某个 webhook)先到了那里,而你看到的是他们的结果。无论哪种 方式,队列都对账到一个一致的状态。
因为解决是幂等的,一个不稳定的网络或一次双击无法破坏一个挂起或翻转一个 决策。第一个 approve/reject 是唯一算数的那个;它之后的一切只是回读 结果。

6. 一次具体地处理队列

一个 balanced-autonomy 工作区挂起了一个智能体的 shell.exec 调用,因为一条 规则匹配了 command contains rm -rf。作为审查者,你:
  1. 打开 Approvals——被挂起的 shell.exec 位于最旧优先的 pending 列表 顶部。
  2. 读取该行:工具 shell.execargs_hash 指纹、请求 id,以及 “Held because… command contains rm -rf” 行(从匹配规则的子句渲染)。 没有 rule_changed 标志,所以来源是最新的。
  3. 目标是一个临时目录,所以你带一个原因批准
  4. 你的 PATCH 返回 resolved: true;智能体的下一次轮询看到 approved、 携带它的一次性头重新提交,而该命令恰好运行一次。
要是一名队友早一秒批准了它,你的点击会返回带他们决策的 already_resolved: true——无害,无双重运行。

接下来去哪里

审批参考

完整的 HITL 循环:挂起、轮询、重新提交以及一次性头。

审批 webhook

用一个 HMAC 签名的回调从你自己的系统解决挂起。

判定

pending_approval 在六个防火墙判定中的位置。

事件日志

在信息流中确认一个已解决调用的下游结果。
关于这些挂起意在捕获的风险,参见 危险工具调用过度代理