CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-claude-agent-sdk

Python SDK for programmatically interacting with Claude Code, enabling AI-powered automation workflows with support for bidirectional conversations, custom in-process tools, hooks, and fine-grained permission control

Quality

Does it follow best practices?

Run evals on this skill

Adds up to 20 points to the overall score

View guide

SecuritybySnyk

The risk profile of this skill

This plugin was archived by the owner on Jun 3, 2026

Reason: Retiring all tiles created prior to the transition to plugin support

Overview
Eval results
Files

content-blocks.mddocs/

Content Blocks

Content blocks are the building blocks of messages in conversations with Claude. They represent different types of content including text, thinking, tool uses, and tool results.

Capabilities

ContentBlock Union Type

Union of all possible content block types.

ContentBlock = TextBlock | ThinkingBlock | ToolUseBlock | ToolResultBlock
"""
Union of all content block types.

Content blocks appear in AssistantMessage and UserMessage objects to
represent different types of content:

- TextBlock: Normal text output from Claude
- ThinkingBlock: Extended thinking content (when enabled)
- ToolUseBlock: Request to execute a tool
- ToolResultBlock: Result from tool execution

Use isinstance() to determine the specific block type and access
type-specific fields.
"""

TextBlock

Plain text content from Claude or user.

@dataclass
class TextBlock:
    """
    Text content block.

    Represents plain text in a message. This is the most common content
    block type for normal conversation text.

    Attributes:
        text: The text content
    """

    text: str
    """Text content.

    The plain text content of this block. Can be a single word, sentence,
    paragraph, or longer text.

    Examples:
        "Hello, how can I help you?"
        "To solve this problem, we need to..."
        "The result is 42."
    """

ThinkingBlock

Extended thinking content from Claude.

@dataclass
class ThinkingBlock:
    """
    Thinking content block.

    Represents extended thinking from Claude when using models with
    thinking capabilities (like Claude Opus with extended thinking enabled).
    This shows Claude's internal reasoning process.

    Attributes:
        thinking: The thinking content
        signature: Digital signature for the thinking block
    """

    thinking: str
    """Thinking content.

    Claude's internal reasoning and thought process. This text shows how
    Claude is analyzing the problem, considering options, and planning
    its response.

    Example:
        "Let me think through this step by step. First, I need to
        understand what the user is asking. They want to know about...
        I should consider... The best approach would be..."
    """

    signature: str
    """Digital signature.

    Cryptographic signature that verifies the authenticity of the thinking
    content. Ensures the thinking wasn't modified after generation.
    """

ToolUseBlock

Request from Claude to execute a tool.

@dataclass
class ToolUseBlock:
    """
    Tool use content block.

    Represents a request from Claude to execute a tool. When Claude needs
    to perform an action like reading a file or running a command, it
    generates a ToolUseBlock with the tool name and input parameters.

    The SDK or CLI handles executing the tool and providing results back
    to Claude via ToolResultBlock.

    Attributes:
        id: Unique identifier for this tool use
        name: Name of the tool to execute
        input: Input parameters for the tool
    """

    id: str
    """Unique tool use identifier.

    A unique ID for this specific tool execution. Used to match tool
    uses with their results (ToolResultBlock.tool_use_id).

    Example: "toolu_01A2B3C4D5E6F7G8H9I0J1K2"
    """

    name: str
    """Tool name.

    The name of the tool Claude wants to execute. This matches tool
    names from the allowed_tools configuration or MCP server tools.

    Examples:
        "Read" - Read a file
        "Write" - Write a file
        "Bash" - Execute a bash command
        "Grep" - Search files
        "custom_tool" - Your custom MCP tool
    """

    input: dict[str, Any]
    """Tool input parameters.

    Dictionary of parameters to pass to the tool. Structure varies by
    tool type.

    Examples:
        {"file_path": "/home/user/file.txt"}  # Read tool
        {"command": "ls -la"}  # Bash tool
        {"pattern": "TODO", "path": "./src"}  # Grep tool
    """

ToolResultBlock

Result from executing a tool.

@dataclass
class ToolResultBlock:
    """
    Tool result content block.

    Contains the result of a tool execution. After Claude requests a tool
    use via ToolUseBlock, the SDK executes the tool and provides results
    back to Claude in a ToolResultBlock.

    Attributes:
        tool_use_id: ID of the tool use this is a result for
        content: The result content
        is_error: Whether the tool execution resulted in an error
    """

    tool_use_id: str
    """Tool use identifier.

    The ID of the ToolUseBlock this result corresponds to. Used to match
    results with their requests.

    Example: "toolu_01A2B3C4D5E6F7G8H9I0J1K2"
    """

    content: str | list[dict[str, Any]] | None = None
    """Result content.

    The output from the tool execution. Can be:
    - A string for simple text results
    - A list of content dictionaries for rich content
    - None if the tool produced no output

    Examples:
        "File contents: Hello World"
        [{"type": "text", "text": "Success"}]
        None
    """

    is_error: bool | None = None
    """Error flag.

    Indicates whether the tool execution resulted in an error:
    - True: Tool execution failed
    - False: Tool execution succeeded
    - None: Error status not specified (usually means success)

    When True, the content typically contains error details.
    """

Usage Examples

Extracting Text from Messages

from claude_agent_sdk import query, AssistantMessage, TextBlock

async for msg in query(prompt="Explain Python"):
    if isinstance(msg, AssistantMessage):
        for block in msg.content:
            if isinstance(block, TextBlock):
                print(block.text)

Handling All Block Types

from claude_agent_sdk import (
    query, AssistantMessage, TextBlock, ThinkingBlock,
    ToolUseBlock, ToolResultBlock, ClaudeAgentOptions
)

options = ClaudeAgentOptions(allowed_tools=["Read", "Bash"])

async for msg in query(prompt="Analyze this project", options=options):
    if isinstance(msg, AssistantMessage):
        for block in msg.content:
            if isinstance(block, TextBlock):
                print(f"[Text] {block.text}")

            elif isinstance(block, ThinkingBlock):
                print(f"[Thinking] {block.thinking}")

            elif isinstance(block, ToolUseBlock):
                print(f"[Tool Use] {block.name}: {block.input}")

            elif isinstance(block, ToolResultBlock):
                error_status = " (ERROR)" if block.is_error else ""
                print(f"[Tool Result{error_status}] {block.content}")

Collecting Text Content

from claude_agent_sdk import query, AssistantMessage, TextBlock

all_text = []

async for msg in query(prompt="Write a story"):
    if isinstance(msg, AssistantMessage):
        for block in msg.content:
            if isinstance(block, TextBlock):
                all_text.append(block.text)

full_response = "\n".join(all_text)
print(full_response)

Monitoring Tool Usage

from claude_agent_sdk import (
    query, AssistantMessage, ToolUseBlock, ClaudeAgentOptions
)

options = ClaudeAgentOptions(allowed_tools=["Read", "Write", "Bash"])

tools_used = []

async for msg in query(prompt="Build a web server", options=options):
    if isinstance(msg, AssistantMessage):
        for block in msg.content:
            if isinstance(block, ToolUseBlock):
                tools_used.append({
                    "id": block.id,
                    "name": block.name,
                    "input": block.input
                })

print(f"Claude used {len(tools_used)} tools:")
for tool in tools_used:
    print(f"  - {tool['name']}: {tool['input']}")

Detecting Tool Errors

from claude_agent_sdk import (
    query, AssistantMessage, ToolResultBlock, ClaudeAgentOptions
)

options = ClaudeAgentOptions(allowed_tools=["Bash"])

async for msg in query(prompt="Run an invalid command", options=options):
    if isinstance(msg, AssistantMessage):
        for block in msg.content:
            if isinstance(block, ToolResultBlock):
                if block.is_error:
                    print(f"Error in tool {block.tool_use_id}:")
                    print(f"  {block.content}")

Building a Conversation Log

from claude_agent_sdk import (
    query, AssistantMessage, TextBlock, ToolUseBlock,
    ToolResultBlock, ClaudeAgentOptions
)

options = ClaudeAgentOptions(allowed_tools=["Read"])

log = []

async for msg in query(prompt="Read config.json", options=options):
    if isinstance(msg, AssistantMessage):
        for block in msg.content:
            if isinstance(block, TextBlock):
                log.append({"type": "text", "content": block.text})

            elif isinstance(block, ToolUseBlock):
                log.append({
                    "type": "tool_use",
                    "tool": block.name,
                    "input": block.input
                })

            elif isinstance(block, ToolResultBlock):
                log.append({
                    "type": "tool_result",
                    "content": block.content,
                    "error": block.is_error
                })

# Display log
for entry in log:
    print(f"{entry['type']}: {entry.get('content', entry.get('tool', ''))}")

Filtering by Block Type

from claude_agent_sdk import (
    query, AssistantMessage, TextBlock, ToolUseBlock
)

text_blocks = []
tool_blocks = []

async for msg in query(prompt="Analyze files"):
    if isinstance(msg, AssistantMessage):
        text_blocks.extend([b for b in msg.content if isinstance(b, TextBlock)])
        tool_blocks.extend([b for b in msg.content if isinstance(b, ToolUseBlock)])

print(f"Text blocks: {len(text_blocks)}")
print(f"Tool blocks: {len(tool_blocks)}")

Extracting Thinking Content

from claude_agent_sdk import (
    query, AssistantMessage, ThinkingBlock, ClaudeAgentOptions
)

# Note: Thinking blocks require extended thinking enabled
options = ClaudeAgentOptions(
    model="claude-opus-4-20250514"  # Model with extended thinking
)

async for msg in query(prompt="Solve this complex problem", options=options):
    if isinstance(msg, AssistantMessage):
        for block in msg.content:
            if isinstance(block, ThinkingBlock):
                print("=== Claude's Thinking Process ===")
                print(block.thinking)
                print(f"Signature: {block.signature[:50]}...")

Tool Use Chain Analysis

from claude_agent_sdk import (
    query, AssistantMessage, ToolUseBlock, ToolResultBlock,
    ClaudeAgentOptions
)

options = ClaudeAgentOptions(allowed_tools=["Read", "Write", "Bash"])

tool_chain = []

async for msg in query(prompt="Create and test a script", options=options):
    if isinstance(msg, AssistantMessage):
        for block in msg.content:
            if isinstance(block, ToolUseBlock):
                tool_chain.append({
                    "id": block.id,
                    "type": "use",
                    "name": block.name,
                    "input": block.input
                })

            elif isinstance(block, ToolResultBlock):
                # Find the matching tool use
                for entry in tool_chain:
                    if entry["id"] == block.tool_use_id and entry["type"] == "use":
                        entry["result"] = block.content
                        entry["error"] = block.is_error
                        break

# Display tool chain
print("Tool Execution Chain:")
for i, entry in enumerate(tool_chain, 1):
    if entry["type"] == "use":
        status = "ERROR" if entry.get("error") else "SUCCESS"
        print(f"{i}. {entry['name']} [{status}]")
        print(f"   Input: {entry['input']}")
        if "result" in entry:
            result_preview = str(entry["result"])[:100]
            print(f"   Result: {result_preview}...")

Content Block Statistics

from claude_agent_sdk import (
    query, AssistantMessage, TextBlock, ThinkingBlock,
    ToolUseBlock, ToolResultBlock
)

stats = {
    "text": 0,
    "thinking": 0,
    "tool_use": 0,
    "tool_result": 0
}

async for msg in query(prompt="Complex task"):
    if isinstance(msg, AssistantMessage):
        for block in msg.content:
            if isinstance(block, TextBlock):
                stats["text"] += 1
            elif isinstance(block, ThinkingBlock):
                stats["thinking"] += 1
            elif isinstance(block, ToolUseBlock):
                stats["tool_use"] += 1
            elif isinstance(block, ToolResultBlock):
                stats["tool_result"] += 1

print("Content Block Statistics:")
for block_type, count in stats.items():
    print(f"  {block_type}: {count}")

Rich Content Handling

from claude_agent_sdk import query, AssistantMessage, ToolResultBlock

async for msg in query(prompt="Task with rich output"):
    if isinstance(msg, AssistantMessage):
        for block in msg.content:
            if isinstance(block, ToolResultBlock):
                content = block.content

                # Handle different content types
                if isinstance(content, str):
                    print(f"Text result: {content}")

                elif isinstance(content, list):
                    print("Rich content result:")
                    for item in content:
                        if isinstance(item, dict):
                            item_type = item.get("type", "unknown")
                            print(f"  - Type: {item_type}")
                            if item_type == "text":
                                print(f"    Text: {item.get('text', '')}")

                elif content is None:
                    print("No output from tool")

Tool Input Analysis

from claude_agent_sdk import (
    query, AssistantMessage, ToolUseBlock, ClaudeAgentOptions
)

options = ClaudeAgentOptions(allowed_tools=["Bash", "Read", "Write"])

tool_inputs = {}

async for msg in query(prompt="Work on this project", options=options):
    if isinstance(msg, AssistantMessage):
        for block in msg.content:
            if isinstance(block, ToolUseBlock):
                if block.name not in tool_inputs:
                    tool_inputs[block.name] = []

                tool_inputs[block.name].append(block.input)

print("Tool Input Analysis:")
for tool_name, inputs in tool_inputs.items():
    print(f"\n{tool_name} ({len(inputs)} uses):")
    for i, input_data in enumerate(inputs, 1):
        print(f"  {i}. {input_data}")

Separating Text and Actions

from claude_agent_sdk import (
    query, AssistantMessage, TextBlock, ToolUseBlock,
    ClaudeAgentOptions
)

options = ClaudeAgentOptions(allowed_tools=["Read", "Write"])

explanations = []
actions = []

async for msg in query(prompt="Fix this bug", options=options):
    if isinstance(msg, AssistantMessage):
        for block in msg.content:
            if isinstance(block, TextBlock):
                explanations.append(block.text)

            elif isinstance(block, ToolUseBlock):
                actions.append(f"{block.name}: {block.input}")

print("=== What Claude Said ===")
print("\n".join(explanations))

print("\n=== What Claude Did ===")
print("\n".join(actions))

Error Recovery Pattern

from claude_agent_sdk import (
    query, AssistantMessage, ToolUseBlock, ToolResultBlock,
    ClaudeAgentOptions
)

options = ClaudeAgentOptions(allowed_tools=["Bash"])

current_tool_use = None

async for msg in query(prompt="Try a command", options=options):
    if isinstance(msg, AssistantMessage):
        for block in msg.content:
            if isinstance(block, ToolUseBlock):
                current_tool_use = block
                print(f"Attempting: {block.name} with {block.input}")

            elif isinstance(block, ToolResultBlock):
                if block.is_error and current_tool_use:
                    print(f"Failed: {current_tool_use.name}")
                    print(f"Error: {block.content}")
                    print("Claude will likely try an alternative...")
                elif current_tool_use:
                    print(f"Success: {current_tool_use.name}")

                current_tool_use = None

Block Type Distribution

from claude_agent_sdk import (
    query, AssistantMessage, TextBlock, ThinkingBlock,
    ToolUseBlock, ToolResultBlock
)

def get_block_type_name(block):
    if isinstance(block, TextBlock):
        return "text"
    elif isinstance(block, ThinkingBlock):
        return "thinking"
    elif isinstance(block, ToolUseBlock):
        return "tool_use"
    elif isinstance(block, ToolResultBlock):
        return "tool_result"
    else:
        return "unknown"

block_sequence = []

async for msg in query(prompt="Multi-step task"):
    if isinstance(msg, AssistantMessage):
        for block in msg.content:
            block_sequence.append(get_block_type_name(block))

print("Block sequence:")
print(" -> ".join(block_sequence))

docs

agent-definitions.md

agents.md

client.md

configuration-options.md

content-blocks.md

core-query-interface.md

custom-tools.md

error-handling.md

errors.md

hook-system.md

hooks.md

index.md

mcp-config.md

mcp-server-configuration.md

messages-and-content.md

messages.md

options.md

permission-control.md

permissions.md

query.md

transport.md

COMPLETION_SUMMARY.md

tile.json