# OmniRoute A2A Server (Español) 🌐 **Languages:** 🇺🇸 [English](../../../../../../src/lib/a2a/README.md) · 🇪🇸 [es](../../../../es/src/lib/a2a/README.md) · 🇫🇷 [fr](../../../../fr/src/lib/a2a/README.md) · 🇩🇪 [de](../../../../de/src/lib/a2a/README.md) · 🇮🇹 [it](../../../../it/src/lib/a2a/README.md) · 🇷🇺 [ru](../../../../ru/src/lib/a2a/README.md) · 🇨🇳 [zh-CN](../../../../zh-CN/src/lib/a2a/README.md) · 🇯🇵 [ja](../../../../ja/src/lib/a2a/README.md) · 🇰🇷 [ko](../../../../ko/src/lib/a2a/README.md) · 🇸🇦 [ar](../../../../ar/src/lib/a2a/README.md) · 🇮🇳 [hi](../../../../hi/src/lib/a2a/README.md) · 🇮🇳 [in](../../../../in/src/lib/a2a/README.md) · 🇹🇭 [th](../../../../th/src/lib/a2a/README.md) · 🇻🇳 [vi](../../../../vi/src/lib/a2a/README.md) · 🇮🇩 [id](../../../../id/src/lib/a2a/README.md) · 🇲🇾 [ms](../../../../ms/src/lib/a2a/README.md) · 🇳🇱 [nl](../../../../nl/src/lib/a2a/README.md) · 🇵🇱 [pl](../../../../pl/src/lib/a2a/README.md) · 🇸🇪 [sv](../../../../sv/src/lib/a2a/README.md) · 🇳🇴 [no](../../../../no/src/lib/a2a/README.md) · 🇩🇰 [da](../../../../da/src/lib/a2a/README.md) · 🇫🇮 [fi](../../../../fi/src/lib/a2a/README.md) · 🇵🇹 [pt](../../../../pt/src/lib/a2a/README.md) · 🇷🇴 [ro](../../../../ro/src/lib/a2a/README.md) · 🇭🇺 [hu](../../../../hu/src/lib/a2a/README.md) · 🇧🇬 [bg](../../../../bg/src/lib/a2a/README.md) · 🇸🇰 [sk](../../../../sk/src/lib/a2a/README.md) · 🇺🇦 [uk-UA](../../../../uk-UA/src/lib/a2a/README.md) · 🇮🇱 [he](../../../../he/src/lib/a2a/README.md) · 🇵🇭 [phi](../../../../phi/src/lib/a2a/README.md) · 🇧🇷 [pt-BR](../../../../pt-BR/src/lib/a2a/README.md) · 🇨🇿 [cs](../../../../cs/src/lib/a2a/README.md) · 🇹🇷 [tr](../../../../tr/src/lib/a2a/README.md) --- > **Protocolo de agente a agente v0.3**: permite que cualquier agente de IA utilice OmniRoute como agente de enrutamiento inteligente a través de JSON-RPC 2.0. El servidor A2A expone a OmniRoute como un**agente de primera clase**que otros agentes pueden descubrir, delegar tareas y colaborar mediante el [Protocolo A2A](https://google.github.io/A2A/).--- ## Arquitectura ``` ┌──────────────────────────────────────────────────────────────────┐ │ Orchestrator Agent │ │ (LangChain, CrewAI, AutoGen, Custom Agent) │ └──────────────────────┬───────────────────────────────────────────┘ │ 1. GET /.well-known/agent.json (discover) │ 2. POST /a2a (JSON-RPC 2.0) ▼ ┌──────────────────────────────────────────────────────────────────┐ │ OmniRoute A2A Server │ │ ┌────────────────┐ ┌────────────────┐ ┌───────────────────┐ │ │ │ Task Manager │ │ Skill Engine │ │ SSE Streaming │ │ │ │ (lifecycle) │──│ (registry) │──│ (real-time) │ │ │ └────────────────┘ └────────┬───────┘ └───────────────────┘ │ │ │ │ │ Skills: │ │ │ ├─ smart-routing ──────────┤ ┌────────────────────────────┐ │ │ └─ quota-management ───────┘ │ Routing Decision Logger │ │ │ └────────────────────────────┘ │ └──────────────────────────────────────────────────────────────────┘ │ ▼ OmniRoute Gateway (internal) /v1/chat/completions, /api/combos, /api/usage/quota ``` --- ## Inicio Rápido ### Agent Discovery Cada agente compatible con A2A expone una**Tarjeta de agente**en `/.well-known/agent.json`:```bash curl http://localhost:20128/.well-known/agent.json ```` **Respuesta:**```json { "name": "OmniRoute", "description": "Intelligent AI gateway with auto-routing across 50+ providers", "url": "http://localhost:20128/a2a", "version": "1.8.1", "capabilities": { "streaming": true, "pushNotifications": false }, "skills": [ { "id": "smart-routing", "name": "Smart Routing", "description": "Routes prompts through OmniRoute intelligent pipeline", "tags": ["routing", "llm", "multi-provider", "cost-optimization"], "examples": [ "Write a hello world in Python", "Explain quantum computing using the cheapest provider" ] }, { "id": "quota-management", "name": "Quota Management", "description": "Natural-language queries about provider quotas", "tags": ["quota", "analytics", "cost"], "examples": [ "Which provider has the most quota remaining?", "Suggest a free combo for coding" ] } ], "authentication": { "schemes": ["bearer"], "apiKeyHeader": "Authorization" } } ```` --- ## JSON-RPC 2.0 Methods ### `message/send` — Synchronous Execution Envía un mensaje a una habilidad y recibe la respuesta completa.```bash curl -X POST http://localhost:20128/a2a \ -H "Content-Type: application/json" \ -H "Authorization: Bearer YOUR_KEY" \ -d '{ "jsonrpc": "2.0", "id": "1", "method": "message/send", "params": { "skill": "smart-routing", "messages": [{"role": "user", "content": "Write a Python hello world"}], "metadata": {"model": "auto", "combo": "fast-coding"} } }' ```` **Respuesta:**```json { "jsonrpc": "2.0", "id": "1", "result": { "task": { "id": "a1b2c3d4-...", "state": "completed" }, "artifacts": [{ "type": "text", "content": "print('Hello, World!')" }], "metadata": { "routing_explanation": "Selected claude-sonnet via provider \"anthropic\" (latency: 1200ms, cost: $0.0030)", "cost_envelope": { "estimated": 0.005, "actual": 0.003, "currency": "USD" }, "resilience_trace": [ { "event": "primary_selected", "provider": "anthropic", "timestamp": "2026-03-04T..." } ], "policy_verdict": { "allowed": true, "reason": "within budget and quota limits" } } } } ```` ### `message/stream` — SSE Streaming Igual que "mensaje/enviar", pero devuelve eventos enviados por el servidor para transmisión en tiempo real.```bash curl -N -X POST http://localhost:20128/a2a \ -H "Content-Type: application/json" \ -H "Authorization: Bearer YOUR_KEY" \ -d '{ "jsonrpc": "2.0", "id": "1", "method": "message/stream", "params": { "skill": "smart-routing", "messages": [{"role": "user", "content": "Explain quantum computing"}] } }' ```` **Eventos de ESS:**``` data: {"jsonrpc":"2.0","method":"message/stream","params":{"task":{"id":"...","state":"working"},"chunk":{"type":"text","content":"Quantum computing..."}}} : heartbeat 2026-03-04T21:00:00Z data: {"jsonrpc":"2.0","method":"message/stream","params":{"task":{"id":"...","state":"completed"},"metadata":{...}}} ```` ### `tasks/get` — Query Task Status ```bash curl -X POST http://localhost:20128/a2a \ -H "Content-Type: application/json" \ -H "Authorization: Bearer YOUR_KEY" \ -d '{"jsonrpc":"2.0","id":"2","method":"tasks/get","params":{"taskId":"TASK_UUID"}}' ``` ### `tasks/cancel` — Cancel a Running Task ```bash curl -X POST http://localhost:20128/a2a \ -H "Content-Type: application/json" \ -H "Authorization: Bearer YOUR_KEY" \ -d '{"jsonrpc":"2.0","id":"3","method":"tasks/cancel","params":{"taskId":"TASK_UUID"}}' ``` --- ## Skills Reference ### `smart-routing` Enruta indicaciones a través del canal inteligente de OmniRoute con total observabilidad. **Parámetros (en `metadatos`):** | Parámetro | Tipo | Predeterminado | Descripción | | ------------- | -------- | ------------------ | ------------------------------------------------------------------------------------------------------------------ | | `modelo` | `cadena` | `"automático"` | Modelo de destino (por ejemplo, `claude-sonnet-4`, `gpt-4o`, `auto`) | | `combinado` | `cadena` | combinación activa | Combo específico para enrutar | | `presupuesto` | `número` | ninguno | Costo máximo en USD para esta solicitud | | `rol` | `cadena` | ninguno | Sugerencia de rol de tarea: `codificación`, `revisión`, `planificación`, `análisis`, `depuración`, `documentación` | **Devoluciones:** | Campo | Descripción | | --------------------------------------- | -------------------------------------------------------------- | ---------------------- | | `artefactos[].content` | El texto de respuesta del LLM | | `metadatos.explicación_de_enrutamiento` | Explicación legible por humanos de la decisión de enrutamiento | | `metadatos.cost_envelope` | Costo estimado versus costo real con moneda | | `metadatos.resilience_trace` | Matriz de eventos (primary_selected, fallback_needed, etc.) | | `metadatos.policy_verdict` | Si se permitió la solicitud y por qué | ### `quota-management` | Responde consultas en lenguaje natural sobre cuotas de proveedores. **Tipos de consulta (inferidos del contenido del mensaje):** | Patrón de consulta | Tipo de respuesta | | ------------------------------------------------ | ---------------------------------------------------------------------------- | --- | | Contiene `"ranking"`, `"mayor cuota"`, `"mejor"` | Proveedores clasificados por cuota restante | | Contiene `"gratis"`, `"sugerir"` | Enumera combinaciones gratuitas o sugiere proveedores de nivel gratuito | | Predeterminado | Resumen completo de cuotas con advertencias para proveedores de cuotas bajas | --- | ## Task Lifecycle ``` submitted ──→ working ──→ completed ──→ failed ──────────→ cancelled ``` | Estado | Descripción | | ------------ | ----------------------------------------------------------------------------- | | `enviado` | Tarea creada, en cola para ejecución | | `trabajando` | El manejador de habilidades se está ejecutando | | `completado` | Ejecución exitosa, artefactos disponibles | | `fallido` | La ejecución falló o la tarea expiró (TTL: valor predeterminado de 5 minutos) | | `cancelado` | Cancelado por el cliente a través de `tareas/cancelar` | - Estados del terminal: "completado", "fallido", "cancelado" (sin más transiciones) - Las tareas caducadas en "enviadas" o "en funcionamiento" se marcan automáticamente como "fallidas" - Las tareas se recolectan como basura después de 2× TTL--- ## Client Examples ### Python — Orchestrator Agent ```python """ A2A Client — Python example. Discovers OmniRoute agent, sends a task, and processes the result. """ import requests import json BASE_URL = "http://localhost:20128" API_KEY = "your-api-key" HEADERS = { "Content-Type": "application/json", "Authorization": f"Bearer {API_KEY}", } # 1. Discover agent capabilities agent_card = requests.get(f"{BASE_URL}/.well-known/agent.json").json() print(f"Agent: {agent_card['name']} v{agent_card['version']}") print(f"Skills: {[s['id'] for s in agent_card['skills']]}") # 2. Send a smart-routing task response = requests.post(f"{BASE_URL}/a2a", headers=HEADERS, json={ "jsonrpc": "2.0", "id": "task-1", "method": "message/send", "params": { "skill": "smart-routing", "messages": [{"role": "user", "content": "Write a Python quicksort implementation"}], "metadata": { "model": "auto", "combo": "fast-coding", "budget": 0.10, } } }) result = response.json()["result"] print(f"\n📝 Response: {result['artifacts'][0]['content'][:200]}...") print(f"🔀 Routing: {result['metadata']['routing_explanation']}") print(f"💰 Cost: ${result['metadata']['cost_envelope']['actual']}") print(f"🛡️ Policy: {result['metadata']['policy_verdict']['reason']}") # 3. Query quota status quota_resp = requests.post(f"{BASE_URL}/a2a", headers=HEADERS, json={ "jsonrpc": "2.0", "id": "task-2", "method": "message/send", "params": { "skill": "quota-management", "messages": [{"role": "user", "content": "Which provider has the most quota remaining?"}], } }) quota_result = quota_resp.json()["result"] print(f"\n📊 Quota: {quota_result['artifacts'][0]['content']}") ``` ### TypeScript — Multi-Agent Orchestrator ```typescript /** * A2A Client — TypeScript example. * Shows agent discovery, task delegation, and streaming. */ const BASE_URL = "http://localhost:20128"; const API_KEY = "your-api-key"; interface JsonRpcResponse { jsonrpc: "2.0"; id: string | number; result?: T; error?: { code: number; message: string }; } async function a2aCall(method: string, params: Record): Promise { const resp = await fetch(`${BASE_URL}/a2a`, { method: "POST", headers: { "Content-Type": "application/json", Authorization: `Bearer ${API_KEY}`, }, body: JSON.stringify({ jsonrpc: "2.0", id: `${method}-${Date.now()}`, method, params, }), }); const json: JsonRpcResponse = await resp.json(); if (json.error) throw new Error(`[${json.error.code}] ${json.error.message}`); return json.result!; } // ── Agent Discovery ── const agentCard = await fetch(`${BASE_URL}/.well-known/agent.json`).then((r) => r.json()); console.log(`Connected to: ${agentCard.name} (${agentCard.skills.length} skills)`); // ── Smart Routing: Send a coding task ── const routingResult = await a2aCall("message/send", { skill: "smart-routing", messages: [{ role: "user", content: "Implement a Redis cache wrapper in TypeScript" }], metadata: { model: "claude-sonnet-4", role: "coding" }, }); console.log("Response:", routingResult.artifacts[0].content); console.log("Provider:", routingResult.metadata.routing_explanation); // ── Quota Management: Find free alternatives ── const quotaResult = await a2aCall("message/send", { skill: "quota-management", messages: [{ role: "user", content: "Suggest free combos for documentation" }], }); console.log("Free combos:", quotaResult.artifacts[0].content); // ── Streaming: Real-time response ── const streamResp = await fetch(`${BASE_URL}/a2a`, { method: "POST", headers: { "Content-Type": "application/json", Authorization: `Bearer ${API_KEY}`, }, body: JSON.stringify({ jsonrpc: "2.0", id: "stream-1", method: "message/stream", params: { skill: "smart-routing", messages: [{ role: "user", content: "Explain microservices architecture" }], }, }), }); const reader = streamResp.body!.getReader(); const decoder = new TextDecoder(); while (true) { const { done, value } = await reader.read(); if (done) break; const chunk = decoder.decode(value); for (const line of chunk.split("\n")) { if (line.startsWith("data: ")) { const event = JSON.parse(line.slice(6)); if (event.params.chunk) { process.stdout.write(event.params.chunk.content); } if (event.params.task.state === "completed") { console.log("\n✅ Stream completed"); } } } } ``` ### Python — LangChain A2A Integration ```python """ LangChain integration — Use OmniRoute A2A as a custom LLM. """ from langchain.llms.base import BaseLLM from langchain.schema import LLMResult, Generation import requests from typing import List, Optional class OmniRouteA2A(BaseLLM): base_url: str = "http://localhost:20128" api_key: str = "" model: str = "auto" combo: Optional[str] = None @property def _llm_type(self) -> str: return "omniroute-a2a" def _call(self, prompt: str, stop: Optional[List[str]] = None, **kwargs) -> str: response = requests.post( f"{self.base_url}/a2a", headers={ "Content-Type": "application/json", "Authorization": f"Bearer {self.api_key}", }, json={ "jsonrpc": "2.0", "id": "langchain-1", "method": "message/send", "params": { "skill": "smart-routing", "messages": [{"role": "user", "content": prompt}], "metadata": { "model": self.model, **({"combo": self.combo} if self.combo else {}), }, }, }, ) result = response.json()["result"] return result["artifacts"][0]["content"] def _generate(self, prompts: List[str], stop=None, **kwargs) -> LLMResult: return LLMResult( generations=[[Generation(text=self._call(p, stop))] for p in prompts] ) # Usage llm = OmniRouteA2A( base_url="http://localhost:20128", api_key="your-key", model="auto", combo="fast-coding", ) result = llm("Write a Python function to merge two sorted lists") print(result) ``` ### Go — A2A Client ```go package main import ( "bytes" "encoding/json" "fmt" "io" "net/http" ) const baseURL = "http://localhost:20128" const apiKey = "your-api-key" type JsonRpcRequest struct { Jsonrpc string `json:"jsonrpc"` ID string `json:"id"` Method string `json:"method"` Params interface{} `json:"params"` } type JsonRpcResponse struct { Jsonrpc string `json:"jsonrpc"` ID string `json:"id"` Result interface{} `json:"result"` Error *struct { Code int `json:"code"` Message string `json:"message"` } `json:"error"` } func a2aCall(method string, params interface{}) (*JsonRpcResponse, error) { body, _ := json.Marshal(JsonRpcRequest{ Jsonrpc: "2.0", ID: "go-1", Method: method, Params: params, }) req, _ := http.NewRequest("POST", baseURL+"/a2a", bytes.NewReader(body)) req.Header.Set("Content-Type", "application/json") req.Header.Set("Authorization", "Bearer "+apiKey) resp, err := http.DefaultClient.Do(req) if err != nil { return nil, err } defer resp.Body.Close() data, _ := io.ReadAll(resp.Body) var result JsonRpcResponse json.Unmarshal(data, &result) return &result, nil } func main() { // Discover agent resp, _ := http.Get(baseURL + "/.well-known/agent.json") defer resp.Body.Close() body, _ := io.ReadAll(resp.Body) fmt.Println("Agent Card:", string(body)) // Send smart-routing task result, _ := a2aCall("message/send", map[string]interface{}{ "skill": "smart-routing", "messages": []map[string]string{{"role": "user", "content": "Hello from Go!"}}, "metadata": map[string]interface{}{"model": "auto"}, }) out, _ := json.MarshalIndent(result.Result, "", " ") fmt.Println("Result:", string(out)) } ``` --- ## Use Cases ### 🤖 Use Case 1: Multi-Agent Coding Pipeline Un agente orquestador delega la generación de código a OmniRoute y luego pasa el resultado a un agente de revisión.```python def coding_pipeline(task: str): # Step 1: Generate code via OmniRoute A2A code_result = a2a_send("smart-routing", [ {"role": "user", "content": f"Write production-quality code: {task}"} ], metadata={"model": "auto", "role": "coding"}) code = code_result["artifacts"][0]["content"] # Step 2: Review the code via OmniRoute A2A (different model) review_result = a2a_send("smart-routing", [ {"role": "user", "content": f"Review this code for bugs and improvements:\n\n{code}"} ], metadata={"model": "auto", "role": "review"}) review = review_result["artifacts"][0]["content"] # Step 3: Check costs print(f"Code cost: ${code_result['metadata']['cost_envelope']['actual']}") print(f"Review cost: ${review_result['metadata']['cost_envelope']['actual']}") return {"code": code, "review": review} ```` ### 💡 Use Case 2: Quota-Aware Agent Swarm Varios agentes comparten cuota a través de OmniRoute y utilizan la habilidad de cuota para coordinarse.```python async def quota_aware_agent(agent_name: str, task: str): # Check quota before starting quota = a2a_send("quota-management", [ {"role": "user", "content": "Which provider has the most quota remaining?"} ]) print(f"[{agent_name}] {quota['artifacts'][0]['content']}") # Send request with budget constraint result = a2a_send("smart-routing", [ {"role": "user", "content": task} ], metadata={"budget": 0.05}) policy = result["metadata"]["policy_verdict"] if not policy["allowed"]: print(f"[{agent_name}] ⚠️ Budget exceeded: {policy['reason']}") # Fall back to free combo quota = a2a_send("quota-management", [ {"role": "user", "content": "Suggest free combos"} ]) print(f"[{agent_name}] Free alternatives: {quota['artifacts'][0]['content']}") return result ```` ### 📊 Use Case 3: Real-Time Streaming Dashboard Un agente de monitoreo transmite respuestas y muestra el progreso en tiempo real.```typescript async function streamingDashboard(prompt: string) { const response = await fetch(`${BASE_URL}/a2a`, { method: "POST", headers: { "Content-Type": "application/json", Authorization: `Bearer ${API_KEY}` }, body: JSON.stringify({ jsonrpc: "2.0", id: "dash-1", method: "message/stream", params: { skill: "smart-routing", messages: [{ role: "user", content: prompt }] }, }), }); let totalChunks = 0; const reader = response.body!.getReader(); const decoder = new TextDecoder(); while (true) { const { done, value } = await reader.read(); if (done) break; for (const line of decoder.decode(value).split("\n")) { if (line.startsWith("data: ")) { const event = JSON.parse(line.slice(6)); const state = event.params.task.state; if (state === "working" && event.params.chunk) { totalChunks++; process.stdout.write( `\r[Chunk ${totalChunks}] ${event.params.chunk.content.slice(0, 50)}...` ); } if (state === "completed") { const meta = event.params.metadata; console.log( `\n✅ Done | Cost: $${meta?.cost_envelope?.actual || 0} | Route: ${meta?.routing_explanation || "N/A"}` ); } if (state === "failed") { console.error(`\n❌ Failed: ${event.params.metadata?.error}`); } } } } } ```` ### 🔁 Use Case 4: Task Polling Pattern Para tareas de larga duración, sondee el estado de la tarea en lugar de esperar sincrónicamente.```python import time def poll_task(task_id: str, timeout: int = 60): """Poll task status until completion or timeout.""" start = time.time() while time.time() - start < timeout: result = requests.post(f"{BASE_URL}/a2a", headers=HEADERS, json={ "jsonrpc": "2.0", "id": "poll-1", "method": "tasks/get", "params": {"taskId": task_id}, }).json() task = result["result"]["task"] state = task["state"] print(f" Task {task_id[:8]}... state={state}") if state in ("completed", "failed", "cancelled"): return task time.sleep(2) # Timeout — cancel the task requests.post(f"{BASE_URL}/a2a", headers=HEADERS, json={ "jsonrpc": "2.0", "id": "cancel-1", "method": "tasks/cancel", "params": {"taskId": task_id}, }) raise TimeoutError(f"Task {task_id} timed out after {timeout}s") ```` --- ## Error Codes | Código | Constante | Significado | | ------ | ------------------------ | ---------------------------------------------- | --- | | -32700 | — | Error de análisis (JSON no válido) | | -32600 | `INVALID_REQUEST` | Solicitud JSON-RPC no válida o no autorizada | | -32601 | `METHOD_NOT_FOUND` | Método o habilidad desconocida | | -32602 | `INVALID_PARAMS` | Parámetros faltantes o no válidos | | -32603 | `ERROR_INTERNO` | La ejecución de la habilidad falló | | -32001 | `TASK_NOT_FOUND` | ID de tarea no encontrada | | -32002 | `TASK_ALREADY_COMPLETED` | No se puede modificar una tarea completada | | -32003 | `NO AUTORIZADO` | Clave API no válida o faltante | | -32004 | `PRESUPUESTO_EXCEEDED` | La solicitud supera el presupuesto configurado | | -32005 | `PROVIDER_UNAVAILABLE` | No hay proveedores disponibles | --- | ## Authentication Todas las solicitudes `/a2a` requieren un token de portador a través del encabezado `Authorization`:``` Authorization: Bearer YOUR_OMNIROUTE_API_KEY ``` Si no se configura ninguna clave API en el servidor (`OMNIROUTE_API_KEY` está vacía), se omite la autenticación.--- ## File Structure ``` src/lib/a2a/ ├── taskManager.ts # Task lifecycle (create/update/cancel/list), TTL, cleanup ├── taskExecution.ts # Generic task executor with state management ├── streaming.ts # SSE stream formatting, heartbeat, chunk/completion events ├── routingLogger.ts # Routing decision logger (stats, history, retention) └── skills/ ├── smartRouting.ts # Smart routing skill (routes via /v1/chat/completions) └── quotaManagement.ts # Quota management skill (natural-language quota queries) src/app/a2a/ └── route.ts # Next.js API route handler (JSON-RPC 2.0 dispatch) open-sse/mcp-server/ └── schemas/a2a.ts # Zod schemas (AgentCard, Task, JSON-RPC, SSE events) ``` --- ## Comparison: MCP vs A2A | Característica | Servidor MCP | Servidor A2A | | ----------------- | ---------------------------- | ------------------------------------------------- | |**Protocolo**| Protocolo de contexto modelo | Protocolo de agente a agente v0.3 | |**Transporte**| estándar / HTTP | HTTP (JSON-RPC 2.0) | |**Descubrimiento**| Listado de herramientas a través de MCP | `/.well-known/agent.json` | |**Granularidad**| 16 herramientas individuales | 2 habilidades de alto nivel | |**Mejor para**| Agentes IDE (Cursor, Código VS) | Sistemas multiagente (LangChain, CrewAI) | |**Transmisión**| No compatible | SSE a través de `mensaje/transmisión` | |**Seguimiento de tareas**| No | Ciclo de vida completo (enviado → completado) | |**Observabilidad**| Registro de auditoría por llamada a herramienta | Sobre de costos + seguimiento de resiliencia + veredicto de política |--- ## Licencia Parte de [OmniRoute](https://github.com/diegosouzapw/OmniRoute) — Licencia MIT. ```