/** * @license * Copyright 2025 Qwen Team * SPDX-License-Identifier: Apache-2.0 */ /** * Control Service - Public Programmatic API * * Provides type-safe access to control plane functionality for internal * CLI code. This is the ONLY programmatic interface that should be used by: * - nonInteractiveCli * - Session managers * - Tool execution handlers * - Internal CLI logic * * DO NOT use ControlDispatcher or controllers directly from application code. * * Architecture: * - ControlContext stores shared session state (Layer 1) * - ControlDispatcher handles protocol-level routing (Layer 2) * - ControlService provides programmatic API for internal CLI usage (Layer 3) * * ControlService and ControlDispatcher share controller instances to ensure * a single source of truth. All higher level code MUST access the control * plane exclusively through ControlService. */ import type { IControlContext } from './ControlContext.js'; import type { ControlDispatcher } from './ControlDispatcher.js'; import type { PermissionServiceAPI, SystemServiceAPI, // McpServiceAPI, // HookServiceAPI, } from './types/serviceAPIs.js'; /** * Control Service * * Facade layer providing domain-grouped APIs for control plane operations. * Shares controller instances with ControlDispatcher to ensure single source * of truth and state consistency. */ export class ControlService { private dispatcher: ControlDispatcher; /** * Construct ControlService * * @param context - Control context (unused directly, passed to dispatcher) * @param dispatcher - Control dispatcher that owns the controller instances */ constructor(context: IControlContext, dispatcher: ControlDispatcher) { this.dispatcher = dispatcher; } /** * Permission Domain API * * Handles tool execution permissions, approval checks, and callbacks. * Delegates to the shared PermissionController instance. */ get permission(): PermissionServiceAPI { const controller = this.dispatcher.permissionController; return { /** * Check if a tool should be allowed based on current permission settings * * Evaluates permission mode and tool registry to determine if execution * should proceed. Can optionally modify tool arguments based on confirmation details. * * @param toolRequest - Tool call request information * @param confirmationDetails - Optional confirmation details for UI * @returns Permission decision with optional updated arguments */ shouldAllowTool: controller.shouldAllowTool.bind(controller), /** * Build UI suggestions for tool confirmation dialogs * * Creates actionable permission suggestions based on tool confirmation details. * * @param confirmationDetails - Tool confirmation details * @returns Array of permission suggestions or null */ buildPermissionSuggestions: controller.buildPermissionSuggestions.bind(controller), /** * Get callback for monitoring tool call status updates * * Returns callback function for integration with CoreToolScheduler. * * @returns Callback function for tool call updates */ getToolCallUpdateCallback: controller.getToolCallUpdateCallback.bind(controller), }; } /** * System Domain API * * Handles system-level operations and session management. * Delegates to the shared SystemController instance. */ get system(): SystemServiceAPI { const controller = this.dispatcher.systemController; return { /** * Get control capabilities * * Returns the control capabilities object indicating what control * features are available. Used exclusively for the initialize * control response. System messages do not include capabilities. * * @returns Control capabilities object */ getControlCapabilities: () => controller.buildControlCapabilities(), }; } /** * MCP Domain API * * Handles Model Context Protocol server interactions. * Delegates to the shared MCPController instance. */ // get mcp(): McpServiceAPI { // return { // /** // * Get or create MCP client for a server (lazy initialization) // * // * Returns existing client or creates new connection. // * // * @param serverName - Name of the MCP server // * @returns Promise with client and config // */ // getMcpClient: async (serverName: string) => { // // MCPController has a private method getOrCreateMcpClient // // We need to expose it via the API // // For now, throw error as placeholder // // The actual implementation will be added when we update MCPController // throw new Error( // `getMcpClient not yet implemented in ControlService. Server: ${serverName}`, // ); // }, // // /** // * List all available MCP servers // * // * Returns names of configured/connected MCP servers. // * // * @returns Array of server names // */ // listServers: () => { // // Get servers from context // const sdkServers = Array.from( // this.dispatcher.mcpController['context'].sdkMcpServers, // ); // const cliServers = Array.from( // this.dispatcher.mcpController['context'].mcpClients.keys(), // ); // return [...new Set([...sdkServers, ...cliServers])]; // }, // }; // } /** * Hook Domain API * * Handles hook callback processing (placeholder for future expansion). * Delegates to the shared HookController instance. */ // get hook(): HookServiceAPI { // // HookController has no public methods yet - controller access reserved for future use // return {}; // } /** * Cleanup all controllers * * Should be called on session shutdown. Delegates to dispatcher's shutdown * method to ensure all controllers are properly cleaned up. */ cleanup(): void { // Delegate to dispatcher which manages controller cleanup this.dispatcher.shutdown(); } }