Déployer A2A sur Hermes Agent : Une pile de référence Docker Gateway
Exécuter A2A en production signifie créer un pont entre deux protocoles qui n'ont jamais été conçus pour communiquer entre eux — et le faire derrière une passerelle qui gère l'authentification, l'isolation des locataires et le streaming sans perdre de tokens. Cette pile de référence résout les trois problèmes qui bloquent les déploiements A2A : la traduction de protocole (JSON-RPC 2.0 vers chat completions compatible OpenAI), la réconciliation du streaming (SSE d'artifacts A2A vers SSE d'événements d'exécution Hermes) et la sécurité multi-locataire (Row-Level Security de PostgreSQL sur chaque requête). Si vous avez besoin que des agents sur différents frameworks se délègent du travail, le modèle ici est le chemin de déploiement.
Points clés
- 3 couches, 1 pile Docker Compose — SilvaEngine Gateway gère le transport et l'authentification, A2A Daemon Engine gère la logique de protocole, HermesAgentHandler fait le pont vers l'API OpenAI-compatible de Hermes Agent. Le dépôt docker-a2a-hermes-agent-gateway regroupe les trois.
- 5 surfaces de protocole sur un port — JSON-RPC 2.0, GraphQL, flux SSE, push SSE et découverte de l'Agent Card, toutes derrière une passerelle unique sur le port 8765 avec authentification JWT ou AWS Cognito.
- La sécurité au niveau des lignes PostgreSQL applique l'isolation des tenants — la clé composite
partition_key = "{endpoint_id}#{Part-Id}"est imposée au niveau base de données via des politiques RLS sur les quatre tables A2A, et non seulement dans le code applicatif. - La contrainte de message unique du SDK A2A v2 façonne l'architecture de streaming — le pont émet des morceaux de jetons vers SSE en temps réel et un unique Message accumulé vers l'EventQueue du SDK après l'achèvement du flux, évitant
InvalidAgentResponseError. - 15 vérifications E2E réparties sur 5 scripts — des tests de fumée non-streaming aux pipelines SSE complets avec vérification de repli HTTP, exécutables avec
pip install requests.
Le protocole Agent2Agent (A2A) définit comment les agents IA se découvrent, se délèguent et diffusent des tâches entre eux via JSON-RPC 2.0. Hermes Agent (par Nous Research) expose un serveur d'API OpenAI-compatible à /v1/chat/completions et une interface de streaming SSE basée sur les runs à /v1/runs et /v1/runs/{id}/events. Les deux ne parlent pas le même langage. A2A envoie message/send avec des parties structurées ; Hermes reçoit des payloads de complétion de chat. A2A diffuse les artefacts de tâche via SSE ; Hermes diffuse des deltas de jetons via des événements de run.
Le dépôt docker-a2a-hermes-agent-gateway comble cet écart dans une image de conteneur unique et une pile docker compose. Il exécute SilvaEngine Gateway avec uniquement le module a2a_daemon_engine enregistré, exposant l'intégralité de la surface du protocole A2A et pontant les tâches A2A vers une instance du serveur d'API Hermes Agent via HTTP + SSE. L'état persiste vers un backend PostgreSQL embarqué avec sécurité au niveau des lignes pour l'isolation des tenants.
Cet article cartographie l'architecture en trois couches, le cycle de vie d'une requête du client A2A vers Hermes et retour, les modèles de configuration et de déploiement, ainsi que les considérations opérationnelles pour exécuter A2A sur Hermes Agent en production. Il s'agit d'une procédure de déploiement de référence — le motif général (pont A2A médié par passerelle vers tout framework d'agents) en est le sujet ; la pile Docker en est l'implémentation concrète.
L'architecture en trois couches
La pile sépare les préoccupations en trois couches, chacune possédée par un composant distinct :
La passerelle est le seul service toujours actif. Hermes et PostgreSQL sont tous deux des siblings profilés — embarquez-les pour une pile autonome, ou désactivez les profils et pointez HERMES_API_URL et PG_HOST vers des instances externes. Cela compte en production : vous pouvez exécuter la passerelle dans votre VPC et la pointer vers un Postgres managé (RDS, Cloud SQL) et une instance Hermes s'exécutant sur un nœud GPU ailleurs.
Couche 1 : SilvaEngine Gateway — transport et auth
SilvaEngine Gateway est une passerelle FastAPI pour un accès authentifié en processus aux modules installés. Elle expose les routes GraphQL et REST des modules via un manifeste de routes YAML configurable — l'ajout d'un nouveau module ne nécessite que des modifications du manifeste, sans aucun code Python de la passerelle. Dans cette pile, seul A2A Daemon Engine est enregistré.
La passerelle possède :
- Authentification — JWT local (HS256) ou AWS Cognito (RS256 + JWKS), sélectionné par
GATEWAY_AUTH_PROVIDER - Routage — le manifeste YAML mappe les chemins d'URL vers les fonctions de dispatch des modules
- Cycle de vie du client SSE — le
sse_managerrésout par module et gère les connexions clients longues - Limitation de débit — limitation de débit en mémoire par IP (
GATEWAY_RATE_LIMITrequêtes par fenêtre deGATEWAY_RATE_WINDOWsecondes) - Dispatch par pool de threads — les fonctions de dispatch synchrones des modules s'exécutent dans un pool de threads configurable (
GATEWAY_DISPATCH_WORKERS, 32 par défaut dans l'image Docker)
La passerelle construit partition_key = "{endpoint_id}#{Part-Id}" à partir du segment de chemin d'URL et de l'en-tête de requête Part-Id. Chaque requête à portée de tenant nécessite cet en-tête. L'endpoint de l'Agent Card à /{ep}/.well-known/agent-card.json est public (sans auth) selon la spécification A2A, mais requiert tout de même Part-Id car la carte est résolue par partition.
Couche 2 : A2A Daemon Engine — logique de protocole
a2a_daemon_engine n'est pas un service autonome. Il est chargé comme module de passerelle enregistré via deploy() dans main.py, qui déclare trois points d'entrée exposés à la passerelle :
| Point d'entrée | Route de passerelle | Méthode | Rôle |
|---|---|---|---|
a2a_core_graphql |
POST /{ep}/a2a_core_graphql |
POST | GraphQL CRUD pour agents, tâches, messages, paramètres |
a2a |
POST /{ep}/a2a |
POST | Protocole A2A JSON-RPC (message/send, tasks/get, tasks/cancel, tasks/list) |
sse_message |
POST /{ep}/a2a_sse |
POST | Message A2A JSON-RPC + push vers clients SSE |
La passerelle expose également GET /{ep}/a2a_sse pour le flux SSE. Le daemon n'écoute pas sur son propre port et n'exécute pas son propre serveur HTTP en production. Tout le transport, l'auth et le cycle de vie du client SSE sont possédés par la passerelle.
Le daemon fournit :
- SDK A2A v1.0 — JSON-RPC sur HTTP, basé sur le motif serveur officiel du SDK A2A
- Agent Card publique à
/.well-known/agent-card.jsonavec support ETag et Last-Modified - Machine à états des tâches —
submitted→working→input-required|completed|failed|canceled - Persistance double backend — DynamoDB (PynamoDB) ou PostgreSQL (SQLAlchemy + Alembic). L'image Docker force PostgreSQL.
- Isolation multi-tenant — clés de partition composites (
{endpoint_id}#{part_id}) avec sécurité au niveau des lignes PostgreSQL - Handlers LLM enfichables — sélection
module_name/class_namepar agent dans le registre d'agents
Couche 3 : HermesAgentHandler — le pont
Le handler de pont Hermes (a2a_daemon_engine/handlers/a2a_hermes_handler.py) est le seul code spécifique au framework. Il implémente une interface ask_model() : accepter les parties de message A2A et le contexte, appeler le serveur d'API Hermes Agent, reconvertir la réponse en parties de message A2A, et en streaming, transférer les deltas de jetons vers le canal SSE.
Le handler prend en charge deux modes d'exécution :
Non-streaming mappe vers POST /v1/chat/completions sur le serveur d'API Hermes — l'endpoint OpenAI-compatible. La requête transporte les parties de message A2A converties en payload de complétion de chat. Hermes traite la requête 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.
Streaming mappe vers 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 fil : deltas de jetons (message.delta), métadonnées de raisonnement (reasoning.available), notifications d'appel/résultat d'outil, requêtes d'approbation (approval.required), et événements de cycle de vie (run.created, run.completed, run.failed). Le handler exécute une boucle de drainage 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. Lorsque run.completed arrive, le texte accumulé est émis en tant que Message A2A unique vers l'EventQueue du SDK.
Le cycle de vie d'une requête
Un message/send unique avec stream=true traverse huit étapes :
1. Client POST /{ep}/a2a {jsonrpc, method:"message/send", params}
Headers: Authorization: Bearer *** Part-Id:
2. Passerelle auth (JWT local / Cognito) → correspondance de route depuis routes.yaml
→ partition_key = "{ep}#{Part-Id}"
3. a2a_daemon dispatch_a2a → A2ADaemonExecutor
→ resolve_agent(): métadonnées agent (DB) > dict de paramètres > Config (env)
4. Handler HermesAgentHandler (A2A_AI_AGENT_MODULE / _CLASS)
5. Hermes POST {HERMES_API_URL}/v1/runs (Bearer HERMES_API_KEY)
GET {HERMES_API_URL}/v1/runs/{id}/events (SSE)
6. Diffusion morceaux de jetons → abonnés sur GET /{ep}/a2a_sse
7. Persistance tâche + messages écrits dans PostgreSQL (tables a2a_*, à portée RLS)
8. Réponse la réponse accumulée est aussi renvoyée dans le résultat HTTP JSON-RPC L'étape 8 compte : même en streaming, la réponse HTTP transporte la réponse complète. Un client qui manque les trames SSE peut toujours se replier sur la réponse HTTP. La suite de tests E2E (test_hermes_sse_live.py) vérifie explicitement ce repli dans son étape 06.
Priorité de résolution d'agent
La résolution de configuration suit une chaîne de priorité : métadonnées agent (DB) → dict de paramètres → valeurs par défaut de Config (variables d'env). Les surcharges par agent priment sur les valeurs par défaut globales. Deux agents peuvent pointer vers des frameworks différents — l'un vers Hermes pour des tâches à forte charge de raisonnement, un autre vers un handler différent pour des tâches d'orchestration de workflow — et la surface du protocole A2A paraît identique à l'agent appelant.
Pour un agent soutenu par Hermes, les métadonnées stockées dans la table a2a_agents ressemblent à :
{
"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
}Les valeurs par défaut via variables d'environnement (HERMES_API_URL, HERMES_API_KEY, HERMES_MODEL) permettent au pont d'atteindre Hermes sans enregistrement d'agent en base — la fonction resolve_agent() dans a2a_ai_agent_utility.py se replie sur les variables d'environnement lorsqu'aucun enregistrement d'agent n'existe. Vous pouvez donc démarrer la pile et envoyer un message/send sans enregistrer d'agent, et il sera routé vers Hermes via les valeurs par défaut de l'environnement.
Mappage d'état A2A
Le pont mappe les événements SSE de Hermes vers les états de tâche A2A. Ce tableau est le cœur du pont — chaque intégration de framework produit un tableau équivalent :
| Événement SSE Hermes | État de tâche A2A | Action du pont |
|---|---|---|
run.created (run_id renvoyé) |
WORKING |
Enregistrer run_id pour le support d'annulation |
message.delta |
WORKING |
Accumuler le jeton ; émettre vers SSE par morceau |
reasoning.available |
WORKING |
Métadonnées de raisonnement — pas d'émission de jeton |
tool.call / tool.result |
WORKING |
Métadonnées d'exécution d'outil uniquement |
approval.required |
INPUT_REQUIRED |
Émettre le morceau d'approbation ; stocker pending_approval |
run.completed |
COMPLETED |
Définir l'événement de flux ; accumuler le texte final |
run.failed |
FAILED |
Émettre le morceau 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" |
Le document HERMES_INTEGRATION.md dans le dépôt a2a_daemon_engine enregistre le format exact des événements Hermes, les clés de configuration et les détails du flux de bout en bout.
Approbation humaine dans la boucle au-delà des frontières d'agents
Hermes prend en charge les portes d'approbation humaine dans la boucle — lorsqu'un agent a besoin d'autorisation pour exécuter une action sensible, il se met en pause et émet une requête 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 se poursuit.
C'est ici que le motif de pont montre sa valeur. A2A définit INPUT_REQUIRED comme un état de tâche de premier ordre. Hermes possède 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 nécessitant une approbation humaine (une autorisation d'achat, une décision d'accès aux données, une approbation de devis), et le protocole A2A transporte cette porte de façon transparente au-delà des frontières des frameworks.
La contrainte du SDK A2A v2 et la correction à double voie
Le SDK A2A v2 (a2a-sdk==1.0.2) impose deux contraintes sur le chemin on_message_send qui ont façonné l'implémentation du pont :
- Un seul Message. É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 jeton — le motif de streaming naturel. Le SDK le rejette. Il rejette aussi les événements de statut (WORKING, COMPLETED) sur le chemin message/send.
La correction est un canal de sortie à double voie :
- SSE (géré par la passerelle) : Les morceaux de jetons sont poussés vers SSE en temps réel. Les clients connectés voient la sortie en streaming au fur et à mesure. Les événements de statut (WORKING, COMPLETED, FAILED) ne vont également qu'à SSE.
- EventQueue du SDK : Une fois le flux achevé, 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 streaming en temps réel via SSE et une réponse JSON-RPC propre à message unique via le SDK. Les deux canaux fonctionnent ; aucun ne viole les contraintes du SDK.
Surfaces de protocole sur un port
La passerelle expose cinq surfaces de protocole sur un seul port (8765 par défaut) :
| Protocole | Route | Auth | Rôle |
|---|---|---|---|
| GraphQL | POST /{ep}/a2a_core_graphql |
Oui | Requêtes/mutations A2A core (agents, tâches, messages, paramètres) |
| JSON-RPC 2.0 | POST /{ep}/a2a |
Oui | Protocole A2A : message/send, tasks/get, tasks/cancel, tasks/list |
| SSE (flux) | GET /{ep}/a2a_sse |
Oui | Flux d'événements de tâche A2A long par partition |
| SSE (push) | POST /{ep}/a2a_sse |
Oui | Message JSON-RPC + push vers clients SSE connectés |
| Agent Card | GET /{ep}/.well-known/agent-card.json |
Public | Document de découverte A2A (en-tête Part-Id toujours requis) |
La forme des paramètres JSON-RPC message/send utilisée par les harnais de test :
{
"message": {
"role": "ROLE_USER",
"parts": [{ "text": "Say hello from A2A" }]
},
"metadata": {
"operation": "task_execution",
"agent_uuid": "a2a-hermes-agent",
"stream": true,
"task_data": { "task_id": "my-task-001", "task_type": "hermes_test" },
"system_prompt": "You are a concise assistant.",
"conversation_history": []
}
}Le champ metadata.operation sélectionne le chemin d'exécution : task_execution pour des runs d'agent avec support du streaming, message_response pour le chat non-streaming. L'agent_uuid cible un agent spécifique dans le registre. Le drapeau stream active la diffusion SSE. Le task_data.task_id est un identifiant fourni par l'appelant, utilisé par tasks/get et tasks/cancel.
SSE est par partition, pas par tâche. Chaque tâche dans {ep}#{Part-Id} diffuse vers tous les abonnés de cette partition. L'ordre des opérations compte : connectez l'écouteur SSE avant d'envoyer le message, sinon les premiers morceaux de jetons sont perdus.
Persistance et multi-tenancy
L'image Docker force db_backend=postgresql — DynamoDB n'est pas pris en charge. Le daemon utilise des noms de tables littéraux non préfixés :
| Table | Contient |
|---|---|
a2a_agents |
Enregistrements d'agents + métadonnées handler/modèle par agent |
a2a_tasks |
Cycle de vie des tâches + statut |
a2a_messages |
Tours de messages par tâche |
a2a_settings |
Dicts de paramètres par partition |
Comme les noms ne sont pas préfixés, ne partagez pas PG_DB avec un autre module qui utilise les mêmes noms.
L'isolation des tenants utilise la sécurité au niveau des lignes PostgreSQL. La variable de session app.tenant_id est positionnée au partition_key de la requête ("{endpoint_id}#{Part-Id}"), et les politiques RLS limitent chaque requête à cette valeur. Les tables et politiques sont créées automatiquement au démarrage de la passerelle lorsque initialize_tables=1. Cela signifie qu'un filtre partition_key oublié dans le code applicatif ne peut pas faire fuiter des lignes entre tenants — la base de données impose la frontière.
L'implémentation RLS réside dans a2a_daemon_engine/utils/rls.py (set_rls_context et create_rls_policies) et la migration 0005_enable_rls_policies. La fonction set_rls_context exécute un SET app.tenant_id par requête sur la connexion, et create_rls_policies active et force RLS avec une politique tenant_isolation sur les quatre tables A2A. RLS est inactif en mode DynamoDB.
Déploiement avec Docker Compose
La pile a un service toujours actif et deux siblings optionnels profilés :
| Service | Nom du conteneur | Toujours actif ? | Profil | Rôle |
|---|---|---|---|---|
a2a-gateway |
a2a-hermes-gateway |
Oui | — | SilvaEngine Gateway (routes A2A uniquement) + pont Hermes |
postgres |
a2a-postgres |
Optionnel | postgres |
Backend de persistance PostgreSQL embarqué |
hermes |
container-hermes |
Optionnel | hermes |
Hermes Agent embarqué (API OpenAI-compatible + tableau de bord) |
COMPOSE_PROFILES est l'unique commutateur pour les deux siblings :
| Valeur | Services démarrés |
|---|---|
| vide | passerelle seule (Postgres externe + Hermes externe) |
postgres |
passerelle + Postgres embarqué |
hermes |
passerelle + Hermes embarqué (Postgres externe) |
postgres,hermes |
passerelle + Postgres et Hermes embarqués (par défaut) |
Lorsqu'un sibling est embarqué, gardez sa référence d'hôte pointée vers le nom du service : PG_HOST=postgres et HERMES_API_URL=http://hermes:<API_SERVER_PORT>. Lorsqu'un sibling est externe, pointez ceux-ci vers votre propre instance (par ex. PG_HOST=host.docker.internal, HERMES_API_URL=http://host.docker.internal:8642).
Démarrage rapide
cp .env.example .env
# Remplir : JWT_SECRET_KEY, ADMIN_PASSWORD, API_SERVER_KEY,
# HERMES_API_KEY (= API_SERVER_KEY), HERMES_MODEL_PROVIDER + clé du fournisseur, HERMES_MODEL
mkdir -p www/hermes www/projects
DOCKER_BUILDKIT=1 docker compose build
docker compose up -d # COMPOSE_PROFILES=postgres,hermes est la valeur par défaut
docker compose ps # attendre (healthy)
curl -f http://localhost:8765/health
pip install requests
python test_hermes_hello.py # test de fumée de bout en boutsilvaengine_gateway et a2a_daemon_engine sont tous deux pip-installés depuis git dans l'image (aucun montage de source depuis l'hôte). L'image est générique et entièrement pilotée par l'environnement — aucun secret n'est codé en dur. Les modules sont clonés depuis des dépôts GitHub publics sous ideabosque via git+https — aucune credential ni clé de déploiement SSH nécessaire.
Le piège des commentaires en ligne dans .env
L'analyseur env_file de Docker Compose ne supprime pas les commentaires en ligne. Une ligne comme :
HERMES_API_KEY=hermes-local-key # token pour Hermespositionne HERMES_API_KEY à la chaîne littérale hermes-local-key # token pour Hermes (commentaire inclus), ce qui casse silencieusement l'authentification. La règle : ne rien mettre après la valeur sur une ligne KEY=value. Placez les notes sur leurs propres lignes de commentaire # au-dessus de la variable.
Vérification : 15 vérifications E2E sur 5 scripts
La pile est livrée avec des harnais de test Python autonomes (seule dépendance : requests). Ils chargent ./.env, résolvent ou frappent un JWT de passerelle, et parlent à la pile en cours d'exécution :
| Script | Type | Ce qu'il fait |
|---|---|---|
test_hermes_hello.py |
Fumée | message/send non-streaming, affiche la réponse |
test_hermes_hello_sse.py |
Fumée | Un prompt retransmis en streaming via SSE |
test_hermes_gateway_live.py |
Suite E2E | 9 vérifications : santé Hermes, santé passerelle, agent card, ping GraphQL, message/send, tasks/get, tasks/list, tasks/cancel, chemin d'échec |
test_hermes_sse_live.py |
Suite E2E | 6 vérifications : santé x2, connexion SSE, morceaux de jetons en direct, statut COMPLETED, repli HTTP |
test_hermes_chatbot.py |
Interactif | REPL sur la surface A2A avec streaming SSE en direct |
Tous les scripts non interactifs affichent PASS/FAIL par étape et sortent en non-zéro en cas d'échec, ils fonctionnent donc comme des portes CI. La suite de tests unitaires (test_hermes_handler.py) exécute 24 tests avec HTTP simulé via httpx.MockTransport — aucun service requis.
Modèles opérationnels
Changements de routes sans reconstructions
routes.yaml est monté en lecture seule par bind-mount dans le conteneur. Éditez le fichier hôte et redémarrez le processus passerelle — aucune reconstruction nécessaire :
make restartAprès un changement en amont
Comme silvaengine_gateway et a2a_daemon_engine sont pip-installés depuis git au moment de la construction, un changement en amont nécessite une reconstruction avec --no-cache afin que la couche git reclone le dernier @main :
DOCKER_BUILDKIT=1 docker compose build --no-cache
docker compose up -d --force-recreateIl n'y a pas de verrouillage de version — @main est une cible mouvante. Verrouillez un tag ou un commit dans requirements-modules.txt si vous avez besoin de reproductibilité.
Mise à l'échelle au-delà d'un worker
L'état de tâche en mémoire, les compteurs de limitation de débit et le registre des clients SSE sont par processus. Avec GATEWAY_WORKERS > 1, passez à des backends partagés (GATEWAY_TASK_BACKEND=dynamodb, GATEWAY_RATE_LIMIT_BACKEND=dynamodb, plus region_name et credentials aws_*) et utilisez des sessions collantes pour SSE. La configuration par défaut démarre un processus Uvicorn.
Valeurs de sécurité à modifier
JWT_SECRET_KEY=change-me-in-production— remplacez paropenssl rand -hex 32ADMIN_PASSWORD=change-me— remplacez par un vrai mot de passePOSTGRES_PASSWORD=silvaengine— remplacez par un vrai mot de passeGATEWAY_CORS_ORIGINS=*autorise toute origine sans credentials. Définissez une liste explicite si vous avez besoin de cookies/credentials.- Le Hermes embarqué monte le socket Docker de l'hôte (
/var/run/docker.sock). Cela équivaut à root sur l'hôte pour quoi que ce soit dans ce conteneur. N'exécutez le profilhermesque sur un hôte que vous contrôlez, et retirez le montage si l'agent n'a pas besoin de lancer de conteneurs. - Le tableau de bord Hermes est activé par défaut sur le port 9119 avec des credentials basic-auth vides. Définissez
HERMES_DASHBOARD_BASIC_AUTH_*ou liez le port à localhost avant d'exposer l'hôte. - RLS est la frontière de tenant. Un appelant capable de positionner un
Part-Idarbitraire lit les données de cette partition — traitezPart-Idcomme une entrée à valeur d'autorisation dans tout frontal que vous placez devant.
Ce que cela rend possible
La pile en trois couches vous donne trois capacités difficiles à assembler from scratch :
1. Conformité au protocole A2A sans réécrire Hermes. Tout client A2A peut découvrir l'agent soutenu par Hermes via son Agent Card, envoyer des tâches via message/send, diffuser les réponses via SSE, et suivre le cycle de vie des tâches via des états A2A standard. Le client ne sait pas que l'agent distant exécute Hermes — il voit un endpoint A2A avec une interface JSON-RPC.
2. Service d'agents multi-tenant depuis une passerelle unique. L'en-tête Part-Id combiné à PostgreSQL RLS signifie qu'une instance de passerelle sert plusieurs tenants avec une isolation stricte au niveau base de données. Chaque tenant obtient son propre registre d'agents, son historique de tâches et son magasin de messages — tous dans les mêmes quatre tables, délimités par partition_key.
3. Approbation humaine dans la boucle au-delà des frontières d'agents. Les portes d'approbation Hermes se mappent aux états A2A INPUT_REQUIRED. Une chaîne de délégation d'agents peut inclure une étape nécessitant une approbation humaine, et le protocole A2A transporte 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.
L'implémentation de référence prend aussi en charge le dispatch AWS Lambda pour A2A serverless, un transport gRPC expérimental avec streaming bidirectionnel, et une persistance double backend (DynamoDB ou PostgreSQL). 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 de mappage d'état. Le dépôt SilvaEngine Gateway documente le système de manifeste de routes, les fournisseurs d'authentification et l'auto-initialisation des modules.
Lectures associées
- MCP + A2A : Les deux protocoles derrière tout système d'IA agentique en production — les rôles complémentaires de MCP (agents vers outils) et A2A (agents vers agents) dans la pile de protocoles à deux couches
- Intégrer A2A avec des frameworks d'agents existants : une démonstration Hermes Agent — le motif de pont général et la manière dont il s'applique à OpenClaw et autres frameworks au-delà de Hermes
- Standard de code de module MCP — le motif structurel pour des modules d'agents prêts pour la production, applicable aussi au code de handler A2A
Un distributeur mid-market 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 commun. Une couche de pont permet à Hermes Agent de participer sans réécrire ses internes. Le docker-a2a-hermes-agent-gateway empaquette ce pont dans une image de conteneur unique avec persistance PostgreSQL, multi-tenancy RLS et 15 vérifications E2E.
Demander un build cadré
Découverte d'une semaine. Vous obtenez un inventaire système, une cartographie des workflows et un périmètre fixé — 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.