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ôle | Responsabilités |
|---|---|
| Client / hôte | Dé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 agent | Accepte 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.
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
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/closelibère la session active et ses processus ;session/resumese rattache à l’état de session persistant ADK ;session/loadréactive une session persistante et rejoue sa conversation stockée vers le client sous forme de notificationssession/updateordonnées avant que la requête ne se termine ;session/forkcré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/deletesupprime la session persistante ;session/listrenvoie les sessions visibles via leSessionServiceconfiguré.
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_modevalide le mode demandé par rapport à l’ensemble annoncé, l’enregistre et émet unCurrentModeUpdate; 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_optionvalide la valeur par rapport aux choix déclarés de l’option, l’enregistre et émet unConfigOptionUpdate; une option inconnue ou une valeur invalide est rejetée. - Commandes disponibles — des slash-commands ACP exposées comme un
AvailableCommandsUpdatelorsqu’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
UsageUpdatereflé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
ToolCallavec unkindd’outil déduit du comportement déclaré de l’outil. SonToolCallUpdateulté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 leToolCalld’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.