fix: keep stdin open for can_use_tool control responses#715
Open
Ch1ldKing wants to merge 1 commit intoanthropics:mainfrom
Open
fix: keep stdin open for can_use_tool control responses#715Ch1ldKing wants to merge 1 commit intoanthropics:mainfrom
Ch1ldKing wants to merge 1 commit intoanthropics:mainfrom
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
query()currently closes stdin too early whencan_use_toolis used with an async prompt stream.The SDK correctly switches permission handling to the stdio control path when
can_use_toolis configured, butQuery.wait_for_result_and_end_input()only waits for bidirectional control traffic when SDK MCP servers or hooks are present. That means stdin can be closed before the CLI sends acan_use_toolcontrol request, or before the SDK writes the corresponding control response back to the CLI.The result is that a valid permission decision can be replaced by a generic
Stream closedtransport failure.Reproduction Scenario
A downstream application uses
query()with:ClaudeAgentOptions(can_use_tool=...)A typical example is a path sandbox implemented with
can_use_tool, where Claude attempts a file tool such asRead,Glob, orGrepand the host application returns a normal permission decision.Before this change, stdin can already be closed by the time the CLI tries to round-trip the permission request through the SDK. Instead of preserving the callback result, the session can surface a generic
Stream closedfailure.Why This Matters
can_use_toolis used to enforce policy decisions such as path restrictions and tool gating. When the callback result is replaced by a transport error, downstream callers lose the real denial reason and Claude sees the wrong tool outcome. That makes permission failures much harder to debug and can send the agent down the wrong recovery path.Root Cause
There is a mismatch between the control path setup and the stdin lifecycle:
InternalClient.process_query()enables stdio-based permission handling whenevercan_use_toolis configuredQuery.wait_for_result_and_end_input()only delaysend_input()forsdk_mcp_serversandhooksstream_input()therefore closes stdin too early forcan_use_toolcontrol trafficFix
This change treats
can_use_toolas another bidirectional control-path dependency inQuery.wait_for_result_and_end_input().The patch:
can_use_toolis configuredtests/test_query.pyfor async iterable prompts withcan_use_tool, including a control-request round trip