mega-minds
Version:
Enhanced multi-agent workflow system for Claude Code projects with automated handoff management and Claude Code hooks integration
584 lines (499 loc) • 22.1 kB
JavaScript
// lib/utils/RequestRouter.js
/**
* RequestRouter - Intelligent request analysis and agent selection
* Analyzes user requests and automatically routes to the most appropriate agents
*/
class RequestRouter {
constructor() {
this.agentCapabilities = this.initializeAgentCapabilities();
this.routingHistory = [];
this.learningEnabled = true;
}
/**
* Analyze request and route to appropriate agents
*/
async routeRequest(userRequest, projectContext = {}) {
console.log('🔍 Analyzing request for optimal agent routing...');
// Analyze the request
const analysis = this.analyzeRequest(userRequest);
// Get project context factors
const contextFactors = this.analyzeProjectContext(projectContext);
// Determine optimal agent sequence
const routing = this.determineAgentSequence(analysis, contextFactors);
// Validate routing based on agent availability
const validatedRouting = await this.validateRouting(routing, projectContext);
// Save for learning
if (this.learningEnabled) {
this.saveRoutingDecision(userRequest, analysis, validatedRouting);
}
console.log(`🤖 Routing: ${validatedRouting.primary.join(' → ')}`);
return validatedRouting;
}
/**
* Analyze user request to understand intent and complexity
*/
analyzeRequest(request) {
const requestLower = request.toLowerCase();
const analysis = {
keywords: this.extractKeywords(requestLower),
intent: this.classifyIntent(requestLower),
complexity: this.assessComplexity(requestLower),
urgency: this.assessUrgency(requestLower),
scope: this.determineScope(requestLower),
requiredCapabilities: this.identifyRequiredCapabilities(requestLower)
};
return analysis;
}
/**
* Extract relevant keywords from request
*/
extractKeywords(request) {
const keywordPatterns = {
// Frontend development
frontend: ['ui', 'interface', 'component', 'react', 'vue', 'frontend', 'page', 'form', 'button', 'styling', 'css', 'responsive', 'mobile'],
// Backend development
backend: ['api', 'endpoint', 'server', 'backend', 'database', 'auth', 'authentication', 'validation', 'business logic'],
// Database
database: ['database', 'db', 'sql', 'table', 'schema', 'query', 'migration', 'data model', 'postgresql', 'mysql'],
// Authentication
auth: ['login', 'register', 'auth', 'authentication', 'authorization', 'user', 'session', 'token', 'oauth', 'jwt'],
// Testing
testing: ['test', 'testing', 'unit test', 'integration test', 'e2e', 'coverage', 'spec', 'jest'],
// DevOps
devops: ['deploy', 'deployment', 'ci/cd', 'pipeline', 'infrastructure', 'cloud', 'aws', 'docker', 'kubernetes'],
// Design
design: ['design', 'mockup', 'wireframe', 'prototype', 'ux', 'user experience', 'layout', 'brand'],
// Planning
planning: ['plan', 'architecture', 'structure', 'organize', 'strategy', 'requirement', 'analyze', 'research'],
// Performance
performance: ['performance', 'optimize', 'slow', 'fast', 'speed', 'cache', 'load time', 'bottleneck'],
// Security
security: ['security', 'secure', 'vulnerability', 'encryption', 'ssl', 'https', 'audit', 'compliance']
};
const foundKeywords = {};
for (const [category, keywords] of Object.entries(keywordPatterns)) {
foundKeywords[category] = keywords.filter(keyword => request.includes(keyword));
}
return foundKeywords;
}
/**
* Classify the intent of the request
*/
classifyIntent(request) {
const intentPatterns = {
create: ['create', 'build', 'make', 'develop', 'add', 'implement', 'generate'],
modify: ['update', 'change', 'modify', 'edit', 'refactor', 'improve', 'enhance'],
fix: ['fix', 'debug', 'resolve', 'solve', 'repair', 'troubleshoot', 'issue'],
analyze: ['analyze', 'review', 'check', 'evaluate', 'assess', 'investigate'],
plan: ['plan', 'design', 'architect', 'structure', 'organize', 'strategy'],
test: ['test', 'verify', 'validate', 'check', 'ensure'],
deploy: ['deploy', 'release', 'publish', 'launch', 'go live'],
document: ['document', 'write docs', 'documentation', 'readme', 'guide']
};
for (const [intent, patterns] of Object.entries(intentPatterns)) {
if (patterns.some(pattern => request.includes(pattern))) {
return intent;
}
}
return 'unknown';
}
/**
* Assess complexity of the request
*/
assessComplexity(request) {
let complexity = 1; // Base complexity
// Complexity indicators
const complexityIndicators = {
high: ['integration', 'system', 'architecture', 'complex', 'multiple', 'advanced', 'enterprise'],
medium: ['feature', 'component', 'service', 'workflow', 'process'],
simple: ['simple', 'basic', 'quick', 'small', 'minor']
};
if (complexityIndicators.high.some(indicator => request.includes(indicator))) {
complexity = 5;
} else if (complexityIndicators.medium.some(indicator => request.includes(indicator))) {
complexity = 3;
} else if (complexityIndicators.simple.some(indicator => request.includes(indicator))) {
complexity = 1;
} else {
// Count different technical areas mentioned
const technicalAreas = ['frontend', 'backend', 'database', 'auth', 'testing', 'devops'].filter(area =>
request.includes(area)
);
complexity = Math.min(5, technicalAreas.length + 1);
}
return complexity;
}
/**
* Assess urgency of the request
*/
assessUrgency(request) {
const urgencyIndicators = {
urgent: ['urgent', 'asap', 'immediately', 'critical', 'emergency', 'now', 'urgent'],
high: ['quickly', 'soon', 'priority', 'important', 'deadline'],
normal: ['when possible', 'eventually', 'future', 'later']
};
if (urgencyIndicators.urgent.some(indicator => request.includes(indicator))) {
return 'urgent';
} else if (urgencyIndicators.high.some(indicator => request.includes(indicator))) {
return 'high';
} else if (urgencyIndicators.normal.some(indicator => request.includes(indicator))) {
return 'normal';
}
return 'normal'; // Default
}
/**
* Determine scope of work
*/
determineScope(request) {
const scopeIndicators = {
full_project: ['project', 'application', 'app', 'system', 'platform'],
feature: ['feature', 'functionality', 'capability', 'module'],
component: ['component', 'widget', 'element', 'part'],
task: ['task', 'item', 'piece', 'small']
};
for (const [scope, indicators] of Object.entries(scopeIndicators)) {
if (indicators.some(indicator => request.includes(indicator))) {
return scope;
}
}
return 'feature'; // Default
}
/**
* Identify required capabilities based on request
*/
identifyRequiredCapabilities(request) {
const capabilities = [];
const keywords = this.extractKeywords(request);
// Map keywords to capabilities
if (keywords.frontend.length > 0) capabilities.push('frontend_development');
if (keywords.backend.length > 0) capabilities.push('backend_development');
if (keywords.database.length > 0) capabilities.push('database_management');
if (keywords.auth.length > 0) capabilities.push('authentication');
if (keywords.testing.length > 0) capabilities.push('testing');
if (keywords.devops.length > 0) capabilities.push('devops');
if (keywords.design.length > 0) capabilities.push('ui_design');
if (keywords.planning.length > 0) capabilities.push('planning');
if (keywords.performance.length > 0) capabilities.push('performance_optimization');
if (keywords.security.length > 0) capabilities.push('security');
return capabilities.length > 0 ? capabilities : ['general_development'];
}
/**
* Determine optimal sequence of agents
*/
determineAgentSequence(analysis, contextFactors) {
const routing = {
primary: [], // Main sequence of agents
parallel: [], // Agents that can work in parallel
optional: [], // Agents that might be helpful
priority: analysis.urgency === 'urgent' ? 'high' : 'normal'
};
// Start with project orchestrator for complex requests
if (analysis.complexity >= 3 || analysis.scope === 'full_project') {
routing.primary.push('project-orchestrator-agent');
}
// Add agents based on required capabilities
const agentSequence = this.mapCapabilitiesToAgents(analysis.requiredCapabilities, analysis.intent);
// Add planning agents for new features/projects
if (analysis.intent === 'create' && (analysis.scope === 'feature' || analysis.scope === 'full_project')) {
if (!routing.primary.includes('project-orchestrator-agent')) {
routing.primary.push('requirements-analysis-agent');
}
if (analysis.complexity >= 4) {
routing.optional.push('risk-assessment-agent');
routing.optional.push('market-research-agent');
}
}
// Add design agents for UI work
if (analysis.requiredCapabilities.includes('frontend_development') ||
analysis.requiredCapabilities.includes('ui_design')) {
if (analysis.intent === 'create') {
routing.primary.push('ux-ui-design-agent');
}
}
// Add technical architecture for complex systems
if (analysis.complexity >= 4 || analysis.scope === 'full_project') {
routing.primary.push('technical-architecture-agent');
}
// Add database design for data-related work
if (analysis.requiredCapabilities.includes('database_management')) {
if (analysis.intent === 'create' || analysis.intent === 'modify') {
routing.primary.push('database-schema-agent');
}
routing.primary.push('database-agent');
}
// Add API design for backend work
if (analysis.requiredCapabilities.includes('backend_development')) {
if (analysis.intent === 'create') {
routing.primary.push('api-design-agent');
}
routing.primary.push('backend-development-agent');
}
// Add security for auth or security work
if (analysis.requiredCapabilities.includes('authentication') ||
analysis.requiredCapabilities.includes('security')) {
routing.primary.push('security-architecture-agent');
routing.primary.push('authentication-agent');
}
// Add frontend development
if (analysis.requiredCapabilities.includes('frontend_development')) {
routing.primary.push('frontend-development-agent');
}
// Add testing agents
if (analysis.requiredCapabilities.includes('testing') || analysis.intent === 'create') {
routing.primary.push('testing-agent');
if (analysis.requiredCapabilities.includes('security')) {
routing.parallel.push('security-testing-agent');
}
if (analysis.requiredCapabilities.includes('performance_optimization')) {
routing.parallel.push('performance-testing-agent');
}
}
// Add DevOps for deployment
if (analysis.requiredCapabilities.includes('devops') || analysis.intent === 'deploy') {
routing.primary.push('ci-cd-pipeline-agent');
routing.primary.push('infrastructure-agent');
}
// Always add code review for code changes
if (['create', 'modify', 'fix'].includes(analysis.intent)) {
routing.primary.push('code-review-agent');
}
return routing;
}
/**
* Map capabilities to specific agents
*/
mapCapabilitiesToAgents(capabilities, intent) {
const mapping = {
frontend_development: ['frontend-development-agent'],
backend_development: ['backend-development-agent'],
database_management: ['database-agent'],
authentication: ['authentication-agent'],
testing: ['testing-agent'],
devops: ['ci-cd-pipeline-agent', 'infrastructure-agent'],
ui_design: ['ux-ui-design-agent'],
planning: ['requirements-analysis-agent', 'project-orchestrator-agent'],
performance_optimization: ['performance-testing-agent'],
security: ['security-architecture-agent', 'security-testing-agent']
};
const agents = [];
capabilities.forEach(capability => {
if (mapping[capability]) {
agents.push(...mapping[capability]);
}
});
return [...new Set(agents)]; // Remove duplicates
}
/**
* Validate routing based on agent availability and project state
*/
async validateRouting(routing, projectContext) {
// Check agent availability
const agentWorkload = projectContext.agentWorkload || {};
// Filter out busy agents and suggest alternatives
const validatedRouting = {
...routing,
primary: await this.validateAgentSequence(routing.primary, agentWorkload),
parallel: await this.validateAgentSequence(routing.parallel, agentWorkload),
blocked: [],
alternatives: []
};
// Check for blocked agents and suggest alternatives
for (const agent of routing.primary) {
if (agentWorkload[agent]?.availability === 'blocked') {
validatedRouting.blocked.push(agent);
const alternative = this.findAlternativeAgent(agent);
if (alternative) {
validatedRouting.alternatives.push({
blocked: agent,
alternative: alternative,
reason: agentWorkload[agent].blockedOn
});
}
}
}
return validatedRouting;
}
/**
* Validate agent sequence for availability
*/
async validateAgentSequence(agentSequence, agentWorkload) {
return agentSequence.filter(agent => {
const workload = agentWorkload[agent];
return !workload || workload.availability !== 'blocked';
});
}
/**
* Find alternative agent for blocked agent
*/
findAlternativeAgent(blockedAgent) {
const alternatives = {
'frontend-development-agent': ['ux-ui-design-agent'],
'backend-development-agent': ['api-design-agent', 'database-agent'],
'testing-agent': ['code-review-agent'],
'database-agent': ['database-schema-agent'],
'infrastructure-agent': ['ci-cd-pipeline-agent']
};
return alternatives[blockedAgent]?.[0] || null;
}
/**
* Analyze project context factors
*/
analyzeProjectContext(projectContext) {
return {
projectPhase: projectContext.phase || 'development',
teamSize: this.calculateTeamSize(projectContext.agentWorkload),
currentLoad: this.calculateCurrentLoad(projectContext.agentWorkload),
recentActivity: projectContext.recentActivity || [],
priorities: projectContext.priorities || []
};
}
/**
* Calculate team size (active agents)
*/
calculateTeamSize(agentWorkload) {
if (!agentWorkload) return 0;
return Object.values(agentWorkload).filter(agent =>
agent.availability === 'busy' || agent.availability === 'available'
).length;
}
/**
* Calculate current team load
*/
calculateCurrentLoad(agentWorkload) {
if (!agentWorkload) return 0;
const total = Object.keys(agentWorkload).length;
const busy = Object.values(agentWorkload).filter(agent =>
agent.availability === 'busy'
).length;
return total > 0 ? (busy / total) * 100 : 0;
}
/**
* Save routing decision for learning
*/
saveRoutingDecision(request, analysis, routing) {
this.routingHistory.push({
timestamp: new Date().toISOString(),
request: request,
analysis: analysis,
routing: routing,
success: null // Will be updated based on outcome
});
// Keep only recent history (last 100 decisions)
if (this.routingHistory.length > 100) {
this.routingHistory = this.routingHistory.slice(-100);
}
}
/**
* Learn from routing outcomes
*/
updateRoutingOutcome(requestId, success, feedback = null) {
const decision = this.routingHistory.find(h => h.timestamp === requestId);
if (decision) {
decision.success = success;
decision.feedback = feedback;
// Use this data to improve future routing decisions
this.updateRoutingModel(decision);
}
}
/**
* Update routing model based on outcomes (simple learning)
*/
updateRoutingModel(decision) {
// Simple learning: adjust agent preferences based on success
if (decision.success) {
// Increase preference for successful routing patterns
// This is a simplified implementation
console.log(`✅ Successful routing pattern learned: ${decision.routing.primary.join(' → ')}`);
} else {
// Decrease preference for failed routing patterns
console.log(`❌ Failed routing pattern noted: ${decision.routing.primary.join(' → ')}`);
}
}
/**
* Get routing suggestions based on similar past requests
*/
getSimilarRoutingPatterns(analysis) {
return this.routingHistory
.filter(h => h.success === true)
.filter(h => {
// Find similar requests based on intent and capabilities
return h.analysis.intent === analysis.intent &&
h.analysis.requiredCapabilities.some(cap =>
analysis.requiredCapabilities.includes(cap)
);
})
.slice(-5) // Last 5 similar successful patterns
.map(h => ({
routing: h.routing.primary,
similarity: this.calculateSimilarity(analysis, h.analysis)
}))
.sort((a, b) => b.similarity - a.similarity);
}
/**
* Calculate similarity between requests
*/
calculateSimilarity(analysis1, analysis2) {
let similarity = 0;
// Intent match
if (analysis1.intent === analysis2.intent) similarity += 0.3;
// Capability overlap
const overlap = analysis1.requiredCapabilities.filter(cap =>
analysis2.requiredCapabilities.includes(cap)
).length;
const union = [...new Set([...analysis1.requiredCapabilities, ...analysis2.requiredCapabilities])].length;
similarity += (overlap / union) * 0.5;
// Complexity similarity
const complexityDiff = Math.abs(analysis1.complexity - analysis2.complexity);
similarity += (1 - complexityDiff / 5) * 0.2;
return similarity;
}
/**
* Initialize agent capabilities matrix
*/
initializeAgentCapabilities() {
return {
'project-orchestrator-agent': {
capabilities: ['coordination', 'planning', 'task_management'],
workload_capacity: 10,
parallel_capable: true
},
'requirements-analysis-agent': {
capabilities: ['requirements_gathering', 'analysis', 'documentation'],
workload_capacity: 5,
parallel_capable: false
},
'ux-ui-design-agent': {
capabilities: ['ui_design', 'user_experience', 'prototyping'],
workload_capacity: 3,
parallel_capable: true
},
'frontend-development-agent': {
capabilities: ['frontend_development', 'react', 'ui_implementation'],
workload_capacity: 5,
parallel_capable: true
},
'backend-development-agent': {
capabilities: ['backend_development', 'api_development', 'business_logic'],
workload_capacity: 5,
parallel_capable: true
},
'database-agent': {
capabilities: ['database_management', 'sql', 'data_operations'],
workload_capacity: 3,
parallel_capable: false
},
'authentication-agent': {
capabilities: ['authentication', 'security', 'user_management'],
workload_capacity: 3,
parallel_capable: false
},
'testing-agent': {
capabilities: ['testing', 'quality_assurance', 'test_automation'],
workload_capacity: 5,
parallel_capable: true
}
// Add more agents as needed
};
}
}
module.exports = RequestRouter;