Agent SDK

工具权限与人工审批

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

三个不同的配置层

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

初次接入可只提供 Read、Glob、Grep,确认流程后再开放写入。已经批准的工具可能直接执行;若要记录每次工具事件,应使用 Hooks

未决工具请求进入宿主后的人工审批与策略决策流程

选择权限模式

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

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

安装宿主权限处理器

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

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 自定义工具在宿主进程中执行,需要自行校验当前用户和数据归属,不能假设它继承运行时沙箱。详见部署与隔离