Two situations require user participation while the Agent is working:
You can configure the callback with either a single-message or streaming
After the Agent requests a tool, the SDK evaluates your permission configuration. One of three outcomes follows:
The following snippets only show callback configuration.
In TypeScript,
To allow the tool to run, return its input:
When denying a call, include a short reason. The Agent can use it to choose another approach or explain why the operation was not performed:
To stop the entire task immediately after the denial, set
These rules can prevent the same type of operation from being requested again during the current session. For the complete
Keep these constraints in mind:
Return
Encode
The following example handles both questions and ordinary tool approvals. A real application can replace terminal input with a dialog, web page, or approval service.
The Python terminal example uses blocking
Do not use
- The Agent wants to run a tool and needs the user to approve it.
- The Agent lacks required information and needs the user to answer a question.
canUseTool (can_use_tool in Python), both requests arrive through the same callback. Your application displays an approval prompt or question and returns the user's choice to the SDK.
| What the user sees | Typical tool | What the user provides | What the application returns |
|---|---|---|---|
| Tool approval | Bash, Write, or an MCP tool | Whether to allow this operation | The original or reviewed tool input |
| Clarification question | AskUserQuestion | The actual answer | questions and answers |
prompt. A one-off query() can also display tool approvals and clarification questions.
When canUseTool runs
After the Agent requests a tool, the SDK evaluates your permission configuration. One of three outcomes follows:
- Already allowed: the tool runs without calling
canUseTool. - Already denied: the tool is rejected without calling
canUseTool. - User approval required: the SDK calls
canUseTooland waits for your application to allow or deny the request.
AskUserQuestion is different from an ordinary tool because it requires a real user answer. When canUseTool / can_use_tool is configured, the SDK calls the callback for an answer unless user interaction has been explicitly disabled.
Because the callback does not receive every tool call, do not use canUseTool as a complete tool-execution log. Use hooks to observe every tool call. See Permission Control for the permission evaluation order.
To let your application handle dynamic approval or AskUserQuestion, configure canUseTool / can_use_tool, or use an external permission prompt tool. If the runtime sends a permission request but the SDK has no corresponding callback, the SDK fails closed and reports an error; it never executes the tool automatically.
Configure the callback
The following snippets only show callback configuration. showApprovalDialog / show_approval_dialog represents an approval UI implemented by the host application; it is not an SDK function. For a runnable terminal implementation, see the complete example.
context.signal is an AbortSignal. In Python, it is asyncio.Event | None. If the task has been cancelled, close the approval UI and end the callback. The TypeScript example returns toolUseID to identify the specific tool call being handled.
Use canUseTool / can_use_tool when your application supplies the approval UI. If an external permission prompt tool already exists, use permissionPromptToolName / permission_prompt_tool_name instead. You cannot configure both approaches at the same time.
Return approval results
Allow once
To allow the tool to run, return its input:
updatedInput / updated_input is the input the tool ultimately receives. You can return it unchanged, or remove unsafe flags, restrict a path, or modify another field before allowing the call. Validate any modified input against that tool's input format.
Deny
When denying a call, include a short reason. The Agent can use it to choose another approach or explain why the operation was not performed:
interrupt: true (interrupt=True in Python).
Always allow for this session
context.suggestions may contain permission rules that the SDK recommends saving. When the user selects “Always allow for this session,” include those suggestions in the allow result:
PermissionUpdate type and custom rule construction, see Update permissions during a session.
How permission modes affect the callback
permissionMode / permission_mode sets the default tool-request behavior for the session. It affects whether the user sees an approval prompt and whether canUseTool is called. The following table assumes that canUseTool / can_use_tool is configured and that AskUserQuestion is visible in tools:
| Permission mode | Ordinary tools | AskUserQuestion |
|---|---|---|
default | Tools that need approval call the callback | Calls the callback for the user's answer |
acceptEdits | Common file edits are allowed directly; other tools may still require approval | Calls the callback for the user's answer |
plan | Does not perform actual modifications; approval may still be requested when needed | Can ask questions to clarify requirements or a plan |
auto | The SDK automatically allows or denies some tools, so the callback is not guaranteed for every call | Calls the callback for the user's answer |
dontAsk | Tools that were not pre-authorized are denied without prompting | The question is also denied, so the Agent cannot wait for an answer |
bypassPermissions / yolo | Ordinary tools run without an approval prompt | Still calls the callback; the SDK cannot answer on the user's behalf |
- If
disallowedTools/disallowed_toolsor a deny rule blocksAskUserQuestion, the Agent cannot ask the user a question. - If
toolsis set explicitly, includeAskUserQuestion; otherwise the Agent cannot see the tool. - Use
bypassPermissionsandyoloonly in trusted environments. They skip approval for ordinary tools but do not answer questions for the user. - To show every not-yet-authorized operation in your own approval UI, normally use
defaultand do not add those tools toallowedTools/allowed_tools.
Handle AskUserQuestion
AskUserQuestion asks a small number of structured questions before the Agent continues the current task—for example, to choose a target environment, implementation approach, or output format. It is not a new chat message. After the user answers, the Agent resumes the current task.
When canUseTool receives toolName === 'AskUserQuestion', the callback's input has this runtime structure:
- A request contains 1–4 questions.
- Each question has a short
headerand 2–4 options. - If
multiSelectisfalseor omitted, the user can select one option. If it istrue, the user can select multiple options. - Your UI should also let the user enter an answer that is not one of the options.
- An option can include
preview. In TypeScript,toolConfig.askUserQuestion.previewFormatspecifies whether previews are interpreted asmarkdownorhtml. The Python SDK currently has no equivalenttool_configoption.
In acanUseToolcallback, use the runtimequestions/answersstructure shown here, not singularquestion/answerfields.
Return question answers
Return behavior: 'allow' when submitting answers. Here, allow means “accept these answers and continue the task.” Include both the questions and answers in updatedInput:
answers as follows:
- Each key must be the complete
questiontext for the corresponding question. - For a single selection, use the option's
label. For a custom answer, use the text entered by the user. - For multiple selections, join the labels into one string with
,. - If the user cancels the questions, return deny with a reason. Do not continue with invented or blank answers.
Complete example
The following example handles both questions and ordinary tool approvals. A real application can replace terminal input with a dialog, web page, or approval service.
input(). After a task is cancelled, it cannot check context.signal until the current input call returns. A web or desktop application should not inherit this limitation: listen for context.signal, close the dialog immediately when it fires, and end the callback.
Capability boundaries
| Requirement | Recommended capability | Why |
|---|---|---|
| Confirm whether a tool should run | canUseTool / can_use_tool | Can allow, deny, or revise tool input first |
| Collect 1–4 short answers before the Agent continues | AskUserQuestion | The Agent supplies questions and options, then continues after the user answers |
| Let the user follow up, add long text, or redirect the task | Streaming input | This is a new user message |
| Collect fixed fields, enforce strict validation, upload files, or display a complex form | Custom tools | The application controls the data format and UI |
| Let an MCP server request form or authorization information | MCP Elicitation | These requests use onElicitation / on_elicitation |
| Record every tool call or apply a uniform tool interceptor | Hooks and Permission Control | canUseTool does not receive calls that were automatically allowed or denied |
AskUserQuestion as a replacement for multi-turn conversation. New messages initiated by the user should use streaming input. Do not use a normal text response in place of tool approval either, because the SDK requires an explicit allow or deny result.