Skip to main content
Glama
workflow-orchestrator.js19 kB
/** * Workflow Orchestrator * Combines all intelligent components to orchestrate complex development workflows */ import { ContextManager } from '../intelligence/context-manager.js'; import { WorkflowOptimizer } from '../intelligence/workflow-optimizer.js'; import { SessionTracker } from '../intelligence/session-tracker.js'; import { PatternRecognizer } from '../intelligence/pattern-recognizer.js'; import { DecisionHelper } from '../intelligence/decision-helper.js'; import { DevelopmentStateMachine } from '../reasoning/state-machine.js'; import { DecisionTree } from '../reasoning/decision-tree.js'; import { ContextRouter } from '../reasoning/context-router.js'; import { FeedbackLoop } from '../reasoning/feedback-loop.js'; import { SemanticSearch } from '../local-ai/semantic-search.js'; import { IntentRecognizer } from '../local-ai/intent-recognition.js'; import { KnowledgeGraph } from '../local-ai/knowledge-graph.js'; import { SmartSuggestionsGenerator } from '../local-ai/smart-suggestions.js'; import { CrossClientSynchronizer } from './cross-client-sync.js'; import { ToolEnhancer } from './tool-enhancer.js'; export class WorkflowOrchestrator { constructor() { this.components = { context: null, optimizer: null, session: null, patterns: null, decisions: null, stateMachine: null, decisionTree: null, router: null, feedback: null, search: null, intent: null, graph: null, suggestions: null, sync: null, enhancer: null, }; this.initialized = false; this.activeWorkflows = new Map(); this.workflowHistory = []; this.maxHistorySize = 100; } async initialize() { if (this.initialized) return; try { // Initialize all components this.components.context = new ContextManager(); await this.components.context.initialize(); this.components.optimizer = new WorkflowOptimizer(); this.components.session = new SessionTracker(); this.components.patterns = new PatternRecognizer(); await this.components.patterns.initialize(); this.components.decisions = new DecisionHelper(); this.components.stateMachine = new DevelopmentStateMachine(); this.components.decisionTree = new DecisionTree(); this.components.router = new ContextRouter(); this.components.feedback = new FeedbackLoop(); this.components.search = new SemanticSearch(); await this.components.search.initialize(); this.components.intent = new IntentRecognizer(); await this.components.intent.initialize(); this.components.graph = new KnowledgeGraph(); this.components.suggestions = new SmartSuggestionsGenerator(); await this.components.suggestions.initialize(); this.components.sync = new CrossClientSynchronizer(); await this.components.sync.initialize(); this.components.enhancer = new ToolEnhancer(); await this.components.enhancer.initialize(); this.initialized = true; } catch (error) { console.warn('WorkflowOrchestrator initialization warning:', error.message); // Continue with partial initialization this.initialized = true; } } /** * Start a new workflow */ async startWorkflow(options = {}) { const { type = 'general', goals = [], context = {}, clientType = 'unknown', sessionId = null, } = options; await this.initialize(); // Create workflow instance const workflow = { id: this.generateWorkflowId(), type, goals, context, clientType, sessionId, startTime: Date.now(), status: 'active', steps: [], results: [], metrics: { toolsUsed: 0, stateTransitions: 0, suggestionsGenerated: 0, patternsRecognized: 0, decisionsМade: 0, }, }; // Initialize context await this.components.context.initializeContext(clientType, context.projectPath || '.', sessionId); // Create or update session if (sessionId) { await this.components.session.updateSession(sessionId, { goals }); } else { const session = await this.components.session.createSession({ goals, context, clientType }); workflow.sessionId = session.id; } // Initialize state machine await this.components.stateMachine.initialize(this.components.context.getCurrentContext()); // Register with sync await this.components.sync.registerClient(workflow.id, clientType, { activeWorkflow: type, goals, currentFocus: context.currentFile, }); this.activeWorkflows.set(workflow.id, workflow); return workflow; } /** * Execute a workflow step */ async executeStep(workflowId, step) { const workflow = this.activeWorkflows.get(workflowId); if (!workflow) { throw new Error(`Workflow ${workflowId} not found`); } const stepResult = { id: this.generateStepId(), type: step.type, input: step.input, startTime: Date.now(), status: 'running', results: [], errors: [], }; workflow.steps.push(stepResult); try { switch (step.type) { case 'analyze': stepResult.results = await this.executeAnalysisStep(workflow, step); break; case 'optimize': stepResult.results = await this.executeOptimizationStep(workflow, step); break; case 'decide': stepResult.results = await this.executeDecisionStep(workflow, step); break; case 'search': stepResult.results = await this.executeSearchStep(workflow, step); break; case 'suggest': stepResult.results = await this.executeSuggestionStep(workflow, step); break; case 'coordinate': stepResult.results = await this.executeCoordinationStep(workflow, step); break; case 'execute_tools': stepResult.results = await this.executeToolsStep(workflow, step); break; default: throw new Error(`Unknown step type: ${step.type}`); } stepResult.status = 'completed'; stepResult.endTime = Date.now(); // Update metrics this.updateWorkflowMetrics(workflow, stepResult); // Record feedback await this.components.feedback.recordOutcome({ workflowId, stepId: stepResult.id, success: true, duration: stepResult.endTime - stepResult.startTime, resultsCount: stepResult.results.length, }); } catch (error) { stepResult.status = 'failed'; stepResult.errors.push({ message: error.message, stack: error.stack, timestamp: Date.now(), }); // Record failure await this.components.feedback.recordOutcome({ workflowId, stepId: stepResult.id, success: false, error: error.message, }); } return stepResult; } /** * Execute analysis step */ async executeAnalysisStep(workflow, step) { const results = []; // Analyze project context const context = await this.components.context.getCurrentContext(); results.push({ type: 'context_analysis', data: context, }); // Recognize patterns const patterns = await this.components.patterns.recognizePatterns({ context, recentActions: workflow.steps.slice(-10), }); results.push({ type: 'pattern_recognition', data: patterns, }); workflow.metrics.patternsRecognized += patterns.length; // Analyze intent if (step.input.query) { const intent = await this.components.intent.recognizeIntent(step.input.query); results.push({ type: 'intent_analysis', data: intent, }); } // Build knowledge graph if (step.input.buildGraph) { const graph = await this.components.graph.buildFromProject(context.project); results.push({ type: 'knowledge_graph', data: { nodes: graph.nodes.size, edges: graph.edges.length, insights: await this.components.graph.getInsights(), }, }); } return results; } /** * Execute optimization step */ async executeOptimizationStep(workflow, step) { const results = []; // Generate optimal tool sequence const sequence = await this.components.optimizer.generateOptimalSequence({ files: step.input.files || [], context: workflow.context, goals: workflow.goals, }); results.push({ type: 'tool_sequence', data: sequence, }); // Optimize based on patterns const patterns = await this.components.patterns.getRecentPatterns(); const optimizations = this.components.optimizer.optimizeBasedOnPatterns(patterns); results.push({ type: 'pattern_optimizations', data: optimizations, }); return results; } /** * Execute decision step */ async executeDecisionStep(workflow, step) { const results = []; // Make decision using decision tree const decision = await this.components.decisionTree.makeDecision( workflow.context, step.input.decisionType || 'development_approach' ); results.push({ type: 'decision_tree', data: decision, }); workflow.metrics.decisionsМade++; // Get recommendations from decision helper const recommendations = await this.components.decisions.getRecommendations({ context: workflow.context, goals: workflow.goals, currentState: await this.components.stateMachine.getCurrentState(), }); results.push({ type: 'recommendations', data: recommendations, }); // Route based on context const route = await this.components.router.route({ context: workflow.context, intent: step.input.intent, capabilities: step.input.capabilities || [], }); results.push({ type: 'context_route', data: route, }); return results; } /** * Execute search step */ async executeSearchStep(workflow, step) { const results = []; // Perform semantic search const searchResults = await this.components.search.search({ query: step.input.query, type: step.input.searchType || 'similar_code', searchPath: step.input.searchPath || '.', maxResults: step.input.maxResults || 10, context: workflow.context, }); results.push({ type: 'semantic_search', data: searchResults, }); // Search in knowledge graph if (this.components.graph.nodes.size > 0) { const graphResults = await this.components.graph.searchRelated( step.input.query, step.input.relationTypes ); results.push({ type: 'graph_search', data: graphResults, }); } return results; } /** * Execute suggestion step */ async executeSuggestionStep(workflow, step) { const results = []; // Generate smart suggestions const suggestions = await this.components.suggestions.generateSuggestions({ context: workflow.context, files: step.input.files || [], recentActions: workflow.steps.slice(-5).map(s => ({ tool: s.type, timestamp: s.startTime, })), currentState: await this.components.stateMachine.getCurrentState(), requestedTypes: step.input.suggestionTypes || ['next_steps', 'code_improvements'], }); results.push({ type: 'smart_suggestions', data: suggestions, }); workflow.metrics.suggestionsGenerated += suggestions.length; // Get decision helper recommendations const helperSuggestions = await this.components.decisions.getRecommendations({ context: workflow.context, goals: workflow.goals, }); results.push({ type: 'decision_recommendations', data: helperSuggestions, }); return results; } /** * Execute coordination step */ async executeCoordinationStep(workflow, step) { const results = []; // Get synchronized context const syncContext = await this.components.sync.getSynchronizedContext(); results.push({ type: 'sync_context', data: syncContext, }); // Share artifact if specified if (step.input.artifact) { const shared = await this.components.sync.shareArtifact({ type: step.input.artifact.type, source: workflow.id, content: step.input.artifact.content, metadata: step.input.artifact.metadata, }); results.push({ type: 'shared_artifact', data: shared, }); } // Coordinate action if specified if (step.input.coordination) { const coordination = await this.components.sync.coordinateAction({ type: step.input.coordination.type, initiator: workflow.id, target: step.input.coordination.target, payload: step.input.coordination.payload, }); results.push({ type: 'coordination_request', data: coordination, }); } return results; } /** * Execute tools step */ async executeToolsStep(workflow, step) { const results = []; const { tools = [], sequential = false } = step.input; // Update state machine await this.components.stateMachine.transition('IMPLEMENTING'); workflow.metrics.stateTransitions++; if (sequential) { // Execute tools sequentially for (const tool of tools) { const result = await this.executeTool(tool, workflow); results.push(result); // Update context after each tool await this.components.context.updateToolUsage(tool.name); workflow.metrics.toolsUsed++; } } else { // Execute tools in parallel const promises = tools.map(tool => this.executeTool(tool, workflow)); const toolResults = await Promise.all(promises); results.push(...toolResults); // Update context for (const tool of tools) { await this.components.context.updateToolUsage(tool.name); } workflow.metrics.toolsUsed += tools.length; } // Record patterns await this.components.patterns.recordEvent({ type: 'tool_execution', tools: tools.map(t => t.name), sequential, workflowType: workflow.type, timestamp: Date.now(), }); return results; } /** * Execute a single tool */ async executeTool(tool, workflow) { // This would integrate with actual tool handlers // For now, return a mock result return { tool: tool.name, args: tool.args, result: { success: true, output: `Executed ${tool.name}`, }, timestamp: Date.now(), }; } /** * Complete a workflow */ async completeWorkflow(workflowId, summary = {}) { const workflow = this.activeWorkflows.get(workflowId); if (!workflow) { throw new Error(`Workflow ${workflowId} not found`); } workflow.status = 'completed'; workflow.endTime = Date.now(); workflow.duration = workflow.endTime - workflow.startTime; workflow.summary = summary; // Update session if (workflow.sessionId) { await this.components.session.updateSession(workflow.sessionId, { lastActivity: Date.now(), completedWorkflows: 1, }); } // Record in history this.workflowHistory.push({ id: workflow.id, type: workflow.type, duration: workflow.duration, metrics: workflow.metrics, summary: workflow.summary, timestamp: workflow.endTime, }); // Trim history if (this.workflowHistory.length > this.maxHistorySize) { this.workflowHistory.shift(); } // Clean up this.activeWorkflows.delete(workflowId); // Update state machine await this.components.stateMachine.transition('COMPLETED'); return workflow; } /** * Get workflow status */ getWorkflowStatus(workflowId) { const workflow = this.activeWorkflows.get(workflowId); if (!workflow) { return null; } return { id: workflow.id, type: workflow.type, status: workflow.status, duration: Date.now() - workflow.startTime, steps: workflow.steps.length, lastStep: workflow.steps[workflow.steps.length - 1], metrics: workflow.metrics, }; } /** * Get active workflows */ getActiveWorkflows() { return Array.from(this.activeWorkflows.values()).map(w => ({ id: w.id, type: w.type, status: w.status, duration: Date.now() - w.startTime, goals: w.goals, })); } /** * Update workflow metrics */ updateWorkflowMetrics(workflow, stepResult) { // Update based on step type and results if (stepResult.type === 'suggest') { const suggestions = stepResult.results.find(r => r.type === 'smart_suggestions'); if (suggestions) { workflow.metrics.suggestionsGenerated += suggestions.data.length; } } } /** * Generate workflow ID */ generateWorkflowId() { return `wf_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`; } /** * Generate step ID */ generateStepId() { return `step_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`; } /** * Get workflow insights */ async getWorkflowInsights() { const insights = { activeWorkflows: this.activeWorkflows.size, totalCompleted: this.workflowHistory.length, averageDuration: 0, commonPatterns: [], toolUsageStats: {}, successRate: 0, }; if (this.workflowHistory.length > 0) { // Calculate average duration const totalDuration = this.workflowHistory.reduce((sum, w) => sum + w.duration, 0); insights.averageDuration = totalDuration / this.workflowHistory.length; // Get common patterns insights.commonPatterns = await this.components.patterns.getCommonPatterns(); // Calculate tool usage stats for (const workflow of this.workflowHistory) { for (const [tool, count] of Object.entries(workflow.metrics)) { insights.toolUsageStats[tool] = (insights.toolUsageStats[tool] || 0) + count; } } // Calculate success rate const successful = this.workflowHistory.filter(w => w.summary?.success).length; insights.successRate = successful / this.workflowHistory.length; } return insights; } }

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/moikas-code/moidvk'

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