/** * Conductor - orchestrates ACP proxy chains * * The conductor sits between a client and an agent, managing message routing * through a chain of proxy components. It: * * 1. Manages the message event loop * 2. Routes messages left-to-right (client → proxies → agent) * 3. Routes messages right-to-left (agent → proxies → client) * 4. Handles `_proxy/successor/*` message wrapping/unwrapping * 5. Manages proxy capability handshake during initialization * 6. Correlates requests with responses via a pending request map * 7. Bridges MCP-over-ACP for agents without native ACP transport support */ import type { ComponentConnector, ComponentInstantiator } from "./types.js"; import { type LoggerOptions, type TraceOptions } from "./logger.js"; /** * Configuration for the Conductor */ export interface ConductorConfig { /** Optional name for this conductor (for debugging) */ name?: string; /** The instantiator that creates components when initialization arrives */ instantiator: ComponentInstantiator; /** MCP bridge mode (disabled by default for Phase 2) */ mcpBridgeMode?: "http" | "disabled"; /** Logging configuration */ logging?: LoggerOptions; /** JSONL trace output configuration */ trace?: TraceOptions; } /** * The Conductor orchestrates ACP proxy chains. * * It sits between a client and an agent, routing all messages through * a central event loop to preserve message ordering. * * ## Message Flow with Proxies * * ### Left-to-Right (client → agent): * 1. Client sends request to conductor * 2. Conductor forwards to proxy[0] (normal ACP) * 3. Proxy[0] sends `_proxy/successor/request` to conductor * 4. Conductor unwraps and forwards to proxy[1] (normal ACP) * 5. ... until agent receives normal ACP * * ### Right-to-Left (agent → client): * 1. Agent sends notification/request to conductor * 2. Conductor wraps in `_proxy/successor/request` and sends to proxy[n-1] * 3. Proxy[n-1] processes and forwards to conductor * 4. ... until client receives normal ACP */ export declare class Conductor { private readonly config; private readonly messageQueue; private readonly logger; private state; private clientConnection; private proxies; private agentConnection; private pendingRequests; private nextRequestId; private mcpBridge; private agentSupportsMcpAcpTransport; private pendingSessionRequests; private mcpConnectResponders; constructor(config: ConductorConfig); /** * Connect to a client and run the conductor's message loop. * * This method blocks until the conductor shuts down. */ connect(clientConnector: ComponentConnector): Promise; /** * Shut down the conductor */ shutdown(): Promise; /** * Pump messages from the client into the message queue */ private pumpClientMessages; /** * Pump messages from a proxy into the message queue */ private pumpProxyMessages; /** * Pump messages from the agent into the message queue */ private pumpAgentMessages; /** * Handle a `_proxy/successor/request` from a proxy * * The proxy is forwarding a request to its successor (next proxy or agent). * We unwrap the inner request and forward it. */ private handleProxySuccessorRequest; /** * Handle a `_proxy/successor/notification` from a proxy * * The proxy is forwarding a notification to its successor. */ private handleProxySuccessorNotification; /** * Convert a JSON-RPC message to a Dispatch */ private messageToDispatch; /** * Create a responder that routes the response back to the appropriate destination */ private createResponderForSource; /** * Run the main event loop, processing messages from the queue */ private runEventLoop; /** * Handle a message from the queue */ private handleMessage; /** * Get the source identifier for a message (for tracing) */ private getMessageSource; /** * Get the target identifier for a message (for tracing) */ private getMessageTarget; /** * Handle a left-to-right message (client → agent direction) */ private handleLeftToRight; /** * Handle a right-to-left message (agent/proxy → client direction) */ private handleRightToLeft; /** * Forward a dispatch to a proxy, wrapped in `_proxy/successor/*` * * This is used when routing messages FROM a successor (agent or later proxy) * TO an earlier proxy in the chain. */ private forwardWrappedToProxy; /** * Handle the initialize request - instantiate components and perform initialization sequence * * The initialization follows this sequence: * 1. Instantiate all components (connect to proxies and agent) * 2. Send `initialize` with `_meta.proxy: true` to proxy[0] * 3. Proxy[0] will use `_proxy/successor/request` to forward to proxy[1], etc. * 4. Agent receives `initialize` without proxy capability * 5. Responses flow back up the chain * 6. Conductor verifies each proxy accepted the proxy capability */ private handleInitialize; /** * Add proxy capability to initialize params */ private addProxyCapability; /** * Remove proxy capability from initialize params (for forwarding to agent) */ private removeProxyCapability; /** * Create a responder that verifies the proxy accepted the capability */ private createProxyInitializeResponder; /** * Create a responder that captures the agent's mcp_acp_transport capability */ private createAgentInitializeResponder; /** * Handle a response by routing it back to the original requester */ private handleResponse; /** * Forward a dispatch to a connection, handling request ID rewriting */ private forwardToConnection; /** * Get the target connection for a given index * Index 0..n-1 are proxies, index n is the agent */ private getTargetConnection; /** * Handle a session/new request - transform acp: URLs to http: URLs * * If the request contains MCP servers with acp: URLs and the agent doesn't * support mcp_acp_transport, we: * 1. Spawn HTTP listeners for each acp: URL * 2. Transform the URLs to http://localhost:$PORT * 3. Forward the modified request to the agent * 4. When the response comes back with session_id, deliver it to the listeners */ private handleSessionNew; /** * Handle an MCP connection received from the HTTP bridge * * When an agent connects to our HTTP listener, we need to: * 1. Send _mcp/connect to the proxy that owns this acp: URL * 2. Wait for the connection_id in the response */ private handleMcpConnectionReceived; /** * Handle an MCP message from a client (through the HTTP bridge) * * This routes MCP tool calls and other messages through the ACP chain. */ private handleMcpClientToServer; /** * Handle an MCP connection being disconnected */ private handleMcpConnectionDisconnected; /** * Generate a unique request ID for outgoing requests */ private generateRequestId; } export { fromCommands, fromConnectors, dynamic, staticInstantiator } from "./instantiators.js"; export type { CommandSpec, CommandOptions, StaticInstantiatorConfig, DynamicInstantiatorFactory } from "./instantiators.js"; //# sourceMappingURL=conductor.d.ts.map