> ## Documentation Index
> Fetch the complete documentation index at: https://docs.qoder.com/llms.txt
> Use this file to discover all available pages before exploring further.

# 权限策略

> 控制工具调用是允许、询问还是拒绝。

权限策略控制 Agent 想调用工具时会发生什么。内置工具和 MCP 工具会被评估为 `allow`、`ask` 或 `deny`；client-side 自定义工具始终暂停，由你的应用执行后回传结果。

## 运行时行为

工具调用进入事件流时，会投影为：

| 事件                      | 含义                  | 关键字段                                                             |
| ----------------------- | ------------------- | ---------------------------------------------------------------- |
| `agent.tool_use`        | 内置工具调用              | `id`, `name`, `input`, `evaluated_permission`                    |
| `agent.mcp_tool_use`    | MCP 工具调用            | `id`, `name`, `input`, `mcp_server_name`, `evaluated_permission` |
| `agent.custom_tool_use` | Client-side 自定义工具请求 | `id`, `name`, `input`                                            |

`evaluated_permission` 可能为：

| 值       | 行为                                     |
| ------- | -------------------------------------- |
| `allow` | 平台直接执行工具                               |
| `ask`   | 当前 turn 暂停，等待 `user.tool_confirmation` |
| `deny`  | 平台向 Agent 返回被拒绝的工具结果                   |

自定义工具不支持 `permission_policy`；它们由客户端执行，并通过 `user.custom_tool_result` 恢复。

## 在 Agent 中配置权限

内置工具和 MCP 工具的权限配置写在 Agent 的 `tools` 数组里：

```json theme={null}
{
  "tools": [
    {
      "type": "agent_toolset_20260401",
      "enabled_tools": ["Bash", "Read", "Write"],
      "configs": [
        {"name": "Read", "permission_policy": {"type": "always_allow"}},
        {"name": "Write", "permission_policy": {"type": "always_ask"}},
        {"name": "Bash", "permission_policy": {"type": "always_deny"}}
      ]
    },
    {
      "type": "mcp_toolset",
      "mcp_server_name": "weather-service",
      "configs": [
        {"name": "get_forecast", "permission_policy": {"type": "always_ask"}}
      ]
    }
  ]
}
```

| 位置                                    | 作用范围   | 说明                                                                           |
| ------------------------------------- | ------ | ---------------------------------------------------------------------------- |
| `tools[].configs[].permission_policy` | 一个具名工具 | 单工具权限覆盖。内置工具的 `name` 使用 `Read` 等内置工具名；MCP 工具的 `name` 使用该 MCP server 暴露的原始工具名 |
| `tools[].configs[].enabled`           | 一个具名工具 | 设为 `false` 时会禁用并拒绝该工具。如果同时使用 `enabled_tools` 白名单，不要把已禁用工具放进白名单               |

`permission_policy.type` 可选值：

| 值              | 运行时结果                                                             |
| -------------- | ----------------------------------------------------------------- |
| `always_allow` | `evaluated_permission: "allow"`                                   |
| `always_ask`   | `evaluated_permission: "ask"`，当前 turn 等待 `user.tool_confirmation` |
| `always_deny`  | `evaluated_permission: "deny"`                                    |

## Pending Action 流程

当工具调用需要人工或客户端输入时：

1. 事件流先发送 `agent.tool_use` 或 `agent.custom_tool_use`
2. 事件流再发送 `session.status_idle`，其中 `stop_reason.type` 为 `"requires_action"`
3. `stop_reason.event_ids` 列出需要响应的事件 ID
4. 客户端向 `POST /api/v1/cloud/sessions/{session_id}/events` 发送响应事件
5. Agent 继续同一个 turn

```json theme={null}
{
  "type": "session.status_idle",
  "status": "idle",
  "stop_reason": {
    "type": "requires_action",
    "event_ids": ["evt_01JZ6Q3FB6SG8F7J1M2N"]
  }
}
```

Pending action 不会自动超时。它会一直保持 pending，直到客户端解决，或 session/turn 被取消。

## 确认工具调用

使用 `agent.tool_use` 事件的 `id` 作为 `tool_use_id`。这里传的是 `evt_...` 事件 ID，不是模型供应商内部的 tool-use ID。

<Tabs>
  <Tab title="批准">
    ```bash theme={null}
    curl -X POST https://api.qoder.com/api/v1/cloud/sessions/sess_abc123/events \
      -H "Authorization: Bearer $QODER_PAT" \
      -H "Content-Type: application/json" \
      -d '{
        "events": [
          {
            "type": "user.tool_confirmation",
            "tool_use_id": "evt_01JZ6Q3FB6SG8F7J1M2N",
            "result": "allow"
          }
        ]
      }'
    ```
  </Tab>

  <Tab title="拒绝">
    ```bash theme={null}
    curl -X POST https://api.qoder.com/api/v1/cloud/sessions/sess_abc123/events \
      -H "Authorization: Bearer $QODER_PAT" \
      -H "Content-Type: application/json" \
      -d '{
        "events": [
          {
            "type": "user.tool_confirmation",
            "tool_use_id": "evt_01JZ6Q3FB6SG8F7J1M2N",
            "result": "deny",
            "deny_message": "只允许检查文件，不要删除。"
          }
        ]
      }'
    ```
  </Tab>
</Tabs>

## 完成自定义工具

自定义工具通过 Agent 的 `type: "custom"` 配置，详见 [Agent 工具配置](/zh/cloud-agents/tools)。当 Agent 请求自定义工具时，你的应用执行该工具，然后使用 `agent.custom_tool_use` 事件 ID 回传：

```bash theme={null}
curl -X POST https://api.qoder.com/api/v1/cloud/sessions/sess_abc123/events \
  -H "Authorization: Bearer $QODER_PAT" \
  -H "Content-Type: application/json" \
  -d '{
    "events": [
      {
        "type": "user.custom_tool_result",
        "custom_tool_use_id": "evt_01JZ6R1V9Z8K2M3N4P5Q",
        "content": [{"type": "text", "text": "订单状态：已发货"}]
      }
    ]
  }'
```

`content` 可以是字符串、单个 text block 或 text block 数组。返回事件会以 content block 结构保存。

## 常见问题

**Q：一个 turn 可以有多个待响应操作吗？** A：可以。`stop_reason.event_ids` 可能包含多个事件 ID，需要逐个响应。

**Q：pending action 会超时吗？** A：不会。它会保持 pending，直到被解决，或 session/turn 被取消。

**Q：自定义工具能使用 `permission_policy` 吗？** A：不能。自定义工具是 client-side 工具，是否执行或拒绝由客户端负责。

## 下一步

<CardGroup cols={2}>
  <Card title="Agent 工具" icon="wrench" href="/zh/cloud-agents/tools">
    为 Agent 配备内置、MCP 和自定义工具。
  </Card>

  <Card title="Session 事件流" icon="wave-pulse" href="/zh/cloud-agents/events-stream">
    通过 SSE 实时获取 Agent 的思考、消息、工具调用与状态。
  </Card>

  <Card title="启动 Session" icon="play" href="/zh/cloud-agents/sessions">
    管理会话生命周期。
  </Card>

  <Card title="定义 Agent" icon="user-gear" href="/zh/cloud-agents/define-agent">
    回顾 Agent 配置。
  </Card>
</CardGroup>
