Architecture du protocole Agent Client

ACP standardise la relation entre une interface de codage et un agent de codage. Il leur donne une manière commune d’établir des capacités, d’ouvrir une session de projet, d’échanger des invites, de diffuser la progression en continu, de demander une autorisation, d’annuler le travail et de fermer ou reprendre la session.

Les deux rôles

RôleResponsabilités
Client / hôteDémarre le processus de l’agent, présente l’interface humaine, sélectionne l’espace de travail, fournit des fichiers, des terminaux et des serveurs MCP facultatifs, applique la politique d’autorisation et affiche les mises à jour en direct
ACP agentAccepte les sessions et les invites du projet, effectue le travail de codage, signale les messages et l’activité des outils, demande une autorisation lorsque nécessaire et renvoie une raison d’arrêt typée

ADK-Rust peut occuper l’un ou l’autre rôle. Ce sont deux directions de déploiement, pas deux protocoles différents.

Rendering architecture…

Lorsque ADK-Rust consomme un autre agent de codage, le côté gauche est ADK-Rust et le côté droit est le processus externe. Lorsqu’un éditeur consomme un agent ADK-Rust, l’éditeur possède le côté gauche et AcpServer possède le côté droit.

Un tour de ACP

Rendering architecture…

La connexion est bidirectionnelle. Un client doit continuer à lire pendant qu’une invite s’exécute, car l’agent peut envoyer des notifications ou des demandes d’autorisation avant la réponse finale de l’invite.

Identité et état de la session

Une session ACP identifie une conversation en cours au sujet d’un projet. Elle contient un cwd absolu, des répertoires supplémentaires facultatifs, plusieurs invitations, des mises à jour diffusées en continu et un cycle de vie. Dans le serveur ADK-Rust, une session ACP correspond à une session ADK-Rust afin que l’historique du modèle et l’état de la session restent attachés à la même conversation.

Fermer une connexion active est différent de supprimer l’historique persistant :

  • session/close libère la session active et ses processus ;
  • session/resume se rattache à l’état de session persistant ADK ;
  • session/load réactive une session persistante et rejoue sa conversation stockée vers le client sous forme de notifications session/update ordonnées avant que la requête ne se termine ;
  • session/fork crée une branche d’une session persistante vers un nouvel identifiant de session dont l’historique stocké est une copie de celui de la source, en laissant la source intacte ;
  • session/delete supprime la session persistante ;
  • session/list renvoie les sessions visibles via le SessionService configuré.

session/load valide le cwd fourni par rapport au répertoire de travail stocké de la session de la même manière que session/resume, et renvoie une erreur de session introuvable pour un identifiant de session inconnu. La relecture mappe chaque événement utilisateur, agent, réflexion et outil stocké vers son variant SessionUpdate correspondant dans l’ordre chronologique d’origine, de sorte qu’un éditeur qui se reconnecte restaure l’historique visible dans l’ordre où il s’est produit.

Contrôles de session interactive

Un agent peut exposer des contrôles interactifs au client en fournissant un fournisseur SessionControls. Lorsqu’il le fait, le serveur les annonce dans les réponses session/new, session/load, session/resume et session/fork :

  • Modes — un ensemble de modes nommés (par exemple "ask" versus "code") avec une sélection actuelle. session/set_mode valide le mode demandé par rapport à l’ensemble annoncé, l’enregistre et émet un CurrentModeUpdate ; un mode inconnu est rejeté et le mode actuel reste inchangé.
  • Options de configuration — des sélecteurs et des commutateurs que le client peut lire et modifier. session/set_config_option valide la valeur par rapport aux choix déclarés de l’option, l’enregistre et émet un ConfigOptionUpdate ; une option inconnue ou une valeur invalide est rejetée.
  • Commandes disponibles — des slash-commands ACP exposées comme un AvailableCommandsUpdate lorsqu’une session devient active.

Les sélections de mode et de configuration persistent dans l’état de session ADK (acp:mode, acp:config:<id>), elles survivent donc au chargement, à la reprise et à la division. Un titre de session enregistré apparaît comme un SessionInfoUpdate à l’activation et chaque fois qu’il change. Une mapping de mise à jour Plan existe mais reste dormante jusqu’à ce qu’une primitive de plan ADK fasse remonter les entrées de plan. Un agent qui ne fournit aucun SessionControls n’annonce aucun mode ni aucune option, ce qui maintient les capacités annoncées exactement alignées sur ce que le serveur implémente.

Le contenu traverse la frontière via un seul mapping

Les invites qui arrivent d’un client et les mises à jour qui lui sont renvoyées passent toutes deux par un seul module de contenu qui mappe des valeurs ACP ContentBlock vers des valeurs adk_core::Part et inversement. Le fait de conserver un seul mapping dans les deux sens signifie que le parseur d’invite du serveur, le diffuseur du serveur et le client s’accordent tous sur la représentation de chaque type de contenu.

Le mapping préserve fidèlement les charges utiles. Les blocs de texte se mappent vers Part::Text avec la chaîne intacte. Les blocs de ressource intégrée se mappent vers Part::EmbeddedResource, en conservant la source URI, le type MIME facultatif et le contenu. Une ressource textuelle circule verbatim dans les deux sens et n’est jamais encodée en base64 ; une ressource binaire est encodée en base64 sur le fil et décodée en octets bruts du côté ADK de la frontière. Les blocs d’image et d’audio se mappent vers Part::InlineData, en préservant le type MIME et les octets décodés ; le serveur annonce et accepte ces médias d’invite, et le client transmet le contenu non textuel ADK (ressource intégrée, image, audio) sous forme du bloc ACP correspondant plutôt que de l’abandonner.

Les mises à jour diffusées en continu transportent plus que du texte

Pendant qu’une invite s’exécute, le serveur traduit les événements ADK typés en notifications ACP session/update. Le texte du modèle et les réflexions deviennent des fragments de message et de réflexion, et le contenu de ressource intégrée devient un fragment de message de ressource intégrée. Au-delà de cette surface, deux types de mise à jour donnent au client une vue plus riche du tour :

  • Mises à jour d’utilisation. Lorsqu’un événement ADK transporte des métadonnées d’utilisation, le serveur envoie un UsageUpdate reflétant les décomptes de jetons signalés, ainsi que le coût en USD lorsque l’exécution l’indique. Les événements sans métadonnées d’utilisation ne produisent aucune mise à jour, et le serveur n’invente jamais de décomptes.
  • Mises à jour enrichies des appels d’outil. Un appel d’outil commence comme un ToolCall avec un kind d’outil déduit du comportement déclaré de l’outil. Son ToolCallUpdate ultérieur transporte le contenu du résultat de l’outil et les emplacements de fichiers que l’outil indique avoir affectés, afin qu’un éditeur puisse afficher des diffs et des listes de fichiers affectés. La mise à jour conserve le même identifiant que le ToolCall d’origine, préservant ainsi la corrélation tout au long du tour.

La direction du client a la fidélité correspondante. Lorsqu’une application ADK-Rust consomme un External_Agent, sa surface de diffusion en continu (OutputChunk) expose non seulement le texte et les pensées de l’agent, mais aussi le External_Agent ToolCallUpdate (sous la forme d’une mise à jour d’outil corrélée à l’id, contenant le statut, le type, le titre, le texte du contenu et les emplacements de fichiers affectés) ainsi que son UsageUpdate (tokens utilisés et taille, plus le coût et la devise lorsqu’ils sont renseignés). Le texte des messages de l’agent est exposé exactement comme auparavant, donc les consommateurs de texte existants ne sont pas affectés.

Les demandes d’autorisation font le pont avec les confirmations d’outil

Un agent ADK-Rust peut suspendre un tour dans l’attente de l’approbation humaine d’un appel d’outil (ToolConfirmationRequest). Côté serveur, cette suspension devient une demande native ACP session/request_permission décrivant l’outil et ses arguments. Le résultat du client reprend le tour : une approbation se mappe à allow, et un refus ou une annulation se mappent tous deux à deny, de sorte qu’une demande annulée n’exécute jamais l’outil. Chaque résultat est corrélé à l’appel exact par son identifiant d’appel de fonction et renvoyé au runner via ses décisions de confirmation d’outil. La demande d’autorisation imbriquée est émise depuis la tâche de prompt générée, donc la réponse externe session/prompt se termine toujours normalement.

Les capacités sont un contrat

L’initialisation n’est pas une poignée de main décorative. Chaque partie annonce uniquement les opérations et le contenu qu’elle prend en charge. ADK-Rust utilise ces capacités pour éviter d’envoyer une configuration facultative HTTP ou SSE MCP à un agent qui n’accepte que stdio, et il n’annonce les opérations d’hôte du système de fichiers ou du terminal que lorsque l’application fournit l’implémentation correspondante.

Le serveur annonce exactement les types de contenu que son gestionnaire de prompt accepte. Il annonce les capacités de prompt embedded_context, image et audio parce que le contenu de ressource intégrée se mappe à adk_core::Part::EmbeddedResource et que le contenu d’image et d’audio se mappe à adk_core::Part::InlineData. Il annonce load_session parce qu’il enregistre un gestionnaire session/load, et la capacité de session fork parce qu’il enregistre un gestionnaire session/fork. Les modes de session et les options de configuration ne sont annoncés que lorsque l’agent fournit un fournisseur SessionControls, donc un agent qui n’en a pas n’annonce ni l’un ni l’autre. Les transports distants, les sélecteurs de modèle et les ajouts expérimentaux au protocole restent non annoncés. Un prompt portant un type de contenu que le serveur n’a pas annoncé est rejeté avec une erreur descriptive plutôt que d’être traité partiellement. Les appelants doivent concevoir en fonction de l’objet de capacité négocié plutôt que de supposer que chaque implémentation ACP a la même surface.

Suivant