Skip to content

docs: ThinkingConfig, SyncHookJSONOutput and other TypedDicts behave as plain dicts at runtime — not documented #623

@AlexChen31337

Description

@AlexChen31337

Summary

When working with ThinkingConfig variants and SyncHookJSONOutput, it's not immediately clear from the type annotations or docstrings that these are TypedDict classes — meaning they behave as plain dict objects at runtime, not as dataclass/object instances.

Observed behaviour

from claude_agent_sdk import ThinkingConfigEnabled, SyncHookJSONOutput

# Looks like a constructor call — but returns a plain dict
config = ThinkingConfigEnabled(type="enabled", budget_tokens=20000)
print(type(config))   # <class 'dict'>
print(config)         # {'type': 'enabled', 'budget_tokens': 20000}

# Attribute access FAILS at runtime (works only under type checkers)
config.budget_tokens  # AttributeError: 'dict' object has no attribute 'budget_tokens'
config["budget_tokens"]  # ✅ correct way

Same applies to:

  • SyncHookJSONOutput — access via result["hookSpecificOutput"], not result.hookSpecificOutput
  • AsyncHookJSONOutput
  • PreToolUseHookSpecificOutput and all other HookSpecificOutput variants
  • McpStdioServerConfig, McpSSEServerConfig, McpHttpServerConfig
  • SandboxSettings, SandboxNetworkConfig

Why it matters

Developers (and LLMs writing integration code) naturally write:

# Common mistake — attribute access on a TypedDict
output = SyncHookJSONOutput(continue_=True, hookSpecificOutput={...})
print(output.continue_)  # AttributeError at runtime

This is especially subtle because dataclass types in the same file (AgentDefinition, HookMatcher, TextBlock, etc.) do support attribute access. The mix of @dataclass and TypedDict in types.py creates inconsistent expectations.

Suggested fix

Add a note to the module docstring or the affected TypedDict classes:

class ThinkingConfigEnabled(TypedDict):
    """Enabled thinking configuration with a token budget.
    
    Note: This is a TypedDict — instances are plain dicts at runtime.
    Use dict key access: config["budget_tokens"], not config.budget_tokens.
    """
    type: Literal["enabled"]
    budget_tokens: int

Alternatively, a note in the README / SDK guide comparing TypedDict vs @dataclass types in this SDK would prevent the confusion.

Environment

  • claude-agent-sdk v0.1.44
  • Python 3.11

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions