Aller au contenu

Cycle de vie du lancement d’un agent

Un lancement correspond à une exécution d’un agent, dans une conversation, sur un adaptateur. Tout ce qui s’y rapporte se déroule sur cc_server : le client envoie un message, puis observe les événements qui remontent en flux. Aucun client ne comporte de chemin de lancement.

Les agents sont réveillés pour six raisons, que l’exécution transporte sous forme de contexte de réveil afin que l’agent sache pourquoi il est réveillé :

Raison de réveil Déclencheur
userMessage Quelqu’un a envoyé un message dans un espace ou a mentionné l’agent
assignment Un ticket a été attribué à l’agent
pipelineStep Une étape de pipeline l’a lancé
childCompleted Un ticket enfant s’est terminé
followUp Un battement de relance planifié
recovery Le chemin de récupération a relancé l’exécution après un échec

Le contexte de réveil transporte les identifiants associés à la raison — ticket, espace, message, exécution de pipeline — et ceux-ci sont injectés dans l’environnement et le prompt de l’agent.

Le prompt est construit par couches, chacune formant une section étiquetée :

  • Identité — l’identifiant, le nom et l’identifiant d’espace de travail de l’agent lui-même, accompagnés d’une instruction explicite de transmettre ces UUID exacts aux outils propres à l’espace de travail. L’espace de travail est intrinsèque à l’agent, il est donc toujours présent.
  • Catalogue d’outils et protocoles de ressources, puis la disposition de l’espace de travail.
  • Remplacement du prompt système, si l’agent en a un, puis le persona (paramétré par le rôle) et le brief d’équipe.
  • Skills — les noms portés par l’agent.
  • Contrat d’exécution et procédure pour le mode en cours.
  • Contexte de réveil et contexte de mention : qui a convoqué l’agent et l’effectif qui l’entoure.
  • Bloc de mode — généré à partir du profil de capacités du mode et de sa liste d’outils matérialisée, de sorte qu’un prompt ne peut jamais nommer un outil dont l’exécution ne dispose pas réellement.
  • Contexte de mémoire — les faits récupérés pour la tâche.
  • Contexte de conversation — l’historique récent de l’espace, plafonné à 50 000 caractères de fenêtre textuelle intégrale, peu importe la taille de contexte configurée pour l’agent. L’historique plus ancien n’est pas tronqué : l’agent le récupère à la demande avec get_messages, et les messages plus anciens pertinents sur le plan sémantique refont tout de même surface.

Les commandes se répartissent en deux endroits. /todo et /compact sont interceptées dans le composeur et ne sont délibérément jamais consignées comme messages ni transmises à l’agent — consigner /compact repousserait la coupure de compactage d’un tour et polluerait la transcription. /plan est traitée aux deux endroits : le composeur bascule le mode de l’espace, ce qui fait que la surface d’outils, le préréglage de garde-fous et le prompt s’accordent pour ce tour et pour tous les tours suivants. /goal, /loop et /skill:<name> sont traitées à l’intérieur de l’exécution elle-même et uniquement sur le harnais intégré — /goal et /loop amorcent un travail autonome assorti d’un budget de coûts, et un nom préfixé par skill: est résolu comme un skill dont le corps du SKILL.md devient la directive du tour. C’est l’espace de noms qui tient les deux vocabulaires séparés : résoudre un nom brut par rapport aux skills faisait qu’un skill nommé plan ou compact était éclipsé en permanence par la commande intégrée. Un nom brut non intégré est tout de même résolu, pour les messages écrits avant l’existence de l’espace de noms. Un nom non reconnu passe simplement comme texte brut.

Avant que quoi que ce soit ne s’exécute, la conversation obtient sa propre racine de travail, sous laquelle se trouve un arbre de travail isolé avec copie sur écriture pour chaque dépôt. Par défaut, il s’agit de tous les dépôts liés à l’espace de travail ; un espace de PR — ou un espace créé avec une sélection explicite — ne provisionne que ceux figurant sur la liste d’autorisation, et une conversation de révision de PR fixe son unique dépôt sur la référence de tête de la demande de tirage, tandis que les autres restent sur leur branche par défaut. La copie source n’est jamais modifiée et l’ensemble du répertoire de conversation est récupéré lorsque l’espace est supprimé.

La copie sur écriture est la seule implémentation partout où rift est livré, soutenue par le module natif fourni. Un système de fichiers qui ne peut pas effectuer de reflink — ou un répertoire de données situé sur un volume différent de celui du dépôt — fait échouer le provisionnement plutôt que de se rabattre sur un repli. git worktree est le backend sur Windows, où il n’y a aucun backend de copie sur écriture à compiler, et il ne s’agit pas d’une dégradation silencieuse sur les autres hôtes. Un rift manquant sur une plateforme où il est livré constitue une installation défectueuse — le serveur refuse de démarrer plutôt que de se rabattre discrètement, car un repli silencieux dissimule la panne derrière un chemin plus lent pour toujours.

Deux identités sont résolues par exécution, avant le lancement de tout processus.

Paternité Git. Les commits produits par un agent lui sont attribués en tant qu’agent — <Name> (agent) <agentId@agents.control-center.local> dans GIT_AUTHOR_* et GIT_COMMITTER_* — sans jamais usurper l’identité d’un humain. La partie locale est l’UUID de l’agent, et non son slug de nom. La personne à l’origine de la demande est créditée d’une ligne de pied Co-Authored-By:, transportée dans l’environnement et prescrite dans le prompt système. Une identité explicite définie par l’appelant l’emporte toujours sur les deux.

Identité de la forge. L’identifiant GitHub de l’exécution n’est jamais que celui du courtier — un jeton d’installation d’App limité à un dépôt, ou son repli par PAT défini dans l’environnement — jamais le jeton personnel enregistré du membre à l’origine de la demande. actingUserId borne le repli PAT pour qu’un membre qui n’est pas le propriétaire du serveur n’hérite pas de la portée du serveur ; il ne superpose pas un jeton personnel à l’environnement de l’agent.

Les identifiants de fournisseur de modèle sont résolus dans un ordre fixe, et cet ordre importe :

  1. une substitution par variable d’environnement propre à l’adaptateur,
  2. l’environnement de l’appelant,
  3. le magasin d’identifiants du serveur (avec rafraîchissement d’un jeton OAuth s’il approche de l’expiration),
  4. l’environnement du processus.

Parce que la substitution propre à l’adaptateur vient en premier, elle l’emporte silencieusement sur un compte de fournisseur connecté dans l’application. Si une exécution est facturée au mauvais compte, cette substitution est le premier endroit à vérifier. Les identifiants de fournisseur sont globaux à l’hôte — partagés entre tous les espaces de travail de l’installation.

Le jeton GitHub de l’exécution provient du courtier d’identifiants : un jeton en lecture seule, limité au dépôt de l’arbre de travail. Un push passe par la passerelle d’exécution d’agent, qui interroge la règle Pousser vers un dépôt distant avant de le transmettre, et aucune clé de tickets n’est injectée. Voir Bac à sable et sécurité.

L’exécution est lancée avec son arbre de travail comme répertoire de travail et, pour Claude Code, une configuration MCP générée afin que l’agent puisse atteindre la surface d’outils de Control Center. ACP et le bash du harnais reçoivent un environnement assaini ; Claude Code au moyen de NoSandboxAdapter hérite de l’environnement de l’hôte.

L’exécution renvoie en flux une séquence d’événements typés, que le processeur de flux consigne sous forme de deltas de messages, replie en segments de transcription et transforme en événements de messagerie :

Événement Ce qu’il transporte
thinking Sortie de raisonnement, rendue en ligne
text Sortie visible
toolCall Une invocation d’outil, avec son identifiant et ses arguments structurés
toolResult Le résultat correspondant, signalé lorsqu’il a produit une erreur ou qu’il s’agit d’un flux partiel
usage Nombre de jetons et coût pour une fenêtre de mesure
error Une erreur, accompagnée du code structuré de l’adaptateur lorsqu’il en a signalé un
sandboxViolation Le système d’exploitation a refusé un appel système. Émis uniquement là où un bac à sable enveloppe réellement le processus — voir la note ci-dessus
debug Diagnostics d’exécution (marqueurs de lancement, décisions des garde-fous, rappels de contrat)
done L’exécution est terminée

Il n’existe délibérément aucun plafond de tours, nulle part. Un nombre d’itérations fixe tue du travail légitime de longue haleine (migrations, nettoyage en éventail) et n’attrape rien que les gardes ci-dessous n’attrapent plus tôt. Une exécution se termine lorsque :

  • le modèle s’arrête de lui-même ;
  • un humain l’arrête ou prend en main la conversation (ce qui met en pause le harnais intégré à sa prochaine limite de tour propre — une exécution de Claude Code, qui n’a pas de limite sûre, est plutôt arrêtée) ;
  • le chien de garde de silence se déclenche. Aucune sortie pendant le seuil et la session est interrompue avec une défaillance silentRun. La valeur par défaut est de 15 minutes, ramenée à 10 dans les modes essentiellement en lecture (révision et plan) ; un agent peut la remplacer pour une valeur entre 1 et 240 minutes. Le chien de garde est armé lorsqu’un processus enfant signale son PID, de sorte qu’il couvre la CLI de Claude Code — pas le harnais intégré, qui ne lance aucun processus ;
  • un plafond de coûts mord — mais uniquement pour les commandes autonomes.

Le garde-fou anti-boucle n’est pas un terminateur : après trois appels d’outil identiques d’affilée, la boucle oriente l’agent vers un changement d’approche.

Pris dans leur ensemble, un tour interactif ordinaire sur le harnais intégré n’a ni plafond de tours, ni plafond de coûts, ni chien de garde de silence. Il se termine lorsque le modèle s’arrête ou lorsque vous l’arrêtez. C’est un compromis délibéré — les solutions de rechange tuent toutes du travail légitime de longue haleine — mais cela signifie bel et bien qu’une exécution interactive sans surveillance n’est bornée par rien d’autre que le jugement du modèle lui-même.

En cours d’exécution, un message envoyé à un agent en marche est mis en file à titre de pilotage et drainé à la limite de tour suivante, de sorte que vous pouvez orienter une exécution sans la tuer. Le pilotage, la mise en pause, les sous-agents et le contrat d’achèvement sont des fonctionnalités du harnais intégré ; Claude Code n’en possède aucune.

Chaque lancement écrit un AgentRunLog : heure de début et de fin, résumé, nombre de jetons et coût estimé (y compris le coût cumulé des sous-agents), adaptateur et modèle, identifiant de processus et chemin du journal, la conversation ainsi que tout ticket ou toute exécution de pipeline à laquelle elle appartient, en plus de deux champs de classification qui portent l’essentiel de la vérité.

  • Le statut est grossier : pending, running, completed, error.
  • La vitalité est la lecture plus fine : alive, productive, completed, blocked, empty, looping, failed, stalled, dead.
  • La famille d’erreurs regroupe utilement les défaillances : transientUpstream, sandboxInfrastructure, budgetExceeded, processLost, silentRun, unknown.

La fermeture de l’exécution publie AgentRunCompleted, et beaucoup de choses en dépendent : le cumul des coûts de pipeline, la reprise d’une étape de pipeline qui attendait l’exécution, l’achèvement du ticket sous-jacent, le mappage d’une orchestration vers un état terminal, la décision de continuer ou d’arrêter du superviseur d’objectifs, le rôle de vérificateur et l’évaluation budgétaire après l’exécution. La liste de présence suit séparément, en observant les journaux d’exécution récents plutôt que l’événement. La notification « Agent terminé » ne figure pas dans cette liste : l’événement se déclenche à la fin du flux du processus, avant l’écriture de la réponse. La notification est donc le MessageReceived du tour, publié une fois le message enregistré.

L’application du budget est une réaction, et non un verrou. Lorsqu’une exécution se termine, l’évaluateur compare les dépenses de l’agent depuis le début du mois à son plafond effectif (une politique budgétaire liée s’il en existe une, sinon le chiffre mensuel de l’agent lui-même ; zéro signifie illimité). Le franchissement du seuil souple consigne un incident d’avertissement ; l’épuisement du budget consigne un incident grave et bascule le statut de cycle de vie de l’agent à paused dans l’organigramme. Le lancement accepte tout de même du travail de la part de cet agent. Un déclencheur de pipeline BudgetThresholdCrossed peut amorcer un travail de suivi à partir du même événement.

Chaque journal d’exécution peut porter une filiation de reprise — un identifiant d’exécution parente, un compteur de tentatives et un résumé de continuation. L’arborescence d’exécution de la conversation affiche le numéro de tentative lorsqu’il est différent de zéro. Un « réessayer » depuis le clavardage est un nouveau lancement assorti d’un nouveau journal d’exécution.