Agent の実行中にユーザーの操作が必要になるのは、主に次の 2 つの場合です。
このコールバックは、単一メッセージ入力とストリーミング入力のどちらの
Agent がツールの使用を要求すると、SDK は最初に権限設定を評価します。その結果は次の 3 つです。
次のコードはコールバックの設定方法だけを示しています。
TypeScript の
ツールの実行を許可する場合は、ツール入力を返します。
拒否する場合は、短い理由を指定してください。Agent はその理由に基づいて別の方法を選ぶか、操作を実行しなかった理由をユーザーに説明できます。
拒否した後にタスク全体をすぐ停止する場合は、
このルールにより、同種の操作について現在のセッション内で繰り返し確認されるのを防げます。完全な
次の制約に注意してください。
回答を送信するときも
次の例は、質問と通常のツール承認の両方を処理します。実際のアプリケーションでは、ターミナル入力をダイアログ、Web ページ、承認サービスに置き換えられます。
Python のターミナル例はブロッキング
- Agent がツールを実行しようとしており、ユーザーの許可が必要な場合。
- Agent に必要な情報がなく、ユーザーの回答が必要な場合。
canUseTool(Python では can_use_tool)でユーザー操作を処理する場合、どちらのリクエストも同じコールバックに届きます。アプリケーションは確認画面または質問を表示し、ユーザーの選択を SDK に返します。
| ユーザーに表示する内容 | 代表的なツール | ユーザーが入力するもの | アプリケーションが返すもの |
|---|---|---|---|
| ツール承認 | Bash、Write、MCP ツール | この操作を許可するかどうか | 元のツール入力、または確認後に修正した入力 |
| 確認質問 | AskUserQuestion | 質問への実際の回答 | questions と answers |
prompt にも設定できます。1 回限りの query() でもツール承認や確認質問を表示できます。
canUseTool が呼ばれるタイミング
Agent がツールの使用を要求すると、SDK は最初に権限設定を評価します。その結果は次の 3 つです。
- すでに許可されている:
canUseToolを呼ばずにツールを実行します。 - すでに拒否されている:
canUseToolを呼ばずにツールを拒否します。 - ユーザーの確認が必要:SDK が
canUseToolを呼び出し、アプリケーションから許可または拒否が返るのを待ちます。
AskUserQuestion は通常のツールとは異なり、実際のユーザー回答が必要です。canUseTool / can_use_tool が設定されている場合、ユーザー操作が明示的に禁止されていなければ、SDK は回答を受け取るためにコールバックを呼び出します。
canUseTool はすべてのツール呼び出しを受け取るわけではないため、完全なツール実行ログには使用できません。すべてのツール呼び出しを監視するには hooks を使用してください。権限設定の評価順序は権限制御を参照してください。
アプリケーションで動的な承認または AskUserQuestion を処理するには、canUseTool / can_use_tool か、外部 permission prompt tool を設定する必要があります。ランタイムが権限リクエストを送信したときに対応するコールバックが SDK にない場合、SDK は fail closed としてエラーを報告し、ツールを自動実行しません。
コールバックを設定する
次のコードはコールバックの設定方法だけを示しています。showApprovalDialog / show_approval_dialog はホストアプリケーション側で実装する確認 UI であり、SDK の関数ではありません。実行可能なターミナル版は後述の完全な例を参照してください。
context.signal は AbortSignal、Python の context.signal は asyncio.Event | None です。タスクがキャンセルされた場合、確認画面を閉じてコールバックを終了してください。TypeScript の例では、処理中のツール呼び出しを識別するために toolUseID を返しています。
アプリケーションが確認 UI を提供する場合は canUseTool / can_use_tool を使用します。外部 permission prompt tool がすでにある場合は、代わりに permissionPromptToolName / permission_prompt_tool_name を使用します。2 つを同時に設定することはできません。
承認結果を返す
一度だけ許可する
ツールの実行を許可する場合は、ツール入力を返します。
updatedInput / updated_input はツールが最終的に受け取る入力です。そのまま返すことも、許可する前に危険なオプションを削除する、ファイルパスを制限する、その他のフィールドを変更することもできます。変更後の入力は、そのツールの入力形式に従って検証してください。
拒否する
拒否する場合は、短い理由を指定してください。Agent はその理由に基づいて別の方法を選ぶか、操作を実行しなかった理由をユーザーに説明できます。
interrupt: true(Python では interrupt=True)を設定します。
このセッションでは常に許可する
context.suggestions には、SDK が保存を推奨する権限ルールが含まれる場合があります。ユーザーが「このセッションでは常に許可」を選んだ場合、その候補を allow の結果に含めます。
PermissionUpdate 型とカスタムルールの作成方法は、セッション中の権限更新を参照してください。
権限モードがコールバックに与える影響
permissionMode / permission_mode は、そのセッションにおけるツールリクエストのデフォルト動作を決めます。ユーザーに確認画面を表示するか、canUseTool を呼び出すかにも影響します。次の表は、canUseTool / can_use_tool が設定され、AskUserQuestion が tools から見えることを前提としています。
| 権限モード | 通常のツール | AskUserQuestion |
|---|---|---|
default | 確認が必要なツールはコールバックを呼び出す | ユーザーの回答を得るためにコールバックを呼び出す |
acceptEdits | 一般的なファイル編集は直接許可し、その他のツールでは確認が必要な場合がある | ユーザーの回答を得るためにコールバックを呼び出す |
plan | 実際の変更は行わず、必要に応じて確認を要求できる | 計画や要件を確認するために質問できる |
auto | SDK が一部のツールを自動的に許可または拒否するため、毎回コールバックが呼ばれるとは限らない | ユーザーの回答を得るためにコールバックを呼び出す |
dontAsk | 事前に許可されていないツールは確認を表示せずに拒否する | 質問も拒否されるため、ユーザーの回答を待てない |
bypassPermissions / yolo | 通常のツールは確認なしで実行する | 引き続きコールバックを呼び出す。SDK がユーザーの代わりに回答することはない |
disallowedTools/disallowed_toolsまたは deny ルールでAskUserQuestionを禁止すると、Agent はユーザーに質問できません。toolsを明示的に設定する場合はAskUserQuestionを含めてください。含めないと Agent からこのツールが見えません。bypassPermissionsとyoloは信頼できる環境でのみ使用してください。通常のツール承認は省略しますが、ユーザーの代わりに質問へ回答することはありません。- 未承認のすべての操作を独自の確認 UI に表示する場合は、通常
defaultを使用し、そのツールをallowedTools/allowed_toolsに追加しないでください。
AskUserQuestion を処理する
AskUserQuestion は、現在のタスクを続ける前に少数の構造化された質問を行うために使用します。たとえば、対象環境、実装方法、出力形式を選択してもらう場合です。これは新しいチャットメッセージではありません。ユーザーが回答すると、Agent は現在のタスクを再開します。
canUseTool が toolName === 'AskUserQuestion' を受け取ったとき、コールバックの input は次のランタイム構造です。
- 1 回のリクエストには 1~4 個の質問が含まれます。
- 各質問には短い
headerと 2~4 個の選択肢があります。 multiSelectがfalseまたは省略されている場合は 1 項目、trueの場合は複数項目を選択できます。- UI では、選択肢にない回答もユーザーが入力できるようにしてください。
- 選択肢には
previewが含まれる場合があります。TypeScript では、toolConfig.askUserQuestion.previewFormatでプレビューをmarkdownまたはhtmlとして解釈するよう指定できます。Python SDK には現在、対応するtool_configオプションがありません。
canUseToolコールバックでは、ここに示すランタイムのquestions/answers構造を使用してください。単数形のquestion/answerフィールドとして処理しないでください。
質問への回答を返す
回答を送信するときも behavior: 'allow' を返します。ここでの allow は「この回答を受け入れてタスクを続ける」という意味です。updatedInput には質問と回答の両方を含めます。
answers は次の規則でエンコードします。
- 各 key には、対応する質問の完全な
questionテキストを使用します。 - 単一選択では選択肢の
label、自由入力ではユーザーが入力したテキストを使用します。 - 複数選択では、複数の label を
,で連結した 1 つの文字列にします。 - ユーザーが質問をキャンセルした場合は、理由を付けて deny を返します。架空の回答や空白の回答で処理を続けないでください。
完全な例
次の例は、質問と通常のツール承認の両方を処理します。実際のアプリケーションでは、ターミナル入力をダイアログ、Web ページ、承認サービスに置き換えられます。
input() を使用するため、タスクがキャンセルされても現在の入力が戻るまで context.signal を確認できません。Web またはデスクトップアプリケーションではこの制約を引き継がず、context.signal を監視し、シグナル発生時にダイアログをすぐ閉じてコールバックを終了してください。
機能の使い分け
| 要件 | 推奨機能 | 理由 |
|---|---|---|
| ツールを実行してよいか確認する | canUseTool / can_use_tool | 許可、拒否、またはツール入力の修正ができる |
| Agent が続行する前に 1~4 個の短い回答を得る | AskUserQuestion | Agent が質問と選択肢を提示し、ユーザーの回答後に現在のタスクを続ける |
| ユーザーが追加質問、長いテキストの追加、タスクの方向変更を行う | ストリーミング入力 | 新しいユーザーメッセージとして扱う必要がある |
| 固定フィールド、厳密な検証、ファイルアップロード、複雑なフォームが必要 | カスタムツール | アプリケーションがデータ形式と UI を定義できる |
| MCP server がフォームまたは認証情報を要求する | MCP Elicitation | このリクエストでは onElicitation / on_elicitation を使用する |
| すべてのツール呼び出しを記録する、または統一的にインターセプトする | Hooks と権限制御 | canUseTool は自動的に許可または拒否された呼び出しを受け取らない |
AskUserQuestion をマルチターン会話の代わりに使用しないでください。ユーザーが自発的に送る新しいメッセージにはストリーミング入力を使用します。また、通常のテキスト応答をツール承認の代わりに使用しないでください。SDK には明示的な allow または deny の結果が必要です。