Skip to content

Opus 4.7 returns empty thinking text: ThinkingConfig.display not forwarded to CLI #831

@maxim092001

Description

@maxim092001

Summary

On Opus 4.7+, ThinkingBlock.thinking is always \"\" and no thinking_delta stream events arrive, even when thinking={\"type\": \"adaptive\"} is set on ClaudeAgentOptions. There is no supported SDK knob to fix this — the underlying CLI flag exists but isn't reachable.

Background

Opus 4.7 silently changed the default of the API's thinking.display field from \"summarized\" (Opus 4.6) to \"omitted\". With \"omitted\", the API deliberately returns:

  • content_block_start with empty thinking
  • one or more signature_delta events (encrypted envelope)
  • no thinking_delta events
  • terminal ThinkingBlock.thinking == \"\"

The bundled Claude Code CLI 2.1.111 accepts --thinking-display <summarized|omitted> to override this default. You can verify the flag exists (it's hidden from --help):

$ claude --thinking-display bogus
error: option '--thinking-display <display>' argument 'bogus' is invalid. Allowed choices are summarized, omitted.

The bug in the SDK

In claude-agent-sdk 0.1.60, two things combine to make this flag unreachable:

  1. ThinkingConfigAdaptive and ThinkingConfigEnabled in src/claude_agent_sdk/types.py don't declare a display field. Passing {\"type\": \"adaptive\", \"display\": \"summarized\"} requires # type: ignore[typeddict-unknown-key].
  2. SubprocessCLITransport._build_command at src/claude_agent_sdk/_internal/transport/subprocess_cli.py:303-316 only reads t[\"type\"]. Any other keys in the thinking dict are silently dropped, so display never reaches the CLI.

Workaround today: extra_args={\"thinking-display\": \"summarized\"}, which works but relies on a hidden flag and bypasses the typed API.

Reproduction

from claude_agent_sdk import ClaudeAgentOptions, query

options = ClaudeAgentOptions(
    model=\"claude-opus-4-7\",
    thinking={\"type\": \"adaptive\"},
    effort=\"max\",
    include_partial_messages=True,
)

async for msg in query(prompt=\"what is 2+2, think step by step\", options=options):
    # Every ThinkingBlock returned has thinking == \"\" — only signatures come through
    ...

Verified against Opus 4.7 on Vertex: raising effort from default → \"max\" grows the signature payload (424 → 2852 bytes = more thinking is happening) but plaintext remains empty.

Proposed fix

Surface display on the TypedDicts and forward it to --thinking-display. PR: #830

# before
options = ClaudeAgentOptions(thinking={\"type\": \"adaptive\"})          # plaintext empty on Opus 4.7
# after
options = ClaudeAgentOptions(thinking={\"type\": \"adaptive\", \"display\": \"summarized\"})  # plaintext returned

Related

  • TypeScript SDK (@anthropic-ai/claude-agent-sdk) appears to have the same gap — happy to file a sibling issue/PR if useful.
  • Worth confirming whether --thinking-display is intended to be a public flag; if so, a docs entry would pair nicely with the SDK fix.

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