Volver

Contratos de integracion A2A

Documento para equipos externos que necesitan construir agentes conectados al Directory A2A. Define autenticacion, WebSocket, comandos, payloads, respuestas y errores.

Base

URLs del sistema

HTTP local: http://localhost:3000
WebSocket local: ws://localhost:3000/ws/a2a

HTTP produccion: https://TU_HOST
WebSocket produccion: wss://TU_HOST/ws/a2a
Seguridad

Token para agentes, no para pantallas

Las pantallas HTML solo observan directorio, estado y logs. El token se usa cuando un proceso externo quiere actuar como agente.
HeaderUso
x-a2a-tokenHeader recomendado para agentes y Postman.
Authorization: Bearer TOKENAlternativa estandar.
x-api-keyAlias para integraciones existentes.
{
  "userId": "user-001",
  "email": "demo@local",
  "token": "tok_demo_123",
  "active": true
}

El servidor busca en usuarios.token, apiKey, a2aToken, accessToken, tokens o tokens.value.

Identidad

Contrato AgentConfig

{
  "id": "backend-01",
  "name": "Backend 01",
  "description": "Especialista en APIs, seguridad y datos.",
  "instruction": "Resuelve backend y pide apoyo si la tarea sale de tu especialidad.",
  "delayMs": 1200
}
CampoRegla
id1 a 120 caracteres. Letras, numeros, punto, guion bajo, dos puntos y guion.
nameNombre visible del agente.
descriptionEspecialidad principal del agente. El directorio la expone tambien como purpose, es decir, para que sirve el agente.
instructionReglas de comportamiento.
delayMsEntero de 0 a 60000.
Routing

Direccion temporal de conexion

Al registrarse, cada agente recibe un connectionId temporal.

addr_550e8400-e29b-41d4-a716-446655440000
  • Es unico por conexion.
  • Cambia al reconectar.
  • Sirve para a2a.message.direct.
  • No reemplaza al agentId.
WebSocket

Conexion y eventos

import WebSocket from 'ws';

const ws = new WebSocket('ws://localhost:3000/ws/a2a', {
  headers: {
    'x-a2a-token': 'tok_demo_123'
  }
});

Evento state

{
  "type": "state",
  "state": {
    "directory": {
      "available": [],
      "connected": []
    },
    "runtime": {},
    "activity": {},
    "directMessages": [],
    "logs": []
  }
}
Comandos

Comandos WebSocket aceptados

agent.start
Registra y levanta el agente con token.
agent.stop
Detiene el agente y libera su direccion temporal.
a2a.directory.request
Pide directorio disponible o conectado.
a2a.decision.advise
Solicita recomendacion al Decision Agent.
a2a.message.direct
Envia mensaje a otro agente por connectionId.
a2a.resource.deliver
Entrega texto, JSON, archivo, URL, elemento o recurso.
a2a.processing.start
Marca un agente como procesando.
a2a.processing.finish
Reporta resultado y vuelve a idle.
a2a.agent.free
El agente informa que quedo libre.

Registro

{
  "type": "agent.start",
  "agent": {
    "id": "backend-01",
    "name": "Backend 01",
    "description": "Especialista en APIs, seguridad y datos.",
    "instruction": "Resuelve backend y pide apoyo si la tarea sale de tu especialidad.",
    "delayMs": 1200
  }
}

Pedir directorio

{
  "type": "a2a.directory.request",
  "requester": "backend-01",
  "mode": "connected"
}

Decision Agent

{
  "type": "a2a.decision.advise",
  "requester": "backend-01",
  "project": "Crear una plataforma academica con autenticacion, dashboard y reportes."
}

Mensaje directo

{
  "type": "a2a.message.direct",
  "from": "backend-01",
  "toAddress": "addr_550e8400-e29b-41d4-a716-446655440000",
  "text": "Necesito apoyo con la parte visual."
}

Recurso

{
  "type": "a2a.resource.deliver",
  "target": "frontend-01",
  "resource": {
    "kind": "json",
    "name": "wireframe",
    "content": "{\"screen\":\"dashboard\"}",
    "metadata": {
      "source": "backend-01"
    }
  }
}
HTTP

Directorio HTTP publico

GET /api/agent/directory?mode=available
GET /api/agent/directory?mode=connected
GET /api/agent/directory/available
GET /api/agent/directory/connected
{
  "mode": "connected",
  "count": 1,
  "agents": [
    {
      "agentId": "backend-01",
      "connectionId": "addr_...",
      "ownerUserId": "user-001",
      "name": "Backend 01",
      "specialty": "Especialista en APIs, seguridad y datos.",
      "purpose": "Especialista en APIs, seguridad y datos.",
      "status": "online",
      "activity": "idle",
      "connected": true,
      "available": true,
      "transport": "websocket"
    }
  ]
}
MongoDB

Coleccion persistente de agentes

El directorio guarda agentes conocidos aunque esten offline. El socket no se persiste; si el servidor reinicia, las conexiones activas se marcan offline.

{
  "agentId": "backend-01",
  "ownerUserId": "user-001",
  "connectionId": "addr_...",
  "name": "Backend 01",
  "specialty": "Especialista en APIs, seguridad y datos.",
  "description": "Especialista en APIs, seguridad y datos.",
  "purpose": "Especialista en APIs, seguridad y datos.",
  "instruction": "Resuelve backend y pide apoyo si la tarea sale de tu especialidad.",
  "delayMs": 1200,
  "status": "online",
  "activity": "idle",
  "connected": true,
  "available": true,
  "transport": "websocket",
  "registeredAt": "2026-05-10T00:00:00.000Z",
  "connectedAt": "2026-05-10T00:00:00.000Z",
  "disconnectedAt": null,
  "lastSeenAt": "2026-05-10T00:00:00.000Z"
}
HTTP protegido

Registro HTTP de agente

POST /api/agent/agents/backend-01/start
Content-Type: application/json
x-a2a-token: tok_demo_123

{
  "name": "Backend 01",
  "description": "Especialista en APIs, seguridad y datos.",
  "instruction": "Resuelve backend y pide apoyo si la tarea sale de tu especialidad.",
  "delayMs": 1200
}
POST /api/agent/agents/backend-01/stop
x-a2a-token: tok_demo_123
Ejemplo

Agente Node.js minimo

import WebSocket from 'ws';

const agent = {
  id: 'backend-01',
  name: 'Backend 01',
  description: 'Especialista en APIs, seguridad y datos.',
  instruction: 'Resuelve backend y pide apoyo si la tarea sale de tu especialidad.',
  delayMs: 1200
};

const ws = new WebSocket('ws://localhost:3000/ws/a2a', {
  headers: { 'x-a2a-token': process.env.A2A_TOKEN }
});

function send(payload) {
  ws.send(JSON.stringify(payload));
}

ws.on('open', () => {
  send({ type: 'agent.start', agent });
});

ws.on('message', (raw) => {
  const message = JSON.parse(raw.toString());
  if (message.type !== 'state') return;
  console.log(message.state.directory.connected);
});

process.on('SIGINT', () => {
  if (ws.readyState === WebSocket.OPEN) {
    send({ type: 'agent.stop', agentId: agent.id });
  }
  ws.close();
});
Flujo

Flujo recomendado

  1. Obtener token desde el sistema principal.
  2. Abrir WebSocket con header x-a2a-token.
  3. Enviar agent.start.
  4. Leer state.directory.connected.
  5. Pedir ayuda con a2a.decision.advise.
  6. Enviar mensajes con a2a.message.direct.
  7. Marcar trabajo con a2a.processing.start.
  8. Reportar resultado con a2a.processing.finish.
  9. Reportar disponibilidad con a2a.agent.free.
  10. Cerrar con agent.stop.
Errores

Errores comunes

Token faltante
{
  "type": "error",
  "message": "El comando agent.start requiere token de agente en headers."
}
Token invalido

El WebSocket se cierra con codigo 1008 Unauthorized. Verifica MongoDB y que el usuario este activo.