跳转至

权限请求

插件权限请求允许插件代码暂停工具调用或插件自有操作,直到用户批准或拒绝。它们使用 Gateway 的 plugin.approval.* 流程,以及处理聊天审批按钮和 /approve 命令的相同审批 UI 界面。

将插件权限请求用于插件/应用权限。它们不会替代主机 exec 审批、可选工具允许列表或 Codex 的原生权限审查。

选择正确的门禁

选择与你所需决策点匹配的门禁:

门禁 何时使用 控制内容
可选工具 在用户选择加入之前,工具不应向模型可见。 通过 tools.allow 控制工具暴露。
插件权限请求 插件钩子或插件自有操作必须在某个操作运行前询问。 通过 plugin.approval.* 进行运行时审批。
Exec 审批 主机命令或类似 shell 的工具需要操作员审批。 主机 exec 策略和持久 exec 允许列表。
Codex 原生权限请求 Codex 在执行原生 shell、文件、MCP 或 app-server 操作前询问。 Codex app-server 或原生钩子审批处理;当 OpenClaw 拥有提示时,通过插件审批路由。
MCP 审批征询 Codex MCP 服务器请求对工具调用进行审批。 通过 OpenClaw 插件审批桥接的 MCP 审批响应。

可选工具是发现阶段门禁。插件权限请求是每次调用门禁。当敏感工具在模型可见之前需要显式选择加入,并在操作运行前需要审批时,请同时使用两者。

在工具调用前请求审批

大多数插件编写的提示应从 before_tool_call 钩子开始。该钩子在模型选择工具之后、OpenClaw 执行之前运行:

import { definePluginEntry } from "openclaw/plugin-sdk/plugin-entry";

export default definePluginEntry({
  id: "deploy-policy",
  name: "Deploy Policy",
  register(api) {
    api.on("before_tool_call", async (event) => {
      if (event.toolName !== "deploy_service") {
        return;
      }

      const environment =
        typeof event.params.environment === "string" ? event.params.environment : "unknown";

      return {
        requireApproval: {
          title: "Deploy service",
          description: `Deploy service to ${environment}.`,
          severity: environment === "production" ? "critical" : "warning",
          allowedDecisions:
            environment === "production"
              ? ["allow-once", "deny"]
              : ["allow-once", "allow-always", "deny"],
          timeoutMs: 120_000,
          onResolution(decision) {
            console.log(`deploy approval resolved: ${decision}`);
          },
        },
      };
    });
  },
});

为将批准该操作的人编写提示文本:

  • 保持 title 简短且以操作为中心。Gateway 将其限制为 80 个字符。
  • 保持 description 具体且有边界。Gateway 将其限制为 512 个字符。
  • 包含操作、目标和风险。不要包含不应出现在聊天审批界面中的密钥、令牌或 私有负载。
  • severity 在省略时默认为 "warning"。仅当错误决策可能导致生产环境损坏或数据丢失时,才使用 "critical"。
  • allowedDecisions 在省略时默认为 ["allow-once", "allow-always", "deny"]。当持久信任对该操作不安全时,传入 ["allow-once", "deny"]。
  • timeoutMs 默认为 120000(2 分钟),无论请求值是多少,上限均为 600000(10 分钟)。

声明审批范围

当你的插件了解某个操作的后果时,设置 requireApproval.scope。Scope 是类型化的、可选的且仅用于显示:它帮助审阅者 理解操作,但从不授予权限或更改审批决定。声明审批的插件提供这些事实。Channels 从不 从命令、标题或消息文本中推断 scope。

对于发送给三位外部收件人的电子邮件,包含目标、收件人总数、可选预览和受众:

requireApproval: {
  title: "Send customer update",
  scope: {
    kind: "message-send",
    target: "email",
    recipientCount: 3,
    recipients: ["alice@example.com", "bob@example.com"],
    audience: "external",
  },
}

对于付款,请以字符串形式提供精确的小数金额、其货币以及收款方或支付系统:

requireApproval: {
  title: "Pay invoice",
  scope: {
    kind: "payment",
    amount: "49.99",
    currency: "EUR",
    target: "Stripe",
  },
}

对于外部帖子,识别其目标并声明其可见性:

requireApproval: {
  title: "Publish announcement",
  scope: {
    kind: "external-post",
    target: "github",
    visibility: "public",
  },
}

消息受众可以是 internal 或 external。外部帖子可见性可以是 public 或 restricted。收件人预览最多包含五个身份。 所有字符串在显示前都会经过清理并设置边界:目标和收件人身份限制为 128 个字符,付款金额限制为 40,货币限制为 12。如果清理会超出边界,OpenClaw 会省略 scope,同时保留正常的审批提示。

决策行为

OpenClaw 会创建一个带有 plugin: ID 的待处理审批,将其投递到可用的审批界面,并等待决策。

决策 结果
allow-once 当前调用继续。
allow-always 当前调用继续,并且该决策会传递给插件。
deny 该调用会被阻止,并返回被拒绝的工具结果。
超时 该调用会被阻止。
取消 当运行被中止时,该调用会被阻止。
无审批路由 该调用会被阻止,因为没有已连接的审批界面可以解析它。

只有请求所允许的精确 allow-once 和 allow-always 决策才允许执行。未知、格式错误、不匹配、缺失以及超时的决策都会失败关闭。旧版 timeoutBehavior 字段仍会被接受以兼容插件,但已弃用且会被忽略。不要在新钩子中设置它。

仅当请求插件或运行时实现了该持久化时,allow-always 才会持久生效。对于普通 before_tool_call.requireApproval 钩子,OpenClaw 将 allow-once 和 allow-always 视为当前调用的审批决策,并将解析后的值传递给 onResolution。如果你的插件提供 allow-always,请准确记录并实现它所信任的未来调用范围。

如果钩子还返回 params,OpenClaw 会在请求审批时对基础参数和这些覆盖项进行快照,并仅在审批成功后应用这些覆盖项。较低优先级的钩子仍可以阻止,但不能重写待处理审批所覆盖的参数。

allowedDecisions 限制向用户显示的按钮和命令。Gateway 会拒绝针对请求未提供的任何决策的解析尝试。

路由审批提示

审批提示可以在本地 UI 界面或支持审批处理的聊天渠道中解析。要将插件审批提示转发到显式聊天目标,请配置 approvals.plugin:

{
  approvals: {
    plugin: {
      enabled: true,
      mode: "targets",
      agentFilter: ["main"],
      targets: [{ channel: "slack", to: "U12345678" }],
    },
  },
}

approvals.plugin 独立于 approvals.exec。启用 exec 审批转发不会路由插件审批提示,启用插件审批转发也不会更改主机 exec 策略。

对于 Slack 决策,approvals.plugin.slack 可以限制审核者,而无需更改机器人的消息访问列表。默认 approvers 列表适用于所有插件审批。plugins 条目会为某个选定的原生工具插件覆盖该列表。工具条目会为某个精确工具覆盖该插件的列表:

{
  approvals: {
    plugin: {
      slack: {
        approvers: ["team:T12345678:user:U12345678"],
        plugins: {
          "catalog-tools": {
            approvers: ["team:T12345678:user:U23456789"],
            tools: {
              "create%20issue": {
                approvers: ["team:T12345678:user:U34567890"],
              },
            },
          },
        },
      },
    },
  },
}

对于原生 OpenClaw 工具,请使用工具注册中的插件 ID,并使用 encodeURIComponent(rawToolName) 作为工具键。仅精确匹配的列表生效:先工具,再插件,最后默认。Slack 审核者接受所选 Slack 账户内的原始 U…/W… 用户 ID,或如上所示的工作区限定 ID。决策绑定到机器人已认证的工作区;来自不同工作区的限定审核者不会收到审批私信。显式空列表会在该层级拒绝 Slack 决策。如果省略默认 approvers 字段,具有已知选定所有者且没有匹配覆盖项的请求将保留现有 Slack 账户的 allowFrom 或 defaultTo 授权。当存在插件覆盖项时,缺少选定所有者会拒绝 Slack 决策。这些列表授权 Slack 卡片按钮和 /approve,而已认证的 Gateway 审批客户端仍使用其自身的作用域。即使没有普通机器人私信访问权限,卡片按钮对列表中的审核者也可用;键入的 /approve 仍需要该访问权限。即使审核者无法读取源私信或私有频道,工具卡片也可以显示插件提供的请求标题和描述;选择审核者时应考虑该可见性。工具覆盖项要求精确匹配所选工具;当该身份不可用时,请求不能继承更广泛的审核者列表。有效的非空审核者列表会为该请求启用原生 Slack 投递,独立于原生 exec 审批和插件转发。原生工具列表仅当策略或钩子请求对该工具进行审批时生效;仅设置审核者本身不会触发审批提示。当选择 Slack 审核者列表时,Slack 仅通过原生审核者私信投递卡片。通用 approvals.plugin.targets Slack 转发无法强制该收件人列表,即使目标指定了审核者。如果原生 Slack 处理器不可用,通用转发不会发送卡片;请连接机器人或支持审批的 Gateway 客户端并重试。

在路由新请求时以及接受审批决策时,都会检查审核者列表。更改列表不会撤回现有卡片,也不会取消已排队等待投递的消息。前审核者可能仍会看到此类卡片,但在失去访问权限后无法批准它。已过期或已取消请求的卡片不能授权操作。

当提示包含手动审批文本时,请使用所提供的决策之一来解析它:

/approve <id> allow-once
/approve <id> allow-always
/approve <id> deny

有关完整的转发模型、同一聊天审批行为、原生渠道投递以及特定渠道的审核者规则,请参阅 高级 exec 审批。

Codex 原生权限

Codex 原生权限提示也可以通过插件审批传递,但它们与插件编写的钩子具有不同的所有权。

  • Codex app-server 审批请求在 Codex 审查后通过 OpenClaw 路由。
  • 当该中继启用时,原生钩子 permission_request 中继可以通过 plugin.approval.request 发起询问。
  • 当 Codex 将 _meta.codex_approval_kind 标记为 "mcp_tool_call" 时,MCP 工具审批提示会通过插件审批路由。

有关 Codex 特定行为和回退规则,请参阅 Codex harness runtime。

故障排查

工具提示插件审批不可用。 没有审批 UI 或已配置的审批路由接受该请求。请连接支持审批的客户端,使用支持同一聊天中 /approve 的渠道,或配置 approvals.plugin。

出现 allow-always,但下一次调用再次提示。 通用插件审批流程不会自动为任意钩子持久化信任。请在插件中于 onResolution("allow-always") 之后持久化插件拥有的信任,或仅提供 allow-once 和 deny。

/approve 拒绝该决定。 该请求限制了 allowedDecisions。请使用提示中打印的决定之一。

Discord、Matrix、Slack 或 Telegram 提示的路由与 exec 审批不同。 插件审批和 exec 审批使用独立的配置,并可能使用不同的授权检查。请验证 approvals.plugin 和该渠道的插件审批支持,而不仅仅是检查 approvals.exec。

本页原文 Markdown:在 AtomGit 查看·内容源自开源项目 cl/openclaw