Mechanism | Description | Scenario |
Permission mode | Globally control permission behavior | Quickly configure global policies |
canUseTool callback | Dynamic approval at runtime | Interactive Permission Confirmation |
Tool allowlist/blocklist | Declarative tool filtering | Static policy configuration |
permissionMode (TypeScript) or permission_mode (Python).Mode | Description |
default | Default mode. All tool operations require confirmation. |
acceptEdits | Automatically approves file edits. Other operations still require confirmation. |
plan | Planning mode. Only read-only tools are allowed. |
bypassPermissions | Skip all permission checks. Use with caution. |
import { query } from '@tencent-ai/agent-sdk';const q = query({prompt: 'Help me refactor this code',options: {model: 'deepseek-v3.1',permissionMode: 'acceptEdits' // Automatically approve edits}});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" # Automatically approve edits)async for message in query(prompt="Help me refactor this code", options=options):print(message)asyncio.run(main())
import { unstable_v2_createSession } from '@tencent-ai/agent-sdk';const session = unstable_v2_createSession({model: 'deepseek-v3.1'});// Send the first message.await session.send('Analyze this project');for await (const msg of session.stream()) {console.log(msg);}// Dynamically switch to acceptEdits mode to accelerate development.// Note: This is an 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("Analyze this project")async for msg in client.receive_response():print(msg)# Dynamically switch the permission modeawait client.set_permission_mode("acceptEdits")await client.query("Now help me modify the code")async for msg in client.receive_response():print(msg)
canUseTool callback is triggered when a tool requires permission confirmation, allowing you to implement custom permission logic.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: 'Help me analyze this codebase',options: {model: 'deepseek-v3.1',canUseTool: async (toolName, input, options) => {console.log(`\\n🔧 Tool request: ${toolName}`);console.log(`Parameters:`, JSON.stringify(input, null, 2));// Read-only tools are automatically allowed.const readOnlyTools = ['Read', 'Glob', 'Grep'];if (readOnlyTools.includes(toolName)) {return { behavior: 'allow', updatedInput: input };}// Reject dangerous commandsif (toolName === 'Bash') {const command = input.command as string;if (command.includes('rm -rf') || command.includes('sudo')) {return {behavior: 'deny',message: 'Dangerous command rejected',interrupt: true // Interrupt the entire session};}}// Other cases: Simulate user confirmationconst approved = await promptUser(`Allow execution of ${toolName}?`);if (approved) {return { behavior: 'allow', updatedInput: input };} else {return { behavior: 'deny', message: 'User rejected' };}}}});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 request: {tool_name}")print(f" Parameters: {input_data}")# Read-only tools are automatically allowed.read_only_tools = ["Read", "Glob", "Grep"]if tool_name in read_only_tools:return PermissionResultAllow(updated_input=input_data)# Reject dangerous commandsif tool_name == "Bash":command = input_data.get("command", "")if "rm -rf" in command or "sudo" in command:return PermissionResultDeny(message="Dangerous command rejected",interrupt=True # Interrupt the entire session)# Other cases: Simulate user confirmationanswer = input(f"Allow execution of {tool_name}? (y/n): ")if answer.lower() == 'y':return PermissionResultAllow(updated_input=input_data)else:return PermissionResultDeny(message="User rejected")async def main():options = CodeBuddyAgentOptions(model="deepseek-v3.1",can_use_tool=can_use_tool)async for message in query(prompt="Help me analyze this codebase", options=options):print(message)
canUseTool:canUseTool: async (toolName, input) => {if (toolName === 'Bash') {// Add a security check before the commandreturn {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":# Add a security check before the commandreturn PermissionResultAllow(updated_input={**input_data,"command": f"set -e; {input_data.get('command', '')}"})return PermissionResultAllow(updated_input=input_data)
AskUserQuestion tool. You need to handle this tool in canUseTool.{questions: [{question: "Which database should be used?",header: "Database",options: [{ label: "PostgreSQL", description: "Relational database" },{ label: "MongoDB", description: "Document database" }],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(`Question: ${q.question}`);for (let i = 0; i < q.options.length; i++) {console.log(` ${i + 1}. ${q.options[i].label}`);}// Get user inputconst 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"Question: {q['question']}")for i, opt in enumerate(q["options"]):print(f" {i + 1}. {opt['label']}")# Get user inputchoice = int(input("Select (1/2/...): ")) - 1answers[q["question"]] = q["options"][choice]["label"]return PermissionResultAllow(updated_input={**input_data, "answers": answers})return PermissionResultAllow(updated_input=input_data)
Option | Description | Priority |
tools | Built-in tool allowlist that fundamentally limits the available tool set | Highest |
allowedTools | Tools allowed (pattern matching supported) | Medium |
disallowedTools | Tools prohibited (pattern matching supported) | Medium |
tools option to fundamentally limit the built-in toolset available to CodeBuddy:const q = query({prompt: 'Analyze the project structure',options: {model: 'deepseek-v3.1',// Only these built-in tools are allowed.tools: ['Read', 'Glob', 'Grep']}});// Disable all built-in tools (use only MCP tools).const q2 = query({prompt: 'Use MCP tools to complete the task',options: {tools: [] // An empty array disables all built-in tools.}});
options = CodeBuddyAgentOptions(model="deepseek-v3.1",# Only these built-in tools are allowed.tools=["Read", "Glob", "Grep"])# Disable all built-in tools (use only MCP tools).options2 = CodeBuddyAgentOptions(model="deepseek-v3.1",tools=[] # An empty array disables all built-in tools.)
allowedTools and disallowedTools for more fine-grained tool filtering with pattern matching support:const q = query({prompt: 'Analyze the project structure',options: {model: 'deepseek-v3.1',// Only these tools are allowed.allowedTools: ['Read', 'Glob', 'Grep'],// Or disallow these tools.disallowedTools: ['Bash', 'Write', 'Edit']}});
options = CodeBuddyAgentOptions(model="deepseek-v3.1",# Only these tools are allowed.allowed_tools=["Read", "Glob", "Grep"],# Or disallow these tools.disallowed_tools=["Bash", "Write", "Edit"])
Tool Name | Function |
Read | Reads files |
Write | Writes files |
Edit | Edits files |
Glob | File pattern matching |
Grep | Content search |
Bash | Executes Shell commands |
Task | Sub-Agent tasks |
WebFetch | Fetches web content |
WebSearch | Web search |
ToolSearch | Searches for lazily loaded tools |
default mode is used: it provides the most complete permission control.plan mode:permissionMode: 'plan' // Only Read, Glob, and Grep are allowed.
allowedTools: ['Read', 'Glob', 'Grep'],permissionMode: 'bypassPermissions' // Allowed tools run automatically.
interrupt for dangerous commands:return {behavior: 'deny',message: 'Dangerous operation',interrupt: true // Interrupt immediately to prevent the AI from continuing to try.};
bypassPermissions in production environments: this mode skips all permission checks.Was this page helpful?
You can also Contact sales or Submit a Ticket for help.
Help us improve! Rate your documentation experience in 5 mins.
Feedback