Skip to main content
Glama
chatDeploymentHandler.ts12.7 kB
/** * @file Chat-based Deployment Handler * @description Integrates command generation and execution into the chat system * allowing users to deploy infrastructure through conversational requests. * * Usage Flow: * 1. User: "Deploy DHCP on 172.251.96.200" * 2. System: Detects deployment request → Generates commands → Sends for confirmation * 3. User: Approves/rejects commands * 4. System: Executes approved commands → Reports results */ import { z } from 'zod'; import { logger } from '../../logging/logger.js'; import { generateCommands, validateCommands, formatCommandsForDisplay, CommandGenerationContext, type CommandGenerationResponse, } from './commandGeneration.js'; import { CommandExecutionManager, formatExecutionResults, type ExecutionSession, } from './commandExecution.js'; /** * Deployment request detected from user message */ export const DeploymentRequestSchema = z.object({ isDeploymentRequest: z.boolean(), taskType: z.enum(['dhcp', 'dns', 'firewall', 'routing', 'vlan', 'other']).optional(), targetDevice: z.string().optional(), connectionId: z.string().optional(), confidence: z.number().min(0).max(1), reasoning: z.string().optional(), }); export type DeploymentRequest = z.infer<typeof DeploymentRequestSchema>; /** * Chat deployment handler */ export class ChatDeploymentHandler { private executionManager: CommandExecutionManager; private pendingGenerations: Map<string, CommandGenerationResponse> = new Map(); constructor() { this.executionManager = new CommandExecutionManager(); } /** * Detect if user message is a deployment request */ async detectDeploymentRequest( message: string, llmClient?: { generateCompletion(messages: any[]): Promise<string> } ): Promise<DeploymentRequest> { try { if (!llmClient) { // Rule-based detection for common deployment patterns return this.detectDeploymentPatterns(message); } const response = await llmClient.generateCompletion([ { role: 'system', content: `Analyze if the user message is requesting infrastructure deployment. Return JSON with: { "isDeploymentRequest": boolean, "taskType": "dhcp|dns|firewall|routing|vlan|other", "targetDevice": "IP or hostname if specified", "confidence": 0-1, "reasoning": "Why you think this is/isn't a deployment request" } Common patterns: - "Deploy DHCP on 172.251.96.200" - "Setup DNS records for domain.com" - "Configure firewall rules" - "Add VLAN 100" - "Setup routing for subnet"`, }, { role: 'user', content: message, }, ]); const parsed = JSON.parse(response); return DeploymentRequestSchema.parse(parsed); } catch (error) { logger.warn('[ChatDeploymentHandler] Failed to detect deployment request', { error: error instanceof Error ? error.message : String(error), }); return this.detectDeploymentPatterns(message); } } /** * Rule-based deployment pattern detection */ private detectDeploymentPatterns(message: string): DeploymentRequest { const lower = message.toLowerCase(); // DHCP patterns if (/dhcp|address\s+pool|lease/i.test(lower)) { return { isDeploymentRequest: true, taskType: 'dhcp', confidence: 0.8, reasoning: 'Contains DHCP-related keywords', }; } // DNS patterns if (/dns|domain|dns\s+record|a\s+record|mx\s+record/i.test(lower)) { return { isDeploymentRequest: true, taskType: 'dns', confidence: 0.8, reasoning: 'Contains DNS-related keywords', }; } // Firewall patterns if (/firewall|iptables|ufw|rules|nat|port\s+forward/i.test(lower)) { return { isDeploymentRequest: true, taskType: 'firewall', confidence: 0.75, reasoning: 'Contains firewall configuration keywords', }; } // Routing patterns if (/routing|route|gateway|bgp|ospf|rip/i.test(lower)) { return { isDeploymentRequest: true, taskType: 'routing', confidence: 0.75, reasoning: 'Contains routing configuration keywords', }; } // VLAN patterns if (/vlan|virtual\s+lan|tagged|untagged|trunk/i.test(lower)) { return { isDeploymentRequest: true, taskType: 'vlan', confidence: 0.75, reasoning: 'Contains VLAN configuration keywords', }; } // Generic deployment patterns if (/deploy|setup|configure|enable|install|provision|create/i.test(lower)) { return { isDeploymentRequest: true, confidence: 0.4, reasoning: 'Contains generic deployment keywords', }; } return { isDeploymentRequest: false, confidence: 0, reasoning: 'No deployment keywords detected', }; } /** * Extract device information from message or configuration */ extractDeviceContext(message: string, _context?: any): Partial<CommandGenerationContext> { // Extract IP addresses const ipMatch = message.match(/\b(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})\b/); const targetDevice = ipMatch ? ipMatch[1] : undefined; // Detect device type let deviceType: 'mikrotik' | 'linux' | 'windows' | 'generic' = 'generic'; if (/mikrotik|routeros|ros/i.test(message)) deviceType = 'mikrotik'; if (/linux|ubuntu|debian|centos/i.test(message)) deviceType = 'linux'; if (/windows|powershell|winrm/i.test(message)) deviceType = 'windows'; // Detect connection type let connectionType: 'ssh' | 'telnet' | 'local' = 'ssh'; if (/telnet/i.test(message)) connectionType = 'telnet'; if (/local|localhost|127\.0\.0\.1/i.test(message)) connectionType = 'local'; return { targetDevice, deviceType, connectionType, }; } /** * Generate deployment commands from user request */ async generateDeploymentCommands( userMessage: string, deployment: DeploymentRequest, llmClient?: { generateCompletion(messages: any[]): Promise<string> } ): Promise<{ generationId: string; response: CommandGenerationResponse }> { try { const context: CommandGenerationContext = { targetDevice: deployment.targetDevice || '172.251.96.200', deviceType: 'mikrotik', connectionType: 'ssh', taskType: deployment.taskType || 'other', details: { userRequest: userMessage, detectionConfidence: deployment.confidence, }, }; logger.info('[ChatDeploymentHandler] Generating deployment commands', { taskType: context.taskType, device: context.targetDevice, }); const response = await generateCommands(userMessage, context, llmClient); // Validate commands const validation = validateCommands(response.commands); if (!validation.valid) { logger.warn('[ChatDeploymentHandler] Command validation failed', { errors: validation.errors, }); } // Store for later reference const generationId = `gen_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`; this.pendingGenerations.set(generationId, response); return { generationId, response }; } catch (error) { logger.error('[ChatDeploymentHandler] Failed to generate commands', { error: error instanceof Error ? error.message : String(error), }); throw error; } } /** * Get generated commands for display */ getGenerationDisplay(generationId: string): { display: string; sessionId?: string } | null { const response = this.pendingGenerations.get(generationId); if (!response) return null; const display = formatCommandsForDisplay(response); // Create execution session for confirmation const session = this.executionManager.createSession( 'web-user', response.commands[0]?.command || 'unknown', response.commands.map(c => c.id) ); return { display, sessionId: session.sessionId }; } /** * Handle user confirmation or rejection */ async handleUserConfirmation( sessionId: string, approved: boolean, selectedCommandIds?: string[] ): Promise<{ approved: boolean; session: ExecutionSession; message: string }> { if (!approved) { this.executionManager.cancelExecution(sessionId, 'User rejected execution'); return { approved: false, session: this.executionManager.getSession(sessionId)!, message: '❌ Deployment cancelled by user', }; } const approved_session = this.executionManager.approveExecution(sessionId, selectedCommandIds); return { approved: approved_session, session: this.executionManager.getSession(sessionId)!, message: `✅ Deployment approved. Executing ${selectedCommandIds?.length || 0} commands...`, }; } /** * Get execution session details */ getExecutionSession(sessionId: string): ExecutionSession | null { return this.executionManager.getSession(sessionId) || null; } /** * Record command execution result */ recordExecutionResult( sessionId: string, commandId: string, result: { success: boolean; stdout?: string; stderr?: string; exitCode: number; duration: number; } ): boolean { return this.executionManager.recordResult(sessionId, commandId, result); } /** * Finalize execution session */ finalizeExecution(sessionId: string, success: boolean, error?: string): ExecutionSession | null { this.executionManager.completeSession(sessionId, success, error); return this.executionManager.getSession(sessionId) || null; } /** * Get formatted results */ getResultsDisplay(sessionId: string): string | null { const session = this.executionManager.getSession(sessionId); if (!session) return null; return formatExecutionResults(session); } /** * Cancel ongoing execution */ cancelExecution(sessionId: string, reason?: string): boolean { return this.executionManager.cancelExecution(sessionId, reason); } } /** * Build chat response for deployment workflow */ export function buildDeploymentChatResponse( stage: 'detection' | 'generation' | 'confirmation' | 'executing' | 'completed' | 'error', data: any ): string { const responses: Record<string, string> = { detection: `🔍 **Deployment Request Detected**\n\nI detected a request to deploy infrastructure. Let me generate the necessary commands for you.`, generation: `📋 **Commands Generated**\n\nI've prepared the deployment commands. Please review them carefully before confirming execution:\n\n${data.display || ''}`, confirmation: `⏳ **Awaiting Your Confirmation**\n\nPlease approve or reject the deployment plan. You can:\n- ✅ Approve all commands\n- ❌ Reject deployment\n- ✏️ Edit command selection\n\nSession ID: \`${data.sessionId}\``, executing: `🚀 **Executing Deployment**\n\nStarting command execution on ${data.device}...\n\nCommands: ${data.commandCount}`, completed: `✅ **Deployment Completed**\n\n${data.results || 'Check the results above.'}`, error: `❌ **Deployment Failed**\n\nError: ${data.error || 'Unknown error occurred'}\n\nPlease check the logs and try again.`, }; return responses[stage] || 'Unknown stage'; } export default ChatDeploymentHandler;

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/babasida246/ai-mcp-gateway'

If you have feedback or need assistance with the MCP directory API, please join our Discord server