版本要求:本文档针对 CodeBuddy Agent SDK v0.1.0 及以上版本。
本文档介绍如何在 SDK 中实现权限控制,包括权限模式、canUseTool 回调和工具白名单/黑名单。
概述
CodeBuddy Agent SDK 提供多种权限控制机制:
机制 | 说明 | 适用场景 |
权限模式 | 全局控制权限行为 | 快速设置整体策略 |
canUseTool 回调 | 运行时动态审批 | 交互式权限确认 |
工具白名单/黑名单 | 声明式工具过滤 | 静态策略配置 |
权限模式
通过
permissionMode(TypeScript)或 permission_mode(Python)设置全局权限行为。可用模式
模式 | 说明 |
default | 默认模式,所有工具操作需要确认 |
acceptEdits | 自动批准文件编辑,其他操作仍需确认 |
plan | 规划模式,仅允许只读工具 |
bypassPermissions | 跳过所有权限检查(谨慎使用) |
初始配置
import { query } from '@tencent-ai/agent-sdk';const q = query({prompt: '帮我重构这段代码',options: {model: 'deepseek-v3.1',permissionMode: 'acceptEdits' // 自动批准编辑}});for await (const message of q) {console.log(message);}
import asynciofrom codebuddy_agent_sdk import query, CodeBuddyAgentOptionsasync def main():options = CodeBuddyAgentOptions(model="deepseek-v3.1",permission_mode="acceptEdits" # 自动批准编辑)async for message in query(prompt="帮我重构这段代码", options=options):print(message)asyncio.run(main())
动态修改权限模式
使用 Session/Client API 可以在运行时动态修改权限模式:
import { unstable_v2_createSession } from '@tencent-ai/agent-sdk';const session = unstable_v2_createSession({model: 'deepseek-v3.1'});// 发送第一条消息await session.send('分析这个项目');for await (const msg of session.stream()) {console.log(msg);}// 动态切换到 acceptEdits 模式加速开发// 注意:这是 unstable API
from codebuddy_agent_sdk import CodeBuddySDKClient, CodeBuddyAgentOptionsasync def main():options = CodeBuddyAgentOptions(model="deepseek-v3.1")async with CodeBuddySDKClient(options=options) as client:await client.query("分析这个项目")async for msg in client.receive_response():print(msg)# 动态切换权限模式await client.set_permission_mode("acceptEdits")await client.query("现在帮我修改代码")async for msg in client.receive_response():print(msg)
canUseTool 回调
canUseTool 回调在工具需要权限确认时触发,允许您实现自定义的权限逻辑。回调签名
type CanUseTool = (toolName: string,input: Record<string, unknown>,options: CanUseToolOptions) => Promise<PermissionResult>;type CanUseToolOptions = {signal: AbortSignal;toolUseID: string;agentID?: string;suggestions?: PermissionUpdate[];blockedPath?: string;decisionReason?: string;};type PermissionResult =| { behavior: 'allow'; updatedInput: Record<string, unknown> }| { behavior: 'deny'; message: string; interrupt?: boolean };
CanUseTool = Callable[[str, dict[str, Any], CanUseToolOptions],Awaitable[PermissionResult],]@dataclassclass CanUseToolOptions:tool_use_id: strsignal: Any | None = Noneagent_id: str | None = Nonesuggestions: list[dict[str, Any]] | None = Noneblocked_path: str | None = Nonedecision_reason: str | None = NonePermissionResult = PermissionResultAllow | PermissionResultDeny
完整示例:交互式审批
import { query } from '@tencent-ai/agent-sdk';const q = query({prompt: '帮我分析这个代码库',options: {model: 'deepseek-v3.1',canUseTool: async (toolName, input, options) => {console.log(`\\n🔧 工具请求: ${toolName}`);console.log(`参数:`, JSON.stringify(input, null,2));// 只读工具自动允许const readOnlyTools = ['Read', 'Glob', 'Grep'];if (readOnlyTools.includes(toolName)) {return { behavior: 'allow', updatedInput: input };}// 危险命令拒绝if (toolName === 'Bash') {const command = input.command as string;if (command.includes('rm -rf') || command.includes('sudo')) {return {behavior: 'deny',message: '危险命令被拒绝',interrupt: true // 中断整个会话};}}// 其他情况:模拟用户确认const approved = await promptUser(`允许执行 ${toolName}?`);if (approved) {return { behavior: 'allow', updatedInput: input };} else {return { behavior: 'deny', message: '用户拒绝' };}}}});for await (const message of q) {console.log(message);}
from codebuddy_agent_sdk import (query, CodeBuddyAgentOptions,CanUseToolOptions, PermissionResultAllow, PermissionResultDeny)async def can_use_tool(tool_name: str,input_data: dict,options: CanUseToolOptions):print(f"\\n🔧 工具请求: {tool_name}")print(f" 参数: {input_data}")# 只读工具自动允许read_only_tools = ["Read", "Glob", "Grep"]if tool_name in read_only_tools:return PermissionResultAllow(updated_input=input_data)# 危险命令拒绝if tool_name == "Bash":command = input_data.get("command", "")if "rm -rf" in command or "sudo" in command:return PermissionResultDeny(message="危险命令被拒绝",interrupt=True # 中断整个会话)# 其他情况:模拟用户确认answer = input(f"允许执行 {tool_name}? (y/n): ")if answer.lower() == 'y':return PermissionResultAllow(updated_input=input_data)else:return PermissionResultDeny(message="用户拒绝")async def main():options = CodeBuddyAgentOptions(model="deepseek-v3.1",can_use_tool=can_use_tool)async for message in query(prompt="帮我分析这个代码库", options=options):print(message)
修改工具输入
可以在
canUseTool 中修改工具的输入参数:canUseTool: async (toolName, input) => {if (toolName === 'Bash') {// 在命令前添加安全检查return {behavior: 'allow',updatedInput: {...input,command: `set -e; ${input.command}`}};}return { behavior: 'allow', updatedInput: input };}
async def can_use_tool(tool_name, input_data, options):if tool_name == "Bash":# 在命令前添加安全检查return PermissionResultAllow(updated_input={**input_data,"command": f"set -e; {input_data.get('command', '')}"})return PermissionResultAllow(updated_input=input_data)
处理 AskUserQuestion
当 AI 需要向用户提问时,会调用
AskUserQuestion 工具。您需要在 canUseTool 中处理这个工具。输入结构
{questions: [{question: "使用哪个数据库?",header: "数据库",options: [{ label: "PostgreSQL", description: "关系型数据库" },{ label: "MongoDB", description: "文档数据库" }],multiSelect: false}]}
返回答案
canUseTool: async (toolName, input) => {if (toolName === 'AskUserQuestion') {const questions = input.questions as any[];const answers: Record<string, string> = {};for (const q of questions) {console.log(`问题: ${q.question}`);for (let i = 0; i < q.options.length; i++) {console.log(` ${i + 1}. ${q.options[i].label}`);}// 获取用户输入const choice = await getUserChoice();answers[q.question] = q.options[choice].label;}return {behavior: 'allow',updatedInput: { ...input, answers }};}return { behavior: 'allow', updatedInput: input };}
async def can_use_tool(tool_name, input_data, options):if tool_name == "AskUserQuestion":questions = input_data.get("questions", [])answers = {}for q in questions:print(f"问题: {q['question']}")for i, opt in enumerate(q["options"]):print(f" {i + 1}. {opt['label']}")# 获取用户输入choice = int(input("选择 (1/2/...): ")) - 1answers[q["question"]] = q["options"][choice]["label"]return PermissionResultAllow(updated_input={**input_data, "answers": answers})return PermissionResultAllow(updated_input=input_data)
工具白名单/黑名单
SDK 提供多种工具过滤机制:
选项 | 说明 | 优先级 |
tools | 内置工具白名单,从根本上限制可用工具集 | 最高 |
allowedTools | 允许使用的工具(支持模式匹配) | 中 |
disallowedTools | 禁止使用的工具(支持模式匹配) | 中 |
tools:内置工具白名单
使用
tools 选项从根本上限制 CodeBuddy 可使用的内置工具集:const q = query({prompt: '分析项目结构',options: {model: 'deepseek-v3.1',// 只允许这些内置工具tools: ['Read', 'Glob', 'Grep']}});// 禁用所有内置工具(仅使用 MCP 工具)const q2 = query({prompt: '使用 MCP 工具完成任务',options: {tools: [] // 空数组禁用所有内置工具}});
options = CodeBuddyAgentOptions(model="deepseek-v3.1",# 只允许这些内置工具tools=["Read", "Glob", "Grep"])# 禁用所有内置工具(仅使用 MCP 工具)options2 = CodeBuddyAgentOptions(model="deepseek-v3.1",tools=[] # 空数组禁用所有内置工具)
allowedTools/disallowedTools:工具过滤
使用
allowedTools 和 disallowedTools 进行更细粒度的工具过滤,支持模式匹配:const q = query({prompt: '分析项目结构',options: {model: 'deepseek-v3.1',// 只允许这些工具allowedTools: ['Read', 'Glob', 'Grep'],// 或者禁止这些工具disallowedTools: ['Bash', 'Write', 'Edit']}});
options = CodeBuddyAgentOptions(model="deepseek-v3.1",# 只允许这些工具allowed_tools=["Read", "Glob", "Grep"],# 或者禁止这些工具disallowed_tools=["Bash", "Write", "Edit"])
常用工具名称
工具名 | 功能 |
Read | 读取文件 |
Write | 写入文件 |
Edit | 编辑文件 |
Glob | 文件模式匹配 |
Grep | 内容搜索 |
Bash | 执行 Shell 命令 |
Task | 子 Agent 任务 |
WebFetch | 获取网页内容 |
WebSearch | 网络搜索 |
ToolSearch | 搜索延迟加载的工具 |
最佳实践
1. 默认使用
default 模式:提供最完整的权限控制2. 只读任务使用
plan 模式:permissionMode: 'plan' // 只允许 Read、Glob、Grep
3. 结合白名单精确控制:
allowedTools: ['Read', 'Glob', 'Grep'],permissionMode: 'bypassPermissions' // 允许的工具自动执行
4. 危险命令使用
interrupt:return {behavior: 'deny',message: '危险操作',interrupt: true // 立即中断,不让 AI 继续尝试};
5. 生产环境避免
bypassPermissions:该模式会跳过所有权限检查相关文档
SDK 概览 - 快速入门和使用示例
SDK Hook 系统 - 更细粒度的工具控制
TypeScript SDK 参考 - 完整 API 参考
Python SDK 参考 - 完整 API 参考