pip install claude-agent-sdkquery() und ClaudeSDKClientDas Python SDK bietet zwei Möglichkeiten, um mit Claude Code zu interagieren:
| Funktion | query() | ClaudeSDKClient |
|---|---|---|
| Sitzung | Erstellt jedes Mal eine neue Sitzung | Verwendet dieselbe Sitzung wieder |
| Konversation | Einzelner Austausch | Mehrere Austausche im gleichen Kontext |
| Verbindung | Automatisch verwaltet | Manuelle Kontrolle |
| Streaming-Eingabe | ✅ Unterstützt | ✅ Unterstützt |
| Unterbrechungen | ❌ Nicht unterstützt | ✅ Unterstützt |
| Hooks | ❌ Nicht unterstützt | ✅ Unterstützt |
| Benutzerdefinierte Tools | ❌ Nicht unterstützt | ✅ Unterstützt |
| Konversation fortsetzen | ❌ Neue Sitzung jedes Mal | ✅ Behält Konversation bei |
| Anwendungsfall | Einmalige Aufgaben | Kontinuierliche Konversationen |
query() verwendet werden sollte (Neue Sitzung jedes Mal)Am besten für:
ClaudeSDKClient verwendet werden sollte (Kontinuierliche Konversation)Am besten für:
query()Erstellt eine neue Sitzung für jede Interaktion mit Claude Code. Gibt einen asynchronen Iterator zurück, der Nachrichten bei ihrer Ankunft liefert. Jeder Aufruf von query() beginnt neu ohne Erinnerung an vorherige Interaktionen.
async def query(
*,
prompt: str | AsyncIterable[dict[str, Any]],
options: ClaudeAgentOptions | None = None
) -> AsyncIterator[Message]| Parameter | Typ | Beschreibung |
|---|---|---|
prompt | str | AsyncIterable[dict] | Die Eingabeaufforderung als Zeichenkette oder asynchroner Iterator für den Streaming-Modus |
options | ClaudeAgentOptions | None | Optionales Konfigurationsobjekt (standardmäßig ClaudeAgentOptions(), wenn None) |
Gibt einen AsyncIterator[Message] zurück, der Nachrichten aus der Konversation liefert.
import asyncio
from claude_agent_sdk import query, ClaudeAgentOptions
async def main():
options = ClaudeAgentOptions(
system_prompt="You are an expert Python developer",
permission_mode='acceptEdits',
cwd="/home/user/project"
)
async for message in query(
prompt="Create a Python web server",
options=options
):
print(message)
asyncio.run(main())tool()Dekorator zum Definieren von MCP-Tools mit Typsicherheit.
def tool(
name: str,
description: str,
input_schema: type | dict[str, Any]
) -> Callable[[Callable[[Any], Awaitable[dict[str, Any]]]], SdkMcpTool[Any]]| Parameter | Typ | Beschreibung |
|---|---|---|
name | str | Eindeutige Kennung für das Tool |
description | str | Benutzerfreundliche Beschreibung der Funktion des Tools |
input_schema | type | dict[str, Any] | Schema, das die Eingabeparameter des Tools definiert (siehe unten) |
Einfache Typ-Zuordnung (empfohlen):
{"text": str, "count": int, "enabled": bool}JSON-Schema-Format (für komplexe Validierung):
{
"type": "object",
"properties": {
"text": {"type": "string"},
"count": {"type": "integer", "minimum": 0}
},
"required": ["text"]
}Eine Dekoratorfunktion, die die Tool-Implementierung umhüllt und eine SdkMcpTool-Instanz zurückgibt.
from claude_agent_sdk import tool
from typing import Any
@tool("greet", "Greet a user", {"name": str})
async def greet(args: dict[str, Any]) -> dict[str, Any]:
return {
"content": [{
"type": "text",
"text": f"Hello, {args['name']}!"
}]
}create_sdk_mcp_server()Erstellen Sie einen In-Process-MCP-Server, der in Ihrer Python-Anwendung ausgeführt wird.
def create_sdk_mcp_server(
name: str,
version: str = "1.0.0",
tools: list[SdkMcpTool[Any]] | None = None
) -> McpSdkServerConfig| Parameter | Typ | Standard | Beschreibung |
|---|---|---|---|
name | str | - | Eindeutige Kennung für den Server |
version | str | "1.0.0" | Versionsnummer des Servers |
tools | list[SdkMcpTool[Any]] | None | None | Liste von Tool-Funktionen, die mit dem @tool-Dekorator erstellt wurden |
Gibt ein McpSdkServerConfig-Objekt zurück, das an ClaudeAgentOptions.mcp_servers übergeben werden kann.
from claude_agent_sdk import tool, create_sdk_mcp_server
@tool("add", "Add two numbers", {"a": float, "b": float})
async def add(args):
return {
"content": [{
"type": "text",
"text": f"Sum: {args['a'] + args['b']}"
}]
}
@tool("multiply", "Multiply two numbers", {"a": float, "b": float})
async def multiply(args):
return {
"content": [{
"type": "text",
"text": f"Product: {args['a'] * args['b']}"
}]
}
calculator = create_sdk_mcp_server(
name="calculator",
version="2.0.0",
tools=[add, multiply] # Pass decorated functions
)
# Use with Claude
options = ClaudeAgentOptions(
mcp_servers={"calc": calculator},
allowed_tools=["mcp__calc__add", "mcp__calc__multiply"]
)ClaudeSDKClientBehält eine Konversationssitzung über mehrere Austausche hinweg bei. Dies ist das Python-Äquivalent dazu, wie die query()-Funktion des TypeScript SDK intern funktioniert - sie erstellt ein Client-Objekt, das Konversationen fortsetzen kann.
query()-Aufrufe hinweg bei@tool-Dekorator) und Hooksclass ClaudeSDKClient:
def __init__(self, options: ClaudeAgentOptions | None = None)
async def connect(self, prompt: str | AsyncIterable[dict] | None = None) -> None
async def query(self, prompt: str | AsyncIterable[dict], session_id: str = "default") -> None
async def receive_messages(self) -> AsyncIterator[Message]
async def receive_response(self) -> AsyncIterator[Message]
async def interrupt(self) -> None
async def rewind_files(self, user_message_uuid: str) -> None
async def disconnect(self) -> None| Methode | Beschreibung |
|---|---|
__init__(options) | Initialisieren Sie den Client mit optionaler Konfiguration |
connect(prompt) | Verbinden Sie sich mit Claude mit einer optionalen anfänglichen Aufforderung oder einem Nachrichtenstrom |
query(prompt, session_id) | Senden Sie eine neue Anfrage im Streaming-Modus |
receive_messages() | Empfangen Sie alle Nachrichten von Claude als asynchronen Iterator |
receive_response() | Empfangen Sie Nachrichten bis einschließlich einer ResultMessage |
interrupt() | Senden Sie ein Unterbrechungssignal (funktioniert nur im Streaming-Modus) |
rewind_files(user_message_uuid) | Stellen Sie Dateien in ihren Zustand bei der angegebenen Benutzernachricht wieder her. Erfordert enable_file_checkpointing=True. Siehe Datei-Checkpointing |
disconnect() | Trennen Sie die Verbindung zu Claude |
Der Client kann als asynchroner Context Manager für automatische Verbindungsverwaltung verwendet werden:
async with ClaudeSDKClient() as client:
await client.query("Hello Claude")
async for message in client.receive_response():
print(message)Wichtig: Vermeiden Sie bei der Iteration über Nachrichten die Verwendung von
breakzum vorzeitigen Beenden, da dies zu asyncio-Bereinigungsproblemen führen kann. Lassen Sie die Iteration stattdessen natürlich abschließen oder verwenden Sie Flags, um zu verfolgen, wann Sie gefunden haben, was Sie brauchen.
import asyncio
from claude_agent_sdk import ClaudeSDKClient, AssistantMessage, TextBlock, ResultMessage
async def main():
async with ClaudeSDKClient() as client:
# First question
await client.query("What's the capital of France?")
# Process response
async for message in client.receive_response():
if isinstance(message, AssistantMessage):
for block in message.content:
if isinstance(block, TextBlock):
print(f"Claude: {block.text}")
# Follow-up question - Claude remembers the previous context
await client.query("What's the population of that city?")
async for message in client.receive_response():
if isinstance(message, AssistantMessage):
for block in message.content:
if isinstance(block, TextBlock):
print(f"Claude: {block.text}")
# Another follow-up - still in the same conversation
await client.query("What are some famous landmarks there?")
async for message in client.receive_response():
if isinstance(message, AssistantMessage):
for block in message.content:
if isinstance(block, TextBlock):
print(f"Claude: {block.text}")
asyncio.run(main())import asyncio
from claude_agent_sdk import ClaudeSDKClient
async def message_stream():
"""Generate messages dynamically."""
yield {"type": "text", "text": "Analyze the following data:"}
await asyncio.sleep(0.5)
yield {"type": "text", "text": "Temperature: 25°C"}
await asyncio.sleep(0.5)
yield {"type": "text", "text": "Humidity: 60%"}
await asyncio.sleep(0.5)
yield {"type": "text", "text": "What patterns do you see?"}
async def main():
async with ClaudeSDKClient() as client:
# Stream input to Claude
await client.query(message_stream())
# Process response
async for message in client.receive_response():
print(message)
# Follow-up in same session
await client.query("Should we be concerned about these readings?")
async for message in client.receive_response():
print(message)
asyncio.run(main())import asyncio
from claude_agent_sdk import ClaudeSDKClient, ClaudeAgentOptions
async def interruptible_task():
options = ClaudeAgentOptions(
allowed_tools=["Bash"],
permission_mode="acceptEdits"
)
async with ClaudeSDKClient(options=options) as client:
# Start a long-running task
await client.query("Count from 1 to 100 slowly")
# Let it run for a bit
await asyncio.sleep(2)
# Interrupt the task
await client.interrupt()
print("Task interrupted!")
# Send a new command
await client.query("Just say hello instead")
async for message in client.receive_response():
# Process the new response
pass
asyncio.run(interruptible_task())from claude_agent_sdk import (
ClaudeSDKClient,
ClaudeAgentOptions
)
async def custom_permission_handler(
tool_name: str,
input_data: dict,
context: dict
):
"""Custom logic for tool permissions."""
# Block writes to system directories
if tool_name == "Write" and input_data.get("file_path", "").startswith("/system/"):
return {
"behavior": "deny",
"message": "System directory write not allowed",
"interrupt": True
}
# Redirect sensitive file operations
if tool_name in ["Write", "Edit"] and "config" in input_data.get("file_path", ""):
safe_path = f"./sandbox/{input_data['file_path']}"
return {
"behavior": "allow",
"updatedInput": {**input_data, "file_path": safe_path}
}
# Allow everything else
return {
"behavior": "allow",
"updatedInput": input_data
}
async def main():
options = ClaudeAgentOptions(
can_use_tool=custom_permission_handler,
allowed_tools=["Read", "Write", "Edit"]
)
async with ClaudeSDKClient(options=options) as client:
await client.query("Update the system config file")
async for message in client.receive_response():
# Will use sandbox path instead
print(message)
asyncio.run(main())SdkMcpToolDefinition für ein SDK MCP-Tool, das mit dem @tool-Dekorator erstellt wurde.
@dataclass
class SdkMcpTool(Generic[T]):
name: str
description: str
input_schema: type[T] | dict[str, Any]
handler: Callable[[T], Awaitable[dict[str, Any]]]| Eigenschaft | Typ | Beschreibung |
|---|---|---|
name | str | Eindeutige Kennung für das Tool |
description | str | Benutzerfreundliche Beschreibung |
input_schema | type[T] | dict[str, Any] | Schema für Eingabevalidierung |
handler | Callable[[T], Awaitable[dict[str, Any]]] | Asynchrone Funktion, die die Tool-Ausführung handhabt |
ClaudeAgentOptionsKonfigurationsdatenklasse für Claude Code-Abfragen.
@dataclass
class ClaudeAgentOptions:
allowed_tools: list[str] = field(default_factory=list)
system_prompt: str | SystemPromptPreset | 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
disallowed_tools: list[str] = field(default_factory=list)
model: str | None = None
output_format: OutputFormat | None = None
permission_prompt_tool_name: str | None = None
cwd: str | Path | None = None
settings: str | None = None
add_dirs: list[str | Path] = field(default_factory=list)
env: dict[str, str] = field(default_factory=dict)
extra_args: dict[str, str | None] = field(default_factory=dict)
max_buffer_size: int | None = None
debug_stderr: Any = sys.stderr # Deprecated
stderr: Callable[[str], None] | None = None
can_use_tool: CanUseTool | None = None
hooks: dict[HookEvent, list[HookMatcher]] | None = None
user: str | None = None
include_partial_messages: bool = False
fork_session: bool = False
agents: dict[str, AgentDefinition] | None = None
setting_sources: list[SettingSource] | None = None| Eigenschaft | Typ | Standard | Beschreibung |
|---|---|---|---|
allowed_tools | list[str] | [] | Liste der zulässigen Tool-Namen |
system_prompt | str | SystemPromptPreset | None | None | Systemanfrage-Konfiguration. Übergeben Sie eine Zeichenkette für eine benutzerdefinierte Aufforderung oder verwenden Sie {"type": "preset", "preset": "claude_code"} für die Systemanfrage von Claude Code. Fügen Sie "append" hinzu, um die Voreinstellung zu erweitern |
mcp_servers | dict[str, McpServerConfig] | str | Path | {} | MCP-Serverkonfigurationen oder Pfad zur Konfigurationsdatei |
permission_mode | PermissionMode | None | None | Berechtigungsmodus für die Tool-Nutzung |
continue_conversation | bool | False | Setzen Sie die neueste Konversation fort |
resume | str | None | None | Sitzungs-ID zum Fortsetzen |
max_turns | int | None | None | Maximale Konversationsdrehungen |
disallowed_tools | list[str] | [] | Liste der nicht zulässigen Tool-Namen |
enable_file_checkpointing | bool | False | Aktivieren Sie die Dateienänderungsverfolgung zum Zurückspulen. Siehe Datei-Checkpointing |
model | str | None | None | Zu verwendendes Claude-Modell |
output_format | OutputFormat | None | None | Definieren Sie das Ausgabeformat für Agent-Ergebnisse. Siehe Strukturierte Ausgaben für Details |
permission_prompt_tool_name | str | None | None | MCP-Tool-Name für Berechtigungsaufforderungen |
cwd | str | Path | None | None | Aktuelles Arbeitsverzeichnis |
settings | str | None | None | Pfad zur Einstellungsdatei |
add_dirs | list[str | Path] | [] | Zusätzliche Verzeichnisse, auf die Claude zugreifen kann |
env | dict[str, str] | {} | Umgebungsvariablen |
extra_args | dict[str, str | None] | {} | Zusätzliche CLI-Argumente, die direkt an die CLI übergeben werden |
max_buffer_size | int | None | None | Maximale Bytes beim Puffern der CLI-Standardausgabe |
debug_stderr | Any | sys.stderr | Veraltet - Dateiähnliches Objekt für Debug-Ausgabe. Verwenden Sie stattdessen den stderr-Callback |
stderr | Callable[[str], None] | None | None | Callback-Funktion für stderr-Ausgabe aus der CLI |
can_use_tool | CanUseTool | None | None | Tool-Berechtigungs-Callback-Funktion |
hooks | dict[HookEvent, list[HookMatcher]] | None | None | Hook-Konfigurationen zum Abfangen von Ereignissen |
user | str | None | None | Benutzerkennung |
include_partial_messages | bool | False | Schließen Sie Streaming-Ereignisse für Teilnachrichten ein |
fork_session | bool | False | Beim Fortsetzen mit resume zu einer neuen Sitzungs-ID verzweigen, anstatt die ursprüngliche Sitzung fortzusetzen |
agents | dict[str, AgentDefinition] | None | None | Programmgesteuert definierte Subagenten |
plugins | list[SdkPluginConfig] | [] | Laden Sie benutzerdefinierte Plugins aus lokalen Pfaden. Siehe Plugins für Details |
sandbox | SandboxSettings | None | None | Konfigurieren Sie das Sandbox-Verhalten programmgesteuert. Siehe Sandbox-Einstellungen für Details |
setting_sources | list[SettingSource] | None | None (keine Einstellungen) | Kontrollieren Sie, welche Dateisystem-Einstellungen geladen werden. Wenn weggelassen, werden keine Einstellungen geladen. Hinweis: Muss "project" enthalten, um CLAUDE.md-Dateien zu laden |
OutputFormatKonfiguration für die Validierung strukturierter Ausgaben.
class OutputFormat(TypedDict):
type: Literal["json_schema"]
schema: dict[str, Any]| Feld | Erforderlich | Beschreibung |
|---|---|---|
type | Ja | Muss "json_schema" für JSON-Schema-Validierung sein |
schema | Ja | JSON-Schema-Definition für Ausgabevalidierung |
SystemPromptPresetKonfiguration für die Verwendung der Systemanfrage-Voreinstellung von Claude Code mit optionalen Ergänzungen.
class SystemPromptPreset(TypedDict):
type: Literal["preset"]
preset: Literal["claude_code"]
append: NotRequired[str]| Feld | Erforderlich | Beschreibung |
|---|---|---|
type | Ja | Muss "preset" sein, um eine Systemanfrage-Voreinstellung zu verwenden |
preset | Ja | Muss "claude_code" sein, um die Systemanfrage von Claude Code zu verwenden |
append | Nein | Zusätzliche Anweisungen, die an die Systemanfrage-Voreinstellung angehängt werden |
SettingSourceKontrolliert, welche dateisystembasierte Konfigurationsquellen das SDK lädt.
SettingSource = Literal["user", "project", "local"]| Wert | Beschreibung | Ort |
|---|---|---|
"user" | Globale Benutzereinstellungen | ~/.claude/settings.json |
"project" | Gemeinsame Projekteinstellungen (versionskontrolliert) | .claude/settings.json |
"local" | Lokale Projekteinstellungen (gitignoriert) | .claude/settings.local.json |
Wenn setting_sources weggelassen oder None ist, lädt das SDK keine Dateisystem-Einstellungen. Dies bietet Isolation für SDK-Anwendungen.
Laden Sie alle Dateisystem-Einstellungen (Legacy-Verhalten):
# Load all settings like SDK v0.0.x did
from claude_agent_sdk import query, ClaudeAgentOptions
async for message in query(
prompt="Analyze this code",
options=ClaudeAgentOptions(
setting_sources=["user", "project", "local"] # Load all settings
)
):
print(message)Laden Sie nur bestimmte Einstellungsquellen:
# Load only project settings, ignore user and local
async for message in query(
prompt="Run CI checks",
options=ClaudeAgentOptions(
setting_sources=["project"] # Only .claude/settings.json
)
):
print(message)Test- und CI-Umgebungen:
# Ensure consistent behavior in CI by excluding local settings
async for message in query(
prompt="Run tests",
options=ClaudeAgentOptions(
setting_sources=["project"], # Only team-shared settings
permission_mode="bypassPermissions"
)
):
print(message)SDK-only-Anwendungen:
# Define everything programmatically (default behavior)
# No filesystem dependencies - setting_sources defaults to None
async for message in query(
prompt="Review this PR",
options=ClaudeAgentOptions(
# setting_sources=None is the default, no need to specify
agents={ /* ... */ },
mcp_servers={ /* ... */ },
allowed_tools=["Read", "Grep", "Glob"]
)
):
print(message)Laden von CLAUDE.md-Projektanweisungen:
# Load project settings to include CLAUDE.md files
async for message in query(
prompt="Add a new feature following project conventions",
options=ClaudeAgentOptions(
system_prompt={
"type": "preset",
"preset": "claude_code" # Use Claude Code's system prompt
},
setting_sources=["project"], # Required to load CLAUDE.md from project
allowed_tools=["Read", "Write", "Edit"]
)
):
print(message)Wenn mehrere Quellen geladen werden, werden Einstellungen mit dieser Priorität zusammengeführt (höchste bis niedrigste):
.claude/settings.local.json).claude/settings.json)~/.claude/settings.json)Programmgesteuerte Optionen (wie agents, allowed_tools) überschreiben immer Dateisystem-Einstellungen.
AgentDefinitionKonfiguration für einen programmgesteuert definierten Subagenten.
@dataclass
class AgentDefinition:
description: str
prompt: str
tools: list[str] | None = None
model: Literal["sonnet", "opus", "haiku", "inherit"] | None = None| Feld | Erforderlich | Beschreibung |
|---|---|---|
description | Ja | Natürlichsprachige Beschreibung, wann dieser Agent verwendet werden sollte |
tools | Nein | Array von zulässigen Tool-Namen. Wenn weggelassen, erbt alle Tools |
prompt | Ja | Die Systemanfrage des Agenten |
model | Nein | Modellüberschreibung für diesen Agenten. Wenn weggelassen, verwendet das Hauptmodell |
PermissionModeBerechtigungsmodi zur Kontrolle der Tool-Ausführung.
PermissionMode = Literal[
"default", # Standard permission behavior
"acceptEdits", # Auto-accept file edits
"plan", # Planning mode - no execution
"bypassPermissions" # Bypass all permission checks (use with caution)
]McpSdkServerConfigKonfiguration für SDK MCP-Server, die mit create_sdk_mcp_server() erstellt wurden.
class McpSdkServerConfig(TypedDict):
type: Literal["sdk"]
name: str
instance: Any # MCP Server instanceMcpServerConfigUnion-Typ für MCP-Serverkonfigurationen.
McpServerConfig = McpStdioServerConfig | McpSSEServerConfig | McpHttpServerConfig | McpSdkServerConfigMcpStdioServerConfigclass McpStdioServerConfig(TypedDict):
type: NotRequired[Literal["stdio"]] # Optional for backwards compatibility
command: str
args: NotRequired[list[str]]
env: NotRequired[dict[str, str]]McpSSEServerConfigclass McpSSEServerConfig(TypedDict):
type: Literal["sse"]
url: str
headers: NotRequired[dict[str, str]]McpHttpServerConfigclass McpHttpServerConfig(TypedDict):
type: Literal["http"]
url: str
headers: NotRequired[dict[str, str]]SdkPluginConfigKonfiguration zum Laden von Plugins im SDK.
class SdkPluginConfig(TypedDict):
type: Literal["local"]
path: str| Feld | Typ | Beschreibung |
|---|---|---|
type | Literal["local"] | Muss "local" sein (derzeit werden nur lokale Plugins unterstützt) |
path | str | Absoluter oder relativer Pfad zum Plugin-Verzeichnis |
Beispiel:
plugins=[
{"type": "local", "path": "./my-plugin"},
{"type": "local", "path": "/absolute/path/to/plugin"}
]Vollständige Informationen zum Erstellen und Verwenden von Plugins finden Sie unter Plugins.
MessageUnion-Typ aller möglichen Nachrichten.
Message = UserMessage | AssistantMessage | SystemMessage | ResultMessageUserMessageBenutzereingabe-Nachricht.
@dataclass
class UserMessage:
content: str | list[ContentBlock]AssistantMessageAssistent-Antwortnachricht mit Inhaltsblöcken.
@dataclass
class AssistantMessage:
content: list[ContentBlock]
model: strSystemMessageSystemnachricht mit Metadaten.
@dataclass
class SystemMessage:
subtype: str
data: dict[str, Any]ResultMessageEndgültige Ergebnismeldung mit Kosten- und Nutzungsinformationen.
@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 = NoneContentBlockUnion-Typ aller Inhaltsblöcke.
ContentBlock = TextBlock | ThinkingBlock | ToolUseBlock | ToolResultBlockTextBlockTextinhaltsblock.
@dataclass
class TextBlock:
text: strThinkingBlockThinking-Inhaltsblock (für Modelle mit Thinking-Fähigkeit).
@dataclass
class ThinkingBlock:
thinking: str
signature: strToolUseBlockTool-Nutzungsanforderungsblock.
@dataclass
class ToolUseBlock:
id: str
name: str
input: dict[str, Any]ToolResultBlockTool-Ausführungsergebnisblock.
@dataclass
class ToolResultBlock:
tool_use_id: str
content: str | list[dict[str, Any]] | None = None
is_error: bool | None = NoneClaudeSDKErrorBasis-Ausnahmeklasse für alle SDK-Fehler.
class ClaudeSDKError(Exception):
"""Base error for Claude SDK."""CLINotFoundErrorWird ausgelöst, wenn Claude Code CLI nicht installiert oder nicht gefunden ist.
class CLINotFoundError(CLIConnectionError):
def __init__(self, message: str = "Claude Code not found", cli_path: str | None = None):
"""
Args:
message: Error message (default: "Claude Code not found")
cli_path: Optional path to the CLI that was not found
"""CLIConnectionErrorWird ausgelöst, wenn die Verbindung zu Claude Code fehlschlägt.
class CLIConnectionError(ClaudeSDKError):
"""Failed to connect to Claude Code."""ProcessErrorWird ausgelöst, wenn der Claude Code-Prozess fehlschlägt.
class ProcessError(ClaudeSDKError):
def __init__(self, message: str, exit_code: int | None = None, stderr: str | None = None):
self.exit_code = exit_code
self.stderr = stderrCLIJSONDecodeErrorWird ausgelöst, wenn das JSON-Parsing fehlschlägt.
class CLIJSONDecodeError(ClaudeSDKError):
def __init__(self, line: str, original_error: Exception):
"""
Args:
line: The line that failed to parse
original_error: The original JSON decode exception
"""
self.line = line
self.original_error = original_errorEinen umfassenden Leitfaden zur Verwendung von Hooks mit Beispielen und häufigen Mustern finden Sie im Hooks-Leitfaden.
HookEventUnterstützte Hook-Ereignistypen. Beachten Sie, dass das Python SDK aufgrund von Setup-Einschränkungen SessionStart-, SessionEnd- und Notification-Hooks nicht unterstützt.
HookEvent = Literal[
"PreToolUse", # Called before tool execution
"PostToolUse", # Called after tool execution
"UserPromptSubmit", # Called when user submits a prompt
"Stop", # Called when stopping execution
"SubagentStop", # Called when a subagent stops
"PreCompact" # Called before message compaction
]HookCallbackTypdefinition für Hook-Callback-Funktionen.
HookCallback = Callable[
[dict[str, Any], str | None, HookContext],
Awaitable[dict[str, Any]]
]Parameter:
input_data: Hook-spezifische Eingabedaten (siehe Hooks-Leitfaden)tool_use_id: Optionale Tool-Use-Kennung (für Tool-bezogene Hooks)context: Hook-Kontext mit zusätzlichen InformationenGibt ein Wörterbuch zurück, das möglicherweise Folgendes enthält:
decision: "block" zum Blockieren der AktionsystemMessage: Systemmeldung zum Hinzufügen zum TranskripthookSpecificOutput: Hook-spezifische AusgabedatenHookContextKontextinformationen, die an Hook-Callbacks übergeben werden.
@dataclass
class HookContext:
signal: Any | None = None # Future: abort signal supportHookMatcherKonfiguration zum Abgleichen von Hooks mit bestimmten Ereignissen oder Tools.
@dataclass
class HookMatcher:
matcher: str | None = None # Tool name or pattern to match (e.g., "Bash", "Write|Edit")
hooks: list[HookCallback] = field(default_factory=list) # List of callbacks to execute
timeout: float | None = None # Timeout in seconds for all hooks in this matcher (default: 60)Dieses Beispiel registriert zwei Hooks: einen, der gefährliche Bash-Befehle wie rm -rf / blockiert, und einen anderen, der alle Tool-Nutzungen für Audits protokolliert. Der Sicherheits-Hook wird nur auf Bash-Befehle ausgeführt (über den matcher), während der Logging-Hook auf alle Tools angewendet wird.
from claude_agent_sdk import query, ClaudeAgentOptions, HookMatcher, HookContext
from typing import Any
async def validate_bash_command(
input_data: dict[str, Any],
tool_use_id: str | None,
context: HookContext
) -> dict[str, Any]:
"""Validate and potentially block dangerous bash commands."""
if input_data['tool_name'] == 'Bash':
command = input_data['tool_input'].get('command', '')
if 'rm -rf /' in command:
return {
'hookSpecificOutput': {
'hookEventName': 'PreToolUse',
'permissionDecision': 'deny',
'permissionDecisionReason': 'Dangerous command blocked'
}
}
return {}
async def log_tool_use(
input_data: dict[str, Any],
tool_use_id: str | None,
context: HookContext
) -> dict[str, Any]:
"""Log all tool usage for auditing."""
print(f"Tool used: {input_data.get('tool_name')}")
return {}
options = ClaudeAgentOptions(
hooks={
'PreToolUse': [
HookMatcher(matcher='Bash', hooks=[validate_bash_command], timeout=120), # 2 min for validation
HookMatcher(hooks=[log_tool_use]) # Applies to all tools (default 60s timeout)
],
'PostToolUse': [
HookMatcher(hooks=[log_tool_use])
]
}
)
async for message in query(
prompt="Analyze this codebase",
options=options
):
print(message)Dokumentation von Input-/Output-Schemata für alle integrierten Claude Code-Tools. Obwohl das Python SDK diese nicht als Typen exportiert, stellen sie die Struktur von Tool-Eingaben und -Ausgaben in Meldungen dar.
Tool-Name: Task
Eingabe:
{
"description": str, # A short (3-5 word) description of the task
"prompt": str, # The task for the agent to perform
"subagent_type": str # The type of specialized agent to use
}Ausgabe:
{
"result": str, # Final result from the subagent
"usage": dict | None, # Token usage statistics
"total_cost_usd": float | None, # Total cost in USD
"duration_ms": int | None # Execution duration in milliseconds
}Tool-Name: Bash
Eingabe:
{
"command": str, # The command to execute
"timeout": int | None, # Optional timeout in milliseconds (max 600000)
"description": str | None, # Clear, concise description (5-10 words)
"run_in_background": bool | None # Set to true to run in background
}Ausgabe:
{
"output": str, # Combined stdout and stderr output
"exitCode": int, # Exit code of the command
"killed": bool | None, # Whether command was killed due to timeout
"shellId": str | None # Shell ID for background processes
}Tool-Name: Edit
Eingabe:
{
"file_path": str, # The absolute path to the file to modify
"old_string": str, # The text to replace
"new_string": str, # The text to replace it with
"replace_all": bool | None # Replace all occurrences (default False)
}Ausgabe:
{
"message": str, # Confirmation message
"replacements": int, # Number of replacements made
"file_path": str # File path that was edited
}Tool-Name: Read
Eingabe:
{
"file_path": str, # The absolute path to the file to read
"offset": int | None, # The line number to start reading from
"limit": int | None # The number of lines to read
}Ausgabe (Textdateien):
{
"content": str, # File contents with line numbers
"total_lines": int, # Total number of lines in file
"lines_returned": int # Lines actually returned
}Ausgabe (Bilder):
{
"image": str, # Base64 encoded image data
"mime_type": str, # Image MIME type
"file_size": int # File size in bytes
}Tool-Name: Write
Eingabe:
{
"file_path": str, # The absolute path to the file to write
"content": str # The content to write to the file
}Ausgabe:
{
"message": str, # Success message
"bytes_written": int, # Number of bytes written
"file_path": str # File path that was written
}Tool-Name: Glob
Eingabe:
{
"pattern": str, # The glob pattern to match files against
"path": str | None # The directory to search in (defaults to cwd)
}Ausgabe:
{
"matches": list[str], # Array of matching file paths
"count": int, # Number of matches found
"search_path": str # Search directory used
}Tool-Name: Grep
Eingabe:
{
"pattern": str, # The regular expression pattern
"path": str | None, # File or directory to search in
"glob": str | None, # Glob pattern to filter files
"type": str | None, # File type to search
"output_mode": str | None, # "content", "files_with_matches", or "count"
"-i": bool | None, # Case insensitive search
"-n": bool | None, # Show line numbers
"-B": int | None, # Lines to show before each match
"-A": int | None, # Lines to show after each match
"-C": int | None, # Lines to show before and after
"head_limit": int | None, # Limit output to first N lines/entries
"multiline": bool | None # Enable multiline mode
}Ausgabe (Content-Modus):
{
"matches": [
{
"file": str,
"line_number": int | None,
"line": str,
"before_context": list[str] | None,
"after_context": list[str] | None
}
],
"total_matches": int
}Ausgabe (files_with_matches-Modus):
{
"files": list[str], # Files containing matches
"count": int # Number of files with matches
}Tool-Name: NotebookEdit
Eingabe:
{
"notebook_path": str, # Absolute path to the Jupyter notebook
"cell_id": str | None, # The ID of the cell to edit
"new_source": str, # The new source for the cell
"cell_type": "code" | "markdown" | None, # The type of the cell
"edit_mode": "replace" | "insert" | "delete" | None # Edit operation type
}Ausgabe:
{
"message": str, # Success message
"edit_type": "replaced" | "inserted" | "deleted", # Type of edit performed
"cell_id": str | None, # Cell ID that was affected
"total_cells": int # Total cells in notebook after edit
}Tool-Name: WebFetch
Eingabe:
{
"url": str, # The URL to fetch content from
"prompt": str # The prompt to run on the fetched content
}Ausgabe:
{
"response": str, # AI model's response to the prompt
"url": str, # URL that was fetched
"final_url": str | None, # Final URL after redirects
"status_code": int | None # HTTP status code
}Tool-Name: WebSearch
Eingabe:
{
"query": str, # The search query to use
"allowed_domains": list[str] | None, # Only include results from these domains
"blocked_domains": list[str] | None # Never include results from these domains
}Ausgabe:
{
"results": [
{
"title": str,
"url": str,
"snippet": str,
"metadata": dict | None
}
],
"total_results": int,
"query": str
}Tool-Name: TodoWrite
Eingabe:
{
"todos": [
{
"content": str, # The task description
"status": "pending" | "in_progress" | "completed", # Task status
"activeForm": str # Active form of the description
}
]
}Ausgabe:
{
"message": str, # Success message
"stats": {
"total": int,
"pending": int,
"in_progress": int,
"completed": int
}
}Tool-Name: BashOutput
Eingabe:
{
"bash_id": str, # The ID of the background shell
"filter": str | None # Optional regex to filter output lines
}Ausgabe:
{
"output": str, # New output since last check
"status": "running" | "completed" | "failed", # Current shell status
"exitCode": int | None # Exit code when completed
}Tool-Name: KillBash
Eingabe:
{
"shell_id": str # The ID of the background shell to kill
}Ausgabe:
{
"message": str, # Success message
"shell_id": str # ID of the killed shell
}Tool-Name: ExitPlanMode
Eingabe:
{
"plan": str # The plan to run by the user for approval
}Ausgabe:
{
"message": str, # Confirmation message
"approved": bool | None # Whether user approved the plan
}Tool-Name: ListMcpResources
Eingabe:
{
"server": str | None # Optional server name to filter resources by
}Ausgabe:
{
"resources": [
{
"uri": str,
"name": str,
"description": str | None,
"mimeType": str | None,
"server": str
}
],
"total": int
}Tool-Name: ReadMcpResource
Eingabe:
{
"server": str, # The MCP server name
"uri": str # The resource URI to read
}Ausgabe:
{
"contents": [
{
"uri": str,
"mimeType": str | None,
"text": str | None,
"blob": str | None
}
],
"server": str
}from claude_agent_sdk import ClaudeSDKClient, ClaudeAgentOptions, AssistantMessage, TextBlock
import asyncio
class ConversationSession:
"""Maintains a single conversation session with Claude."""
def __init__(self, options: ClaudeAgentOptions = None):
self.client = ClaudeSDKClient(options)
self.turn_count = 0
async def start(self):
await self.client.connect()
print("Starting conversation session. Claude will remember context.")
print("Commands: 'exit' to quit, 'interrupt' to stop current task, 'new' for new session")
while True:
user_input = input(f"\n[Turn {self.turn_count + 1}] You: ")
if user_input.lower() == 'exit':
break
elif user_input.lower() == 'interrupt':
await self.client.interrupt()
print("Task interrupted!")
continue
elif user_input.lower() == 'new':
# Disconnect and reconnect for a fresh session
await self.client.disconnect()
await self.client.connect()
self.turn_count = 0
print("Started new conversation session (previous context cleared)")
continue
# Send message - Claude remembers all previous messages in this session
await self.client.query(user_input)
self.turn_count += 1
# Process response
print(f"[Turn {self.turn_count}] Claude: ", end="")
async for message in self.client.receive_response():
if isinstance(message, AssistantMessage):
for block in message.content:
if isinstance(block, TextBlock):
print(block.text, end="")
print() # New line after response
await self.client.disconnect()
print(f"Conversation ended after {self.turn_count} turns.")
async def main():
options = ClaudeAgentOptions(
allowed_tools=["Read", "Write", "Bash"],
permission_mode="acceptEdits"
)
session = ConversationSession(options)
await session.start()
# Example conversation:
# Turn 1 - You: "Create a file called hello.py"
# Turn 1 - Claude: "I'll create a hello.py file for you..."
# Turn 2 - You: "What's in that file?"
# Turn 2 - Claude: "The hello.py file I just created contains..." (remembers!)
# Turn 3 - You: "Add a main function to it"
# Turn 3 - Claude: "I'll add a main function to hello.py..." (knows which file!)
asyncio.run(main())from claude_agent_sdk import (
ClaudeSDKClient,
ClaudeAgentOptions,
HookMatcher,
HookContext
)
import asyncio
from typing import Any
async def pre_tool_logger(
input_data: dict[str, Any],
tool_use_id: str | None,
context: HookContext
) -> dict[str, Any]:
"""Log all tool usage before execution."""
tool_name = input_data.get('tool_name', 'unknown')
print(f"[PRE-TOOL] About to use: {tool_name}")
# You can modify or block the tool execution here
if tool_name == "Bash" and "rm -rf" in str(input_data.get('tool_input', {})):
return {
'hookSpecificOutput': {
'hookEventName': 'PreToolUse',
'permissionDecision': 'deny',
'permissionDecisionReason': 'Dangerous command blocked'
}
}
return {}
async def post_tool_logger(
input_data: dict[str, Any],
tool_use_id: str | None,
context: HookContext
) -> dict[str, Any]:
"""Log results after tool execution."""
tool_name = input_data.get('tool_name', 'unknown')
print(f"[POST-TOOL] Completed: {tool_name}")
return {}
async def user_prompt_modifier(
input_data: dict[str, Any],
tool_use_id: str | None,
context: HookContext
) -> dict[str, Any]:
"""Add context to user prompts."""
original_prompt = input_data.get('prompt', '')
# Add timestamp to all prompts
from datetime import datetime
timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
return {
'hookSpecificOutput': {
'hookEventName': 'UserPromptSubmit',
'updatedPrompt': f"[{timestamp}] {original_prompt}"
}
}
async def main():
options = ClaudeAgentOptions(
hooks={
'PreToolUse': [
HookMatcher(hooks=[pre_tool_logger]),
HookMatcher(matcher='Bash', hooks=[pre_tool_logger])
],
'PostToolUse': [
HookMatcher(hooks=[post_tool_logger])
],
'UserPromptSubmit': [
HookMatcher(hooks=[user_prompt_modifier])
]
},
allowed_tools=["Read", "Write", "Bash"]
)
async with ClaudeSDKClient(options=options) as client:
await client.query("List files in current directory")
async for message in client.receive_response():
# Hooks will automatically log tool usage
pass
asyncio.run(main())from claude_agent_sdk import (
ClaudeSDKClient,
ClaudeAgentOptions,
AssistantMessage,
ToolUseBlock,
ToolResultBlock,
TextBlock
)
import asyncio
async def monitor_progress():
options = ClaudeAgentOptions(
allowed_tools=["Write", "Bash"],
permission_mode="acceptEdits"
)
async with ClaudeSDKClient(options=options) as client:
await client.query(
"Create 5 Python files with different sorting algorithms"
)
# Monitor progress in real-time
files_created = []
async for message in client.receive_messages():
if isinstance(message, AssistantMessage):
for block in message.content:
if isinstance(block, ToolUseBlock):
if block.name == "Write":
file_path = block.input.get("file_path", "")
print(f"🔨 Creating: {file_path}")
elif isinstance(block, ToolResultBlock):
print(f"✅ Completed tool execution")
elif isinstance(block, TextBlock):
print(f"💭 Claude says: {block.text[:100]}...")
# Check if we've received the final result
if hasattr(message, 'subtype') and message.subtype in ['success', 'error']:
print(f"\n🎯 Task completed!")
break
asyncio.run(monitor_progress())from claude_agent_sdk import query, ClaudeAgentOptions, AssistantMessage, ToolUseBlock
import asyncio
async def create_project():
options = ClaudeAgentOptions(
allowed_tools=["Read", "Write", "Bash"],
permission_mode='acceptEdits',
cwd="/home/user/project"
)
async for message in query(
prompt="Create a Python project structure with setup.py",
options=options
):
if isinstance(message, AssistantMessage):
for block in message.content:
if isinstance(block, ToolUseBlock):
print(f"Using tool: {block.name}")
asyncio.run(create_project())from claude_agent_sdk import (
query,
CLINotFoundError,
ProcessError,
CLIJSONDecodeError
)
try:
async for message in query(prompt="Hello"):
print(message)
except CLINotFoundError:
print("Please install Claude Code: npm install -g @anthropic-ai/claude-code")
except ProcessError as e:
print(f"Process failed with exit code: {e.exit_code}")
except CLIJSONDecodeError as e:
print(f"Failed to parse response: {e}")from claude_agent_sdk import ClaudeSDKClient
import asyncio
async def interactive_session():
async with ClaudeSDKClient() as client:
# Send initial message
await client.query("What's the weather like?")
# Process responses
async for msg in client.receive_response():
print(msg)
# Send follow-up
await client.query("Tell me more about that")
# Process follow-up response
async for msg in client.receive_response():
print(msg)
asyncio.run(interactive_session())from claude_agent_sdk import (
ClaudeSDKClient,
ClaudeAgentOptions,
tool,
create_sdk_mcp_server,
AssistantMessage,
TextBlock
)
import asyncio
from typing import Any
# Define custom tools with @tool decorator
@tool("calculate", "Perform mathematical calculations", {"expression": str})
async def calculate(args: dict[str, Any]) -> dict[str, Any]:
try:
result = eval(args["expression"], {"__builtins__": {}})
return {
"content": [{
"type": "text",
"text": f"Result: {result}"
}]
}
except Exception as e:
return {
"content": [{
"type": "text",
"text": f"Error: {str(e)}"
}],
"is_error": True
}
@tool("get_time", "Get current time", {})
async def get_time(args: dict[str, Any]) -> dict[str, Any]:
from datetime import datetime
current_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
return {
"content": [{
"type": "text",
"text": f"Current time: {current_time}"
}]
}
async def main():
# Create SDK MCP server with custom tools
my_server = create_sdk_mcp_server(
name="utilities",
version="1.0.0",
tools=[calculate, get_time]
)
# Configure options with the server
options = ClaudeAgentOptions(
mcp_servers={"utils": my_server},
allowed_tools=[
"mcp__utils__calculate",
"mcp__utils__get_time"
]
)
# Use ClaudeSDKClient for interactive tool usage
async with ClaudeSDKClient(options=options) as client:
await client.query("What's 123 * 456?")
# Process calculation response
async for message in client.receive_response():
if isinstance(message, AssistantMessage):
for block in message.content:
if isinstance(block, TextBlock):
print(f"Calculation: {block.text}")
# Follow up with time query
await client.query("What time is it now?")
async for message in client.receive_response():
if isinstance(message, AssistantMessage):
for block in message.content:
if isinstance(block, TextBlock):
print(f"Time: {block.text}")
asyncio.run(main())SandboxSettingsKonfiguration für Sandbox-Verhalten. Verwenden Sie dies, um Befehlssandboxing zu aktivieren und Netzwerkbeschränkungen programmgesteuert zu konfigurieren.
class SandboxSettings(TypedDict, total=False):
enabled: bool
autoAllowBashIfSandboxed: bool
excludedCommands: list[str]
allowUnsandboxedCommands: bool
network: SandboxNetworkConfig
ignoreViolations: SandboxIgnoreViolations
enableWeakerNestedSandbox: bool| Eigenschaft | Typ | Standard | Beschreibung |
|---|---|---|---|
enabled | bool | False | Aktivieren Sie den Sandbox-Modus für die Befehlsausführung |
autoAllowBashIfSandboxed | bool | False | Bash-Befehle automatisch genehmigen, wenn Sandbox aktiviert ist |
excludedCommands | list[str] | [] | Befehle, die immer Sandbox-Beschränkungen umgehen (z. B. ["docker"]). Diese werden automatisch ohne Modellbeteiligung unsandboxed ausgeführt |
allowUnsandboxedCommands | bool | False | Erlauben Sie dem Modell, Befehle außerhalb der Sandbox auszuführen. Wenn True, kann das Modell dangerouslyDisableSandbox in der Tool-Eingabe setzen, was auf das Berechtigungssystem zurückfällt |
network | SandboxNetworkConfig | None | Netzwerkspezifische Sandbox-Konfiguration |
ignoreViolations | SandboxIgnoreViolations | None | Konfigurieren Sie, welche Sandbox-Verstöße ignoriert werden sollen |
enableWeakerNestedSandbox | bool | False | Aktivieren Sie eine schwächere verschachtelte Sandbox für Kompatibilität |
Dateisystem- und Netzwerkzugriffsbeschränkungen werden NICHT über Sandbox-Einstellungen konfiguriert. Stattdessen werden sie von Berechtigungsregeln abgeleitet:
Verwenden Sie Sandbox-Einstellungen für Befehlsausführungs-Sandboxing und Berechtigungsregeln für Dateisystem- und Netzwerkzugriffskontrolle.
from claude_agent_sdk import query, ClaudeAgentOptions, SandboxSettings
sandbox_settings: SandboxSettings = {
"enabled": True,
"autoAllowBashIfSandboxed": True,
"excludedCommands": ["docker"],
"network": {
"allowLocalBinding": True,
"allowUnixSockets": ["/var/run/docker.sock"]
}
}
async for message in query(
prompt="Build and test my project",
options=ClaudeAgentOptions(sandbox=sandbox_settings)
):
print(message)SandboxNetworkConfigNetzwerkspezifische Konfiguration für den Sandbox-Modus.
class SandboxNetworkConfig(TypedDict, total=False):
allowLocalBinding: bool
allowUnixSockets: list[str]
allowAllUnixSockets: bool
httpProxyPort: int
socksProxyPort: int| Eigenschaft | Typ | Standard | Beschreibung |
|---|---|---|---|
allowLocalBinding | bool | False | Erlauben Sie Prozessen, sich an lokale Ports zu binden (z. B. für Dev-Server) |
allowUnixSockets | list[str] | [] | Unix-Socket-Pfade, auf die Prozesse zugreifen können (z. B. Docker-Socket) |
allowAllUnixSockets | bool | False | Erlauben Sie den Zugriff auf alle Unix-Sockets |
httpProxyPort | int | None | HTTP-Proxy-Port für Netzwerkanfragen |
socksProxyPort | int | None | SOCKS-Proxy-Port für Netzwerkanfragen |
SandboxIgnoreViolationsKonfiguration zum Ignorieren spezifischer Sandbox-Verstöße.
class SandboxIgnoreViolations(TypedDict, total=False):
file: list[str]
network: list[str]| Eigenschaft | Typ | Standard | Beschreibung |
|---|---|---|---|
file | list[str] | [] | Dateipfadmuster zum Ignorieren von Verstößen |
network | list[str] | [] | Netzwerkmuster zum Ignorieren von Verstößen |
Wenn allowUnsandboxedCommands aktiviert ist, kann das Modell anfordern, Befehle außerhalb der Sandbox auszuführen, indem es dangerouslyDisableSandbox: True in der Tool-Eingabe setzt. Diese Anfragen fallen auf das vorhandene Berechtigungssystem zurück, was bedeutet, dass Ihr can_use_tool-Handler aufgerufen wird, sodass Sie benutzerdefinierte Autorisierungslogik implementieren können.
excludedCommands vs allowUnsandboxedCommands:
excludedCommands: Eine statische Liste von Befehlen, die die Sandbox automatisch immer umgehen (z. B. ["docker"]). Das Modell hat keine Kontrolle darüber.allowUnsandboxedCommands: Ermöglicht dem Modell, zur Laufzeit zu entscheiden, ob unsandboxed Ausführung angefordert werden soll, indem dangerouslyDisableSandbox: True in der Tool-Eingabe gesetzt wird.from claude_agent_sdk import query, ClaudeAgentOptions
async def can_use_tool(tool: str, input: dict) -> bool:
# Check if the model is requesting to bypass the sandbox
if tool == "Bash" and input.get("dangerouslyDisableSandbox"):
# The model wants to run this command outside the sandbox
print(f"Unsandboxed command requested: {input.get('command')}")
# Return True to allow, False to deny
return is_command_authorized(input.get("command"))
return True
async def main():
async for message in query(
prompt="Deploy my application",
options=ClaudeAgentOptions(
sandbox={
"enabled": True,
"allowUnsandboxedCommands": True # Model can request unsandboxed execution
},
permission_mode="default",
can_use_tool=can_use_tool
)
):
print(message)Dieses Muster ermöglicht es Ihnen:
Befehle, die mit dangerouslyDisableSandbox: True ausgeführt werden, haben vollständigen Systemzugriff. Stellen Sie sicher, dass Ihr can_use_tool-Handler diese Anfragen sorgfältig validiert.