Skip to content

Add forward_subagent_text option - #1206

Merged
qing-ant merged 1 commit into
mainfrom
qing/forward-subagent-text
Aug 17, 2026
Merged

qing-ant merged 1 commit into
mainfrom
qing/forward-subagent-text

Conversation

@qing-ant

Copy link
Copy Markdown
Contributor

Summary

Adds ClaudeAgentOptions.forward_subagent_text, the Python counterpart of the TypeScript SDK's forwardSubagentText option.

By default the CLI only forwards a foreground subagent's tool_use / tool_result blocks into the parent stream (as AssistantMessage / UserMessage objects whose parent_tool_use_id is the spawning Agent tool_use id) — enough for a progress heartbeat, but not for rendering the nested transcript. forwardSubagentText is an opt-in initialize capability that makes the CLI forward the subagent's text and thinking blocks the same way. The Python SDK had no way to turn it on.

Changes:

  • ClaudeAgentOptions.forward_subagent_text: bool = False with a docstring.
  • Query.initialize() sends forwardSubagentText: true when set; omitted otherwise, so the default wire payload is unchanged and older CLIs are unaffected. Plumbed through both query() and ClaudeSDKClient.
  • SDKControlInitializeRequest now also lists the optional initialize fields the SDK already sends (excludeDynamicSections, skills) alongside the new one.

Test plan

  • Unit: tests/test_query.py asserts the initialize payload with the option on/off and that ClaudeAgentOptions.forward_subagent_text reaches the initialize request via query(); tests/test_streaming_client.py asserts the same via ClaudeSDKClient.
  • New e2e-tests/test_forward_subagent_text.py runs a foreground subagent (custom AgentDefinition with background=False) against the real CLI and asserts that (a) with the option set, at least one AssistantMessage containing a TextBlock arrives with parent_tool_use_id equal to the observed Agent tool_use id, and (b) without it, no attributed text is forwarded. Ran it several times locally; stable.
  • ruff check, ruff format, mypy src/, full pytest tests/ (1372 passed).

By default the CLI only forwards a foreground subagent's tool_use /
tool_result blocks into the parent stream (as assistant/user messages
whose parent_tool_use_id is the spawning Agent tool_use id), which is
enough for a progress heartbeat but not for rendering the nested
transcript. The TypeScript SDK exposes an opt-in `forwardSubagentText`
initialize capability that makes the CLI forward the subagent's text and
thinking blocks the same way; the Python SDK had no counterpart.

Add ClaudeAgentOptions.forward_subagent_text and send it as
`forwardSubagentText: true` in the initialize control request from both
query() and ClaudeSDKClient (omitted when False, so older CLIs and the
default path are untouched). SDKControlInitializeRequest now also lists
the other optional initialize fields the SDK already sends.

Unit tests cover the initialize payload and the plumbing from
ClaudeAgentOptions through both entry points; e2e tests run a foreground
subagent and assert that its text arrives attributed to the Agent
tool_use id only when the option is set.
@qing-ant
qing-ant marked this pull request as ready for review August 14, 2026 21:10

@claude claude Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM — a small, opt-in plumbing change that mirrors the TypeScript SDK's forwardSubagentText and follows the SDK's established initialize-capability pattern.

What was reviewed

  • Plumbing of forward_subagent_text through both entry points (query() and ClaudeSDKClient) into Query.initialize() — identical to the existing excludeDynamicSections/skills handling.
  • Wire-payload compatibility: the field is only sent when enabled, so the default initialize request is byte-identical to before and older CLIs are unaffected.
  • The SDKControlInitializeRequest TypedDict additions — documentation-only (the request is built as a plain dict), consistent with what the SDK already sends.
Extended reasoning...

Overview

This PR adds ClaudeAgentOptions.forward_subagent_text, the Python counterpart of the TypeScript SDK's forwardSubagentText initialize capability. It touches 7 files: a new dataclass field with a docstring in types.py, a new Query.__init__ parameter and one conditional line in Query.initialize(), one-line plumbing in each of the two entry points (_internal/client.py and client.py), TypedDict additions to SDKControlInitializeRequest, unit tests, and a new e2e test. No existing behavior changes.

Security risks

None. The change adds an opt-in boolean that is forwarded to the CLI over the existing control protocol. It does not touch auth, permissions, subprocess spawning, or input parsing. The forwarded subagent text flows through the same message-parsing path already used for tool_use/tool_result blocks; the SDK does not interpret it.

Level of scrutiny

Low-to-moderate. This is a mechanical option-plumbing change following a pattern used three times already in the same function (agents, excludeDynamicSections, skills). The key correctness property — that the default wire payload is unchanged so older CLIs are unaffected — is enforced by only sending the field when true, and is asserted by unit tests for both the enabled and default cases in both entry points.

Other factors

The bug hunting system found no issues. Test coverage is thorough for the size of the change: initialize-payload assertions at the Query layer, end-to-end plumbing assertions through query() and ClaudeSDKClient, and a real-CLI e2e test verifying both the enabled and default behaviors. The SDKControlInitializeRequest TypedDict additions are type-documentation only (the request dict is constructed untyped), so they carry no runtime risk. The docstring accurately matches the TypeScript SDK's documented semantics.

@qing-ant
qing-ant enabled auto-merge (squash) August 17, 2026 23:29
@qing-ant
qing-ant merged commit c97420c into main Aug 17, 2026
12 checks passed
@qing-ant
qing-ant deleted the qing/forward-subagent-text branch August 17, 2026 23:31
Flohs pushed a commit to Flohs/claude-agent-sdk-go that referenced this pull request Aug 18, 2026
…uest

Sends "forwardSubagentText": true in the initialize control request
(omitted when false) so the CLI forwards subagent text and thinking
blocks as messages in the stream, not just tool_use/tool_result blocks.
Threaded through claude.Query, WarmQuery, and Client the same way
Options.Agents/PresetPrompt.ExcludeDynamicSections already are.

Port of Python SDK commit c97420c (anthropics/claude-agent-sdk-python#1206),
matching the TypeScript SDK's existing forwardSubagentText.

Closes #601
Flohs added a commit to Flohs/claude-agent-sdk-go that referenced this pull request Aug 18, 2026
Sends "forwardSubagentText": true in the initialize control request
(omitted when false) so the CLI forwards subagent text and thinking
blocks as messages in the stream, not just tool_use/tool_result blocks.
Threaded through claude.Query, WarmQuery, and Client the same way
Options.Agents/PresetPrompt.ExcludeDynamicSections already are.

Port of Python SDK commit c97420c (anthropics/claude-agent-sdk-python#1206),
matching the TypeScript SDK's existing forwardSubagentText.

Closes #601

Co-authored-by: Claude <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants