Skip to content

Protocole ACP

源码版本v2026.7.20

Responsabilité

ACP (Agent Client Protocol) est un protocole standard de communication entre un éditeur / IDE et un agent. acp_adapter/ expose Hermes comme serveur ACP, afin que les clients compatibles ACP (Zed, extension VS Code, etc.) puissent piloter Hermes directement : gérer les sessions (sessions), lire/écrire des ressources (fichiers/images), approuver des modifications, tracer la provenance, isoler les outils (tools) selon les permissions. Hermes n'est plus seulement une plateforme de messagerie, il peut aussi s'imbriquer dans un flux de développement.

Mot de conception

Hermes a été conçu à l'origine pour les plateformes de messagerie — la couche passerelle (gateway) branche Telegram / Discord, des conversations longues. Mais un IDE est autre chose : le répertoire de travail est ouvert par l'éditeur, le cwd doit suivre l'éditeur ; modifier un fichier ne doit pas se faire au seul motif que l'agent le dit, il faut le remonter à l'utilisateur pour validation ; et il faut pouvoir retracer « celle-ci est compressée à partir de laquelle ». La couche ACP traduit ces contraintes spécifiques à l'IDE en primitives qu'Hermes possède déjà. Le code ne réécrit pas une boucle d'agent : il branche le flux de messages ACP sur run_conversation, convertit les ressources ACP en OpenAI content parts, et transforme les opérations d'écriture de fichier issues des appels d'outils en EditProposal soumis à validation humaine. Le cœur est « adapter, pas réécrire ».

Fichiers clés

Flux de données

  1. Le client ACP (éditeur) découvre et démarre le serveur ACP d'Hermes via acp_registry/agent.json (acp_adapter/__main__.py).
  2. Le client ouvre une session → SessionManager:175 crée un SessionState, aligne le cwd (acp_adapter/session.py:29), déploie les toolsets (acp_adapter/session.py:129).
  3. Le client envoie messages / ressources → conversion de ressource:201 transforme la ressource ACP (fichier/image, sous la limite acp_adapter/server.py:96) en parties de contenu OpenAI, et alimente run_conversation:588.
  4. Quand l'agent veut modifier un fichier, l'appel d'outil devient un EditProposal via build_edit_proposal:178, soumis à l'utilisateur via le demandeur d'approbation (acp_adapter/edit_approval.py:51).
  5. L'exécution des outils est contrôlée par les permissions acp_adapter/permissions.py ; chaque opération est tracée par acp_adapter/provenance.py:22.
  6. Le streaming et les événements (acp_adapter/events.py) sont renvoyés au client.

acp_registry/agent.json est la carte de visite du client la première fois qu'il rencontre Hermes : version, mode de distribution (uvx), commande de démarrage. Ce contrat doit rester aligné avec le binaire réel, sinon le client installe une mauvaise version et ne peut pas démarrer.

La traduction cwd est l'endroit où le scénario ACP piège le plus : un client Windows fait tourner Hermes dans WSL, mais son espace de travail est E:\Projects ou un chemin UNC \\wsl.localhost\.... _translate_acp_cwd convertit tout en POSIX, sinon toutes les opérations Path côté agent sont décalées.

La proposition d'édition est une frozen dataclass, la clé est old_text_proposal_for_write_file lit d'abord le contenu existant du fichier, pour que le diff affiche « avant / après » plutôt qu'une modification aveugle :

python
@dataclass(frozen=True)
class EditProposal:
    tool_name: str
    path: str
    old_text: str | None
    new_text: str
    arguments: dict[str, Any]

Le demandeur d'approbation est lié via un ContextVar, pas une variable globale : plusieurs sessions ACP concurrentes ont chacune leur requester, sans fuite entre elles. .env / id_rsa passent par défaut par ask plutôt que workspace_session, pour ne pas être relâchés par une politique « tout le workspace est de confiance ».

La provenance est spécifique au scénario IDE : en messagerie la session est linéaire, mais en IDE elle est compressée, bifurquée, reprise. build_session_provenance remonte parent_session_id, compte le nombre de niveaux où end_reason == 'compression', marque sessionKind et compressionDepth, et place l'id de session Hermes interne et l'id de session ACP externe ensemble dans _meta.hermes.sessionProvenance.

Limites et échecs

  • Décalage de version au handshake : agent.json épingle hermes-agent[acp]==0.19.0. Quand Hermes passe à 0.20 et que le client a encore l'ancien manifeste en cache, le serveur démarré et le schéma client ne collent plus ; si InitializeResponse manque un champ, le handshake échoue.
  • Traduction WSL cwd qui passe au travers : quand translate_cwd_for_wsl_backend ne couvre pas un nouveau format de chemin Windows, l'agent reçoit un cwd décalé, toutes les opérations Path partent de travers — sans erreur immédiate, ça n'explose qu'à la première écriture avec « répertoire introuvable ».
  • Deadlock du demandeur d'approbation : l'approbation passe par ContextVar + callback utilisateur ; si la event loop du client bloque et ne renvoie pas l'ACK, l'attente après build_edit_proposal reste suspendue. Que le cancel de la couche ACP se propage jusqu'à ce point d'attente dépend de la couverture du chemin d'interruption dans events.py.
  • Chaîne de provenance cassée : lors d'une bifurcation par compression (compression), si parent_session_id est mal écrit, build_session_provenance tombe sur un point de rupture et renvoie root — le client présente alors une continuation comme une nouvelle session, et l'historique paraît « perdu ».

Résumé

ACP permet à Hermes de s'imbriquer dans le flux d'un éditeur : gestion de session, lecture/écriture de ressources, approbation des modifications, isolation des permissions, traçabilité de la provenance. Le cœur est server.py (adaptation de protocole) + session.py (session) + edit_approval.py (édition approuvée par un humain). Complémentaire de la couche passerelle — la passerelle branche les plateformes de messagerie, ACP branche l'IDE.

Site d'apprentissage communautaire non officiel. Basé sur le code source de NousResearch/hermes-agent (licence MIT).