Skip to Content
Guide développeurMode Daemon (Exploration approfondie pour les développeurs)Architecture du démon

Architecture du démon

Vue d’ensemble

Un processus qwen serve héberge un serveur HTTP Express et un workspace principal par défaut. Avec multi_workspace_sessions activé, il peut également héberger des runtimes de workspace supplémentaires pour la boucle fermée de session live ; chaque workspace enregistré possède sa propre paire @qwen-code/acp-bridge / enfant qwen --acp. Plusieurs clients (CLI TUI, companion IDE, bots de canal de messagerie, BFF web, scripts personnalisés) se connectent via HTTP + SSE et partagent soit une seule session ACP (sessionScope: 'single', par défaut), soit répartissent les sessions par fil de conversation (sessionScope: 'thread').

À l’intérieur du processus enfant ACP, les serveurs MCP sont partagés à l’échelle du workspace via McpTransportPool (F2) : un tuple (nom du serveur + empreinte de configuration) unique correspond à un seul transport MCP, quel que soit le nombre de sessions qui le découvrent. Le MultiClientPermissionMediator (F3) du bridge coordonne les votes de permissions entre tous les clients connectés selon l’une des quatre politiques.

Ce document donne le tableau au niveau système sur lequel repose le reste de cette documentation. Chaque flux critique est représenté par un diagramme de séquence Mermaid ; les détails d’implémentation par composant se trouvent dans les 18 autres documents.

Topologie des processus

Le processus démon et le processus enfant ACP sont connectés par un AcpChannel (par défaut : une paire de pipes stdio de sous-processus réel ; inMemoryChannel pour les tests). Tout ce que fait le démon est façonné par cette séparation : le trafic HTTP et SSE se termine dans le démon, les décisions de l’agent et les invocations d’outils se produisent dans l’enfant, et le bridge relie les deux.

Carte des packages

Trois frontières de confiance comptent : la périphérie HTTP (chaîne de middleware serve/auth.ts), la frontière bridge-enfant ACP (NDJSON sur stdio, sans authentification ; l’enfant fait implicitement confiance au pont), et la frontière agent-serveur MCP (l’agent peut invoquer des outils qui touchent l’hôte).

Workflow 1 : Cycle de vie d’une requête HTTP

Les routes non streamées (prompt, annulation, changement de modèle, métadonnées, CRUD du workspace) se terminent par une réponse JSON unique. La sortie en streaming est délivrée hors bande sur le canal SSE, pas comme un corps HTTP fragmenté sur cette connexion. Voir le workflow 2.

Workflow 2 : Distribution et relecture des événements SSE

Le tampon circulaire est limité (eventRingSize, par défaut 8000). Un client qui se reconnecte dont le Last-Event-ID est plus ancien que la tête du tampon reçoit state_resync_required et doit reconstruire à partir de la fenêtre de snapshot de relecture limitée de loadSession ou utiliser resumeSession lorsqu’il dispose déjà d’un historique local. Les clients lents déclenchent slow_client_warning à 75% de remplissage de la file et client_evicted à la limite.

Workflow 3 : Médiation des permissions multi-client

Échappatoire inter-politiques : tout client peut voter CANCEL_VOTE_SENTINEL pour court-circuiter la requête en cancelled / agent_cancelled. Le pont empêche les appelants extérieurs de faire passer la sentinelle via le champ normal optionId (InvalidPermissionOptionError).

Workflow 4 : Acquisition, libération et redémarrage du pool de transports MCP

releaseSession(sessionId) utilise l’index inverse sessionToEntries pour libérer toutes les entrées que la session détient en O(refs). Lors de l’arrêt du démon, drainAll() positionne le drapeau draining (refuse les nouvelles acquisitions) et attend que chaque entrée se ferme dans un délai configurable.

Workflow 5 : Cycle de vie — démarrage et arrêt gracieux

L’arrêt en deux phases est important car les requêtes HTTP en cours, les abonnés SSE en cours et les appels d’outils en cours de l’enfant ACP nécessitent des fenêtres de terminaison limitées. Si quelque chose bloque au-delà de ces délais, le chemin de fermeture forcée prend le relais afin qu’un enfant bloqué ne puisse pas maintenir le processus démon en vie.

Fichiers critiques

SujetFichier
Bootstrappackages/cli/src/serve/run-qwen-serve.ts
Application Expresspackages/cli/src/serve/server.ts
Registre de capacitéspackages/cli/src/serve/capabilities.ts
Middleware d’authpackages/cli/src/serve/auth.ts
Bridgepackages/acp-bridge/src/bridge.ts
BridgeClientpackages/acp-bridge/src/bridgeClient.ts
Médiateur de permissionspackages/acp-bridge/src/permissionMediator.ts
EventBuspackages/acp-bridge/src/eventBus.ts
Pool de transports MCPpackages/core/src/tools/mcp-transport-pool.ts
Budget MCP du workspacepackages/core/src/tools/mcp-workspace-budget.ts
FS du workspacepackages/cli/src/serve/fs/
SDK DaemonClientpackages/sdk-typescript/src/daemon/DaemonClient.ts
SDK SessionClientpackages/sdk-typescript/src/daemon/DaemonSessionClient.ts
Schéma d’événementspackages/sdk-typescript/src/daemon/events.ts

Références

Last updated on