A2A Protocol
Claix como agente A2A
Endpoint
https://claix.dev/a2aClaix expone un agente Agent-to-Agent (A2A) para que otros agentes lo invoquen con JSON-RPC 2.0, sin pasar por MCP ni reescribir la API REST. Reutiliza las mismas operaciones de extracción, consulta y schemas. Las skills se generan desde openapi.yaml.
Endpoint del protocolo: https://claix.dev/a2a. Agent Card pública: https://claix.dev/.well-known/agent.json (también en https://claix.dev/.well-known/agent-card.json).
1. Rutas públicas
| Método | Ruta | Qué hace |
|---|---|---|
| GET | /.well-known/agent.json | Agent Card (descubrimiento). Sin API key. |
| GET | /.well-known/agent-card.json | Misma Agent Card (path del SDK oficial @a2a-js/sdk). |
| POST | /a2a | JSON-RPC 2.0 del protocolo A2A. Requiere API key. |
Conecta el inspector o el cliente A2A al origen del sitio (https://claix.dev), no a /a2a, para que resuelva la Agent Card en /.well-known/. El campo url / supportedInterfaces de la card apunta a https://claix.dev/a2a.
2. Autenticación y límites
En cada POST /a2a envía la misma API key que en REST:
x-api-key: <TU_API_KEY>
Alternativa: Authorization: Bearer <TU_API_KEY>. Sin clave: JSON-RPC -32001 y HTTP 401. Clave inválida o cuenta inactiva: el mismo código. Límite: 60 peticiones por minuto por API key (HTTP 429, Retry-After).
La Agent Card es pública. Los mensajes, DataParts y cualquier card de un agente llamante se tratan como entrada no fiable y se validan antes de ejecutar nada.
3. Agent Card
La card declara name: Claix, la URL JSON-RPC, capabilities.pushNotifications: true, streaming: false y las 20 skills. El esquema de entrada de cada skill (parámetros OpenAPI, con file_base64 / file_path en lugar del file multipart) vive en la extensión https://claix.dev/a2a/extensions/openapi-skills.
Si el OpenAPI cambia, regenera las skills con npm run a2a:skills. No las edites a mano.
4. Cómo usarlo
- Descarga la Agent Card y elige una skill por
id. - Envía
POST https://claix.dev/a2aconmethod: "message/send". - Si ya tienes parámetros tipados, usa un DataPart JSON con
"skill": "<id>". Se ejecuta de forma determinista, sin modelo de lenguaje. - Si solo tienes texto ambiguo, usa un TextPart. Gemini 3.6 Flash elige la skill y los argumentos a partir de los mismos esquemas.
- Reutiliza el mismo
contextIden mensajes siguientes para mantener el hilo (tablaconversaciones).
Métodos JSON-RPC habituales:
| Método | Uso |
|---|---|
| message/send | Crear o continuar una tarea. |
| tasks/get | Consultar el estado de una tarea ya creada. |
| tasks/cancel | Cancelar una tarea en curso. |
| tasks/pushNotificationConfig/set | Registrar el webhook para el resultado de tareas largas. |
No hay message/stream / SSE. Las tareas largas no dejan la conexión abierta.
5. DataPart vs TextPart
| Entrada | Comportamiento |
|---|---|
| DataPart con skill conocida | Enruta directo a la operación interna (misma lógica que la REST). |
| DataPart sin skill | Tarea input-required: indica el id de skill a usar. |
| skill desconocida o parámetro corrupto | JSON-RPC -32602 Invalid params, con el campo y el motivo. |
| Falta un dato recuperable (space_id, schema_id, archivo…) | Estado input-required, no error. El agente llamante puede completar el dato. |
| TextPart en lenguaje natural | Gemini 3.6 Flash elige skill + parámetros. Único punto con LLM de enrutado. |
Ejemplo DataPart: {"skill":"extract-pdf","schema_id":"<uuid>","file_base64":"<base64>"}. El archivo multipart de la REST se envía aquí como file_base64 o file_path (URL https pública).
6. Estados de tarea y formatos de respuesta
Una llamada correcta a message/send devuelve JSON-RPC result con un objeto Task (id, contextId, status.state, artefactos).
| Estado | Cuándo |
|---|---|
| completed | Tarea rápida resuelta en la misma respuesta (get-document, query-document, list/create/delete schema, space o document). |
| working | Tarea larga encolada: extract-*, agent-extract-*, convert-json-to-excel, query-space. El resultado llega por push webhook. |
| input-required | Falta un parámetro que el llamante puede aportar (p. ej. space_id). |
| failed | La operación de negocio falló (HTTP de Claix ≠ 2xx). |
| canceled | El llamante canceló la tarea. |
El resultado de negocio va en un artefacto JSON, no en SSE:
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"id": "<taskId>",
"contextId": "<contextId>",
"status": { "state": "completed" },
"artifacts": [
{
"name": "list-schemas-result",
"parts": [{ "kind": "data", "data": { "success": true, "schemas": [] } }]
}
]
}
}Errores de protocolo (antes de crear la tarea):
| HTTP | code | Significado |
|---|---|---|
| 401 | -32001 | Falta API key o no es válida. |
| 429 | -32000 | Rate limit. Mira Retry-After. |
| 400 | -32602 | Invalid params: tipo/formato corrupto. |
{
"jsonrpc": "2.0",
"id": 1,
"error": { "code": -32602, "message": "Invalid params: schema_id — …" }
}7. Tareas largas y push notifications
Extraer un PDF, razonar en modo agente o preguntar a un space_id con muchos documentos no espera en la conexión HTTP. La primera respuesta queda en working. Configura un webhook A2A (tasks/pushNotificationConfig/set) para recibir la Task final (completed o failed) con el artefacto.
capabilities.pushNotifications está a true. No uses streaming SSE para estas operaciones.
8. Conversación y contextId
El contextId de A2A identifica el hilo entre varias tareas. Claix lo guarda en conversaciones (context_id, user_id, last_task_id, last_activity_at). Reutiliza el mismo contextId en cada message/send del mismo diálogo.
9. Skills (desde OpenAPI)
Cada operación relevante del OpenAPI es una skill. Un DataPart debe incluir "skill": "<id>".
| Skill A2A | operationId OpenAPI | Endpoint REST |
|---|---|---|
| extract-excel | excelToJson | POST /excel-json |
| convert-json-to-excel | jsonToExcel | POST /json-excel |
| extract-pdf | pdfToJson | POST /pdf-json |
| extract-doc | docToJson | POST /doc-json |
| extract-img | imgToJson | POST /img-json |
| extract-txt | txtToJson | POST /txt-json |
| get-document | getDocument | GET /get-document/{document_id} |
| query-document | documentContextAsk | POST /document-context/{document_id} |
| query-space | spaceContextAsk | POST /space-context/{space_id} |
| create-space | createSpace | POST /create-space |
| delete-space | deleteSpace | DELETE /delete-space/{space_id} |
| delete-document | deleteDocument | DELETE /delete-document/{document_id} |
| agent-extract-excel | agentExcelToJson | POST /agent/excel-json |
| agent-extract-pdf | agentPdfToJson | POST /agent/pdf-json |
| agent-extract-doc | agentDocToJson | POST /agent/doc-json |
| agent-extract-img | agentImgToJson | POST /agent/img-json |
| agent-extract-txt | agentTxtToJson | POST /agent/txt-json |
| list-schemas | listSchemas | GET /schemas |
| create-schema | createSchema | POST /create-schema |
| delete-schema | deleteSchema | POST /delete-schema |
10. Clientes
- SDK oficial TypeScript:
@a2a-js/sdk - Inspector: a2aproject/a2a-inspector contra
https://claix.dev - Cualquier cliente JSON-RPC A2A 0.3 / 1.0 con push notifications
MCP y A2A son interfaces distintas. MCP sigue en https://claix.dev/mcp. Este agente no llama al servidor MCP.