Desplegando A2A en Hermes Agent: una pila de referencia con Docker Gateway
Ejecutar A2A en producción significa tender un puente entre dos protocolos que nunca fueron diseñados para comunicarse entre sí — y hacerlo detrás de un gateway que gestiona autenticación, aislamiento de inquilinos y streaming sin perder tokens. Este stack de referencia resuelve los tres problemas que bloquean los despliegues A2A: traducción de protocolo (JSON-RPC 2.0 a chat completions compatibles con OpenAI), reconciliación de streaming (SSE de artefactos A2A a SSE de eventos de ejecución de Hermes) y seguridad multi-inquilino (Row-Level Security de PostgreSQL en cada consulta). Si necesitas que agentes en diferentes frameworks deleguen trabajo entre sí, el patrón aquí es la ruta de despliegue.
Conclusiones clave
- 3 capas, 1 pila de Docker Compose — SilvaEngine Gateway gestiona el transporte y la autenticación, A2A Daemon Engine gestiona la lógica del protocolo y HermesAgentHandler actúa de puente hacia la API compatible con OpenAI de Hermes Agent. El repositorio docker-a2a-hermes-agent-gateway empaqueta los tres.
- 5 superficies de protocolo en un solo puerto — JSON-RPC 2.0, GraphQL, flujo SSE, push SSE y descubrimiento de Agent Card, todo detrás de una única pasarela en el puerto 8765 con autenticación JWT o AWS Cognito.
- Row-Level Security de PostgreSQL aplica el aislamiento entre tenants — la clave compuesta
partition_key = "{endpoint_id}#{Part-Id}"se aplica a nivel de base de datos mediante políticas RLS en las cuatro tablas A2A, no solo en el código de la aplicación. - La restricción de mensaje único del A2A SDK v2 define la arquitectura de streaming — el puente emite fragmentos de tokens a SSE en tiempo real y un único Message acumulado al EventQueue del SDK tras completar el flujo, evitando
InvalidAgentResponseError. - 15 comprobaciones de pruebas E2E en 5 scripts — desde pruebas de humo sin streaming hasta pipelines completos de streaming SSE con verificación de respaldo HTTP, todos ejecutables con
pip install requests.
El Agent2Agent Protocol (A2A) define cómo los agentes de IA se descubren, delegan y transmiten tareas entre sí a través de JSON-RPC 2.0. Hermes Agent (de Nous Research) expone un API Server compatible con OpenAI en /v1/chat/completions y una interfaz de streaming SSE basada en runs en /v1/runs y /v1/runs/{id}/events. Los dos no hablan el mismo idioma. A2A envía message/send con partes estructuradas; Hermes recibe payloads de chat completion. A2A transmite artefactos de tarea vía SSE; Hermes transmite deltas de tokens mediante run events.
El repositorio docker-a2a-hermes-agent-gateway salva esa brecha en una sola imagen de contenedor y una pila de docker compose. Ejecuta el SilvaEngine Gateway con solo el módulo a2a_daemon_engine registrado, exponiendo la superficie completa del protocolo A2A y puentando las tareas A2A hacia una instancia del Hermes Agent API Server a través de HTTP + SSE. El estado persiste en un backend PostgreSQL incluido con Row-Level Security para el aislamiento entre tenants.
Este artículo mapea la arquitectura de tres capas, el ciclo de vida de la solicitud desde el cliente A2A hasta Hermes y de vuelta, los patrones de configuración y despliegue, y los aspectos operativos para ejecutar A2A en Hermes Agent en producción. Es un recorrido por un despliegue de referencia — el patrón general (puente A2A mediado por pasarela hacia cualquier framework de agentes) es el tema; la pila Docker es la implementación desarrollada.
La arquitectura de tres capas
La pila separa las responsabilidades en tres capas, cada una propiedad de un componente distinto:
La pasarela es el único servicio siempre activo. Tanto Hermes como PostgreSQL son hermanos controlados por perfiles — inclúyelos para una pila autónoma, o desactiva los perfiles y apunta HERMES_API_URL y PG_HOST a instancias externas. Esto es importante para producción: puedes ejecutar la pasarela en tu VPC y apuntarla a un Postgres gestionado (RDS, Cloud SQL) y a una instancia de Hermes ejecutándose en un nodo GPU en otra ubicación.
Capa 1: SilvaEngine Gateway — transporte y autenticación
El SilvaEngine Gateway es una pasarela FastAPI para acceso autenticado e en-proceso a módulos instalados. Expone rutas GraphQL y REST de los módulos a través de un manifiesto de rutas YAML configurable — añadir un módulo nuevo requiere solo cambios en el manifiesto, sin código Python de la pasarela. En esta pila, solo el A2A Daemon Engine está registrado.
La pasarela gestiona:
- Autenticación — JWT local (HS256) o AWS Cognito (RS256 + JWKS), seleccionado por
GATEWAY_AUTH_PROVIDER - Enrutamiento — el manifiesto YAML mapea rutas de URL a funciones de despacho de módulos
- Ciclo de vida del cliente SSE — el
sse_managerse resuelve por módulo y gestiona conexiones de cliente de larga duración - Limitación de tasa — limitación de tasa por IP en memoria (
GATEWAY_RATE_LIMITsolicitudes porGATEWAY_RATE_WINDOWsegundos) - Despacho por pool de hilos — las funciones síncronas de despacho de módulos se ejecutan en un pool de hilos configurable (
GATEWAY_DISPATCH_WORKERS, 32 por defecto en la imagen Docker)
La pasarela construye partition_key = "{endpoint_id}#{Part-Id}" a partir del segmento de la ruta URL y de la cabecera Part-Id de la solicitud. Cada solicitud con ámbito de tenant requiere esa cabecera. El endpoint de la Agent Card en /{ep}/.well-known/agent-card.json es público (sin autenticación) según la especificación A2A, pero aún requiere Part-Id porque la tarjeta se resuelve por partición.
Capa 2: A2A Daemon Engine — lógica de protocolo
El a2a_daemon_engine no es un servicio autónomo. Se carga como un módulo registrado de la pasarela a través de deploy() en main.py, que declara tres puntos de entrada orientados a la pasarela:
| Punto de entrada | Ruta de la pasarela | Método | Propósito |
|---|---|---|---|
a2a_core_graphql |
POST /{ep}/a2a_core_graphql |
POST | CRUD GraphQL para agentes, tareas, mensajes, ajustes |
a2a |
POST /{ep}/a2a |
POST | Protocolo A2A JSON-RPC (message/send, tasks/get, tasks/cancel, tasks/list) |
sse_message |
POST /{ep}/a2a_sse |
POST | Mensaje A2A JSON-RPC + push a clientes SSE |
La pasarela además expone GET /{ep}/a2a_sse para el flujo SSE. El daemon no escucha en su propio puerto ni ejecuta su propio servidor HTTP en producción. Todo el transporte, la autenticación y el ciclo de vida del cliente SSE son gestionados por la pasarela.
El daemon proporciona:
- A2A SDK v1.0 — JSON-RPC sobre HTTP, construido sobre el patrón oficial del servidor del A2A SDK
- Agent Card pública en
/.well-known/agent-card.jsoncon soporte de ETag y Last-Modified - Máquina de estados de tarea —
submitted→working→input-required|completed|failed|canceled - Persistencia de doble backend — DynamoDB (PynamoDB) o PostgreSQL (SQLAlchemy + Alembic). La imagen Docker fuerza PostgreSQL.
- Aislamiento multi-tenant — claves de partición compuestas (
{endpoint_id}#{part_id}) con Row-Level Security de PostgreSQL - Handlers LLM conectables — selección
module_name/class_namepor agente en el registro de agentes
Capa 3: HermesAgentHandler — el puente
El handler puente de Hermes (a2a_daemon_engine/handlers/a2a_hermes_handler.py) es el único código específico del framework. Implementa una interfaz ask_model(): aceptar partes de mensaje A2A y contexto, llamar al Hermes Agent API Server, convertir la respuesta de vuelta a partes de mensaje A2A y, para el streaming, reenviar los deltas de tokens al canal SSE.
El handler admite dos modos de ejecución:
Sin streaming se mapea a POST /v1/chat/completions en el Hermes API Server — el endpoint compatible con OpenAI. La solicitud transporta las partes de mensaje A2A convertidas como un payload de chat completion. Hermes procesa la solicitud y devuelve una única respuesta. El handler convierte la respuesta en un Message A2A con ROLE_AGENT y lo emite al EventQueue del SDK. El cliente recibe una única respuesta JSON-RPC con el texto completo del agente.
Con streaming se mapea a POST /v1/runs para crear un run, y luego abre una conexión SSE a GET /v1/runs/{id}/events. Hermes transmite eventos a medida que ocurren: deltas de tokens (message.delta), metadatos de razonamiento (reasoning.available), notificaciones de llamadas/resultado de herramientas, solicitudes de aprobación (approval.required) y eventos de ciclo de vida (run.created, run.completed, run.failed). El handler ejecuta un bucle de drenaje en un hilo en segundo plano. Cada evento message.delta se envía al gestor SSE de la pasarela para su entrega en tiempo real a los clientes conectados. Cuando llega run.completed, el texto acumulado se emite como un único Message A2A al EventQueue del SDK.
El ciclo de vida de la solicitud
Un único message/send con stream=true recorre ocho pasos:
1. Cliente POST /{ep}/a2a {jsonrpc, method:"message/send", params}
Headers: Authorization: Bearer *** Part-Id:
2. Pasarela auth (JWT local / Cognito) → coincidencia de ruta desde routes.yaml
→ partition_key = "{ep}#{Part-Id}"
3. a2a_daemon dispatch_a2a → A2ADaemonExecutor
→ resolve_agent(): metadatos del agente (BD) > dict de ajustes > 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. Broadcast fragmentos de tokens → suscriptores en GET /{ep}/a2a_sse
7. Persistencia tarea + mensajes escritos en PostgreSQL (tablas a2a_*, ámbito RLS)
8. Respuesta la respuesta acumulada también se devuelve en el resultado JSON-RPC HTTP El paso 8 es importante: incluso con streaming, la respuesta HTTP transporta la respuesta completa. Un cliente que pierda frames SSE puede recurrir a la respuesta HTTP. El conjunto de pruebas E2E (test_hermes_sse_live.py) verifica explícitamente este respaldo en su paso 06.
Prioridad de resolución del agente
La resolución de configuración sigue una cadena de prioridad: metadatos del agente (BD) → dict de ajustes → valores por defecto de Config (variables de entorno). Las anulaciones por agente prevalecen sobre los valores por defecto globales. Dos agentes pueden apuntar a frameworks distintos — uno a Hermes para tareas de razonamiento intensivo, otro a un handler diferente para tareas de orquestación de flujos — y la superficie del protocolo A2A se ve idéntica para el agente que llama.
Para un agente respaldado por Hermes, los metadatos almacenados en la tabla a2a_agents se ven así:
{
"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
}Los valores por defecto de las variables de entorno (HERMES_API_URL, HERMES_API_KEY, HERMES_MODEL) permiten que el puente alcance a Hermes sin un registro de agente en la BD — la función resolve_agent() en a2a_ai_agent_utility.py recurre a las variables de entorno cuando no existe un registro de agente. Esto significa que puedes iniciar la pila y enviar un message/send sin registrar ningún agente, y se enrutará a Hermes usando los valores por defecto del entorno.
Mapeo de estado A2A
El puente mapea los eventos SSE de Hermes a estados de tarea A2A. Esta tabla es el corazón del puente — toda integración de framework produce una tabla equivalente:
| Evento SSE de Hermes | Estado de tarea A2A | Acción del puente |
|---|---|---|
run.created (devuelve run_id) |
WORKING |
Registrar run_id para soporte de cancelación |
message.delta |
WORKING |
Acumular token; emitir a SSE por fragmento |
reasoning.available |
WORKING |
Metadatos de razonamiento — sin emisión de token |
tool.call / tool.result |
WORKING |
Solo metadatos de ejecución de herramienta |
approval.required |
INPUT_REQUIRED |
Emitir fragmento de aprobación; almacenar pending_approval |
run.completed |
COMPLETED |
Establecer evento de stream; acumular texto final |
run.failed |
FAILED |
Emitir fragmento de error; establecer estado FAILED |
POST /v1/runs/{id}/stop |
CANCELED |
Cancelación externa vía tasks/cancel |
POST /v1/runs/{id}/approval |
(continúa el run) | Resuelto vía operation="approval_response" |
El documento HERMES_INTEGRATION.md en el repositorio a2a_daemon_engine registra el formato exacto de los eventos de Hermes, las claves de configuración y los detalles del flujo de extremo a extremo.
Aprobación humana en el bucle a través de fronteras de agentes
Hermes soporta puertas de aprobación humana en el bucle — cuando un agente necesita permiso para ejecutar una acción sensible, se detiene y emite una solicitud de aprobación. El puente traduce esto al estado A2A INPUT_REQUIRED, que señala al agente que llama (o al operador humano) que se necesita entrada. La respuesta regresa a través de POST /v1/runs/{id}/approval, y el run continúa.
Aquí es donde el patrón de puente demuestra su valor. A2A define INPUT_REQUIRED como un estado de tarea de primera clase. Hermes tiene su propio mecanismo de aprobación. El puente mapea uno al otro, y el agente que llama — que puede ser a su vez un cliente A2A ejecutándose en un framework completamente distinto — ve una transición de estado de protocolo estándar, no un detalle específico de Hermes. Una cadena de delegación de agentes puede incluir un paso que requiera aprobación humana (una autorización de compra, una decisión de acceso a datos, una aprobación de presupuesto), y el protocolo A2A transporta esa puerta de forma transparente a través de las fronteras del framework.
La restricción del A2A SDK v2 y la solución de doble vía
El A2A SDK v2 (a2a-sdk==1.0.2) impone dos restricciones en la ruta on_message_send que dieron forma a la implementación del puente:
- Solo un Message. Emitir varios objetos
Messageal EventQueue del SDK lanzaInvalidAgentResponseError: Multiple Message objects received. - Sin TaskStatusUpdateEvent. Los eventos de estado lanzan
InvalidAgentResponseError: Received TaskStatusUpdateEvent in message mode.
Un puente ingenuo emitiría un Message por cada delta de token — el patrón natural de streaming. El SDK lo rechaza. También rechaza los eventos de estado (WORKING, COMPLETED) en la ruta message/send.
La solución es un canal de salida de doble vía:
- SSE (gestionado por la pasarela): Los fragmentos de tokens se envían a SSE en tiempo real. Los clientes conectados ven la salida de streaming a medida que ocurre. Los eventos de estado (WORKING, COMPLETED, FAILED) también van solo a SSE.
- EventQueue del SDK: Tras completar el flujo, se emite un único
Messageacumulado que contiene el texto completo de la respuesta al EventQueue del SDK. Esto es lo que devuelve la respuesta JSON-RPCmessage/send.
El cliente obtiene streaming en tiempo real vía SSE y una respuesta JSON-RPC de mensaje único limpia vía el SDK. Ambos canales funcionan; ninguno viola las restricciones del SDK.
Superficies de protocolo en un solo puerto
La pasarela expone cinco superficies de protocolo en un solo puerto (8765 por defecto):
| Protocolo | Ruta | Auth | Propósito |
|---|---|---|---|
| GraphQL | POST /{ep}/a2a_core_graphql |
Sí | Consultas/mutaciones A2A core (agentes, tareas, mensajes, ajustes) |
| JSON-RPC 2.0 | POST /{ep}/a2a |
Sí | Protocolo A2A: message/send, tasks/get, tasks/cancel, tasks/list |
| SSE (flujo) | GET /{ep}/a2a_sse |
Sí | Flujo de eventos de tarea A2A por partición y de larga duración |
| SSE (push) | POST /{ep}/a2a_sse |
Sí | Mensaje JSON-RPC + push a clientes SSE conectados |
| Agent Card | GET /{ep}/.well-known/agent-card.json |
Público | Documento de descubrimiento A2A (la cabecera Part-Id sigue siendo obligatoria) |
La forma de los params de message/send JSON-RPC usada por los harness de prueba:
{
"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": []
}
}El campo metadata.operation selecciona la ruta de ejecución: task_execution para ejecuciones de agente con soporte de streaming, message_response para chat sin streaming. El agent_uuid apunta a un agente específico en el registro. El indicador stream activa la difusión SSE. El task_data.task_id es un id proporcionado por el llamador usado por tasks/get y tasks/cancel.
SSE es por partición, no por tarea. Cada tarea en {ep}#{Part-Id} se difunde a todos los suscriptores de esa partición. El orden de operaciones importa: conecta el listener SSE antes de enviar el mensaje, o se perderán los primeros fragmentos de tokens.
Persistencia y multi-tenencia
La imagen Docker fuerza db_backend=postgresql — no se admite DynamoDB. El daemon usa nombres de tabla literales y sin prefijo:
| Tabla | Contiene |
|---|---|
a2a_agents |
Registros de agente + metadatos de handler/modelo por agente |
a2a_tasks |
Ciclo de vida de tarea + estado |
a2a_messages |
Turnos de mensaje por tarea |
a2a_settings |
Dicts de ajustes por partición |
Dado que los nombres no llevan prefijo, no compartas PG_DB con otro módulo que use los mismos nombres.
El aislamiento entre tenants usa Row-Level Security de PostgreSQL. La variable de sesión app.tenant_id se establece al partition_key de la solicitud ("{endpoint_id}#{Part-Id}"), y las políticas RLS limitan cada consulta a ese valor. Las tablas y políticas se crean automáticamente al iniciar la pasarela cuando initialize_tables=1. Esto significa que un filtro partition_key olvidado en el código de la aplicación no puede filtrar filas entre tenants — la base de datos aplica la frontera.
La implementación RLS reside en a2a_daemon_engine/utils/rls.py (set_rls_context y create_rls_policies) y en la migración 0005_enable_rls_policies. La función set_rls_context ejecuta un SET app.tenant_id por solicitud sobre la conexión, y create_rls_policies habilita y fuerza RLS con una política tenant_isolation en las cuatro tablas A2A. RLS es inerte en modo DynamoDB.
Despliegue con Docker Compose
La pila tiene un servicio siempre activo y dos hermanos opcionales controlados por perfiles:
| Servicio | Nombre del contenedor | ¿Siempre activo? | Perfil | Propósito |
|---|---|---|---|---|
a2a-gateway |
a2a-hermes-gateway |
Sí | — | SilvaEngine Gateway (rutas solo A2A) + puente de Hermes |
postgres |
a2a-postgres |
Opcional | postgres |
Backend de persistencia PostgreSQL incluido |
hermes |
container-hermes |
Opcional | hermes |
Hermes Agent incluido (API compatible con OpenAI + panel) |
COMPOSE_PROFILES es el único interruptor para ambos hermanos:
| Valor | Servicios iniciados |
|---|---|
| vacío | solo pasarela (Postgres externo + Hermes externo) |
postgres |
pasarela + Postgres incluido |
hermes |
pasarela + Hermes incluido (Postgres externo) |
postgres,hermes |
pasarela + Postgres y Hermes incluidos (por defecto) |
Cuando un hermano está incluido, mantén su referencia de host apuntando al nombre del servicio: PG_HOST=postgres y HERMES_API_URL=http://hermes:<API_SERVER_PORT>. Cuando un hermano es externo, apunta esos a tu propia instancia (p. ej. PG_HOST=host.docker.internal, HERMES_API_URL=http://host.docker.internal:8642).
Inicio rápido
cp .env.example .env
# Rellena: JWT_SECRET_KEY, ADMIN_PASSWORD, API_SERVER_KEY,
# HERMES_API_KEY (= API_SERVER_KEY), HERMES_MODEL_PROVIDER + clave del proveedor, HERMES_MODEL
mkdir -p www/hermes www/projects
DOCKER_BUILDKIT=1 docker compose build
docker compose up -d # COMPOSE_PROFILES=postgres,hermes es el valor por defecto
docker compose ps # espera (healthy)
curl -f http://localhost:8765/health
pip install requests
python test_hermes_hello.py # prueba de humo de extremo a extremoTanto silvaengine_gateway como a2a_daemon_engine se instalan vía pip desde git en la imagen (sin montaje de código fuente del host). La imagen es genérica y completamente controlada por variables de entorno — no hay secretos integrados. Los módulos se clonan desde repositorios públicos de GitHub bajo ideabosque vía git+https — no se necesitan credenciales ni clave de despliegue SSH.
La trampa del comentario en línea en .env
El parser env_file de Docker Compose no elimina los comentarios en línea. Una línea como:
HERMES_API_KEY=hermes-local-key # token para Hermesestablece HERMES_API_KEY a la cadena literal hermes-local-key # token para Hermes (comentario incluido), lo que rompe la autenticación de forma silenciosa. Las reglas: no pongas nada después del valor en ninguna línea KEY=value. Pon las notas en sus propias líneas de comentario # encima de la variable.
Verificación: 15 comprobaciones E2E en 5 scripts
La pila incluye harness de prueba en Python autónomos (única dependencia: requests). Cargan ./.env, resuelven o acuñan un JWT de la pasarela y hablan con la pila en ejecución:
| Script | Tipo | Qué hace |
|---|---|---|
test_hermes_hello.py |
Humo | message/send sin streaming, imprime la respuesta |
test_hermes_hello_sse.py |
Humo | Un prompt transmitido vía SSE |
test_hermes_gateway_live.py |
Suite E2E | 9 comprobaciones: salud de Hermes, salud de la pasarela, agent card, ping GraphQL, message/send, tasks/get, tasks/list, tasks/cancel, ruta de fallo |
test_hermes_sse_live.py |
Suite E2E | 6 comprobaciones: salud x2, conexión SSE, fragmentos de tokens en vivo, estado COMPLETED, respaldo HTTP |
test_hermes_chatbot.py |
Interactivo | REPL contra la superficie A2A con streaming SSE en vivo |
Todos los scripts no interactivos imprimen PASS/FAIL por paso y terminan con código distinto de cero en caso de fallo, así que funcionan como puertas de CI. El conjunto de pruebas unitarias (test_hermes_handler.py) ejecuta 24 pruebas con HTTP simulado vía httpx.MockTransport — no se necesitan servicios.
Patrones operativos
Cambios de ruta sin reconstrucciones
routes.yaml se monta por bind-mount como solo lectura en el contenedor. Edita el archivo del host y reinicia el proceso de la pasarela — no hace falta reconstrucción:
make restartTras un cambio en el upstream
Dado que silvaengine_gateway y a2a_daemon_engine se instalan vía pip desde git al compilar, un cambio en el upstream requiere una reconstrucción con --no-cache para que la capa git vuelva a clonar el @main más reciente:
DOCKER_BUILDKIT=1 docker compose build --no-cache
docker compose up -d --force-recreateNo hay fijación de versión — @main es un objetivo móvil. Fija un tag o commit en requirements-modules.txt si necesitas reproducibilidad.
Escalado más allá de un worker
El estado de tarea en memoria, los contadores de limitación de tasa y el registro de clientes SSE son por proceso. Con GATEWAY_WORKERS > 1, cambia a backends compartidos (GATEWAY_TASK_BACKEND=dynamodb, GATEWAY_RATE_LIMIT_BACKEND=dynamodb, más region_name y credenciales aws_*) y usa sesiones pegajosas para SSE. La configuración por defecto inicia un proceso Uvicorn.
Valores de seguridad por defecto a cambiar
JWT_SECRET_KEY=change-me-in-production— sustitúyelo poropenssl rand -hex 32ADMIN_PASSWORD=change-me— sustitúyelo por una contraseña realPOSTGRES_PASSWORD=silvaengine— sustitúyelo por una contraseña realGATEWAY_CORS_ORIGINS=*permite cualquier origen sin credenciales. Establece una lista explícita si necesitas cookies/credenciales.- El Hermes incluido monta el socket de Docker del host (
/var/run/docker.sock). Eso equivale a root en el host para cualquier cosa dentro de ese contenedor. Ejecuta el perfilhermessolo en un host que controles, y elimina el montaje si el agente no necesita lanzar contenedores. - El panel de Hermes está habilitado por defecto en el puerto 9119 con credenciales básicas de autenticación vacías. Establece
HERMES_DASHBOARD_BASIC_AUTH_*o vincula el puerto a localhost antes de exponer el host. - RLS es la frontera entre tenants. Un llamador que pueda establecer un
Part-Idarbitrario lee los datos de esa partición — trataPart-Idcomo una entrada relevante para la autorización en cualquier front-end que pongas delante de esto.
Lo que esto habilita
La pila de tres capas te da tres capacidades difíciles de ensamblar desde cero:
1. Conformidad con el protocolo A2A sin reescribir Hermes. Cualquier cliente A2A puede descubrir el agente respaldado por Hermes vía su Agent Card, enviar tareas vía message/send, transmitir respuestas vía SSE y seguir el ciclo de vida de la tarea a través de estados A2A estándar. El cliente no sabe que el agente remoto ejecuta Hermes — ve un endpoint A2A con una interfaz JSON-RPC.
2. Servicio de agente multi-tenant desde una sola pasarela. La cabecera Part-Id combinada con RLS de PostgreSQL significa que una instancia de pasarela sirve a múltiples tenants con aislamiento estricto a nivel de base de datos. Cada tenant obtiene su propio registro de agentes, historial de tareas y almacén de mensajes — todo en las mismas cuatro tablas, delimitadas por partition_key.
3. Aprobación humana en el bucle a través de fronteras de agentes. Las puertas de aprobación de Hermes se mapean a estados A2A INPUT_REQUIRED. Una cadena de delegación de agentes puede incluir un paso que requiera aprobación humana, y el protocolo A2A transporta esa transición de estado de vuelta al agente u operador de origen — independientemente del framework en el que se ejecute cada agente de la cadena.
La implementación de referencia también soporta despacho en AWS Lambda para A2A sin servidor, transporte gRPC experimental con streaming bidireccional y persistencia de doble backend (DynamoDB o PostgreSQL). El repositorio a2a_daemon_engine y su guía de integración con Hermes contienen la implementación completa, la referencia de configuración y los detalles del mapeo de estados. El repositorio SilvaEngine Gateway documenta el sistema de manifiesto de rutas, los proveedores de autenticación y la auto-inicialización de módulos.
Lecturas relacionadas
- MCP + A2A: los dos protocolos detrás de todo sistema de IA agentica en producción — los roles complementarios de MCP (agentes a herramientas) y A2A (agentes a agentes) en la pila de protocolo de dos capas
- Integración de A2A con frameworks de agentes existentes: una demostración con Hermes Agent — el patrón general de puente y cómo se aplica a OpenClaw y otros frameworks más allá de Hermes
- Estándar de código de módulos MCP — el patrón estructural para módulos de agente listos para producción, aplicable también al código de handlers A2A
Un distribuidor de mercado medio necesita agentes de cotización que hablen con agentes de catálogo que hablen con agentes de inventario — cada uno respaldado por un framework distinto, cada uno propiedad de un equipo distinto. A2A da a esos agentes un protocolo compartido. Una capa de puente permite que Hermes Agent participe sin reescribir sus interioridades. El repositorio docker-a2a-hermes-agent-gateway empaqueta ese puente en una sola imagen de contenedor con persistencia PostgreSQL, multi-tenencia RLS y 15 comprobaciones de prueba E2E.
Solicita un build acotado
Una semana de descubrimiento. Obtienes un inventario de sistemas, un mapa de flujos de trabajo y un alcance fijo — tanto si construyes con nosotros como si no.
¿Quieres esto construido para tus sistemas?
Cada documento aquí viene de trabajo real de producción. Si tienes un sistema objetivo y un flujo en mente, podemos definir un proyecto en una semana.
Solicitar un proyectoDescubrimiento de una semana. Obtienes un inventario de sistemas, mapa de flujos y alcance fijo — decidas o no construir con nosotros.