Intégrer A2A avec les frameworks d'agents existants : une démonstration avec Hermes Agent
Pourquoi A2A compte pour l'orchestration d'agents
Le Agent2Agent Protocol (A2A) est un standard ouvert introduit par Google en avril 2025 pour la communication inter-agents. Il définit comment un agent IA découvre les capacités d'un autre agent, lui envoie une tâche, reçoit la sortie en flux et suit la tâche à travers son cycle de vie — le tout via JSON-RPC 2.0, sans supposer que les deux agents partagent un framework, un fournisseur de modèle ou une topologie de déploiement.
A2A comble une lacune que MCP ne couvre pas. MCP connecte un agent à des outils et des sources de données — c'est un protocole d'appel d'outils. A2A connecte des agents à des agents. Un agent qui a besoin d'une capacité spécialisée (logique de tarification, recherche de catalogue, traitement de RFQ) peut déléguer le travail à un agent distant qui expose cette capacité via un endpoint A2A, recevoir le résultat sous forme de tâche A2A et poursuivre son propre flux de travail. Les deux protocoles sont complémentaires : MCP donne des mains à un agent ; A2A lui donne des collègues.
La spécification A2A définit trois primitives fondamentales :
- Agent Card — un document JSON à
/.well-known/agent-card.jsondécrivant l'identité, les capacités, les compétences et l'endpoint de service de l'agent. C'est ainsi que les agents se découvrent mutuellement. - Task — l'unité de travail. Un client envoie une tâche via
message/send(non-flux) oumessage/stream(flux). La tâche passe par des états :submitted,working,input-required,completed,failed,canceled. - Artifact — sortie structurée produite pendant l'exécution de la tâche, diffusée vers le client au fur et à mesure de sa disponibilité.
Pour les déploiements B2B, la proposition de valeur est précise : au lieu de construire un agent monolithique qui fait tout, vous composez des agents spécialisés qui possèdent chacun un domaine — et ils se coordonnent via un protocole, pas via une mémoire partagée ou des appels de fonction codés en dur.
Le problème d'intégration
La plupart des frameworks d'agents existants ne parlent pas A2A. Ils ont leur propre surface d'API native, leur propre modèle de tâches, leur propre mécanisme de flux. Hermes Agent (par Nous Research) expose une API Server compatible OpenAI à /v1/chat/completions et une interface de flux basée sur les runs avec SSE à /v1/runs et /v1/runs/{id}/events. OpenClaw sert une API compatible OpenResponses à POST /v1/responses. LangGraph a son propre modèle d'exécution de graphe. CrewAI a son propre dispatch de crew.
Aucun de ces frameworks ne réécrira ses internes pour supporter A2A. Et ils ne le devraient pas — leurs APIs natives servent bien leurs propres écosystèmes. La question est : peuvent-ils participer à un réseau d'agents A2A sans changer leur code ?
La réponse est une couche de pont — un composant qui se situe entre le protocole A2A et l'API native du framework. Le pont implémente la surface JSON-RPC A2A d'un côté (Agent Card, cycle de vie des tâches, flux) et traduit vers les appels natifs du framework de l'autre. Le framework ne sait pas qu'il est appelé via A2A. Le client A2A ne sait pas quel framework exécute la tâche.
Cet article parcourt le pattern de pont en utilisant Hermes Agent comme démonstration. Le même pattern s'applique à OpenClaw et aux autres frameworks — le handler du pont est la seule pièce qui change.
L'architecture du pont
Une implémentation de référence fonctionnelle de ce pattern est le a2a_daemon_engine — un daemon de protocole A2A qui s'exécute comme un module de passerelle et achemine l'exécution vers des handlers enfichables. L'architecture est :
A2A Client (any agent or application)
│
POST /{endpoint_id}/a2a (message/send | message/stream)
│
▼
Gateway (auth, routing, SSE client management)
│
▼
A2A Daemon Executor
│
resolve_agent(uuid) → Database lookup
load_agent_handler() ← data-driven, metadata-based routing
│
├── HermesAgentHandler
│ → POST /v1/runs → GET /v1/runs/{id}/events → SSE streaming
│ → POST /v1/chat/completions (non-streaming)
│
└── [AnyFrameworkHandler] ← same interface, different translation
→ framework's native API
Le pont a trois couches :
Couche de protocole A2A — gère le dispatch JSON-RPC, la distribution de l'Agent Card, la machine à états des tâches et l'EventQueue du SDK A2A. Elle est indépendante du framework. Elle est identique pour chaque intégration.
Couche de transport de la passerelle — gère HTTP, l'authentification, le cycle de vie des clients SSE et le routage. Également indépendante du framework. La passerelle possède le fil ; le pont possède la traduction.
Handler de framework — le seul code spécifique au framework. Il implémente une interface
ask_model(): accepter les parties de message A2A et le contexte, appeler l'API native du framework, convertir la réponse en parties de message A2A, et (pour le flux) transférer les deltas de tokens vers le canal SSE.
Ajouter un nouveau framework signifie écrire une classe de handler. Tout le reste — la surface de protocole, le dispatch de la passerelle, la gestion SSE, la persistance des tâches — est une infrastructure partagée.
Démonstration : le pont Hermes Agent
Le HermesAgentHandler est l'exemple détaillé. Il fait le pont entre la sémantique des tâches A2A et l'API Server de Hermes Agent. Le handler supporte deux modes d'exécution :
Non-flux : message/send avec message_response
Le handler appelle POST /v1/chat/completions sur l'API Server de Hermes — l'endpoint compatible OpenAI. La requête transporte les parties de message A2A converties comme payload de chat completion. Hermes traite la requête (inférence de modèle, appels d'outils, raisonnement de l'agent) et renvoie une réponse unique. Le handler convertit la réponse en un Message A2A avec ROLE_AGENT et l'émet vers l'EventQueue du SDK.
Le client reçoit une réponse JSON-RPC unique avec le texte complet de l'agent. Pas d'événements de statut intermédiaires, pas de chunks de flux — la requête bloque jusqu'à ce que Hermes termine.
Flux : message/send avec task_execution et stream: true
Le handler appelle POST /v1/runs pour créer un run, puis ouvre une connexion SSE vers GET /v1/runs/{id}/events. Hermes diffuse les événements au fur et à mesure : deltas de tokens, métadonnées de raisonnement, notifications d'appel/résultat d'outil, demandes d'approbation et événements de cycle de vie (run.created, run.completed, run.failed).
Le handler exécute une boucle de drain dans un thread d'arrière-plan. Chaque événement message.delta est poussé vers le gestionnaire SSE de la passerelle pour une livraison en temps réel aux clients connectés. Le handler accumule les tokens dans un seul buffer. Quand run.completed arrive, le texte accumulé est émis comme un Message A2A unique vers l'EventQueue du SDK, et un événement de statut COMPLETED est poussé vers SSE uniquement.
Ce design à double chemin — SSE pour les chunks en temps réel, EventQueue du SDK pour le message final accumulé — est une réponse à une contrainte du SDK A2A v2, discutée ci-dessous.
Approbation humaine dans la boucle à travers les frontières d'agents
Hermes supporte les portes d'approbation humaine dans la boucle — lorsqu'un agent a besoin de permission pour exécuter une action sensible, il s'interrompt et émet une demande d'approbation. Le pont traduit cela en l'état A2A INPUT_REQUIRED, qui signale à l'agent appelant (ou à l'opérateur humain) qu'une entrée est nécessaire. La réponse revient via POST /v1/runs/{id}/approval, et le run continue.
C'est ici que le pattern de pont montre sa valeur. A2A définit INPUT_REQUIRED comme un état de tâche de premier ordre. Hermes a son propre mécanisme d'approbation. Le pont mappe l'un vers l'autre, et l'agent appelant — qui peut lui-même être un client A2A s'exécutant sur un framework complètement différent — voit une transition d'état de protocole standard, pas un détail spécifique à Hermes. Une chaîne de délégation d'agents peut inclure une étape qui nécessite une approbation humaine (une autorisation d'achat, une décision d'accès aux données, une approbation de devis), et le protocole A2A porte cette porte de manière transparente à travers les frontières de frameworks.
Mapping d'états A2A
A2A définit une machine à états de tâche : submitted → working → input-required | completed | failed | canceled. Chaque framework a son propre vocabulaire d'événements. Le pont fait le mapping entre eux.
Le mapping des événements Hermes vers les états A2A :
| Événement SSE Hermes | État de tâche A2A | Action du pont |
|---|---|---|
run.created |
WORKING |
Enregistrer run_id pour le support d'annulation |
message.delta |
WORKING |
Accumuler le token ; émettre vers SSE par chunk |
reasoning.available |
WORKING |
Métadonnées de raisonnement — pas d'émission de token |
tool.call / tool.result |
WORKING |
Métadonnées d'exécution d'outil uniquement |
approval.required |
INPUT_REQUIRED |
Émettre un chunk d'approbation ; stocker pending_approval |
run.completed |
COMPLETED |
Définir l'événement de flux ; accumuler le texte final |
run.failed |
FAILED |
Émettre un chunk d'erreur ; définir l'état FAILED |
POST /v1/runs/{id}/stop |
CANCELED |
Annulation externe via tasks/cancel |
POST /v1/runs/{id}/approval |
(continue le run) | Résolu via operation=\"approval_response\" |
Ce tableau est le cœur du pont. Chaque intégration de framework produit un tableau équivalent — les événements natifs du framework à gauche, les états A2A à droite, les actions du pont au milieu. Le document HERMES_INTEGRATION.md dans l'implémentation de référence enregistre le format exact des événements Hermes, les clés de configuration et les détails du flux de bout en bout.
La contrainte du SDK A2A v2 et la correction à double chemin
Le SDK A2A v2 (a2a-sdk==1.0.2) impose deux contraintes sur le chemin on_message_send qui ont façonné chaque implémentation du pont :
- Message unique uniquement. Émettre plusieurs objets
Messagevers l'EventQueue du SDK lèveInvalidAgentResponseError: Multiple Message objects received. - Pas de TaskStatusUpdateEvent. Les événements de statut lèvent
InvalidAgentResponseError: Received TaskStatusUpdateEvent in message mode.
Un pont naïf émettrait un Message par delta de token — le pattern de flux naturel. Le SDK rejette cela. Il rejette aussi les événements de statut (WORKING, COMPLETED) sur le chemin message/send.
La correction est un canal de sortie à double chemin :
- SSE (géré par la passerelle) : Les chunks de tokens sont poussés vers SSE en temps réel. Les clients connectés voient la sortie en flux au fur et à mesure. Les événements de statut (WORKING, COMPLETED, FAILED) vont également vers SSE uniquement.
- EventQueue du SDK : Après la fin du flux, un
Messageaccumulé unique contenant le texte complet de la réponse est émis vers l'EventQueue du SDK. C'est ce que la réponse JSON-RPCmessage/sendrenvoie.
Le client obtient le flux en temps réel via SSE et une réponse JSON-RPC à message unique propre via le SDK. Les deux canaux fonctionnent ; aucun ne viole les contraintes du SDK. Ce pattern est indépendant du framework — il s'applique que le backend soit Hermes, OpenClaw ou n'importe quel futur handler.
Appliquer le même pattern à OpenClaw
La Gateway API d'OpenClaw expose une surface native différente de celle de Hermes, mais le pattern de pont est identique. Un OpenClawHandler implémenterait la même interface ask_model() et traduirait la sémantique des tâches A2A en appels à la passerelle OpenClaw :
- Non-flux correspond à
POST /v1/responsesavec les parties de message A2A converties en items d'entrée OpenResponses. La réponse est reconvertie en unMessageA2A. - Flux correspond à
POST /v1/responsesavecstream: true, en consommant le flux d'événements SSE et en transférant les deltas de tokens vers le canal SSE A2A. Le format de flux OpenResponses utiliseresponse.output_text.deltapour les chunks de tokens etresponse.completedpour la fin — des noms d'événements différents, la même structure de pont. - Sélection d'agent utilise le champ
model(openclaw/<agentId>) ou l'en-têtex-openclaw-agent-id, mappé depuis les métadonnées d'agent A2A. - Continuité de session exploite le champ
previous_response_idouuserd'OpenClaw pour un routage de session stable, qui correspond naturellement à la persistance des tâches A2A.
Le tableau de mapping d'états pour OpenClaw ressemblerait à :
| Événement OpenClaw | État de tâche A2A | Action du pont |
|---|---|---|
response.created |
WORKING |
Enregistrer l'ID de réponse |
response.output_text.delta |
WORKING |
Accumuler le token ; émettre vers SSE |
response.completed |
COMPLETED |
Accumuler le texte final ; émettre le Message |
response.failed |
FAILED |
Émettre l'erreur ; définir FAILED |
Mêmes colonnes, même structure, des noms d'événements différents. Le handler du pont est la seule pièce qui change entre les frameworks.
Configuration : routage piloté par les métadonnées
Le routage des agents est piloté par les métadonnées, pas par des variables d'environnement. Chaque enregistrement d'agent dans la base de données transporte sa configuration de handler dans une colonne JSON metadata. Pour un agent soutenu par Hermes :
{
"module_name": "a2a_daemon_engine.handlers.a2a_hermes_handler",
"class_name": "HermesAgentHandler",
"hermes_api_url": "http://127.0.0.1:8642",
"hermes_api_key": "hermes-local-key",
"hermes_model": "hermes-agent",
"hermes_timeout": 300.0
}
Pour un agent soutenu par OpenClaw, les métadonnées pointeraient vers le handler OpenClaw :
{
"module_name": "a2a_daemon_engine.handlers.a2a_openclaw_handler",
"class_name": "OpenClawHandler",
"openclaw_api_url": "http://127.0.0.1:3000",
"openclaw_api_key": "openclaw-key",
"openclaw_agent_id": "pricing-agent",
"openclaw_timeout": 300.0
}
La résolution de configuration suit une chaîne de priorité : métadonnées de l'agent (base de données) → dictionnaire de paramètres → valeurs par défaut de Config (variables d'environnement). Les surcharges par agent l'emportent sur les valeurs par défaut globales. Deux agents peuvent pointer vers des frameworks différents — l'un vers Hermes pour les tâches à forte intensité de raisonnement, l'autre vers OpenClaw pour les tâches d'orchestration de flux de travail — et la surface de protocole A2A paraît identique à l'agent appelant.
Ce que cela rend possible
Le pattern de pont vous donne trois capacités qui sont difficiles à assembler de zéro :
1. Délégation d'agent à agent avec flux. Les agents clients A2A peuvent envoyer des tâches à un agent soutenu par Hermes et recevoir le flux de tokens en temps réel via SSE. L'agent appelant n'a pas besoin de savoir que l'agent distant exécute Hermes — il voit un endpoint A2A avec une Agent Card et une interface JSON-RPC.
2. Approbation humaine dans la boucle à travers les frontières d'agents. Les portes d'approbation natives des frameworks (demandes d'approbation Hermes, approbations d'opérateur OpenClaw) se mappent aux états A2A INPUT_REQUIRED. Une chaîne de délégation d'agents peut inclure une étape qui nécessite une approbation humaine, et le protocole A2A porte cette transition d'état vers l'agent ou l'opérateur d'origine — quel que soit le framework sur lequel chaque agent de la chaîne s'exécute.
3. Routage multi-frameworks depuis une seule passerelle. La même passerelle, le même exécuteur, la même surface de protocole A2A sert des handlers pour différents frameworks. Ajouter un nouveau framework, c'est écrire une classe de handler et insérer un enregistrement d'agent — pas un nouveau déploiement, pas une nouvelle implémentation de protocole.
L'implémentation de référence supporte également le dispatch AWS Lambda pour A2A sans serveur, un transport gRPC expérimental avec flux bidirectionnel, et une persistance double-backend (DynamoDB ou PostgreSQL) avec isolation multi-tenant via des clés de partition composites. Le dépôt a2a_daemon_engine et son guide d'intégration Hermes contiennent l'implémentation complète, la référence de configuration et les détails du mapping d'états.
Un distributeur de taille intermédiaire a besoin d'agents de devis qui parlent à des agents de catalogue qui parlent à des agents d'inventaire — chacun soutenu par un framework différent, chacun possédé par une équipe différente. A2A donne à ces agents un protocole partagé. Une couche de pont permet à Hermes Agent, OpenClaw et n'importe quel autre framework de participer sans réécrire leurs internes. Le a2a_daemon_engine est une implémentation de référence fonctionnelle de ce pattern de pont, démontrée avec Hermes Agent.
Demandez une construction délimitée
Découverte d'une semaine. Vous obtenez un inventaire des systèmes, une cartographie des flux de travail et un périmètre fixe — que vous construisiez avec nous ou non.
Vous voulez cela construit pour vos systèmes ?
Chaque document ici provient d'un travail réel en production. Si vous avez un système cible et un flux en tête, nous pouvons cadrer une construction en une semaine.
Demander un projet cadréDécouverte d'une semaine. Vous obtenez un inventaire des systèmes, une cartographie des flux et un périmètre fixe — que vous construisiez avec nous ou non.