Aller au contenu
OmniRoute source

ACP (Agent Client Protocol) (Français)

ACP (Agent Client Protocol) est un transport « CLI comme backend » pour OmniRoute. Au lieu d’intercepter les appels aux API HTTP des fournisseurs d’IA, ACP lance des agents CLI en tant que processus enfants et leur transmet les prompts via leur interface native.

Avantage Description
Aucune clé API requise Utilise l’authentification existante de votre CLI
Protocole natif Utilise le format d’entrée/sortie natif de chaque CLI
Détection automatique Détecte les CLI installées sur votre système
15 agents intégrés Préconfiguré pour les outils CLI populaires
Agents personnalisés Ajoutez vos propres outils CLI via les paramètres
Gestion des processus Gère le cycle de vie (lancement, envoi, arrêt)

ACP prend en charge 15 agents CLI intégrés prêts à l’emploi :

ID de l’agent Nom d’affichage Binaire Protocole
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

Vous pouvez ajouter vos propres agents CLI via les paramètres. Les agents personnalisés prennent en charge les mêmes fonctionnalités que les agents intégrés.


Fenêtre de terminal
# Exemple : installer Claude Code CLI
npm install -g @anthropic-ai/claude-code
# Vérifier l’installation
claude --version

ACP détecte automatiquement les agents CLI installés sur votre système. Aucune configuration n’est nécessaire !

Une fois détecté, ACP peut être utilisé comme transport pour tout fournisseur pris en charge. OmniRoute utilisera automatiquement ACP lorsque la CLI sera disponible.


┌─────────────────┐
│ OmniRoute │
│ (Proxy HTTP) │
└────────┬────────┘
│
│ spawn()
▼
┌─────────────────┐
│ Processus enfant│
│ (Agent CLI) │
│ │
│ stdin ◄──────┤ Envoyer le prompt
│ stdout ──────►│ Recevoir la réponse
│ stderr ──────►│ Recevoir les erreurs
└─────────────────┘
  1. Lancement — ACP crée un processus enfant pour l’agent CLI
  2. Envoi — ACP écrit les prompts dans le flux stdin du processus
  3. Réception — ACP lit les réponses depuis stdout/stderr
  4. Détection de l’inactivité — ACP attend 2 secondes d’inactivité avant de considérer la réponse comme terminée
  5. Arrêt — ACP met fin au processus (SIGTERM, puis SIGKILL après 5 s)

ACP utilise stdio (entrée/sortie standard) pour communiquer avec les agents CLI. Le protocole est le suivant :

  1. Envoyer le prompt — Écrire dans stdin avec un saut de ligne
  2. Attendre la réponse — Lire depuis stdout jusqu’à détection d’une période d’inactivité (aucune sortie pendant 2 s)
  3. Délai d’expiration — 120 secondes par défaut (configurable)

Détecte tous les agents CLI installés sur le système. Les résultats sont mis en cache pendant 60 secondes.

import { detectInstalledAgents } from "@/lib/acp";
const agents = detectInstalledAgents();
// Renvoie : CliAgentInfo[]
interface CliAgentInfo {
id: string; // p. ex. « codex », « claude »
name: string; // Nom d’affichage
binary: string; // Nom du binaire à lancer
versionCommand: string; // Commande de détection de la version
version: string | null; // Version détectée (null si non installé)
installed: boolean; // Indique si l’agent est installé
providerAlias: string; // ID du fournisseur dans OmniRoute
spawnArgs: string[]; // Arguments à transmettre lors du lancement
protocol: "stdio" | "http"; // Protocole de communication
isCustom?: boolean; // Indique s’il s’agit d’un agent personnalisé défini par l’utilisateur
}

Obtient uniquement les agents installés et disponibles pour ACP.

import { getAvailableAgents } from "@/lib/acp";
const available = getAvailableAgents();
// Renvoie : CliAgentInfo[] (uniquement les agents installés)

Obtient un agent spécifique à partir de son ID.

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

Définit les agents personnalisés à partir des paramètres.

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",
},
]);

Lance un nouveau processus d’agent CLI.

import { acpManager } from "@/lib/acp";
const session = acpManager.spawn("claude", "claude", ["--print", "--output-format", "json"], {
/* variables d’environnement personnalisées */
});
// Renvoie : AcpSession

ID d’agents autorisés : ["claude", "codex", "gemini", "qwen"]

acpManager.sendPrompt(sessionId, prompt, timeoutMs)

Section intitulée « acpManager.sendPrompt(sessionId, prompt, timeoutMs) »

Envoie une invite à un agent CLI et collecte la réponse.

import { acpManager } from "@/lib/acp";
const response = await acpManager.sendPrompt(
"acp-claude-1234567890-abc123",
"What is 2+2?",
120000 // délai d’expiration de 2 minutes
);
// Renvoie : Promise<string>

Arrête une session et effectue le nettoyage.

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

Obtient toutes les sessions actives.

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

Arrête toutes les sessions.

import { acpManager } from "@/lib/acp";
acpManager.killAll();
interface AcpSession {
id: string; // ID de session unique
agentId: string; // ID de l’agent (p. ex. « claude »)
process: ChildProcess; // Référence au processus enfant
alive: boolean; // Indique si le processus est actif
stdoutBuffer: string; // Tampon stdout accumulé
stderrBuffer: string; // Tampon stderr accumulé
createdAt: Date; // Horodatage de création
}

AcpManager étend EventEmitter et émet les événements suivants :

Émis lorsque l’agent CLI écrit dans stdout.

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

Émis lorsque l’agent CLI écrit dans stderr.

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

Émis lorsque le processus de l’agent CLI se termine.

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

Émis lorsqu’une erreur survient dans le processus de l’agent CLI.

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

ACP hérite de toutes les variables d’environnement du processus parent et peut être étendu avec des variables d’environnement personnalisées :

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

Chaque agent possède des arguments de lancement par défaut définis dans le registre. Vous pouvez les remplacer :

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

Le délai d’expiration par défaut d’une requête est de 120 secondes (2 minutes). Vous pouvez le remplacer :

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

La détection des agents est mise en cache pendant 60 secondes afin d’éviter des analyses coûteuses du système de fichiers. Pour forcer l’actualisation :

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

ACP valide les commandes de version afin d’empêcher les attaques par injection de commandes :

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

Les commandes de version contenant ces caractères sont rejetées :

  • ; — Séparateur de commandes
  • & — Processus en arrière-plan
  • | — Tube
  • <, > — Redirection
  • ` — Substitution de commande
  • $ — Expansion de variable
  • \r, \n — Sauts de ligne

ACP vérifie que le binaire de la commande de version correspond au nom de binaire attendu (sauf s’il s’agit d’un agent personnalisé).

Chaque session ACP s’exécute dans son propre processus enfant. Le processus est arrêté lorsque la session se termine ou atteint son délai d’expiration.


  • Premier appel : ~50-200ms (exécute la commande version pour chaque agent)
  • Appels mis en cache : <1ms (retour depuis le cache)
  • Durée de vie du cache : 60 secondes
  • Lancement : ~50-100ms
  • Envoi de la requête : ~10-50ms
  • Attente de la réponse : dépend de l’agent CLI (généralement 1 à 30 secondes)
  • Arrêt : ~5 secondes (SIGTERM) + immédiat (SIGKILL)
  • Mémoire par session : ~10-50MB (dépend de l’agent CLI)
  • CPU : minimale (limitée par les E/S)
  • Disque : aucune

Problème : acpManager.spawn() lève l’erreur Unknown agent: &lt;id&gt;

Solution : seuls les agents suivants sont autorisés dans spawn() :

  • claude
  • codex
  • gemini
  • qwen

Les autres agents doivent être lancés manuellement ou à l’aide de définitions d’agents personnalisés.

Problème : acpManager.sendPrompt() lève l’erreur Session ${sessionId} is not alive

Solution : la session peut s’être terminée ou avoir été arrêtée. Vérifiez son état :

const session = acpManager.getSession(sessionId);
if (!session?.alive) {
// Relancer la session
acpManager.spawn("claude", "claude", [], {});
}

Problème : acpManager.sendPrompt() lève l’erreur ACP timeout after 120000ms

Solution : augmentez le délai d’expiration :

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

Problème : detectInstalledAgents() ne trouve pas votre CLI

Solutions :

  1. Vérifiez PATH : assurez-vous que la CLI figure dans le PATH de votre système
  2. Vérifiez la commande de version : exécutez manuellement claude --version
  3. Vérifiez les autorisations : assurez-vous que la CLI est exécutable
  4. Agent personnalisé : ajoutez une définition d’agent personnalisé pour les CLI non standard

Problème : ACP ne peut pas exécuter la CLI

Solutions :

  1. Vérifiez les autorisations du fichier : chmod +x /usr/local/bin/claude
  2. Vérifiez le propriétaire : assurez-vous qu’OmniRoute dispose des autorisations de lecture et d’exécution
  3. Vérifiez SELinux/AppArmor : ces systèmes peuvent bloquer le lancement de processus

import { acpManager, detectInstalledAgents } from "@/lib/acp";
// Détecter les agents installés
const agents = detectInstalledAgents();
const claude = agents.find((a) => a.id === "claude");
if (claude?.installed) {
// Lancer une nouvelle session
const session = acpManager.spawn("claude", claude.binary, ["--print", "--output-format", "json"]);
// Envoyer une requête
const response = await acpManager.sendPrompt(
session.id,
"Explain quantum computing in 100 words"
);
console.log("Claude's response:", response);
// Nettoyer les ressources
acpManager.kill(session.id);
}

Exemple 2 : Découverte automatique avec solution de repli

Section intitulée « Exemple 2 : Découverte automatique avec solution de repli »
import { acpManager, getAvailableAgents } from "@/lib/acp";
const available = getAvailableAgents();
// Essayer d'abord Claude, puis utiliser Codex comme solution de repli
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";
// Enregistrer un agent CLI personnalisé
setCustomAgents([
{
id: "my-llm-cli",
name: "My LLM CLI",
binary: "myllm",
versionCommand: "myllm --version",
providerAlias: "my-llm-provider",
spawnArgs: ["--format", "json"],
protocol: "stdio",
},
]);
// Désormais, detectInstalledAgents() inclura "my-llm-cli"
const agents = detectInstalledAgents();


  • Projet AionUi — Source d’inspiration pour la détection automatique ACP
  • Code source ACP — Détails de l’implémentation
    • manager.ts — Gestion du cycle de vie des processus
    • registry.ts — Découverte et enregistrement des agents
    • index.ts — Exportations de l’API publique

Code source d’OmniRoute (a58000c7685f)

HagiCode

HagiCode est un espace de développement agentique qui associe workflows structurés, exécution multi-agent et vues Hero Dungeon.

Transformez vos idées en logiciels utiles grâce à un workflow agentique plus intelligent, rapide et agréable.

Interface principale de HagiCode en thème clair
  • SmartDes workflows structurés transforment une intention en parcours exécutable, de l’idée à la livraison.
  • EfficientLes workflows multi-agents font avancer recherche, réalisation et revue en parallèle.
  • FunHero Dungeon rend les longues sessions de code plus visuelles et collaboratives.
Visiter HagiCode