Passer au contenu principal
Lors du travail sur une tâche, Claude a parfois besoin de vérifier auprès des utilisateurs. Il peut avoir besoin d’une permission avant de supprimer des fichiers, ou avoir besoin de demander quelle base de données utiliser pour un nouveau projet. Votre application doit présenter ces demandes aux utilisateurs afin que Claude puisse continuer avec leurs entrées. Claude demande une entrée utilisateur dans deux situations : lorsqu’il a besoin d’une permission pour utiliser un outil (comme supprimer des fichiers ou exécuter des commandes), et lorsqu’il a des questions de clarification (via l’outil AskUserQuestion). Les deux déclenchent votre callback canUseTool, qui met en pause l’exécution jusqu’à ce que vous retourniez une réponse. C’est différent des tours de conversation normaux où Claude termine et attend votre prochain message. Pour les questions de clarification, Claude génère les questions et les options. Votre rôle est de les présenter aux utilisateurs et de retourner leurs sélections. Vous ne pouvez pas ajouter vos propres questions à ce flux ; si vous avez besoin de poser une question aux utilisateurs vous-même, faites-le séparément dans votre logique d’application. Le callback peut rester en attente indéfiniment. L’exécution reste en pause jusqu’à ce que votre callback retourne, et le SDK n’annule l’attente que lorsque la requête elle-même est annulée. Si un utilisateur pourrait prendre plus de temps pour répondre que votre processus ne peut raisonnablement rester en cours d’exécution, retournez la décision du hook defer, qui permet au processus de quitter et de reprendre plus tard à partir de la session persistante. Ce guide vous montre comment détecter chaque type de demande et répondre de manière appropriée.

Détecter quand Claude a besoin d’une entrée

Passez un callback canUseTool dans vos options de requête. Le callback se déclenche chaque fois que Claude a besoin d’une entrée utilisateur, en recevant le nom de l’outil et l’entrée comme arguments :
Le callback se déclenche dans deux cas :
  1. L’outil a besoin d’approbation : Claude veut utiliser un outil qui n’est pas auto-approuvé par une règle de permission ou un mode de permission. Vérifiez tool_name pour l’outil (par exemple, "Bash", "Write").
  2. Claude pose une question : Claude appelle l’outil AskUserQuestion. Vérifiez si tool_name == "AskUserQuestion" pour le gérer différemment. Si vous spécifiez un tableau tools, incluez AskUserQuestion pour que cela fonctionne. Voir Gérer les questions de clarification pour plus de détails.
Le callback ne se déclenche jamais pour les outils auto-approuvés. Toute approbation antérieure dans le flux d’évaluation des permissions, une règle d’autorisation ou un mode comme acceptEdits ou bypassPermissions, résout l’appel avant que canUseTool soit consulté. Si vous listez un outil seul dans allowed_tools, une vérification canUseTool pour cet outil ne s’exécute jamais sauf si une règle d’ask ou le mode plan redirige l’appel vers une invite. Pour une logique qui doit s’appliquer à chaque appel d’outil, utilisez un hook PreToolUse, qui s’exécute avant le reste du flux et peut autoriser, refuser ou modifier les demandes.AskUserQuestion, les outils MCP marqués requiresUserInteraction, et les outils connecteur que votre organisation a définis sur ask atteignent le callback même quand une règle d’autorisation correspond. En mode dontAsk, ces appels sont refusés à la place, sans invoquer le callback.
Vous pouvez également utiliser le hook PermissionRequest pour envoyer des notifications externes (Slack, email, push) quand Claude attend une approbation.

Gérer les demandes d’approbation d’outil

Une fois que vous avez passé un callback canUseTool dans vos options de requête, il se déclenche lorsque Claude veut utiliser un outil qu’aucun élément antérieur du flux de permission n’a approuvé. Votre callback reçoit trois arguments : L’objet input contient des paramètres spécifiques à l’outil. Exemples courants : Voir la référence du SDK pour les schémas d’entrée complets : Python | TypeScript. Vous pouvez afficher ces informations à l’utilisateur afin qu’il puisse décider d’autoriser ou de rejeter l’action, puis retourner la réponse appropriée. L’exemple suivant demande à Claude de créer et de supprimer un fichier de test. Lorsque Claude tente chaque opération, le callback imprime la demande d’outil au terminal et invite à une approbation y/n.
En Python, can_use_tool nécessite le mode streaming. Lorsque vous passez un flux de messages fini via query(prompt=generator) ou ClaudeSDKClient.connect(prompt=async_iterable), le SDK ferme le flux d’entrée après le dernier message, avant que le callback de permission puisse être invoqué, sauf si un hook enregistré ou un serveur MCP en cours de processus le maintient ouvert. L’exemple ci-dessus le maintient ouvert avec un hook PreToolUse qui retourne {"continue_": True}. La connexion sans prompt et l’envoi de messages via ClaudeSDKClient.query() maintiennent le flux ouvert d’eux-mêmes et ne nécessitent aucun hook.
Cet exemple utilise un flux y/n où toute entrée autre que y est traitée comme un refus. En pratique, vous pourriez construire une interface utilisateur plus riche qui permet aux utilisateurs de modifier la demande, de fournir des commentaires, ou de rediriger Claude entièrement. Voir Répondre aux demandes d’outil pour tous les moyens de répondre.

Répondre aux demandes d’outil

Votre callback retourne l’un de deux types de réponse : Lors de l’autorisation, l’outil s’exécute avec l’entrée que Claude a demandée, sauf si vous retournez une entrée modifiée, updatedInput en TypeScript ou updated_input en Python. Avant la v2.1.207, Claude Code rejetait un résultat allow qui omettait updatedInput et refusait l’appel d’outil avec une erreur de validation. Lors du refus, fournissez un message expliquant pourquoi. Claude voit ce message et peut ajuster son approche.
Au-delà de l’autorisation ou du refus, vous pouvez modifier l’entrée de l’outil ou fournir un contexte qui aide Claude à ajuster son approche :
  • Approuver : laisser l’outil s’exécuter comme Claude l’a demandé
  • Approuver avec des modifications : modifier l’entrée avant l’exécution (par exemple, nettoyer les chemins, ajouter des contraintes)
  • Approuver et mémoriser : renvoyer une règle de permission suggérée pour que les appels correspondants ignorent l’invite la prochaine fois
  • Rejeter : bloquer l’outil et dire à Claude pourquoi
  • Suggérer une alternative : bloquer mais guider Claude vers ce que l’utilisateur veut à la place
  • Rediriger entièrement : utiliser streaming input pour envoyer à Claude une instruction complètement nouvelle
L’utilisateur approuve l’action telle quelle. Passez l’input de votre callback inchangée et l’outil s’exécute exactement comme Claude l’a demandé.

Gérer les questions de clarification

Lorsque Claude a besoin de plus de direction sur une tâche avec plusieurs approches valides, il appelle l’outil AskUserQuestion. Cela déclenche votre callback canUseTool avec toolName défini sur AskUserQuestion. L’entrée contient les questions de Claude sous forme d’options à choix multiples, que vous affichez à l’utilisateur et retournez ses sélections.
Les questions de clarification sont particulièrement courantes en mode plan, où Claude explore la base de code et pose des questions avant de proposer un plan. Cela rend le mode plan idéal pour les flux de travail interactifs où vous voulez que Claude rassemble les exigences avant de faire des modifications.
Les étapes suivantes montrent comment gérer les questions de clarification :
1

Passer un callback canUseTool

Passez un callback canUseTool dans vos options de requête. Par défaut, AskUserQuestion est disponible. Si vous spécifiez un tableau tools pour restreindre les capacités de Claude (par exemple, un agent en lecture seule avec seulement Read, Glob, et Grep), incluez AskUserQuestion dans ce tableau. Sinon, Claude ne pourra pas poser de questions de clarification :
2

Détecter AskUserQuestion

Dans votre callback, vérifiez si toolName est égal à AskUserQuestion pour le gérer différemment des autres outils :
3

Analyser l'entrée de la question

L’entrée contient les questions de Claude dans un tableau questions. Chaque question a une question (le texte à afficher), des options (les choix), et multiSelect (si plusieurs sélections sont autorisées) :
Voir Format de question pour les descriptions complètes des champs.
4

Collecter les réponses de l'utilisateur

Présentez les questions à l’utilisateur et collectez ses sélections. La façon dont vous le faites dépend de votre application : une invite de terminal, un formulaire web, un dialogue mobile, etc.
5

Retourner les réponses à Claude

Construisez l’objet answers comme un enregistrement où chaque clé est le texte de question et chaque valeur est le label de l’option sélectionnée :Pour les questions multi-sélection, passez un tableau de labels ou joignez-les avec ", ". Si vous supportez l’entrée de texte libre, utilisez le texte personnalisé de l’utilisateur comme valeur.

Format de question

L’entrée contient les questions générées par Claude dans un tableau questions. Chaque question a ces champs : La structure que votre callback reçoit :

Aperçus d’options (TypeScript)

toolConfig.askUserQuestion.previewFormat ajoute un champ preview à chaque option afin que votre application puisse afficher une maquette visuelle à côté du label. Sans ce paramètre, Claude ne génère pas d’aperçus et le champ est absent. Le format s’applique à toutes les questions de la session. Claude inclut preview sur les options où une comparaison visuelle aide (choix de mise en page, schémas de couleurs) et l’omet où ce ne serait pas le cas (confirmations oui/non, choix texte uniquement). Vérifiez undefined avant de rendre.
Une option avec un aperçu HTML :

Format de réponse

Retournez un objet answers mappant le champ question de chaque question au label de l’option sélectionnée : Pour les questions multi-sélection, passez un tableau de labels ou joignez-les avec ", ". Pour l’entrée de texte libre par question, comme une option « Autre », mettez le texte de l’utilisateur dans answers[question] comme indiqué dans Supporter l’entrée de texte libre. Définissez response uniquement lorsque votre interface utilisateur permet à l’utilisateur de rejeter la carte de question et de taper une réponse générale qui n’est pas une réponse à une question spécifique. Lorsque response est défini, Claude reçoit « L’utilisateur a répondu : … » au lieu de la liste de réponses par question.

Supporter l’entrée de texte libre

Les options prédéfinies de Claude ne couvriront pas toujours ce que les utilisateurs veulent. Pour permettre aux utilisateurs de taper leur propre réponse :
  • Affichez un choix supplémentaire « Autre » après les options de Claude qui accepte l’entrée de texte
  • Utilisez le texte personnalisé de l’utilisateur comme valeur de réponse (pas le mot « Autre »)
Voir l’exemple complet ci-dessous pour une implémentation complète.

Exemple complet

Claude pose des questions de clarification lorsqu’il a besoin d’une entrée utilisateur pour continuer. Par exemple, lorsqu’on lui demande d’aider à décider d’une pile technologique pour une application mobile, Claude pourrait poser des questions sur cross-platform vs native, les préférences de backend, ou les plates-formes cibles. Ces questions aident Claude à prendre des décisions qui correspondent aux préférences de l’utilisateur plutôt que de deviner. Cet exemple gère ces questions dans une application de terminal. Voici ce qui se passe à chaque étape :
  1. Router la demande : Le callback canUseTool vérifie si le nom de l’outil est "AskUserQuestion" et route vers un gestionnaire dédié
  2. Afficher les questions : Le gestionnaire boucle à travers le tableau questions et imprime chaque question avec des options numérotées
  3. Collecter l’entrée : L’utilisateur peut entrer un numéro pour sélectionner une option, ou taper du texte libre directement (par exemple, « jquery », « je ne sais pas »)
  4. Mapper les réponses : Le code vérifie si l’entrée est numérique (utilise le label de l’option) ou du texte libre (utilise le texte directement)
  5. Retourner à Claude : La réponse inclut à la fois le tableau questions original et le mapping answers
Enregistrez la version TypeScript sous ask.ts et exécutez-la avec npx tsx ask.ts, ou enregistrez la version Python sous ask.py et exécutez-la avec python ask.py.

Limitations

  • Subagents : AskUserQuestion n’est actuellement pas disponible dans les subagents générés via l’outil Agent
  • Limites de questions : chaque appel AskUserQuestion supporte 1-4 questions avec 2-4 options chacune

Autres façons d’obtenir une entrée utilisateur

Le callback canUseTool et l’outil AskUserQuestion couvrent la plupart des scénarios d’approbation et de clarification, mais le SDK offre d’autres façons d’obtenir une entrée des utilisateurs :

Streaming input

Utilisez streaming input lorsque vous avez besoin de :
  • Interrompre l’agent en cours de tâche : envoyer un signal d’annulation ou changer de direction pendant que Claude travaille
  • Fournir un contexte supplémentaire : ajouter des informations dont Claude a besoin sans attendre qu’il les demande
  • Construire des interfaces de chat : permettre aux utilisateurs d’envoyer des messages de suivi pendant les opérations longues
Streaming input est idéal pour les interfaces conversationnelles où les utilisateurs interagissent avec l’agent tout au long de l’exécution, pas seulement aux points d’approbation.

Outils personnalisés

Utilisez outils personnalisés lorsque vous avez besoin de :
  • Collecter une entrée structurée : construire des formulaires, des assistants, ou des flux de travail multi-étapes qui vont au-delà du format à choix multiples de AskUserQuestion
  • Intégrer des systèmes d’approbation externes : se connecter à des plates-formes de ticketing, de flux de travail, ou d’approbation existantes
  • Implémenter des interactions spécifiques au domaine : créer des outils adaptés aux besoins de votre application, comme des interfaces d’examen de code ou des listes de contrôle de déploiement
Les outils personnalisés vous donnent un contrôle total sur l’interaction, mais nécessitent plus de travail d’implémentation que d’utiliser le callback canUseTool intégré.