Skip to content

Conversation

@majiayu000
Copy link
Contributor

Summary

Fixes #377

Prevents internal orchestrator-to-subagent communication from leaking into final AssistantMessage content when using multi-agent orchestration.

Problem

When using multi-agent orchestration with ClaudeSDKClient, internal communication between the orchestrator and sub-agents (via the Task tool) was included in the final AssistantMessage content, even when include_partial_messages=False (the default).

Users would see internal delegation prompts like:

  • "Search for marbles matching this profile: elegant white marble with gold veins..."
  • "Return the marble IDs found"
  • Other internal workflow text

This made it impossible to get clean, user-facing responses without internal implementation details.

Solution

Added filtering logic in ClaudeSDKClient.receive_messages():

  • Messages with parent_tool_use_id are now filtered out when include_partial_messages=False
  • Only top-level user-facing messages are yielded to the user
  • Internal Task tool delegation content is properly hidden

Changes

Modified: src/claude_agent_sdk/client.py

async def receive_messages(self) -> AsyncIterator[Message]:
    # ... existing code ...
    
    # Filter out sub-agent messages when include_partial_messages is False
    if not self.options.include_partial_messages:
        # Check if this message is from a sub-agent (has parent_tool_use_id)
        if isinstance(message, (UserMessage, AssistantMessage, StreamEvent)):
            if message.parent_tool_use_id is not None:
                continue  # Skip sub-agent messages
    
    yield message

Testing

  • ✅ Passed ruff linting and formatting
  • ✅ Passed mypy type checking
  • ✅ All existing tests pass

Behavior

Before:

async for msg in client.receive_response():
    # Gets both orchestrator AND sub-agent messages mixed together

After:

async for msg in client.receive_response():
    # Gets only orchestrator messages (clean user-facing responses)

To get all messages including sub-agent communications:

options = ClaudeAgentOptions(include_partial_messages=True)

Type of Change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)

🤖 Generated with Claude Code
via Happy

Co-Authored-By: Claude [email protected]
Co-Authored-By: Happy [email protected]

Fixes anthropics#377

When using multi-agent orchestration, internal communication between
the orchestrator and sub-agents was leaking into final AssistantMessage
content even when include_partial_messages=False (the default).

Changes:
- Added filtering logic in ClaudeSDKClient.receive_messages()
- Messages with parent_tool_use_id are now filtered out when
  include_partial_messages=False
- Only top-level user-facing messages are yielded to the user
- Internal Task tool delegation content is properly hidden

This ensures that only the final orchestrator response is visible,
without internal delegation prompts and sub-agent communications.

🤖 Generated with [Claude Code](https://claude.ai/code)
via [Happy](https://happy.engineering)

Co-Authored-By: Claude <[email protected]>
Co-Authored-By: Happy <[email protected]>
@ashwin-ant
Copy link
Collaborator

This isn't quite what include_partial_messages is for. It's specifically for streaming out chunks as we receive them from the API. In this case I'd recommend filtering out messages with a parent_tool_use_id.

@ashwin-ant ashwin-ant closed this Dec 13, 2025
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.

Internal orchestrator-to-subagent communication leaks into final AssistantMessage

2 participants