Niveaux d’autonomie
L’autonomie est un paramètre par agent qui réside dans un profil de risque nommé : [risk_profiles.<alias>].level. Chaque agent référence un profil de risque via agents.<alias>.risk_profile = "<profile-alias>". Trois paramètres ; supervised est la valeur par défaut.
readonly / supervised / full sont les seules valeurs acceptées ; read_only (avec un tiret de soulignement) est rejeté au chargement de la configuration. Consultez l’Exemple minimal fonctionnel canonique pour voir comment le profil s’intègre dans une configuration complète.
Les trois niveaux
readonly
L’agent peut observer mais ne peut rien modifier. Les outils autorisés sont ceux qui n’ont aucun effet secondaire :
file_read,file_listmemory_searchhttp(GET uniquement ; les POST sont bloqués)web_searchtime
Utile pour : un agent de questions-réponses destiné au public, un déploiement en mode analyse uniquement, ou comme moyen de vérifier une nouvelle configuration d’outil avant de lui permettre d’écrire quoi que ce soit.
supervisé (par défaut)
Les outils à faible risque s’exécutent automatiquement. Les outils à risque moyen déclenchent une invite de validation par l’opérateur. Les outils à risque élevé sont bloqués.
Classification des risques :
| Risque | Exemples | Comportement |
|---|---|---|
| Faible | file_read, http GET, memory_search, web_search, time | Exécute |
| Moyen | file_write dans l’espace de travail, shell avec les commandes autorisées, http POST vers les domaines autorisés | Demande à l’opérateur |
| Élevé | shell avec des commandes inconnues/refusées, file_write en dehors de l’espace de travail, motifs destructeurs | Blocs |
Canal d’approbation : l’invite d’approbation est transmise via le canal qui a initié la conversation. Telegram utilise des boutons de clavier inline ; Slack Socket Mode utilise des boutons Block Kit ; Discord, Signal, Matrix et WhatsApp intègrent un court token dans l’invite et attendent une réponse <token> approve|deny|always. Dans la CLI, c’est une invite inline. Dans ACP, l’agent émet une requête JSON-RPC session/request_permission de l’agent vers le client (et non une notification session/update) ; le client répond avec {"outcome": {"outcome": "selected", "optionId": "allow-once|allow-always|reject-once"}} ou {"outcome": {"outcome": "cancelled"}} pour approuver, toujours approuver ou refuser. Voir ACP → session/request_permission.
Timeout : les demandes d’approbation sans réponse expirent après le approval_timeout_secs du canal (120 par défaut pour la plupart des canaux ; voir le bloc de configuration de chaque canal). Les délais d’attente dépassés sont traités comme des refus.
full
Les appels d’outils non couverts, signalés low/medium/high, s’exécutent sans demander confirmation. always_ask demande tout de même confirmation en mode Full : un nom exact ou "*" affiche une invite d’approbation dans la CLI, achemine une demande via un canal de retour, ou échoue en mode fermé sur une surface non interactive sans approbateur. workspace_only est implicitement désactivé (l’agent peut accéder à des chemins en dehors de l’espace de travail) ; forbidden_paths bloque toujours ; le sandbox au niveau du système d’exploitation (sandbox_enabled + sandbox_backend) s’applique toujours.
Ceci convient à un environnement de développement local de confiance, à la CI, ou aux procédures (SOP) qui doivent s’exécuter de bout en bout sans intervention humaine. Conservez les outils sensibles dans always_ask si vous avez besoin du mode Full pour tout le reste tout en voulant une demande de confirmation (ou un refus en mode fail-closed) pour ces outils. Si vous avez besoin de full + aucune contrainte d’espace de travail + aucun bac à sable, consultez mode YOLO.
Overrides par outil
auto_approve, always_ask et excluded_tools sont des listes plates de noms d’outils dans le profil de risque (et non des tables imbriquées). always_ask est prioritaire sur l’autonomie complète, auto_approve et une autorisation « Toujours » au niveau de la session : un outil listé (ou "*") demande toujours confirmation. excluded_tools est également disponible par canal (channels.<type>.<alias>.excluded_tools) pour masquer des outils sur des surfaces spécifiques sans modifier le profil.
Routage inter-canaux des approbations
Par défaut, une demande d’approbation est transmise via le canal qui a initié la conversation. Pour envoyer les approbations d’outils d’un profil vers un canal d’approbation distinct à la place (par exemple, un agent initié depuis un canal public dont les actions risquées doivent être validées par un canal Ops séparé, ou par un principal différent), définissez approval_route sur le profil de risque :
[risk_profiles.frontline.approval_route]
approver_channel = "matrix.ops" # une clé du registre de canaux, PAS l'expéditeur d'origine
approver_recipient = "!ops:example.org" # identifiant de salle Matrix ; destination propre à la route
on_no_approver = "deny" # valeur par défaut ; ou "inherit-originator"
timeout_secs = 120 # valeur par défaut ; borne la fenêtre de réponse de l'approbateur
approver_channelest la clé du registre des canaux qui reçoit la demande d’approbation. Les clés sont qualifiées par plateforme,<channel>.<alias>(par exemplematrix.opsoutelegram.default) ; un nom de plateforme nu (p. ex.matrix) ne se résout que lorsqu’il s’agit de l’unique canal de cette plateforme. Un alias seul n’est pas une clé de registre et échouera en mode fermé. Lorsque la route est définie, la porte d’approbation interroge uniquement ce canal, pas celui d’origine.approver_recipientest la destination sur ce canal, et non le destinataire d’origine de l’émetteur. Elle dépend du canal : utilisez un identifiant de salle Matrix tel que!ops:example.org, un identifiant de chat Telegram tel que-1001234567890, un identifiant de canal Slack tel queC0123456789, ou un identifiant de canal Discord tel que123456789012345678. La destination configurée est utilisée pour le saut vers l’approbateur ; le destinataire d’origine n’est jamais réutilisé à cette fin.on_no_approverdécide de ce qui se produit lorsque l’approbateur ne répond pas de manière décisive, est inaccessible, n’est pas un canal enregistré, ou expire :deny(par défaut) échoue en mode fermé et refuse l’appel de l’outil.inherit-originatorse rabat sur le prompt du canal d’origine (comportement actuel).
- Une valeur
approver_recipientabsente ou vide rend l’approbateur indisponible. Elle suiton_no_approver: la valeur par défautdenyferme l’accès en cas d’échec (fail closed), tandis queinherit-originatorautorise explicitement le repli sur le canal d’origine. timeout_secs(par défaut 120) borne le temps pendant lequel la porte attend l’approbateur avant d’appliqueron_no_approver, afin qu’un canal d’approbateur bloqué ne puisse pas bloquer un tour.
Lorsque approval_route est absent (par défaut), les approbations se comportent exactement comme décrit ci-dessus : délivrées via le canal qui a initié la conversation. Le comportement par défaut fail-closed signifie qu’un approbateur mal configuré ou inaccessible refuse plutôt que de s’auto-approuver silencieusement.
Portée.
approval_routeest respecté sur les deux chemins de tour : le chemin interactif, piloté par un canal (un tour transportant un identifiant de canal actif, par ex. un chat d’agent en streaming) et le chemin non interactif qui s’exécute sans canal d’origine (dispatch de chat de passerelle et de webhook, ainsi que messages pair à pair entre agents). Sur le chemin non interactif, l’approuveur doit être un canal actif et enregistré dans le daemon en cours d’exécution (il est résolu via le registre des canaux du daemon) ; si ce registre est indisponible (par exemple lors d’une exécution CLI ponctuelle sans canaux démarrés) ou si l’approuveur nommé n’est pas actif, la porte de contrôle utilise la valeur par défaut non interactive du profil, qui échoue en refusant l’accès (denies) par défaut souson_no_approver = "deny".
Les délégués agentiques indépendants peuvent utiliser la route explicite du profil de risque cible pour l’exécution au premier plan, en arrière-plan et en parallèle. Le canal et le destinataire doivent tous deux être configurés. L’enfant reçoit un gestionnaire d’approbation neuf : les autorisations de session de l’appelant et le canal client d’origine ne sont pas hérités. Un approbateur indisponible entraîne un refus par défaut, même avec inherit-originator, car l’enfant ne dispose d’aucun canal d’origine. Consultez Approbations des délégués indépendants pour la configuration et la durée de vie des autorisations. Les délégués agentiques bornés conservent leurs règles d’approbation existantes en l’absence d’opérateur.
Liste d’autorisation des commandes
Pour l’outil shell spécifiquement : si allowed_commands est non vide, le comportement est strict : toute commande non listée est bloquée. Le validateur shell-policy gère la détection des motifs destructeurs en plus de la liste d’autorisation.
Règles de chemin
workspace_only = true limite les lectures et les écritures à <workspace>/**, ainsi qu’à toutes les valeurs configurées de allowed_roots pour le mode d’accès demandé. Les entrées absolues de l’espace de travail, des racines autorisées et de forbidden_paths utilisent des préfixes de composants de chemin. Lorsque plusieurs entrées correspondent, le préfixe le plus spécifique l’emporte ; en cas d’égalité de profondeur, l’entrée interdite l’emporte. Un sous-arbre interdit peut donc bloquer une partie de l’espace de travail ou d’une racine autorisée, tandis qu’une autorisation étroite de l’opérateur peut rester utilisable sous une racine interdite par défaut plus large telle que /home ou /tmp.
Les vérifications des fichiers résolus comparent toutes les entrées correspondantes après résolution des alias du système de fichiers ; ainsi, désigner un sous-arbre interdit via un lien symbolique ne permet pas de contourner le refus. Il s’agit de règles de préfixe absolu : elles ne prennent pas en charge la correspondance par glob ni la sémantique des motifs d’exclusion relatifs à l’espace de travail.
bac à sable
Les champs de bac à sable au niveau du système d’exploitation se trouvent dans le même profil de risque. Consultez Bac à sable pour la sélection du backend selon le système d’exploitation.
Transfert de l’environnement
L’outil shell s’exécute par défaut dans un environnement minimal ; exposez des variables d’environnement spécifiques via le profil de risque. Les secrets (motifs API_KEY, _TOKEN, _SECRET, _PASSWORD) ne sont jamais transmis automatiquement ; listez-les explicitement ou récupérez-les depuis le magasin de secrets à l’intérieur de la commande.
Autonomie plus stricte par canal
L’autonomie est définie par agent, et non par canal. Pour exécuter un canal public à un niveau plus strict que votre agent principal, définissez un second agent lié à un profil de risque plus strict et acheminez ce canal vers lui. Le paramètre excluded_tools par canal (channels.<type>.<alias>.excluded_tools) est l’option la plus économique lorsque vous avez seulement besoin de masquer des outils individuels, sans nécessiter de second agent.
Observabilité
Les demandes d’approbation, les accords, les refus et les délais d’expiration émettent tous des événements structurés via le crate infra :
INFO autonomie:approbation_demandée outil=file_write chemin=/tmp/foo.txt canal=discord utilisateur=alice
INFO autonomie:approbation_accordée outil=file_write chemin=/tmp/foo.txt canal=discord utilisateur=alice
WARN autonomie:expiration_délai_d'approbation outil=shell commande="git push" canal=telegram utilisateur=bob
WARN autonomie:bloqué outil=shell commande="rm -rf /tmp" raison="motif interdit"
Les appels bloqués, les refus et les timeouts sont dignes d’un audit, mais ils ne constituent pas des tool receipts. Ils émettent des événements d’observabilité ; les reçus d’outil sont associés aux résultats d’outils réussis lorsque les reçus sont activés.
Pourquoi ne pas simplement un mode binaire « sûr » ?
Parce que le juste milieu utile est vaste. Un utilisateur qui veut que les agents exécutent des scripts automatiquement mais ne poussent pas sur master a besoin de quelque chose entre « tout est autorisé » et « rien n’est autorisé ». Les trois niveaux d’autonomie + les surcharges par outil + les listes d’autorisation de commandes offrent ce réglage sans fragmenter la configuration.