tencent cloud

Python SDK Reference

Download
Focus Mode
Font Size
Last updated: 2026-09-30 18:41:48
AI-Translated
Version Requirements: This document applies to CodeBuddy Agent SDK v0.1.0 and later versions.
This document provides a complete API reference for the Python SDK. For quick start guides and usage examples, see SDK Overview.

Requirements

Dependency
Version Requirement
Python
>= 3.10
CodeBuddy CLI
Installed
Asynchronous Runtime: The SDK is built on asyncio, and all APIs are asynchronous.

Installation

It is recommended to use uv for dependency management:
uv add codebuddy-agent-sdk
Or use pip:
pip install codebuddy-agent-sdk

Environment Variable

Variable Name
Description
Required
CODEBUDDY_CODE_PATH
CodeBuddy CLI executable file path
Optional
If not set, the SDK searches for the CLI in the following order:
1. The environment variable CODEBUDDY_CODE_PATH
2. The binary file bundled with the SDK package
3. The monorepo path in the development environment

Authentication Configuration

The SDK supports authentication using existing login credentials, API keys, or OAuth Client Credentials. For details, see SDK Overview - Authentication Configuration.

Functions

query()

The primary API entry point that creates a query and returns an asynchronous message iterator.
async def query(
*,
prompt: str | AsyncIterable[dict[str, Any]],
options: CodeBuddyAgentOptions | None = None,
transport: Transport | None = None,
) -> AsyncIterator[Message]:
Parameters:
Parameter
Type
Description
prompt
str | AsyncIterable[dict]
Query prompt or user message stream
options
CodeBuddyAgentOptions
Configuration options (optional)
transport
Transport
Custom transport layer (optional)
Returns: AsyncIterator[Message] - an asynchronous message iterator
Example:
from codebuddy_agent_sdk import query, AssistantMessage, TextBlock

async for message in query(prompt="What is 2+2?"):
if isinstance(message, AssistantMessage):
for block in message.content:
if isinstance(block, TextBlock):
print(block.text)

Client Class

CodeBuddySDKClient

A client class for bidirectional interactive conversations. It supports multi-turn conversations, interruption, and dynamic control.
class CodeBuddySDKClient:
def __init__(
self,
options: CodeBuddyAgentOptions | None = None,
transport: Transport | None = None,
): ...
Methods:

connect()

Connect to CodeBuddy.
async def connect(
self,
prompt: str | AsyncIterable[dict[str, Any]] | None = None
) -> None:

query()

Send a user message.
async def query(
self,
prompt: str | AsyncIterable[dict[str, Any]],
session_id: str = "default",
) -> None:

receive_response()

Receive messages until a ResultMessage is received.
async def receive_response(self) -> AsyncIterator[Message]:

receive_messages()

Receive all messages without stopping automatically.
async def receive_messages(self) -> AsyncIterator[Message]:

disconnect()

Disconnect.
async def disconnect(self) -> None:
Context Manager Support:
async with CodeBuddySDKClient() as client:
await client.query("Hello!")
async for msg in client.receive_response():
print(msg)

mcp_server_status()

Get the MCP server connection status.
async def mcp_server_status(self) -> list[McpServerStatus]:

Authentication

The SDK provides a standalone authentication API that uses a two-phase design: first obtain the login URL, and then wait for the user to complete authentication.

authenticate()

Start the authentication process and return an AuthFlow object.
async def authenticate(
*,
method_id: str = "external",
environment: str | None = None,
endpoint: str | None = None,
codebuddy_code_path: str | None = None,
env: dict[str, str] | None = None,
timeout: float = 300.0,
) -> AuthFlow:
Parameters:
Parameter
Type
Description
method_id
str
Authentication method identifier (default: "external")
environment
str | None
Predefined environment name
endpoint
str | None
Custom endpoint URL (mutually exclusive with environment)
codebuddy_code_path
str | None
CLI executable file path
env
dict[str, str] | None
Additional environment variables
timeout
float
Timeout for users to complete login (in seconds, default: 300)
Return value: AuthFlow — an awaitable object that carries the login URL
Example:
from codebuddy_agent_sdk import authenticate

# Two-phase: obtain the URL → present it to the user → wait for completion
auth = await authenticate()
if auth.auth_url:
print(f"Please visit: {auth.auth_url}")
result = await auth
print(f"Welcome, {result.userinfo.user_name}")

# When already logged in, auth.auth_url is empty and await returns immediately.
auth = await authenticate()
result = await auth # Returns immediately if already logged in.

# Custom timeout
auth = await authenticate()
result = await auth.wait(timeout=60)

AuthFlow

An authentication flow object returned by authenticate(). It implements the __await__ protocol and can be directly awaited with await.
Attributes:
Attribute
Type
Description
auth_url
str
Login URL (empty string when the user is logged in)
method_id
str | None
Authentication method identifier
Methods:

wait()

Wait for the user to complete authentication.
async def wait(self, timeout: float | None = None) -> AuthenticateResponse:

cancel()

Cancel the authentication flow and release resources.
async def cancel(self) -> None:

logout()

Log out and clear the cached authentication token.
async def logout(
*,
environment: str | None = None,
endpoint: str | None = None,
codebuddy_code_path: str | None = None,
env: dict[str, str] | None = None,
) -> None:
Example:
from codebuddy_agent_sdk import logout

await logout()

Unstable API

Warning:
The following APIs are experimental, and their interfaces may change in future versions.

interrupt()

Send an interrupt signal.
async def interrupt(self) -> None:

set_permission_mode()

Dynamically modify the permission mode.
async def set_permission_mode(self, mode: str) -> None:

set_model()

Dynamically modify the model.
async def set_model(self, model: str | None = None) -> None:

Types

CodeBuddyAgentOptions

Complete configuration options:
@dataclass
class CodeBuddyAgentOptions:
allowed_tools: list[str] = field(default_factory=list)
disallowed_tools: list[str] = field(default_factory=list)
system_prompt: str | AppendSystemPrompt | None = None
mcp_servers: dict[str, McpServerConfig] | str | Path = field(default_factory=dict)
permission_mode: PermissionMode | None = None
continue_conversation: bool = False
resume: str | None = None
max_turns: int | None = None
model: str | None = None
fallback_model: str | None = None
cwd: str | Path | None = None
codebuddy_code_path: str | Path | None = None
env: dict[str, str] = field(default_factory=dict)
extra_args: dict[str, str | None] = field(default_factory=dict)
stderr: Callable[[str], None] | None = None
hooks: dict[HookEvent, list[HookMatcher]] | None = None
include_partial_messages: bool = False
fork_session: bool = False
persist_session: bool = True
agents: dict[str, AgentDefinition] | None = None
setting_sources: list[SettingSource] | None = None
can_use_tool: CanUseTool | None = None
Field
Type
Description
allowed_tools
list[str]
Allowlist of Automatically Allowed Tools
disallowed_tools
list[str]
Blocklist of Disallowed Tools
system_prompt
str | AppendSystemPrompt
System Prompt Configuration
mcp_servers
dict[str, McpServerConfig]
MCP server configuration
permission_mode
PermissionMode
Permission Mode
continue_conversation
bool
Continue the most recent session
resume
str
Session ID to resume
max_turns
int
Maximum number of conversation turns
model
str
Specify the model
fallback_model
str
Fallback model
cwd
str | Path
Working Directory
codebuddy_code_path
str | Path
CLI executable file path
env
dict[str, str]
Environment Variable
extra_args
dict[str, str | None]
Additional CLI arguments
stderr
Callable[[str], None]
stderr callback
hooks
dict[HookEvent, list[HookMatcher]]
Hook configuration
include_partial_messages
bool
Include partial messages
fork_session
bool
Fork session
persist_session
bool
Whether to persist session records. Defaults to True. When set to False, sessions are kept only in memory and are not written to local transcripts, and file checkpoints are also skipped. Existing sessions can still be resumed, but they are no longer written. Requires CLI >= 2.125.1.
agents
dict[str, AgentDefinition]
Custom Agent
setting_sources
list[SettingSource]
Setting sources
can_use_tool
CanUseTool
Permission callback function
max_thinking_tokens
int
Maximum thinking tokens (deprecated, use thinking instead).
thinking
ThinkingConfig
Thinking mode configuration: {"type": "adaptive"}, {"type": "enabled", "budget_tokens": N}, or {"type": "disabled"}
effort
'low' | 'medium' | 'high' | 'xhigh'
Model reasoning effort level

PermissionMode

PermissionMode = Literal["default", "acceptEdits", "plan", "bypassPermissions"]
Value
Description
"default"
Default mode. All operations require confirmation.
"acceptEdits"
Automatically approve file edits
"plan"
Planning mode. Only read operations are allowed.
"bypassPermissions"
Skip all permission checks

PermissionResult

PermissionResult = PermissionResultAllow | PermissionResultDeny

@dataclass
class PermissionResultAllow:
updated_input: dict[str, Any]
behavior: Literal["allow"] = "allow"
updated_permissions: list[dict[str, Any]] | None = None

@dataclass
class PermissionResultDeny:
message: str
behavior: Literal["deny"] = "deny"
interrupt: bool = False

CanUseTool

CanUseTool = Callable[
[str, dict[str, Any], CanUseToolOptions],
Awaitable[PermissionResult],
]

@dataclass
class CanUseToolOptions:
tool_use_id: str
signal: Any | None = None
agent_id: str | None = None
suggestions: list[dict[str, Any]] | None = None
blocked_path: str | None = None
decision_reason: str | None = None

AgentDefinition

@dataclass
class AgentDefinition:
description: str # Agent description
prompt: str # System prompt
tools: list[str] | None = None # Allowed tools
disallowed_tools: list[str] | None = None # Disallowed tools
model: str | None = None # Model used

McpServerConfig

class McpStdioServerConfig(TypedDict):
type: NotRequired[Literal["stdio"]]
command: str
args: NotRequired[list[str]]
env: NotRequired[dict[str, str]]

McpServerConfig = McpStdioServerConfig

HookEvent

HookEvent = (
Literal["PreToolUse"]
| Literal["PostToolUse"]
| Literal["UserPromptSubmit"]
| Literal["Stop"]
| Literal["SubagentStop"]
| Literal["PreCompact"]
| Literal["WorktreeCreate"]
| Literal["WorktreeRemove"]
)

HookMatcher

@dataclass
class HookMatcher:
matcher: str | None = None # Matching pattern (regex supported)
hooks: list[HookCallback] = field(default_factory=list)
timeout: float | None = None # Timeout in seconds

HookCallback

HookCallback = Callable[
[Any, str | None, HookContext],
Awaitable[HookJSONOutput],
]

class HookContext(TypedDict):
signal: Any | None

class SyncHookJSONOutput(TypedDict):
continue_: NotRequired[bool]
suppressOutput: NotRequired[bool]
stopReason: NotRequired[str]
decision: NotRequired[Literal["block"]]
reason: NotRequired[str]

SettingSource

Control the file system locations from which the SDK loads configuration.
SettingSource = Literal["user", "project", "local"]
Value
Description
Position
"user"
Global user settings
~/.codebuddy/settings.json
"project"
Project-shared settings
.codebuddy/settings.json
"local"
Project-local settings
.codebuddy/settings.local.json
Default behavior: When setting_sources is not specified, the SDK does not load any file system configuration. This provides a completely clean runtime environment.
# Default: No configuration is loaded (clean environment)
async for msg in query(prompt="..."):
pass

# Load project configuration
options = CodeBuddyAgentOptions(setting_sources=["project"])

# Load all configurations (similar to CLI behavior)
options = CodeBuddyAgentOptions(setting_sources=["user", "project", "local"])

AppendSystemPrompt

@dataclass
class AppendSystemPrompt:
append: str # Content to append to the default system prompt

Message Types

Message

Union of all message types:
Message = UserMessage | AssistantMessage | SystemMessage | ResultMessage | StreamEvent
Note:
TaskStartedMessage / TaskNotificationMessage are subclasses of SystemMessage. They are already covered by the union (isinstance / case SystemMessage() continues to match) and are exported separately for precise type checking at call sites.

SystemMessage

@dataclass
class SystemMessage:
subtype: str
data: dict[str, Any]

TaskStartedMessage

Emitted when a background task (Bash / PowerShell / Workflow / Agent, run_in_background: true) enters the running state. It is a subclass of SystemMessage, so isinstance(msg, SystemMessage) still holds true.
@dataclass
class TaskStartedMessage(SystemMessage):
task_id: str
description: str
uuid: str
session_id: str
tool_use_id: str | None = None
task_type: str | None = None # "Bash" / "PowerShell" / "Workflow" / "Agent"

TaskUsage

Usage statistics carried by task_progress / task_notification (aligned with Claude Code's TaskUsage). This field has a value for sub-agent (task_type == "Agent") background tasks, while it is typically omitted for background shell tasks.
class TaskUsage(TypedDict):
total_tokens: int
tool_uses: int
duration_ms: int

TaskProgressMessage

Background task progress event. Event-driven (not periodic): one event is pushed each time a tool_use is completed, carrying cumulative usage and the most recent tool name last_tool_name. Background shell tasks do not emit progress.
@dataclass
class TaskProgressMessage(SystemMessage):
task_id: str
description: str
usage: TaskUsage
uuid: str
session_id: str
tool_use_id: str | None = None
last_tool_name: str | None = None

TaskUpdatedMessage

Background task state transition event. The patch carries the fields changed in this update (at least status, and end_time is added for terminal states).
Lifecycle note: A background task's terminal state sometimes arrives only via task_updated (patch.status is terminal) without a corresponding task_notification. Consumers tracking "active tasks" should treat the terminal status of both equally—use the TERMINAL_TASK_STATUSES frozenset for the check ({"completed", "failed", "stopped", "killed"}).
@dataclass
class TaskUpdatedMessage(SystemMessage):
task_id: str
patch: dict[str, Any]
status: TaskUpdatedStatus | None = None # pending/running/paused/completed/failed/killed
session_id: str | None = None
uuid: str | None = None

TaskNotificationMessage

Emitted when a background task completes, fails, or is stopped. In stdio stream-json long-connection mode, if a task completes after the result of the turn that triggered it, this message is actively pushed back to the same output stream. Consumers must continuously read with receive_messages() to receive it (query() and receive_response() stop at the first ResultMessage and will miss background completion events). usage is carried on sub-agent tasks and omitted for shell tasks.
query() automatically disables background tasks: because query() stops at the first ResultMessage and closes the child process, it cannot receive cross-turn push-back events. The SDK automatically injects CODEBUDDY_CODE_DISABLE_BACKGROUND_TASKS=1 in the query() path (the run_in_background option for Bash / PowerShell / Agent is hidden or downgraded to foreground). If you need to keep background tasks under query(), explicitly set this variable in options.env or the process environment (any value, including "0") to override it. The CodeBuddySDKClient + receive_messages() path is not affected.
@dataclass
class TaskNotificationMessage(SystemMessage):
task_id: str
status: Literal["completed", "failed", "stopped"]
summary: str
uuid: str
session_id: str
tool_use_id: str | None = None
output_file: str | None = None # Path for writing background task stdout to disk (file mode)
output_stderr_file: str | None = None
usage: TaskUsage | None = None
Multiple concurrent background tasks are distinguished by task_id, and tool_use_id links back to the tool_use that initiated the task. Example (keep reading to receive the notification after overall completion):
from codebuddy_agent_sdk import (
CodeBuddySDKClient,
CodeBuddyAgentOptions,
TaskStartedMessage,
TaskNotificationMessage,
)

async def run_background_tasks():
options = CodeBuddyAgentOptions(permission_mode="bypassPermissions")
async with CodeBuddySDKClient(options=options) as client:
await client.query("Run two background commands in parallel and tell me the results when they finish")
# Keep reading with receive_messages—do not use receive_response (it stops at the first result)
async for msg in client.receive_messages():
if isinstance(msg, TaskStartedMessage):
print(f"[started] {msg.task_id} ({msg.task_type}): {msg.description}")
elif isinstance(msg, TaskNotificationMessage):
print(f"[done] {msg.task_id} status={msg.status} output={msg.output_file}")
# break on your own after collecting all the tasks you care about

UserMessage

@dataclass
class UserMessage:
content: str | list[ContentBlock]
uuid: str | None = None
parent_tool_use_id: str | None = None

AssistantMessage

@dataclass
class AssistantMessage:
content: list[ContentBlock]
model: str
parent_tool_use_id: str | None = None
error: str | None = None

ResultMessage

@dataclass
class ResultMessage:
subtype: str
duration_ms: int
duration_api_ms: int
is_error: bool
num_turns: int
session_id: str
total_cost_usd: float | None = None
usage: dict[str, Any] | None = None
result: str | None = None
errors: list[str] | None = None
# Structured error info aligned with `errors` by index.
# - Length matches `errors` when present; entry is None if no structured dimension available.
# - Field is absent entirely when every entry would be None (backward compatible).
# - Each entry may carry: status (HTTP), code (SDK/business), category (network/quota/auth/model_service/...), details (message).
errors_info: list[dict[str, Any] | None] | None = None

StreamEvent

@dataclass
class StreamEvent:
uuid: str
session_id: str
event: dict[str, Any]
parent_tool_use_id: str | None = None

ContentBlock

ContentBlock = TextBlock | ThinkingBlock | ToolUseBlock | ToolResultBlock

@dataclass
class TextBlock:
text: str

@dataclass
class ThinkingBlock:
thinking: str
signature: str

@dataclass
class ToolUseBlock:
id: str
name: str
input: dict[str, Any]

@dataclass
class ToolResultBlock:
tool_use_id: str
content: str | list[dict[str, Any]] | None = None
is_error: bool | None = None

Input Types

AskUserQuestionInput

@dataclass
class AskUserQuestionInput:
questions: list[AskUserQuestionQuestion]
answers: dict[str, str] | None = None

AskUserQuestionQuestion

@dataclass
class AskUserQuestionQuestion:
question: str # Complete question text (should end with ?)
header: str # Short label (up to 12 characters)
options: list[AskUserQuestionOption]
multi_select: bool # Whether to allow multiple selections

AskUserQuestionOption

@dataclass
class AskUserQuestionOption:
label: str # Display text (1-5 words)
description: str # Option description

Errors

All exceptions inherit from CodeBuddySDKError.

CodeBuddySDKError

class CodeBuddySDKError(Exception):
"""Base exception for CodeBuddy SDK errors."""
pass

CLIConnectionError

Thrown when connecting to the CLI fails or no connection is established.
class CLIConnectionError(CodeBuddySDKError):
pass

CLINotFoundError

Thrown when the CLI executable cannot be found.
class CLINotFoundError(CodeBuddySDKError):
def __init__(
self,
message: str,
platform: str | None = None,
arch: str | None = None,
): ...
Attributes:
Attribute
Type
Description
platform
str | None
Current platform
arch
str | None
Current architecture

CLIJSONDecodeError

Thrown when decoding JSON output from the CLI fails.
class CLIJSONDecodeError(CodeBuddySDKError):
pass

ProcessError

Thrown when the CLI process encounters an error.
class ProcessError(CodeBuddySDKError):
pass

CLIStartupError

Thrown when the CLI process crashes during startup or produces no output.
class CLIStartupError(CodeBuddySDKError):
def __init__(
self,
message: str,
stderr: str = "",
exit_code: int | None = None,
): ...
Attributes:
Attribute
Type
Description
stderr
str
stderr output of the CLI process
exit_code
int | None
Process exit code

ExecutionError

Thrown when execution fails (for example, authentication errors or API errors). Contains the errors array from ResultMessage.
class ExecutionError(CodeBuddySDKError):
def __init__(self, errors: list[str], subtype: str): ...
Attributes:
Attribute
Type
Description
errors
list[str]
List of error messages
subtype
str
Error subtype

AuthenticationError

Thrown when authentication fails.
class AuthenticationError(CodeBuddySDKError):
def __init__(self, error_type: str, message: str): ...
Attributes:
Attribute
Type
Description
error_type
str
Error type (such as "timeout", "auth_failed")

Auth Types

AuthenticateResponse

@dataclass(slots=True)
class AuthenticateResponse:
userinfo: UserInfo

UserInfo

@dataclass(slots=True)
class UserInfo:
user_id: str
user_name: str = ""
user_nickname: str = ""
token: str = ""
enterprise_id: str | None = None
enterprise: str | None = None

McpServerStatus

@dataclass(slots=True)
class McpServerStatus:
name: str
status: Literal["connected", "failed", "needs-auth", "pending"]
server_info: dict[str, Any] | None = None

References

SDK Overview - Quick Start and Usage Examples
TypeScript SDK Reference - TypeScript Version API
Hook Reference Guide - Detailed Hook Configuration Instructions
MCP Integration - MCP Server Configuration Guide


Help and Support

Was this page helpful?

Help us improve! Rate your documentation experience in 5 mins.

Feedback