Ir al contenido
OmniRoute source

ACP (Agent Client Protocol) (Español)

ACP (Agent Client Protocol) es un transporte de «CLI como backend» para OmniRoute. En lugar de interceptar llamadas a las API HTTP de proveedores de IA, ACP inicia agentes CLI como procesos secundarios y envía las instrucciones mediante su interfaz nativa.

Ventaja Descripción
No requiere claves de API Usa la autenticación existente de tu CLI
Protocolo nativo Usa el formato nativo de entrada/salida de cada CLI
Detección automática Detecta las CLI instaladas en tu sistema
15 agentes integrados Preconfigurados para herramientas CLI populares
Agentes personalizados Añade tus propias herramientas CLI mediante la configuración
Gestión de procesos Gestiona el ciclo de vida (iniciar, enviar, finalizar)

ACP admite 15 agentes CLI integrados de forma predeterminada:

ID del agente Nombre para mostrar Binario Protocolo
codex OpenAI Codex CLI codex stdio
claude Claude Code CLI claude stdio
goose Goose CLI goose stdio
openclaw OpenClaw openclaw stdio
aider Aider aider stdio
opencode OpenCode opencode stdio
cline Cline cline stdio
qwen Qwen Code qwen --acp stdio
forge ForgeCode forge stdio
amazon-q Amazon Q Developer q stdio
interpreter Open Interpreter interpreter stdio
cursor-cli Cursor CLI cursor stdio
warp Warp AI warp stdio
gemini Gemini CLI gemini stdio
zcode ZCode zcode stdio

Puedes añadir tus propios agentes CLI mediante la configuración. Los agentes personalizados admiten las mismas funciones que los agentes integrados.


Ventana de terminal
# Ejemplo: instala Claude Code CLI
npm install -g @anthropic-ai/claude-code
# Verifica la instalación
claude --version

ACP detecta automáticamente los agentes CLI instalados en tu sistema. ¡No se necesita ninguna configuración!

Una vez detectado, ACP puede usarse como transporte para cualquier proveedor compatible. OmniRoute usará ACP automáticamente cuando la CLI esté disponible.


┌─────────────────┐
│ OmniRoute │
│ (proxy HTTP) │
└────────┬────────┘
│
│ spawn()
▼
┌─────────────────┐
│ Proceso secund. │
│ (agente CLI) │
│ │
│ stdin ◄──────┤ Enviar instrucción
│ stdout ──────►│ Recibir respuesta
│ stderr ──────►│ Recibir errores
└─────────────────┘
  1. Inicio — ACP crea un proceso secundario para el agente CLI
  2. Envío — ACP escribe las instrucciones en el stdin del proceso
  3. Recepción — ACP lee las respuestas de stdout/stderr
  4. Detección de inactividad — ACP espera 2 segundos de inactividad antes de considerar que la respuesta está completa
  5. Finalización — ACP termina el proceso (SIGTERM y, después de 5 s, SIGKILL)

ACP usa stdio (entrada/salida estándar) para comunicarse con los agentes CLI. El protocolo es:

  1. Enviar instrucción — Escribir en stdin con un salto de línea
  2. Esperar la respuesta — Leer de stdout hasta que quede inactivo (2 s sin salida)
  3. Tiempo de espera — 120 segundos de forma predeterminada (configurable)

Detecta todos los agentes de CLI instalados en el sistema. Los resultados se almacenan en caché durante 60 segundos.

import { detectInstalledAgents } from "@/lib/acp";
const agents = detectInstalledAgents();
// Devuelve: CliAgentInfo[]
interface CliAgentInfo {
id: string; // p. ej., "codex", "claude"
name: string; // Nombre para mostrar
binary: string; // Nombre del binario que se iniciará
versionCommand: string; // Comando de detección de versión
version: string | null; // Versión detectada (null si no está instalado)
installed: boolean; // Indica si el agente está instalado
providerAlias: string; // ID del proveedor en OmniRoute
spawnArgs: string[]; // Argumentos que se pasarán al iniciarlo
protocol: "stdio" | "http"; // Protocolo de comunicación
isCustom?: boolean; // Indica si es un agente personalizado definido por el usuario
}

Obtiene únicamente los agentes que están instalados y disponibles para ACP.

import { getAvailableAgents } from "@/lib/acp";
const available = getAvailableAgents();
// Devuelve: CliAgentInfo[] (solo agentes instalados)

Obtiene un agente específico por su ID.

import { getAgentById } from "@/lib/acp";
const agent = getAgentById("claude");
// Devuelve: CliAgentInfo | undefined

Establece las definiciones de agentes personalizados desde la configuración.

import { setCustomAgents } from "@/lib/acp";
setCustomAgents([
{
id: "my-custom-cli",
name: "My Custom CLI",
binary: "mycli",
versionCommand: "mycli --version",
providerAlias: "my-provider",
spawnArgs: [],
protocol: "stdio",
},
]);

acpManager.spawn(agentId, binary, args, env)

Sección titulada «acpManager.spawn(agentId, binary, args, env)»

Inicia un nuevo proceso de agente de CLI.

import { acpManager } from "@/lib/acp";
const session = acpManager.spawn("claude", "claude", ["--print", "--output-format", "json"], {
/* variables de entorno personalizadas */
});
// Devuelve: AcpSession

ID de agente permitidos: ["claude", "codex", "gemini", "qwen"]

acpManager.sendPrompt(sessionId, prompt, timeoutMs)

Sección titulada «acpManager.sendPrompt(sessionId, prompt, timeoutMs)»

Envía una instrucción a un agente de CLI y recopila la respuesta.

import { acpManager } from "@/lib/acp";
const response = await acpManager.sendPrompt(
"acp-claude-1234567890-abc123",
"What is 2+2?",
120000 // Tiempo de espera de 2 minutos
);
// Devuelve: Promise<string>

Finaliza una sesión y libera sus recursos.

import { acpManager } from "@/lib/acp";
const killed = acpManager.kill("acp-claude-1234567890-abc123");
// Devuelve: boolean

Obtiene todas las sesiones activas.

import { acpManager } from "@/lib/acp";
const sessions = acpManager.getActiveSessions();
// Devuelve: AcpSession[]

Finaliza todas las sesiones.

import { acpManager } from "@/lib/acp";
acpManager.killAll();
interface AcpSession {
id: string; // ID único de la sesión
agentId: string; // ID del agente (p. ej., "claude")
process: ChildProcess; // Identificador del proceso secundario
alive: boolean; // Indica si el proceso está activo
stdoutBuffer: string; // Búfer acumulado de stdout
stderrBuffer: string; // Búfer acumulado de stderr
createdAt: Date; // Marca de tiempo de creación
}

AcpManager extiende EventEmitter y emite los siguientes eventos:

Se emite cuando el agente de CLI escribe en stdout.

acpManager.on("stdout", ({ sessionId, data }) => {
console.log(`[${sessionId}] stdout: ${data}`);
});

Se emite cuando el agente de CLI escribe en stderr.

acpManager.on("stderr", ({ sessionId, data }) => {
console.error(`[${sessionId}] stderr: ${data}`);
});

Se emite cuando finaliza el proceso del agente de CLI.

acpManager.on("exit", ({ sessionId, code, signal }) => {
console.log(`[${sessionId}] exited with code ${code}, signal ${signal}`);
});

Se emite cuando se produce un error en el proceso del agente de CLI.

acpManager.on("error", ({ sessionId, error }) => {
console.error(`[${sessionId}] error: ${error}`);
});

ACP hereda todas las variables de entorno del proceso principal y puede ampliarse con variables de entorno personalizadas:

acpManager.spawn("claude", "claude", [], {
ANTHROPIC_API_KEY: "sk-...",
DEBUG: "true",
});

Cada agente tiene argumentos de inicio predeterminados definidos en el registro. Puede sobrescribirlos:

acpManager.spawn("claude", "claude", ["--print", "--verbose"], {});

El tiempo de espera predeterminado de las solicitudes es de 120 segundos (2 minutos). Puede sobrescribirlo:

await acpManager.sendPrompt(sessionId, prompt, 300000); // 5 minutos

La detección de agentes se almacena en caché durante 60 segundos para evitar análisis costosos del sistema de archivos. Para forzar una actualización:

import { refreshAgentCache } from "@/lib/acp";
refreshAgentCache();

ACP valida los comandos de versión para prevenir ataques de inyección de comandos:

const DISALLOWED_VERSION_COMMAND_CHARS = /[;&|<>`$\r\n]/;

Los comandos de versión que contienen estos caracteres se rechazan:

  • ; — Separador de comandos
  • & — Proceso en segundo plano
  • | — Tubería
  • <, > — Redirección
  • ` — Sustitución de comandos
  • $ — Expansión de variables
  • \r, \n — Saltos de línea

ACP valida que el binario del comando de versión coincida con el nombre de binario esperado (a menos que sea un agente personalizado).

Cada sesión de ACP se ejecuta en su propio proceso secundario. El proceso finaliza cuando termina la sesión o se agota el tiempo de espera.


  • Primera llamada: ~50-200ms (ejecuta el comando version para cada agente)
  • Llamadas almacenadas en caché: <1ms (devuelve el resultado desde la caché)
  • TTL de la caché: 60 segundos
  • Inicio: ~50-100ms
  • Envío de la solicitud: ~10-50ms
  • Espera de la respuesta: Depende del agente de CLI (normalmente entre 1 y 30 segundos)
  • Finalización: ~5 segundos (SIGTERM) + inmediata (SIGKILL)
  • Memoria por sesión: ~10-50MB (depende del agente de CLI)
  • CPU: Mínimo (limitado por E/S)
  • Disco: Ninguno

Problema: acpManager.spawn() genera Unknown agent: &lt;id&gt;

Solución: Solo se permiten estos agentes en spawn():

  • claude
  • codex
  • gemini
  • qwen

Los demás agentes deben iniciarse manualmente o mediante definiciones de agentes personalizados.

Problema: acpManager.sendPrompt() genera Session ${sessionId} is not alive

Solución: Es posible que la sesión haya finalizado o se haya cerrado. Compruebe el estado de la sesión:

const session = acpManager.getSession(sessionId);
if (!session?.alive) {
// Volver a iniciar la sesión
acpManager.spawn("claude", "claude", [], {});
}

Problema: acpManager.sendPrompt() genera ACP timeout after 120000ms

Solución: Aumente el tiempo de espera:

await acpManager.sendPrompt(sessionId, prompt, 300000); // 5 minutos

Problema: detectInstalledAgents() no encuentra su CLI

Soluciones:

  1. Compruebe PATH: Asegúrese de que la CLI esté en la variable PATH de su sistema
  2. Compruebe el comando de versión: Ejecute claude --version manualmente
  3. Compruebe los permisos: Asegúrese de que la CLI sea ejecutable
  4. Agente personalizado: Añada una definición de agente personalizado para las CLI no estándar

Problema: ACP no puede ejecutar la CLI

Soluciones:

  1. Compruebe los permisos del archivo: chmod +x /usr/local/bin/claude
  2. Compruebe la propiedad: Asegúrese de que OmniRoute tenga permisos de lectura y ejecución
  3. Compruebe SELinux/AppArmor: Pueden bloquear el inicio de procesos

import { acpManager, detectInstalledAgents } from "@/lib/acp";
// Detectar los agentes instalados
const agents = detectInstalledAgents();
const claude = agents.find((a) => a.id === "claude");
if (claude?.installed) {
// Iniciar una nueva sesión
const session = acpManager.spawn("claude", claude.binary, ["--print", "--output-format", "json"]);
// Enviar una instrucción
const response = await acpManager.sendPrompt(
session.id,
"Explain quantum computing in 100 words"
);
console.log("Claude's response:", response);
// Limpiar
acpManager.kill(session.id);
}

Ejemplo 2: Detección automática con alternativa

Sección titulada «Ejemplo 2: Detección automática con alternativa»
import { acpManager, getAvailableAgents } from "@/lib/acp";
const available = getAvailableAgents();
// Probar primero Claude y, como alternativa, Codex
let agentId = "claude";
if (!available.find((a) => a.id === "claude")) {
if (available.find((a) => a.id === "codex")) {
agentId = "codex";
} else {
throw new Error("No ACP-compatible CLI agent found");
}
}
const agent = available.find((a) => a.id === agentId)!;
const session = acpManager.spawn(agentId, agent.binary, agent.spawnArgs);
const response = await acpManager.sendPrompt(session.id, "Hello!");
acpManager.kill(session.id);
import { setCustomAgents, detectInstalledAgents } from "@/lib/acp";
// Registrar un agente CLI personalizado
setCustomAgents([
{
id: "my-llm-cli",
name: "My LLM CLI",
binary: "myllm",
versionCommand: "myllm --version",
providerAlias: "my-llm-provider",
spawnArgs: ["--format", "json"],
protocol: "stdio",
},
]);
// Ahora detectInstalledAgents() incluirá "my-llm-cli"
const agents = detectInstalledAgents();


  • Proyecto AionUi — Inspiración para la detección automática de ACP
  • Código fuente de ACP — Detalles de implementación
    • manager.ts — Gestión del ciclo de vida de los procesos
    • registry.ts — Detección y registro de agentes
    • index.ts — Exportaciones de la API pública

Código fuente de OmniRoute (a58000c7685f)

HagiCode

HagiCode es un espacio de trabajo de programación con agentes, flujos estructurados, ejecución multiagente y vistas de Hero Dungeon.

Convierte ideas en software útil con un flujo de trabajo con agentes más inteligente, rápido y ameno.

Interfaz principal de HagiCode con tema claro
  • SmartLos flujos estructurados convierten la intención en un itinerario ejecutable desde la idea hasta la entrega.
  • EfficientLos flujos multiagente permiten avanzar en paralelo con la investigación, implementación y revisión.
  • FunHero Dungeon hace que las largas sesiones de programación sean visuales y colaborativas.
Visitar HagiCode