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

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions