Retour à la Bibliothèque
A2A

Déployer A2A sur Hermes Agent : Une pile de référence Docker Gateway

Dernière mise à jour : 2026年7月23日

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 :

A2A sur Hermes Agent — Pile en trois couches déploiement de référence docker-a2a-hermes-agent-gateway 1 Client A2A Tout agent ou application parlant JSON-RPC 2.0 message/send · tasks/get · SSE 2 SilvaEngine Gateway Transport · auth · routage · cycle de vie du client SSE Auth JWT / Cognito Routage tenant Part-Id Registre clients SSE Limitation de débit 3 A2A Daemon Engine Logique de protocole · machine à états des tâches · dispatch des handlers Service de l'Agent Card Cycle de vie des tâches HermesAgentHandler Streaming à double voie Serveur d'API Hermes Agent OpenAI-compatible · runs SSE /v1/chat/completions /v1/runs + /events PostgreSQL Persistance · isolation tenant RLS a2a_agents / tasks messages / settings La passerelle est le seul service toujours actif — Hermes et PostgreSQL sont des siblings profilés — ideabosque.com/library

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_manager ré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_LIMIT requêtes par fenêtre de GATEWAY_RATE_WINDOW secondes)
  • 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.json avec support ETag et Last-Modified
  • Machine à états des tâchessubmittedworkinginput-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_name par 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 :

  1. Un seul Message. Émettre plusieurs objets Message vers l'EventQueue du SDK lève InvalidAgentResponseError: Multiple Message objects received.
  2. 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 Message accumulé unique contenant le texte complet de la réponse est émis vers l'EventQueue du SDK. C'est ce que la réponse JSON-RPC message/send renvoie.

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 bout

silvaengine_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 Hermes

positionne 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 restart

Aprè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-recreate

Il 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 par openssl rand -hex 32
  • ADMIN_PASSWORD=change-me — remplacez par un vrai mot de passe
  • POSTGRES_PASSWORD=silvaengine — remplacez par un vrai mot de passe
  • GATEWAY_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 profil hermes que 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-Id arbitraire lit les données de cette partition — traitez Part-Id comme 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


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.