Skip to content

fix: route AskUserQuestion/ExitPlanMode replies via can_use_tool#67

Merged
quick-sort merged 2 commits into
mainfrom
quick-sort/fix/can-use-tool-callback
Jun 20, 2026
Merged

fix: route AskUserQuestion/ExitPlanMode replies via can_use_tool#67
quick-sort merged 2 commits into
mainfrom
quick-sort/fix/can-use-tool-callback

Conversation

@hilr

@hilr hilr commented Jun 20, 2026

Copy link
Copy Markdown
Collaborator

Summary

The user's reply to an AskUserQuestion (and the Yes/No on an ExitPlanMode plan) was silently ignored — the LLM proceeded with the default option as if the user had cancelled.

Root cause: the agent runs in bypassPermissions, but that mode does not bypass requiresUserInteraction() tools. In the CLI's permission check the requiresUserInteraction short-circuit (the "1e" step in utils/permissions/permissions.ts) runs before the bypass check, so AskUserQuestion / ExitPlanMode still emit a can_use_tool request. With no callback registered, the SDK raised "canUseTool callback is not provided" (claude_agent_sdk/_internal/query.py); the CLI read that error as a user cancellation and fed the LLM a cancelled tool_result — hence "user cancelled, use defaults".

Fix: register a can_use_tool callback that:

  • allows ordinary tools outright (preserving bypass semantics);
  • for the two user-interaction tools, bridges the CLI permission request to the IM channel via a two-phase handshake on an asyncio.Future keyed by tool_use_id:
    • run() surfaces the question/plan to the channel and returns; the callback awaits the future, holding the CLI's request open;
    • the user's reply arrives as the next run() call, which resolves the future instead of issuing a fresh query; the callback then returns the decision — AskUserQuestion injects parsed answers into updated_input.answers (the CLI formats them into the tool_result), ExitPlanMode maps to allow / deny-with-feedback.

Drops the stdin-hack _send_tool_result and _format_answers_for_tool_result; _build_plan_approval_result_build_exit_plan_permission (returns a PermissionResult). Detailed writeup added as an in-code comment at the callback.

Test plan

  • pytest — 186 passed
  • replaced the flaky LLM-dependent test_ask_user_question_resume with a deterministic future-mechanism test
  • added _can_use_tool callback tests (bypass / ExitPlanMode allow+deny / AskUserQuestion answer injection / parse-failure fallback)
  • validate live IM→agent round-trip after deploy (diagnostic logging from chore: add diagnostic logging for AskUserQuestion / ExitPlanMode reply flow #66 will confirm the can_use_tool: awaiting user replygot user reply chain)

🤖 Generated with Claude Code

hilr and others added 2 commits June 20, 2026 04:30
…es take effect

bypassPermissions does not bypass requiresUserInteraction tools, so the CLI
still sent can_use_tool requests for AskUserQuestion/ExitPlanMode. With no
callback the SDK threw, the CLI treated it as a cancel, and the LLM fell
back to defaults — ignoring the user's actual reply.

Register a can_use_tool callback that allows normal tools (bypass) and, for
the two user-interaction tools, parks on an asyncio.Future shared with run()
until the user's reply arrives. AskUserQuestion answers are injected via
updated_input (the CLI formats them into the tool_result); ExitPlanMode maps
to allow / deny-with-feedback.

Drops the stdin-hack _send_tool_result and _format_answers_for_tool_result;
_build_plan_approval_result becomes _build_exit_plan_permission returning a
PermissionResult. The flaky LLM-dependent resume test is replaced by
deterministic future-mechanism and callback tests.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
In-code writeup of the AskUserQuestion/ExitPlanMode reply bug at the
callback it fixes: symptom, root cause (bypassPermissions doesn't bypass
requiresUserInteraction tools), and the run()↔callback future handshake.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@quick-sort quick-sort merged commit 1d1825f into main Jun 20, 2026
1 check passed
@quick-sort quick-sort deleted the quick-sort/fix/can-use-tool-callback branch June 20, 2026 04:46
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