UNPKG

@boundless-oss/atlas

Version:

Atlas - MCP Server for comprehensive startup project management

373 lines 14.9 kB
export class TriggerSuggestionEngine { store; patterns = new Map(); constructor(store) { this.store = store; this.initializePatterns(); } async suggestTriggers(process) { const suggestions = []; // Analyze activities to understand the process const activityAnalysis = this.analyzeActivities(process.activities); // Get persona-specific patterns const personaPatterns = process.persona ? this.patterns.get(process.persona) || [] : []; // Generate primary suggestions based on activity patterns const primarySuggestion = await this.generatePrimarySuggestion(process, activityAnalysis, personaPatterns); if (primarySuggestion) { suggestions.push(primarySuggestion); } // Generate alternative suggestions const alternatives = await this.generateAlternatives(process, activityAnalysis, primarySuggestion); suggestions.push(...alternatives); // Check for conflicts with existing processes for (const suggestion of suggestions) { suggestion.conflicts = await this.detectConflicts(suggestion.trigger); } return suggestions.sort((a, b) => b.confidence - a.confidence); } analyzeActivities(activities) { const analysis = { types: new Set(), hasHumanInteraction: false, hasExternalCalls: false, estimatedDuration: 0, isReportGeneration: false, isDataProcessing: false, isReview: false, isContinuous: false }; for (const activity of activities) { analysis.types.add(activity.type); if (activity.type === 'human') { analysis.hasHumanInteraction = true; } if (activity.type === 'external') { analysis.hasExternalCalls = true; } // Detect patterns from activity names const nameLower = activity.name.toLowerCase(); if (nameLower.includes('report') || nameLower.includes('summary')) { analysis.isReportGeneration = true; } if (nameLower.includes('process') || nameLower.includes('analyze') || nameLower.includes('extract') || nameLower.includes('transform') || nameLower.includes('load') || nameLower.includes('etl')) { analysis.isDataProcessing = true; } if (nameLower.includes('review') || nameLower.includes('check')) { analysis.isReview = true; } if (nameLower.includes('monitor') || nameLower.includes('watch')) { analysis.isContinuous = true; } } return analysis; } async generatePrimarySuggestion(process, analysis, personaPatterns) { let trigger = null; let confidence = 0; let reasoning = ''; // Check persona patterns first if (personaPatterns.length > 0 && personaPatterns[0].suggestedTriggers.length > 0) { const personaTrigger = personaPatterns[0].suggestedTriggers[0]; trigger = this.createTriggerFromTemplate(personaTrigger); confidence = 0.85; reasoning = personaTrigger.applicableWhen || 'Based on persona-specific patterns'; } // Check for continuous monitoring pattern else if (analysis.isContinuous) { trigger = this.createScheduleTrigger('Continuous Monitoring', '*/15 * * * *', // Every 15 minutes 'UTC'); confidence = 0.9; reasoning = 'Continuous monitoring processes should run frequently to catch issues quickly'; } // Check for report generation pattern else if (analysis.isReportGeneration) { const schedule = this.determineReportSchedule(process.name); trigger = this.createScheduleTrigger('Report Generation Schedule', schedule.cron, schedule.timezone); confidence = 0.85; reasoning = `Report generation typically follows a ${schedule.description} schedule`; } // Check for review/approval processes else if (analysis.isReview && analysis.hasHumanInteraction) { trigger = this.createScheduleTrigger('Review Cycle', '0 9 * * 1-5', // Weekdays at 9 AM 'UTC'); confidence = 0.8; reasoning = 'Review processes work best during business hours when team members are available'; } // Check persona-specific patterns else if (personaPatterns.length > 0) { const bestPattern = this.findBestPattern(personaPatterns, analysis); if (bestPattern) { trigger = this.createTriggerFromTemplate(bestPattern.suggestedTriggers[0]); confidence = 0.75; reasoning = `Common pattern for ${process.persona} persona: ${bestPattern.suggestedTriggers[0].applicableWhen}`; } } if (!trigger) { // Default to manual trigger trigger = this.createManualTrigger(); confidence = 0.5; reasoning = 'No clear pattern detected, manual trigger provides maximum flexibility'; } return { trigger: { ...trigger, aiSuggested: true, reasoning }, confidence, reasoning, alternatives: [] }; } async generateAlternatives(process, analysis, primarySuggestion) { const alternatives = []; // Add persona-specific alternatives if (process.persona) { const personaPatterns = this.patterns.get(process.persona) || []; for (const pattern of personaPatterns) { for (let i = 1; i < pattern.suggestedTriggers.length; i++) { const template = pattern.suggestedTriggers[i]; if (!primarySuggestion || template.type !== primarySuggestion.trigger.type) { const trigger = this.createTriggerFromTemplate(template); alternatives.push({ trigger: { ...trigger, aiSuggested: true }, confidence: 0.75, reasoning: template.applicableWhen || 'Based on persona-specific patterns', alternatives: [] }); } } } } // Event-based alternative for processes that might react to changes if (analysis.hasExternalCalls || analysis.isDataProcessing) { const eventTrigger = this.createEventTrigger('Data Change Event', 'data.updated', 'system'); alternatives.push({ trigger: { ...eventTrigger, aiSuggested: true }, confidence: 0.7, reasoning: 'Trigger immediately when relevant data changes for real-time processing', alternatives: [] }); } // Scheduled batch alternative if (!primarySuggestion || primarySuggestion.trigger.type !== 'schedule') { const batchSchedule = this.determineBatchSchedule(analysis); const scheduleTrigger = this.createScheduleTrigger('Batch Processing', batchSchedule.cron, batchSchedule.timezone); alternatives.push({ trigger: { ...scheduleTrigger, aiSuggested: true }, confidence: 0.65, reasoning: `Batch processing ${batchSchedule.description} for efficiency`, alternatives: [] }); } // Manual with reminder if (analysis.hasHumanInteraction) { const manualTrigger = this.createManualTrigger('Manual with Reminder'); alternatives.push({ trigger: { ...manualTrigger, aiSuggested: true }, confidence: 0.6, reasoning: 'Human-centric processes benefit from manual triggers with email reminders', alternatives: [] }); } return alternatives; } async detectConflicts(trigger) { const conflicts = []; if (trigger.type === 'schedule' && trigger.config.cron) { // Get all processes with schedule triggers const processes = await this.store.getAllProcesses(); for (const process of processes) { for (const existingTrigger of process.triggers) { if (existingTrigger.type === 'schedule' && existingTrigger.config.cron && this.hasScheduleOverlap(trigger.config.cron, existingTrigger.config.cron)) { conflicts.push({ processId: process.id, processName: process.name, triggerName: existingTrigger.name, conflictType: 'time', description: `Both processes scheduled at similar times`, suggestion: 'Consider offsetting schedules by 30 minutes' }); } } } } return conflicts; } hasScheduleOverlap(cron1, cron2) { // Simplified overlap detection // In a real implementation, use a cron parser return cron1 === cron2; } determineReportSchedule(processName) { const nameLower = processName.toLowerCase(); if (nameLower.includes('daily')) { return { cron: '0 8 * * *', timezone: 'UTC', description: 'daily' }; } else if (nameLower.includes('weekly')) { return { cron: '0 8 * * 1', timezone: 'UTC', description: 'weekly (Monday mornings)' }; } else if (nameLower.includes('monthly')) { return { cron: '0 8 1 * *', timezone: 'UTC', description: 'monthly (first day of month)' }; } // Default to weekly return { cron: '0 8 * * 5', timezone: 'UTC', description: 'weekly (Friday mornings)' }; } determineBatchSchedule(analysis) { if (analysis.estimatedDuration > 3600000) { // > 1 hour return { cron: '0 2 * * *', timezone: 'UTC', description: 'nightly at 2 AM when system load is low' }; } else if (analysis.hasExternalCalls) { return { cron: '0 */4 * * *', timezone: 'UTC', description: 'every 4 hours to balance freshness and API limits' }; } return { cron: '0 */2 * * *', timezone: 'UTC', description: 'every 2 hours for regular updates' }; } findBestPattern(patterns, analysis) { // Find pattern with most matching activity types let bestPattern = null; let bestScore = 0; for (const pattern of patterns) { let score = 0; for (const activityType of pattern.activityTypes) { if (analysis.types.has(activityType)) { score++; } } if (score > bestScore) { bestScore = score; bestPattern = pattern; } } return bestPattern; } createScheduleTrigger(name, cron, timezone) { return { id: this.generateId(), type: 'schedule', name, enabled: true, config: { cron, timezone } }; } createEventTrigger(name, event, source) { return { id: this.generateId(), type: 'event', name, enabled: true, config: { event, source } }; } createManualTrigger(name = 'Manual Trigger') { return { id: this.generateId(), type: 'manual', name, enabled: true, config: {} }; } createTriggerFromTemplate(template) { return { id: this.generateId(), type: template.type, name: template.name, enabled: true, config: template.defaultConfig }; } generateId() { return `trigger-${Date.now()}-${Math.random().toString(36).substring(2, 11)}`; } initializePatterns() { // Software Engineer patterns this.patterns.set('software-engineer', [ { persona: 'software-engineer', activityTypes: ['tool', 'agent'], suggestedTriggers: [ { type: 'schedule', name: 'Daily Development Routine', defaultConfig: { cron: '0 9 * * 1-5', timezone: 'local' }, applicableWhen: 'Daily development tasks like checking CI/CD, reviewing PRs' }, { type: 'event', name: 'On Code Push', defaultConfig: { event: 'git.push', source: 'repository' }, applicableWhen: 'Automated checks and workflows triggered by code changes' } ] } ]); // CTO patterns this.patterns.set('cto', [ { persona: 'cto', activityTypes: ['tool', 'human'], suggestedTriggers: [ { type: 'schedule', name: 'Weekly Technical Review', defaultConfig: { cron: '0 10 * * 1', timezone: 'local' }, applicableWhen: 'Weekly review of technical metrics and team performance' } ] } ]); // CEO patterns this.patterns.set('ceo', [ { persona: 'ceo', activityTypes: ['tool', 'human', 'external'], suggestedTriggers: [ { type: 'schedule', name: 'Monthly Business Review', defaultConfig: { cron: '0 9 1 * *', timezone: 'local' }, applicableWhen: 'Monthly business metrics and strategic planning' } ] } ]); // Add more persona patterns as needed } } //# sourceMappingURL=trigger-suggestion-engine.js.map