# 工具权限与人工审批

设置权限模式，处理宿主回调，并区分单次允许、持久规则和隔离。

## 三个不同的配置层

`WithTools` 选择向模型提供的内置工具集合；`WithAllowedTools` 与 `WithDisallowedTools` 表达权限规则；`WithPermissionHandler` 处理运行时交给宿主的权限请求。规则、运行时模式和回调一起决定执行路径，不能把回调当作每次工具调用都会经过的审计入口。

初次接入可只提供 Read、Glob、Grep，确认流程后再开放写入。已经批准的工具可能直接执行；若要记录每次工具事件，应使用 [Hooks](/docs/sdk-hooks)。


![未决工具请求进入宿主后的人工审批与策略决策流程](/images/docs/sdk-permission-flow.svg)

## 选择权限模式

| 模式 | 使用目的 |
| --- | --- |
| `ModeDefault` | 按运行时规则处理，未决请求交给审批路径 |
| `ModeAcceptEdits` | 接受文件编辑；其他操作仍按规则处理 |
| `ModePlan` | 规划任务；不是操作系统只读沙箱 |
| `ModeDontAsk` | 按预设规则处理，不依赖交互式提问 |
| `ModeAuto` | 对未决操作使用运行时自动审核，需要能力和模式确认 |
| `ModeBypassPermissions` | 跳过运行时权限检查，只用于已有明确隔离和授权的环境 |

不要把无人值守服务配置成需要人工审批、却没有审批界面的状态。运行期切换到 bypass 还需要启动时允许 `WithAllowDangerouslySkipPermissions(true)`；不要把它作为解决超时的通用办法。

## 安装宿主权限处理器

下面的片段展示保守的无界面策略：显式需要人的请求和未预先批准的操作都拒绝。它可以用于接入验证；要允许操作，应接入自己的审批界面，并把用户决定返回给该次请求。

```go
options = options.WithPermissionMode(permission.ModeDefault).
    WithPermissionHandler(func(ctx context.Context, request permission.Request) (permission.Decision, error) {
        if err := ctx.Err(); err != nil { return permission.Decision{}, err }
        if request.RequiresHuman {
            return permission.Deny("当前入口没有人工确认界面，请在可审批的会话中重试。", false), nil
        }
        return permission.Deny("该操作尚未获得批准。", false), nil
    })
```

展示审批时至少包含工具名称、参数、请求理由和影响对象。使用 ToolUseID 关联请求；若 AgentID 有值，还要标出发起请求的 Agent。不要仅凭模型生成的描述隐藏实际命令或目标路径。

## 返回单次允许或拒绝

`permission.Allow(updatedInput, updates)` 返回允许决策。仅允许本次时，传入 nil 的规则更新列表；确实需要修改参数时才提供 UpdatedInput。`UpdatedPermissions` 会改变规则状态，不能顺手把一次确认升级成持久允许。

`permission.Deny(message, interrupt)` 的说明会用于解释为什么未执行。`interrupt=false` 允许运行时根据拒绝结果选择其他办法，`true` 表达中断意图。不要把拒绝伪装成执行成功。

`RequiresHuman` 表示该请求不能由自动审核替代用户确认。用户页面关闭、等待超时或请求被取消时，不要默认允许。权限等待和运行回合需要各自的超时策略。

## 自动审核的边界

nxs 的 auto 模式需要 `auto_review_v1` 协商；Claude Code 使用原生权限模式确认。Bridge 不运行审核模型。即使 Supports 返回 true，设置模式仍可能因账号、模型或策略不可用而失败。

调用 `session.Control().SetPermissionMode(ctx, permission.ModeAuto)` 后必须处理错误，不要在界面上先显示“已开启”。

## 权限与沙箱

审批回答的是“这次操作是否获得授权”；沙箱限制的是“进程能触及哪些系统资源”。Go 自定义工具在宿主进程中执行，需要自行校验当前用户和数据归属，不能假设它继承运行时沙箱。详见[部署与隔离](/docs/sdk-hosting)。
