@boundless-oss/atlas
Version:
Atlas - MCP Server for comprehensive startup project management
373 lines • 14.9 kB
JavaScript
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