@gork-labs/secondbrain-mcp
Version:
Second Brain MCP Server - Agent team orchestration with dynamic tool discovery
276 lines (275 loc) • 10.4 kB
JavaScript
import { AnalyticsStorage } from './storage.js';
import { QualityAnalyzer } from './quality-analyzer.js';
import { MetricsCollector } from './metrics-collector.js';
import { logger } from '../utils/logger.js';
/**
* Analytics Manager
* Central coordinator for all analytics and intelligence features
*/
export class AnalyticsManager {
storage;
qualityAnalyzer;
metricsCollector;
initialized = false;
constructor(analyticsConfig) {
this.storage = new AnalyticsStorage();
this.qualityAnalyzer = new QualityAnalyzer(this.storage, analyticsConfig);
this.metricsCollector = new MetricsCollector(this.storage);
this.initialized = true;
logger.info('Analytics Manager initialized', {
storageLocation: this.storage.getStorageHealth().storageLocation,
intelligenceEnabled: analyticsConfig?.intelligence?.enablePredictiveScoring ?? true
});
}
/**
* Record a complete validation event for analytics
*/
recordValidationEvent(assessment, context, sessionId, operationId) {
if (!this.initialized) {
logger.warn('Analytics Manager not initialized - skipping event recording');
return;
}
try {
// Record quality assessment
this.qualityAnalyzer.recordQualityAssessment(assessment, context, sessionId);
// Record usage metric
this.metricsCollector.recordUsage(context.subagent, sessionId || 'unknown', 'validation', assessment.passed, {
taskType: context.taskType,
complexity: this.determineTaskComplexity(context)
});
// End performance timing if operation ID provided
if (operationId) {
this.metricsCollector.endOperation(operationId, 'quality_validation', true, undefined, {
requestSize: JSON.stringify(context).length,
responseSize: JSON.stringify(assessment).length
});
}
logger.debug('Recorded validation event for analytics', {
subagent: context.subagent,
score: assessment.overallScore,
passed: assessment.passed,
sessionId,
operationId
});
}
catch (error) {
logger.error('Failed to record validation event', {
error: error instanceof Error ? error.message : String(error),
subagent: context.subagent,
sessionId
});
}
}
determineTaskComplexity(context) {
const requirements = context.requirements || '';
const criteria = context.qualityCriteria || '';
const totalLength = requirements.length + criteria.length;
const complexityWords = ['comprehensive', 'detailed', 'complex', 'multiple', 'advanced', 'sophisticated'];
const hasComplexityWords = complexityWords.some(word => requirements.toLowerCase().includes(word) || criteria.toLowerCase().includes(word));
if (totalLength > 500 || hasComplexityWords) {
return 'high';
}
else if (totalLength > 200) {
return 'medium';
}
else {
return 'low';
}
}
/**
* Start timing an operation for performance analytics
*/
startTiming(operationId, operation) {
this.metricsCollector.startOperation(operationId, operation);
}
/**
* End timing an operation and record results
*/
endTiming(operationId, operation, success, errorType) {
return this.metricsCollector.endOperation(operationId, operation, success, errorType);
}
/**
* Record a refinement event
*/
recordRefinementEvent(sessionId, chatmode, originalScore, improvedScore, successful) {
try {
// Record usage for refinement
this.metricsCollector.recordUsage(chatmode, sessionId, 'refinement', successful, {
taskType: 'quality_improvement'
});
logger.debug('Recorded refinement event', {
sessionId,
chatmode,
originalScore,
improvedScore,
improvement: improvedScore - originalScore,
successful
});
}
catch (error) {
logger.error('Failed to record refinement event', {
error: error instanceof Error ? error.message : String(error),
sessionId,
chatmode
});
}
}
/**
* Get quality trends for dashboard/reporting
*/
getQualityTrends(chatmode, days = 7) {
return this.qualityAnalyzer.analyzeQualityTrends(chatmode, days);
}
/**
* Get quality insights for proactive management
*/
getQualityInsights(chatmode) {
return this.qualityAnalyzer.generateQualityInsights(chatmode);
}
/**
* Get performance insights for optimization
*/
getPerformanceInsights(operation, days = 7) {
if (operation) {
return this.metricsCollector.analyzeOperationPerformance(operation, days);
}
else {
return this.metricsCollector.getPerformanceSummary(days);
}
}
/**
* Get usage patterns for understanding user behavior
*/
getUsagePatterns(chatmode, days = 7) {
return this.metricsCollector.analyzeUsagePatterns(chatmode, days);
}
/**
* Get current system health status
*/
getSystemHealth() {
return this.metricsCollector.getSystemHealth();
}
/**
* Compare performance across chatmodes
*/
compareSubagentPerformance() {
return this.qualityAnalyzer.compareSubagentPerformance();
}
/**
* Predict quality score for context (if intelligence enabled)
*/
predictQualityScore(context) {
return this.qualityAnalyzer.predictQualityScore(context);
}
/**
* Get adaptive quality threshold (if intelligence enabled)
*/
getAdaptiveQualityThreshold(subagent) {
return this.qualityAnalyzer.getAdaptiveQualityThreshold(subagent);
}
/**
* Generate comprehensive analytics report
*/
generateAnalyticsReport(days = 30) {
try {
const qualityReport = this.qualityAnalyzer.generateQualityReport(days);
const performanceReport = this.metricsCollector.getPerformanceSummary(days);
const usageReport = this.metricsCollector.analyzeUsagePatterns(undefined, days);
const systemStatus = this.metricsCollector.getSystemHealth();
// Generate executive summary
const totalValidations = qualityReport.overview.totalValidations;
const avgQualityScore = qualityReport.overview.scoreAverage;
const successRate = qualityReport.overview.successRate;
const keyInsights = [
`Processed ${totalValidations} validations with ${(avgQualityScore || 0).toFixed(1)} average quality score`,
`${(successRate * 100).toFixed(1)}% validation success rate`,
`System health: ${systemStatus.status}`,
...qualityReport.insights.slice(0, 2).map(insight => insight.title)
];
return {
executiveSummary: {
totalValidations,
avgQualityScore: avgQualityScore || 0,
successRate,
systemHealth: systemStatus.status,
keyInsights
},
qualityReport,
performanceReport,
usageReport,
systemStatus,
generatedAt: new Date().toISOString()
};
}
catch (error) {
logger.error('Failed to generate analytics report', {
error: error instanceof Error ? error.message : String(error)
});
// Return minimal report on error
return {
executiveSummary: {
totalValidations: 0,
avgQualityScore: 0,
successRate: 0,
systemHealth: 'unknown',
keyInsights: ['Error generating report - check logs for details']
},
qualityReport: {
overview: {
subagent: 'overall',
timeRange: `${days} days`,
scoreAverage: 0,
scoreTrend: 'stable',
successRate: 0,
refinementRate: 0,
totalValidations: 0,
insights: ['Error loading data'],
recommendations: ['Check system health']
},
subagentBreakdown: {},
insights: [],
recommendations: ['Error generating report - check system status']
},
performanceReport: {},
usageReport: [],
systemStatus: this.metricsCollector.getSystemHealth(),
generatedAt: new Date().toISOString()
};
}
}
/**
* Export all analytics data for external analysis
*/
exportAnalyticsData() {
const analyticsData = this.storage.getAnalyticsData();
const metricsExport = this.metricsCollector.exportMetrics();
return {
qualityData: analyticsData.qualityMetrics,
performanceData: metricsExport.performance,
usageData: metricsExport.usage,
metadata: {
exportedAt: new Date().toISOString(),
dataRange: analyticsData.lastUpdated,
totalRecords: analyticsData.totalRecords
}
};
}
/**
* Clear all analytics data (for testing or reset)
*/
clearAnalyticsData() {
this.storage.clearAnalytics();
logger.info('Cleared all analytics data');
}
/**
* Get analytics configuration and status
*/
getAnalyticsStatus() {
return {
initialized: this.initialized,
storageHealth: this.storage.getStorageHealth(),
configStatus: 'active',
lastActivity: new Date().toISOString()
};
}
}