Exposer un agent ADK-Rust via ACP
Utilisez l’orientation serveur lorsqu’un éditeur ou un autre client ACP doit démarrer votre binaire ADK-Rust et utiliser son agent dans une interface de codage. Votre processus Rust gère l’agent, le modèle, les outils, les flux de travail, les sessions, la mémoire et la politique d’exploitation. Le client ne voit que les capacités et le cycle de vie des sessions publiés via ACP.
Installer la fonctionnalité serveur
[dependencies]
adk-acp = { version = "2.1.0", features = ["server"] }
Construire et servir un agent
use adk_acp::server::{AcpServer, AcpServerConfigBuilder};
use adk_session::InMemorySessionService;
use std::sync::Arc;
let config = AcpServerConfigBuilder::new()
.agent(Arc::new(repository_agent))
.session_service(Arc::new(InMemorySessionService::new()))
.agent_name("repository-guide")
.agent_description("Explains and improves this Rust workspace")
.max_sessions(16)
.build()?;
let handle = AcpServer::run(config).await?;
handle.wait().await?;
Le serveur utilise le générateur officiel Agent de SDK et le transport stdio. Le trafic
du protocole est la seule donnée écrite sur stdout ; configurez la journalisation et les
diagnostics pour utiliser stderr.
Correspondance d’exécution
Le gestionnaire valide un cwd absolu, réserve la capacité de session, crée ou reprend la
session ADK et exécute l’agent configuré. Les événements ADK typés sont traduits en
notifications session/update ACP pendant que l’invite est active.
Cycle de vie implémenté
| Opération ACP | Comportement ADK-Rust |
|---|---|
initialize | Négocie le protocole v1 et renvoie les métadonnées exactes de l’implémentation et des capacités |
session/new | Valide les chemins de l’espace de travail et crée une session ADK persistante |
session/prompt | Convertit les blocs de contenu pris en charge (text, resource-link, embedded-resource, image, audio) et diffuse le Runner |
session/load | Réactive une session persistée (en validant cwd) et rejoue sa conversation enregistrée sous forme de notifications session/update ordonnées avant de terminer |
session/cancel | Annule l’invocation active du Runner et renvoie une raison d’arrêt indiquant l’annulation |
$/cancel_request | Annule la requête JSON-RPC correspondante sans corrompre la session |
session/close | Annule le travail actif et libère les processus appartenant à la session |
session/list | Répertorie les sessions persistées visibles par ACP |
session/resume | Se rattache à la session et à l’espace de travail d’origine |
session/fork | Crée une branche d’une session persistée dans une nouvelle session, en copiant son historique et l’état pertinent, tout en laissant la source inchangée |
session/set_mode | Valide et enregistre un mode de session déclaré par le SessionControls de l’agent, en émettant un CurrentModeUpdate |
session/set_config_option | Valide et enregistre une valeur de configuration déclarée par le SessionControls de l’agent, en émettant un ConfigOptionUpdate |
session/delete | Supprime l’historique persistant et libère les ressources actives |
Une seule invite peut s’exécuter à la fois dans une session. Différentes sessions peuvent s’exécuter simultanément jusqu’à max_sessions.
Mappage des événements
- le texte du modèle devient
agent_message_chunk; - le contenu de réflexion du modèle devient
agent_thought_chunk; - le contenu de la ressource intégrée devient une ressource intégrée
agent_message_chunkde ACP ; - les appels de fonction ADK deviennent des mises à jour de démarrage d’outil ACP avec un outil
kinddéduit ; - les réponses de fonction deviennent des mises à jour d’achèvement de l’outil enrichies du contenu du résultat et de tout emplacement de fichier affecté, associées à l’appel d’outil d’origine ;
- les événements contenant des métadonnées d’utilisation deviennent des notifications
UsageUpdate(nombre de jetons, ainsi que le coût en USD lorsqu’il est communiqué) ; - les commandes déclarées par l’agent deviennent un
AvailableCommandsUpdatelorsqu’une session devient active, et un titre de session enregistré devient unSessionInfoUpdate; - les entrées du plan deviendraient une mise à jour
Plan— ce mappage existe, mais reste inactif jusqu’à ce qu’une primitive de plan ADK expose les entrées du plan ; - l’annulation devient
StopReason::Cancelled; - l’achèvement normal devient
StopReason::EndTurn.
Un module de contenu partagé gère la correspondance ContentBlock ↔ adk_core::Part
dans les deux sens. Le contenu d’invite d’une ressource intégrée est converti en
Part::EmbeddedResource, en préservant la source URI, le type MIME
facultatif et le contenu ; les ressources textuelles sont préservées à l’identique,
tandis que les ressources binaires sont encodées en base64 sur le réseau, puis
décodées en octets bruts en interne. Le contenu d’invite d’image et audio est
converti en Part::InlineData, en préservant le type MIME, les octets
décodés, les annotations et la source URI facultative d’une
image. Ces champs restent dans la JSON de session et sont restaurés
par session/load. Comme le gestionnaire d’invites accepte le contenu de
ressources intégrées, d’images et audio, le serveur annonce les capacités
d’invite embedded_context, image et audio. Une invite
contenant un type de contenu que le serveur n’a pas annoncé est rejetée avec une
erreur explicite au lieu d’être traitée partiellement.
Chargement et relecture de l’historique
session/load restaure l’historique visible d’une session persistante lorsqu’un
client se reconnecte. Le gestionnaire réactive la session de la même manière que
session/resume — en vérifiant que l’appelant a fourni le cwd
d’origine et en renvoyant une erreur indiquant que la session est introuvable pour
un identifiant inconnu — puis effectue une passe de relecture. Il lit les
événements persistants via le service de session et convertit chaque événement
stocké d’utilisateur, d’agent, de réflexion et d’outil en sa notification
session/update correspondante, dans l’ordre chronologique d’origine, avant la fin de
la requête de chargement. Le serveur annonce la capacité load_session afin qu’un
client sache qu’il peut se reconnecter et reconstruire la vue de la conversation.
Modes de session, options de configuration et bifurcation
Un agent active les contrôles de session interactive en fournissant un fournisseur SessionControls
via AcpServerConfigBuilder::session_controls. Le fournisseur déclare
les modes disponibles (un SessionModeState), les options de configuration (sélections et
boutons bascule), ainsi que les commandes slash ACP. Le serveur annonce exactement ce que le fournisseur
déclare — un agent sans fournisseur n’annonce aucun mode ni aucune option — et
les expose dans les réponses session/new, session/load, session/resume et
session/fork.
session/set_mode valide l’identifiant du mode demandé par rapport à l’ensemble annoncé,
l’enregistre et émet un CurrentModeUpdate ; un identifiant inconnu est rejeté et le
mode actuel reste inchangé. session/set_config_option valide la valeur
par rapport aux choix déclarés pour l’option, l’enregistre et émet un
ConfigOptionUpdate ; une option inconnue ou une valeur non valide est rejetée. Les deux
sélections sont conservées dans l’état de session ADK sous acp:mode et acp:config:<id>,
et persistent donc lors du chargement, de la reprise et de la création d’une branche.
session/fork crée une branche d’une session persistante : il lit la session source, crée
un nouvel identifiant de session, y copie les événements enregistrés et l’état
pertinent (cwd, les répertoires supplémentaires, le mode et la configuration),
puis renvoie le nouvel identifiant. L’historique persistant de la session source
reste inchangé octet par octet. La création d’une branche pour un identifiant de
session inconnu renvoie une erreur indiquant que la session est introuvable. Le serveur annonce la capacité de session
fork, car le gestionnaire est enregistré.
Lors de l’activation d’une session, le serveur émet également un AvailableCommandsUpdate pour toutes les
commandes déclarées par le fournisseur (et aucun lorsqu’il n’en déclare aucune), ainsi qu’un
SessionInfoUpdate contenant le titre de la session lorsqu’un titre est enregistré sous
acp:title (défini via set_session_title). Un mappage de mise à jour Plan existe, mais
reste inactif jusqu’à ce qu’une primitive de plan ADK expose des entrées de plan.
Serveurs MCP fournis par le client
Le client peut inclure des serveurs stdio MCP dans session/new ou session/resume.
Le serveur valide les noms, les commandes, les arguments et les entrées d’environnement avant
de démarrer un processus. Il :
- démarre chaque processus enfant dans l’espace de travail de la session ;
- applique une négociation de démarrage limitée ;
- encapsule la connexion en tant que ADK
McpToolset; - injecte l’ensemble d’outils dans cette invocation de Runner ;
- annule les services MCP lors de la fermeture, de la suppression, d’un échec du démarrage ou de l’arrêt du serveur.
Les ensembles d’outils associés à une invocation sont actuellement résolus par LlmAgent et
CodeActAgent. Les transports HTTP et SSE MCP facultatifs ne sont pas annoncés par le
serveur.
Décisions de persistance
InMemorySessionService convient à un processus d’éditeur local et aux tests. Utilisez
un service durable lorsque les sessions doivent survivre aux redémarrages du processus. La reprise valide
que l’appelant fournit le cwd d’origine ; une session ne peut pas être rattachée
silencieusement à un autre projet.
Limite d’approbation des outils
Le serveur fait le lien entre les confirmations d’outils ADK et les demandes d’autorisation
natives ACP. Lorsque l’agent configuré se met en pause sur un ToolConfirmationRequest pendant un tour
de requête — signalé sur event.actions.tool_confirmation lorsqu’un agent attend
l’approbation humaine d’un appel d’outil — le serveur envoie une requête session/request_permission
décrivant l’outil et ses arguments, attend le résultat du client, puis
reprend l’exécution avec la décision correspondante. Une approbation est mappée vers l’autorisation,
et un refus ou une annulation sont tous deux mappés vers le refus, de sorte qu’une requête annulée
n’exécute jamais l’outil. Chaque résultat est associé à l’appel exact au moyen de son identifiant
d’appel de fonction et renvoyé au Runner via
RunConfig::tool_confirmation_decisions.
Le session/request_permission imbriqué est émis depuis la tâche qui gère déjà le session/prompt externe, généré via ConnectionTo::spawn ; il ne bloque donc pas la boucle de distribution de la connexion, et la réponse à l’invite externe s’achève tout de même. Une inquiétude précédente selon laquelle le SDK Rust officiel perdrait la réponse à l’invite externe après une requête bidirectionnelle imbriquée ne se reproduit pas avec ce flux de suspension/reprise ; ce cas est couvert par les tests d’interopérabilité en mémoire.
L’autorisation des outils gérée par le serveur, les outils en lecture seule, RBAC, les garde-fous et les interruptions de workflow restent disponibles lorsque l’approbation doit avoir lieu entièrement au sein du processus ADK-Rust. Le chemin d’autorisation côté client pour les agents ACP externes est également entièrement implémenté.
Déployer en toute sécurité
- Démarrez le binaire avec l’espace de travail du projet prévu.
- Considérez
cwdet les racines supplémentaires comme un contexte, et non comme un mécanisme d’isolation du système d’exploitation. - Appliquez
adk-sandbox, un conteneur ou une autre limite de processus pour les invites et commandes non fiables. - Conservez les identifiants du modèle et de MCP dans un magasin de secrets client ou dans l’environnement du processus.
- N’écrivez jamais de bannières, d’objets de débogage ou de journaux sur la sortie standard du protocole.
- Utilisez un
SessionServicedurable lorsque la reprise doit survivre au redémarrage du processus. - Définissez une limite de session finie et fermez les sessions inactives.
Le crate acp_server exécutable inclut un agent basé sur Gemini, des outils de lecture limités à l’espace de travail, la journalisation de suivi vers la sortie d’erreur et la configuration du processus de l’éditeur.