UNPKG

snow-flow

Version:

Snow-Flow v3.2.0: Complete ServiceNow Enterprise Suite with 180+ MCP Tools. ATF Testing, Knowledge Management, Service Catalog, Change Management with CAB scheduling, Virtual Agent chatbots with NLU, Performance Analytics KPIs, Flow Designer automation, A

704 lines 32 kB
"use strict"; /** * Intelligent Parallel Agent Engine * Automatically detects parallelizable work and spawns optimized agent teams * Integrates with Queen Agent for enhanced multi-agent coordination */ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); Object.defineProperty(exports, "__esModule", { value: true }); exports.ParallelAgentEngine = void 0; const eventemitter3_1 = require("eventemitter3"); const logger_1 = require("../utils/logger"); const crypto = __importStar(require("crypto")); class ParallelAgentEngine extends eventemitter3_1.EventEmitter { constructor(memory) { super(); this.logger = new logger_1.Logger('ParallelAgentEngine'); this.memory = memory; this.activeExecutionPlans = new Map(); this.agentWorkloads = new Map(); this.parallelizationHistory = new Map(); this.initializeCapabilityMap(); this.setupLearningSystem(); } /** * Main entry point: Analyze todos and detect parallelization opportunities */ async detectParallelizationOpportunities(todos, objectiveType, currentAgents) { this.logger.info('🧠 Analyzing parallelization opportunities', { todoCount: todos.length, objectiveType, currentAgentCount: currentAgents.length }); const opportunities = []; // 1. Detect independent tasks (can run simultaneously) const independentOpportunity = await this.detectIndependentTasks(todos); if (independentOpportunity) opportunities.push(independentOpportunity); // 2. Detect specialized breakdown opportunities (split complex task) const specializedOpportunity = await this.detectSpecializedBreakdown(todos, objectiveType); if (specializedOpportunity) opportunities.push(specializedOpportunity); // 3. Detect load distribution opportunities (same type, multiple agents) const loadOpportunity = await this.detectLoadDistribution(todos, currentAgents); if (loadOpportunity) opportunities.push(loadOpportunity); // 4. Detect capability split opportunities (different skills needed) const capabilityOpportunity = await this.detectCapabilitySplit(todos); if (capabilityOpportunity) opportunities.push(capabilityOpportunity); // 🚀 ENHANCED: More lenient filtering to ensure parallel execution happens const rankedOpportunities = opportunities .filter(opp => opp.confidence > 0.5 && opp.estimatedSpeedup > 1.1) // Lower thresholds .sort((a, b) => (b.confidence * b.estimatedSpeedup) - (a.confidence * a.estimatedSpeedup)); this.logger.info(`🎯 Found ${rankedOpportunities.length} high-confidence parallelization opportunities`, { totalOpportunities: opportunities.length, rankedCount: rankedOpportunities.length, averageConfidence: rankedOpportunities.reduce((sum, opp) => sum + opp.confidence, 0) / rankedOpportunities.length || 0 }); // Store opportunities for learning await this.storeOpportunities(todos, rankedOpportunities); return rankedOpportunities; } /** * Create optimal execution plan based on opportunities */ async createExecutionPlan(opportunities, todos, maxAgents = 8) { const planId = this.generateId('plan'); // Calculate optimal agent team const agentTeam = await this.calculateOptimalTeam(opportunities, todos, maxAgents); // Determine execution strategy const strategy = this.determineExecutionStrategy(opportunities, agentTeam); // Estimate completion time const estimatedCompletion = this.estimateCompletionTime(agentTeam, strategy); const plan = { planId, opportunities, agentTeam, executionStrategy: strategy, estimatedCompletion, maxParallelism: Math.min(agentTeam.length, maxAgents), failureRecovery: 'reassign' }; this.activeExecutionPlans.set(planId, plan); this.logger.info(`📋 Created execution plan ${planId}`, { planId, strategy, teamSize: agentTeam.length, estimatedCompletion, maxParallelism: plan.maxParallelism, opportunityCount: opportunities.length }); return plan; } /** * Execute parallel plan and coordinate agents */ async executeParallelPlan(plan, spawnAgentCallback) { this.logger.info(`🚀 Executing parallel plan ${plan.planId}`, { planId: plan.planId, strategy: plan.executionStrategy, agentTeamSize: plan.agentTeam.length, maxParallelism: plan.maxParallelism }); const spawnedAgents = []; // Spawn agents based on plan for (const workload of plan.agentTeam) { if (workload.agentId === 'new') { // Spawn new agent with specialization const specialization = this.determineAgentSpecialization(workload); const agent = await spawnAgentCallback(workload.agentType, specialization); spawnedAgents.push(agent); // Update workload with actual agent ID workload.agentId = agent.id; this.agentWorkloads.set(agent.id, workload); } } // Set up parallel coordination await this.setupParallelCoordination(plan, spawnedAgents); // Calculate speedup const sequentialTime = plan.agentTeam.reduce((sum, w) => sum + w.estimatedDuration, 0); const parallelTime = plan.estimatedCompletion; const actualSpeedup = sequentialTime / parallelTime; this.emit('parallel_execution_started', { planId: plan.planId, agentCount: spawnedAgents.length, estimatedSpeedup: actualSpeedup }); return { spawnedAgents, executionDetails: { totalAgentsSpawned: spawnedAgents.length, parallelWorkflows: plan.opportunities.length, estimatedSpeedup: `${actualSpeedup.toFixed(1)}x faster` } }; } /** * Detect independent tasks that can run in parallel */ async detectIndependentTasks(todos) { const independentGroups = []; const processed = new Set(); for (const todo of todos) { if (processed.has(todo.id)) continue; const group = [todo.id]; processed.add(todo.id); // Find todos that can run with this one for (const otherTodo of todos) { if (processed.has(otherTodo.id)) continue; if (this.areTasksIndependent(todo, otherTodo)) { group.push(otherTodo.id); processed.add(otherTodo.id); } } if (group.length > 1) { independentGroups.push(group); } } if (independentGroups.length === 0) return null; // Find the largest independent group const largestGroup = independentGroups.reduce((max, group) => group.length > max.length ? group : max); return { id: this.generateId('independent'), type: 'independent_tasks', todos: largestGroup, suggestedAgents: this.suggestAgentsForTodos(largestGroup, todos), estimatedSpeedup: largestGroup.length * 0.8, // Account for coordination overhead confidence: 0.9, // High confidence for independent tasks dependencies: [], blockers: [] }; } /** * Detect opportunities to break down complex tasks into specialized agents */ async detectSpecializedBreakdown(todos, objectiveType) { // 🚀 ENHANCED: More intelligent detection of tasks that benefit from specialization const canBenefitFromSpecialization = todos.filter(todo => { const content = todo.content.toLowerCase(); // Widget development indicators if (content.includes('widget') || content.includes('portal') || content.includes('ui')) { return true; } // Development indicators if (content.includes('develop') || content.includes('create') || content.includes('build')) { return true; } // Multiple component indicators if (content.includes('and') || content.includes('with') || content.includes('including')) { return true; } // Complex task indicators if (todo.priority === 'high' || todo.priority === 'medium') { return true; } // Any development-related task benefits from specialization if (content.includes('test') || content.includes('style') || content.includes('script')) { return true; } return false; }); // 🚀 Be more aggressive - even single development tasks benefit from parallel specialists if (canBenefitFromSpecialization.length === 0 && todos.length > 0) { // If no specific indicators, but we have todos, still try to parallelize canBenefitFromSpecialization.push(...todos.slice(0, Math.min(3, todos.length))); } if (canBenefitFromSpecialization.length === 0) return null; // 🚀 ENHANCED: More specialized agent teams with specific roles const breakdownMap = { 'widget': [ 'widget-creator', // HTML structure specialist 'css-specialist', // Styling and responsive design specialist 'backend-specialist', // Server script specialist 'frontend-specialist', // Client script specialist 'integration-specialist', // API integration specialist 'ui-ux-specialist', // User experience specialist 'performance-specialist', // Performance optimization 'accessibility-specialist', // Accessibility compliance 'tester' // Testing specialist ], 'flow': [ 'flow-builder', // Flow structure specialist 'trigger-specialist', // Trigger configuration specialist 'action-specialist', // Action development specialist 'integration-specialist', // External system integration 'approval-specialist', // Approval process specialist 'notification-specialist', // Notification configuration 'error-handler', // Error handling specialist 'tester' // Flow testing specialist ], 'application': [ 'app-architect', // Application architecture 'widget-creator', // UI components 'css-specialist', // Styling specialist 'flow-builder', // Business logic flows 'script-writer', // Script includes and business rules 'security-specialist', // Security implementation 'integration-specialist', // System integration 'performance-specialist', // Performance optimization 'documentation-specialist', // Documentation 'tester' // Comprehensive testing ], 'script': [ 'script-writer', // Core script development 'api-specialist', // API integration specialist 'performance-specialist', // Code optimization 'security-specialist', // Security review 'documentation-specialist', // Code documentation 'tester' // Script testing ], 'integration': [ 'integration-specialist', // Core integration 'api-specialist', // API development 'transform-specialist', // Data transformation 'error-handler', // Error handling 'monitoring-specialist', // Integration monitoring 'security-specialist', // Security implementation 'tester' // Integration testing ] }; // Select appropriate specialists based on task let suggestedAgents = breakdownMap[objectiveType] || breakdownMap['widget']; // 🚀 Limit to reasonable number but ensure good coverage const maxSpecialists = Math.min(8, Math.max(4, canBenefitFromSpecialization.length * 2)); suggestedAgents = suggestedAgents.slice(0, maxSpecialists); const todoIds = canBenefitFromSpecialization.map(t => t.id); return { id: this.generateId('specialized'), type: 'specialized_breakdown', todos: todoIds, suggestedAgents: suggestedAgents, estimatedSpeedup: Math.min(3.5, 1.5 + (suggestedAgents.length * 0.3)), // More realistic speedup confidence: 0.85, // Higher confidence for specialization benefits dependencies: [], blockers: [] }; } /** * Detect load distribution opportunities (same work type, multiple agents) */ async detectLoadDistribution(todos, currentAgents) { // Group todos by capability requirement const todoGroups = new Map(); for (const todo of todos) { const capability = this.inferTodoCapability(todo); if (!todoGroups.has(capability)) { todoGroups.set(capability, []); } todoGroups.get(capability).push(todo.id); } // Find groups with multiple todos that can be distributed for (const [capability, todoIds] of todoGroups) { if (todoIds.length >= 3) { // Worth distributing if 3+ similar tasks const agentType = this.capabilityToAgentType(capability); return { id: this.generateId('load'), type: 'load_distribution', todos: todoIds, suggestedAgents: [agentType, agentType, agentType], // Multiple agents of same type estimatedSpeedup: Math.min(todoIds.length, 3) * 0.75, // Account for coordination confidence: 0.85, dependencies: [], blockers: [] }; } } return null; } /** * Detect capability split opportunities (different skills for different parts) */ async detectCapabilitySplit(todos) { const capabilityGroups = new Map(); // Group todos by required capabilities for (const todo of todos) { const capabilities = this.analyzeTodoCapabilities(todo); for (const capability of capabilities) { if (!capabilityGroups.has(capability)) { capabilityGroups.set(capability, []); } capabilityGroups.get(capability).push(todo.id); } } // If we have multiple capability groups, we can split if (capabilityGroups.size >= 2) { const allTodos = Array.from(new Set(Array.from(capabilityGroups.values()).flat())); const agentTypes = Array.from(capabilityGroups.keys()) .map(cap => this.capabilityToAgentType(cap)); return { id: this.generateId('capability'), type: 'capability_split', todos: allTodos, suggestedAgents: agentTypes, estimatedSpeedup: 1.8, confidence: 0.75, dependencies: [], blockers: [] }; } return null; } /** * Calculate optimal agent team for execution plan */ async calculateOptimalTeam(opportunities, todos, maxAgents) { const team = []; const usedAgentTypes = new Set(); for (const opportunity of opportunities) { for (const agentType of opportunity.suggestedAgents) { if (team.length >= maxAgents) break; // Avoid duplicate agent types unless it's load distribution if (usedAgentTypes.has(agentType) && opportunity.type !== 'load_distribution') { continue; } const workload = { agentId: 'new', // Will be assigned when spawned agentType, assignedTodos: opportunity.todos.filter(todoId => this.todoRequiresAgentType(todoId, agentType, todos)), estimatedDuration: this.estimateTodoDuration(opportunity.todos, todos), utilization: 0.8, // Start at 80% utilization capabilities: this.getAgentCapabilities(agentType), specializations: this.getAgentSpecializations(agentType, opportunity.type) }; team.push(workload); usedAgentTypes.add(agentType); } } return team; } /** * Determine execution strategy based on opportunities and team */ determineExecutionStrategy(opportunities, agentTeam) { const hasIndependent = opportunities.some(o => o.type === 'independent_tasks'); const hasSpecialized = opportunities.some(o => o.type === 'specialized_breakdown'); const hasLoadDistribution = opportunities.some(o => o.type === 'load_distribution'); if (hasIndependent && hasSpecialized) { return 'hybrid'; // Mix of parallel and sequential } else if (hasLoadDistribution) { return 'concurrent'; // All agents work simultaneously } else if (hasSpecialized) { return 'pipeline'; // Sequential handoffs between specialists } else { return 'wave_based'; // Waves of parallel execution } } /** * Estimate completion time for agent team */ estimateCompletionTime(agentTeam, strategy) { const coordinationOverhead = agentTeam.length * 2; // 2 minutes per agent for coordination switch (strategy) { case 'concurrent': return Math.max(...agentTeam.map(w => w.estimatedDuration)) + coordinationOverhead; case 'pipeline': return agentTeam.reduce((sum, w) => sum + w.estimatedDuration, 0) * 0.7 + coordinationOverhead; case 'wave_based': const avgDuration = agentTeam.reduce((sum, w) => sum + w.estimatedDuration, 0) / agentTeam.length; return avgDuration * 1.5 + coordinationOverhead; case 'hybrid': return agentTeam.reduce((sum, w) => sum + w.estimatedDuration, 0) * 0.6 + coordinationOverhead; default: return Math.max(...agentTeam.map(w => w.estimatedDuration)) + coordinationOverhead; } } /** * Set up coordination between parallel agents */ async setupParallelCoordination(plan, agents) { // Store coordination plan in memory for agents to access await this.memory.store(`parallel_coordination_${plan.planId}`, { planId: plan.planId, strategy: plan.executionStrategy, agentTeam: plan.agentTeam, sharedContext: { objectiveId: plan.planId, coordinationMode: 'parallel', checkpoints: this.createCoordinationCheckpoints(plan), failureRecovery: plan.failureRecovery }, timestamp: new Date().toISOString() }); // Set up shared memory spaces for agent coordination for (let i = 0; i < agents.length; i++) { const agent = agents[i]; const workload = plan.agentTeam[i]; await this.memory.store(`agent_workload_${agent.id}`, { agentId: agent.id, assignedTodos: workload.assignedTodos, specializations: workload.specializations, coordinationKey: `parallel_coordination_${plan.planId}`, peerAgents: agents.filter(a => a.id !== agent.id).map(a => a.id), timestamp: new Date().toISOString() }); } } /** * Utility methods */ areTasksIndependent(todo1, todo2) { // Check if tasks have no direct dependencies const todo1Keywords = todo1.content.toLowerCase().split(' '); const todo2Keywords = todo2.content.toLowerCase().split(' '); // Tasks are independent if they don't share critical keywords const sharedCriticalKeywords = ['deploy', 'test', 'validate', 'create table', 'configure'].filter(keyword => todo1.content.toLowerCase().includes(keyword) && todo2.content.toLowerCase().includes(keyword)); return sharedCriticalKeywords.length === 0; } suggestAgentsForTodos(todoIds, todos) { const agents = []; const todoContents = todoIds.map(id => todos.find(t => t.id === id)?.content || ''); for (const content of todoContents) { const agentType = this.inferBestAgentType(content); if (!agents.includes(agentType)) { agents.push(agentType); } } return agents; } inferTodoCapability(todo) { const content = todo.content.toLowerCase(); if (content.includes('widget') || content.includes('template')) return 'widget_development'; if (content.includes('flow') || content.includes('workflow')) return 'flow_creation'; if (content.includes('script') || content.includes('code')) return 'scripting'; if (content.includes('test') || content.includes('validate')) return 'testing'; if (content.includes('deploy') || content.includes('configuration')) return 'deployment'; return 'general_development'; } capabilityToAgentType(capability) { const mapping = { 'widget_development': 'widget-creator', 'flow_creation': 'flow-builder', 'scripting': 'script-writer', 'testing': 'tester', 'deployment': 'app-architect', 'general_development': 'script-writer' }; return mapping[capability] || 'script-writer'; } analyzeTodoCapabilities(todo) { const content = todo.content.toLowerCase(); const capabilities = []; if (content.includes('widget') || content.includes('ui')) capabilities.push('widget_development'); if (content.includes('script') || content.includes('code')) capabilities.push('scripting'); if (content.includes('flow') || content.includes('workflow')) capabilities.push('flow_creation'); if (content.includes('test') || content.includes('validate')) capabilities.push('testing'); if (content.includes('deploy') || content.includes('install')) capabilities.push('deployment'); if (content.includes('integrate') || content.includes('api')) capabilities.push('integration'); return capabilities.length > 0 ? capabilities : ['general_development']; } todoRequiresAgentType(todoId, agentType, todos) { const todo = todos.find(t => t.id === todoId); if (!todo) return false; const requiredType = this.inferBestAgentType(todo.content); return requiredType === agentType; } inferBestAgentType(content) { const lower = content.toLowerCase(); if (lower.includes('widget') || lower.includes('template')) return 'widget-creator'; if (lower.includes('flow') || lower.includes('workflow')) return 'flow-builder'; if (lower.includes('script') || lower.includes('business rule')) return 'script-writer'; if (lower.includes('test') || lower.includes('validate')) return 'tester'; if (lower.includes('integrate') || lower.includes('api')) return 'integration-specialist'; if (lower.includes('catalog') || lower.includes('item')) return 'catalog-manager'; if (lower.includes('research') || lower.includes('analyze')) return 'researcher'; return 'script-writer'; } estimateTodoDuration(todoIds, todos) { let totalDuration = 0; for (const todoId of todoIds) { const todo = todos.find(t => t.id === todoId); if (!todo) continue; // Estimate based on content complexity const words = todo.content.split(' ').length; const baseDuration = 15; // 15 minutes base const complexityMultiplier = todo.priority === 'high' ? 1.5 : 1.0; totalDuration += baseDuration + (words * 2) * complexityMultiplier; } return Math.max(10, totalDuration); // Minimum 10 minutes } getAgentCapabilities(agentType) { const capabilityMap = { 'widget-creator': ['html_generation', 'css_styling', 'javascript_development'], 'flow-builder': ['flow_design', 'trigger_configuration', 'action_creation'], 'script-writer': ['glide_scripting', 'business_logic', 'error_handling'], 'app-architect': ['system_design', 'architecture_planning', 'integration'], 'integration-specialist': ['rest_api', 'soap_services', 'data_transformation'], 'catalog-manager': ['catalog_creation', 'variable_management', 'workflow_linking'], 'researcher': ['requirement__analysis', 'feasibility_study', 'solution_research'], 'tester': ['test_planning', 'test_execution', 'mock_data_creation'] }; return capabilityMap[agentType] || ['general_development']; } getAgentSpecializations(agentType, opportunityType) { const specializationMap = { 'independent_tasks': { 'widget-creator': ['parallel_ui_development', 'component_isolation'], 'script-writer': ['parallel_scripting', 'independent_logic'], 'tester': ['parallel_testing', 'test_isolation'] }, 'specialized_breakdown': { 'widget-creator': ['ui_specialist', 'template_expert'], 'script-writer': ['logic_specialist', 'performance_expert'], 'flow-builder': ['workflow_specialist', 'integration_expert'] }, 'load_distribution': { 'widget-creator': ['high_throughput_ui', 'batch_processing'], 'script-writer': ['concurrent_scripting', 'load_handling'], 'tester': ['bulk_testing', 'parallel_validation'] } }; return specializationMap[opportunityType]?.[agentType] || ['general_specialist']; } determineAgentSpecialization(workload) { return workload.specializations[0] || 'general'; } createCoordinationCheckpoints(plan) { return [ 'initialization_complete', 'halfway_milestone', 'integration_ready', 'testing_phase', 'deployment_ready' ]; } async storeOpportunities(todos, opportunities) { await this.memory.store(`parallelization_analysis_${Date.now()}`, { todoCount: todos.length, opportunitiesFound: opportunities.length, opportunities: opportunities.map(opp => ({ type: opp.type, confidence: opp.confidence, estimatedSpeedup: opp.estimatedSpeedup, agentCount: opp.suggestedAgents.length })), timestamp: new Date().toISOString() }); } setupLearningSystem() { this.on('parallel_execution_completed', async (data) => { // Store execution results for learning this.parallelizationHistory.set(data.planId, { success: data.success, speedup: data.actualSpeedup }); await this.memory.store(`execution_result_${data.planId}`, { planId: data.planId, actualSpeedup: data.actualSpeedup, success: data.success, timestamp: new Date().toISOString() }); }); } initializeCapabilityMap() { this.capabilityMap = { 'widget.*template': { primaryCapability: 'template_development', requiredAgentTypes: ['widget-creator'], parallelizable: true, estimatedDuration: 20, dependencies: [] }, 'server.*script': { primaryCapability: 'server_development', requiredAgentTypes: ['script-writer'], parallelizable: true, estimatedDuration: 25, dependencies: ['template_development'] }, 'client.*script': { primaryCapability: 'client_development', requiredAgentTypes: ['script-writer'], parallelizable: true, estimatedDuration: 20, dependencies: ['template_development'] }, 'css.*style': { primaryCapability: 'styling', requiredAgentTypes: ['widget-creator'], parallelizable: true, estimatedDuration: 15, dependencies: ['template_development'] }, 'test.*validate': { primaryCapability: 'testing', requiredAgentTypes: ['tester'], parallelizable: false, estimatedDuration: 30, dependencies: ['server_development', 'client_development', 'styling'] }, 'deploy': { primaryCapability: 'deployment', requiredAgentTypes: ['app-architect'], parallelizable: false, estimatedDuration: 10, dependencies: ['testing'] } }; } generateId(prefix) { return `${prefix}_${Date.now()}_${crypto.randomBytes(4).toString('hex')}`; } } exports.ParallelAgentEngine = ParallelAgentEngine; //# sourceMappingURL=parallel-agent-engine.js.map