UNPKG

recoder-analytics

Version:

Comprehensive analytics and monitoring for the Recoder.xyz ecosystem

774 lines 32.4 kB
"use strict"; /** * Advanced Cost Monitor with Real-time Tracking & Predictions * * Comprehensive cost monitoring system with user attribution, predictive analytics, * and real-time budget enforcement for AI model usage optimization. */ Object.defineProperty(exports, "__esModule", { value: true }); exports.advancedCostMonitor = exports.AdvancedCostMonitor = void 0; const shared_1 = require("@recoder/shared"); const events_1 = require("events"); class AdvancedCostMonitor extends events_1.EventEmitter { constructor() { super(); this.costEvents = new Map(); // By user this.userProfiles = new Map(); this.projectCosts = new Map(); this.anomalies = new Map(); this.modelPricing = new Map(); this.config = { maxEventsPerUser: 10000, // Maximum events to store per user anomalyDetectionWindow: 3600000, // 1 hour window for anomaly detection anomalyThreshold: 2.0, // Standard deviations for anomaly profileUpdateInterval: 300000, // 5 minutes forecastingWindow: 30, // Days for forecasting qualityWeightInEfficiency: 0.4, // Weight of quality in efficiency calculation }; this.profileUpdateTimer = null; this.isRunning = false; this.initializePricing(); } initializePricing() { // Initialize with current model pricing this.modelPricing.set('claude-sonnet-4', { input: 0.000003, output: 0.000015, lastUpdated: new Date() }); this.modelPricing.set('claude-haiku-3', { input: 0.00000025, output: 0.00000125, lastUpdated: new Date() }); this.modelPricing.set('gpt-4-turbo', { input: 0.00001, output: 0.00003, lastUpdated: new Date() }); this.modelPricing.set('gpt-4o', { input: 0.000005, output: 0.000015, lastUpdated: new Date() }); this.modelPricing.set('gemini-2.5-pro', { input: 0.00000125, output: 0.000005, lastUpdated: new Date() }); this.modelPricing.set('deepseek-v3', { input: 0.00000027, output: 0.0000011, lastUpdated: new Date() }); shared_1.Logger.info(`Initialized pricing for ${this.modelPricing.size} models`); } /** * Start advanced cost monitoring */ async start() { if (this.isRunning) { shared_1.Logger.warn('Advanced cost monitor is already running'); return; } shared_1.Logger.info('Starting advanced cost monitoring...'); // Start profile updates this.profileUpdateTimer = setInterval(() => { this.updateUserProfiles(); this.detectAnomalies(); }, this.config.profileUpdateInterval); this.isRunning = true; this.emit('monitoringStarted'); shared_1.Logger.info('Advanced cost monitoring started successfully'); } /** * Stop advanced cost monitoring */ async stop() { if (!this.isRunning) { return; } shared_1.Logger.info('Stopping advanced cost monitoring...'); if (this.profileUpdateTimer) { clearInterval(this.profileUpdateTimer); this.profileUpdateTimer = null; } this.isRunning = false; this.emit('monitoringStopped'); shared_1.Logger.info('Advanced cost monitoring stopped'); } /** * Track usage with comprehensive attribution */ async trackUsage(userId, modelName, inputTokens, outputTokens, options) { const pricing = this.modelPricing.get(modelName); if (!pricing) { shared_1.Logger.warn(`No pricing data for model: ${modelName}`); return { cost: 0, efficiency: 0 }; } const inputCost = inputTokens * pricing.input; const outputCost = outputTokens * pricing.output; const totalCost = inputCost + outputCost; const costEvent = { id: `cost_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`, timestamp: new Date(), userId, projectId: options.projectId, modelName, provider: this.getProviderFromModel(modelName), taskType: options.taskType, inputTokens, outputTokens, totalTokens: inputTokens + outputTokens, inputCost, outputCost, totalCost, qualityScore: options.qualityScore, latency: options.latency, region: options.region, metadata: { requestId: options.requestId, agentType: options.agentType, promptComplexity: options.promptComplexity, cacheHit: options.cacheHit, retryCount: options.retryCount } }; // Store the event const userEvents = this.costEvents.get(userId) || []; userEvents.push(costEvent); // Maintain event limit per user if (userEvents.length > this.config.maxEventsPerUser) { userEvents.splice(0, userEvents.length - this.config.maxEventsPerUser); } this.costEvents.set(userId, userEvents); // Calculate efficiency const efficiency = this.calculateEfficiency(costEvent); // Real-time anomaly detection for this event await this.checkEventForAnomalies(costEvent); // Emit cost tracking event this.emit('costTracked', { userId, modelName, cost: totalCost, efficiency, event: costEvent }); shared_1.Logger.debug(`Tracked usage: ${userId} - ${modelName} - $${totalCost.toFixed(4)}`); return { cost: totalCost, efficiency }; } /** * Get comprehensive cost metrics */ async getCostMetrics(timeRange = '24h') { const cutoff = this.getTimeRangeCutoff(timeRange); const allEvents = this.getAllEventsInRange(cutoff); if (allEvents.length === 0) { return this.getEmptyCostMetrics(timeRange); } // Calculate basic metrics const totalSpend = allEvents.reduce((sum, event) => sum + event.totalCost, 0); const uniqueUsers = new Set(allEvents.map(e => e.userId)).size; const costPerUser = uniqueUsers > 0 ? totalSpend / uniqueUsers : 0; const totalTokens = allEvents.reduce((sum, event) => sum + event.totalTokens, 0); const costPerToken = totalTokens > 0 ? totalSpend / totalTokens : 0; // Calculate cost breakdowns const costByModel = this.calculateCostByModel(allEvents); const costByUser = this.calculateCostByUser(allEvents); const costByProject = this.calculateCostByProject(allEvents); const costByTaskType = this.calculateCostByTaskType(allEvents); // Calculate trends const trends = await this.calculateCostTrends(timeRange); // Calculate efficiency metrics const efficiency = await this.calculateEfficiencyMetrics(allEvents); // Get current anomalies const anomalies = Array.from(this.anomalies.values()) .filter(a => !a.resolved && Date.now() - a.detectedAt.getTime() < 24 * 60 * 60 * 1000); // Project monthly spending const projectedMonthly = await this.predictMonthlySpend(); // Calculate budget utilization (would need budget data) const budgetUtilization = 0.75; // Placeholder return { totalSpend, costPerUser, costPerToken, projectedMonthly, budgetUtilization, costByModel, costByUser, costByProject, costByTaskType, trends, efficiency, anomalies }; } /** * Predict monthly spending with trend analysis */ async predictMonthlySpend() { const last30Days = this.getAllEventsInRange(new Date(Date.now() - 30 * 24 * 60 * 60 * 1000)); if (last30Days.length === 0) return 0; // Group by day const dailySpend = new Map(); last30Days.forEach(event => { const day = event.timestamp.toDateString(); dailySpend.set(day, (dailySpend.get(day) || 0) + event.totalCost); }); const spendingArray = Array.from(dailySpend.values()); // Simple linear regression for trend const n = spendingArray.length; if (n < 7) { // Not enough data, use average const avgDaily = spendingArray.reduce((sum, val) => sum + val, 0) / n; return avgDaily * 30; // 30 days } // Calculate trend const x = Array.from({ length: n }, (_, i) => i); const sumX = x.reduce((sum, val) => sum + val, 0); const sumY = spendingArray.reduce((sum, val) => sum + val, 0); const sumXY = x.reduce((sum, xi, i) => sum + xi * spendingArray[i], 0); const sumXX = x.reduce((sum, xi) => sum + xi * xi, 0); const slope = (n * sumXY - sumX * sumY) / (n * sumXX - sumX * sumX); const intercept = (sumY - slope * sumX) / n; // Project 30 days from the last data point const lastIndex = n - 1; const projectedDaily = intercept + slope * (lastIndex + 15); // Mid-month projection const projectedMonthly = Math.max(0, projectedDaily * 30); // Add seasonal adjustments (placeholder - would use historical data) const seasonalMultiplier = 1.1; // 10% seasonal increase return projectedMonthly * seasonalMultiplier; } /** * Optimize model selection for cost efficiency */ async optimizeForCost(maxBudget) { const recommendations = []; const recentEvents = this.getAllEventsInRange(new Date(Date.now() - 24 * 60 * 60 * 1000) // Last 24 hours ); // Group by model const modelUsage = new Map(); recentEvents.forEach(event => { const events = modelUsage.get(event.modelName) || []; events.push(event); modelUsage.set(event.modelName, events); }); // Analyze each model for optimization opportunities for (const [modelName, events] of modelUsage) { const totalCost = events.reduce((sum, e) => sum + e.totalCost, 0); const avgQuality = events .filter(e => e.qualityScore !== undefined) .reduce((sum, e, _, arr) => sum + (e.qualityScore / arr.length), 0) || 0.8; // Find cheaper alternatives const alternatives = await this.findCheaperAlternatives(modelName, avgQuality); for (const alt of alternatives) { if (alt.costSavings > 0 && alt.qualityImpact < 0.1) { // Less than 10% quality loss recommendations.push({ currentModel: modelName, recommendedModel: alt.model, costSavings: alt.costSavings * events.length, // Total savings for this usage qualityImpact: alt.qualityImpact, confidence: alt.confidence }); } } } return recommendations.sort((a, b) => b.costSavings - a.costSavings); } /** * Get detailed user spending profile */ async getUserSpendingProfile(userId, timeframe = '30d') { const cached = this.userProfiles.get(userId); if (cached && cached.timeframe === timeframe) { return cached; } const cutoff = this.getTimeRangeCutoff(timeframe); const userEvents = (this.costEvents.get(userId) || []) .filter(event => event.timestamp >= cutoff); if (userEvents.length === 0) { return null; } const profile = await this.buildUserProfile(userId, userEvents, timeframe); this.userProfiles.set(userId, profile); return profile; } /** * Get project cost breakdown */ async getProjectCostBreakdown(projectId, timeframe = '30d') { const cutoff = this.getTimeRangeCutoff(timeframe); const projectEvents = this.getAllEventsInRange(cutoff) .filter(event => event.projectId === projectId); if (projectEvents.length === 0) { return null; } return this.buildProjectBreakdown(projectId, projectEvents, timeframe); } /** * Alert on budget threshold */ async alertOnBudgetThreshold(threshold, timeframe = '24h') { const metrics = await this.getCostMetrics(timeframe); if (metrics.totalSpend >= threshold) { const alert = { type: 'budget_threshold', severity: 'high', message: `Budget threshold of $${threshold} exceeded. Current spend: $${metrics.totalSpend.toFixed(2)}`, timeframe, currentSpend: metrics.totalSpend, threshold, overage: metrics.totalSpend - threshold }; this.emit('budgetAlert', alert); shared_1.Logger.warn(`Budget threshold alert: $${metrics.totalSpend.toFixed(2)} >= $${threshold}`); } } // Private helper methods calculateEfficiency(event) { const baseEfficiency = event.totalTokens / event.totalCost; // tokens per dollar // Adjust for quality if available if (event.qualityScore) { const qualityWeight = this.config.qualityWeightInEfficiency; return baseEfficiency * (1 + qualityWeight * (event.qualityScore - 0.5)); } return baseEfficiency; } async checkEventForAnomalies(event) { // Check for unusually high cost per request const userEvents = this.costEvents.get(event.userId) || []; const recentEvents = userEvents.filter(e => Date.now() - e.timestamp.getTime() < this.config.anomalyDetectionWindow); if (recentEvents.length < 10) return; // Need baseline data const costs = recentEvents.map(e => e.totalCost); const mean = costs.reduce((sum, cost) => sum + cost, 0) / costs.length; const variance = costs.reduce((sum, cost) => sum + Math.pow(cost - mean, 2), 0) / costs.length; const stdDev = Math.sqrt(variance); const deviation = Math.abs(event.totalCost - mean) / stdDev; if (deviation > this.config.anomalyThreshold) { const anomaly = { id: `anomaly_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`, type: event.totalCost > mean * 2 ? 'spike' : 'unusual_pattern', severity: deviation > 4 ? 'critical' : deviation > 3 ? 'high' : 'medium', description: `Unusual cost detected for user ${event.userId}: $${event.totalCost.toFixed(4)} (${deviation.toFixed(1)}σ from normal)`, detectedAt: new Date(), affectedEntity: { type: 'user', id: event.userId }, metrics: { currentValue: event.totalCost, expectedValue: mean, deviation: deviation, confidence: Math.min(0.99, deviation / 5) }, impact: { costImpact: event.totalCost - mean, timeframe: '5m', affectedRequests: 1 }, recommendations: [ 'Review request parameters and input size', 'Check for model selection appropriateness', 'Investigate potential prompt injection or misuse' ], resolved: false }; this.anomalies.set(anomaly.id, anomaly); this.emit('anomalyDetected', anomaly); } } getTimeRangeCutoff(timeRange) { const now = new Date(); const match = timeRange.match(/^(\d+)([mhd])$/); if (!match) return new Date(now.getTime() - 24 * 60 * 60 * 1000); // Default 24h const value = parseInt(match[1]); const unit = match[2]; let milliseconds = 0; switch (unit) { case 'm': milliseconds = value * 60 * 1000; break; case 'h': milliseconds = value * 60 * 60 * 1000; break; case 'd': milliseconds = value * 24 * 60 * 60 * 1000; break; } return new Date(now.getTime() - milliseconds); } getAllEventsInRange(cutoff) { const allEvents = []; for (const events of this.costEvents.values()) { allEvents.push(...events.filter(event => event.timestamp >= cutoff)); } return allEvents.sort((a, b) => a.timestamp.getTime() - b.timestamp.getTime()); } calculateCostByModel(events) { const costs = {}; events.forEach(event => { costs[event.modelName] = (costs[event.modelName] || 0) + event.totalCost; }); return costs; } calculateCostByUser(events) { const costs = {}; events.forEach(event => { costs[event.userId] = (costs[event.userId] || 0) + event.totalCost; }); return costs; } calculateCostByProject(events) { const costs = {}; events.forEach(event => { if (event.projectId) { costs[event.projectId] = (costs[event.projectId] || 0) + event.totalCost; } }); return costs; } calculateCostByTaskType(events) { const costs = {}; events.forEach(event => { costs[event.taskType] = (costs[event.taskType] || 0) + event.totalCost; }); return costs; } async calculateCostTrends(timeRange) { // Get last 30 days for daily trend const last30Days = this.getAllEventsInRange(new Date(Date.now() - 30 * 24 * 60 * 60 * 1000)); const dailyTrend = new Array(30).fill(0); last30Days.forEach(event => { const daysAgo = Math.floor((Date.now() - event.timestamp.getTime()) / (24 * 60 * 60 * 1000)); if (daysAgo < 30) { dailyTrend[29 - daysAgo] += event.totalCost; } }); // Get last 24 hours for hourly trend const last24Hours = this.getAllEventsInRange(new Date(Date.now() - 24 * 60 * 60 * 1000)); const hourlyTrend = new Array(24).fill(0); last24Hours.forEach(event => { const hoursAgo = Math.floor((Date.now() - event.timestamp.getTime()) / (60 * 60 * 1000)); if (hoursAgo < 24) { hourlyTrend[23 - hoursAgo] += event.totalCost; } }); // Get last 12 weeks for weekly trend const last12Weeks = this.getAllEventsInRange(new Date(Date.now() - 12 * 7 * 24 * 60 * 60 * 1000)); const weeklyTrend = new Array(12).fill(0); last12Weeks.forEach(event => { const weeksAgo = Math.floor((Date.now() - event.timestamp.getTime()) / (7 * 24 * 60 * 60 * 1000)); if (weeksAgo < 12) { weeklyTrend[11 - weeksAgo] += event.totalCost; } }); return { daily: dailyTrend, hourly: hourlyTrend, weekly: weeklyTrend }; } async calculateEfficiencyMetrics(events) { const qualityEvents = events.filter(e => e.qualityScore !== undefined); const avgQuality = qualityEvents.length > 0 ? qualityEvents.reduce((sum, e) => sum + e.qualityScore, 0) / qualityEvents.length : 0.8; const totalCost = events.reduce((sum, e) => sum + e.totalCost, 0); const costPerQualityPoint = totalCost / (avgQuality * events.length); const avgTokensPerRequest = events.length > 0 ? events.reduce((sum, e) => sum + e.totalTokens, 0) / events.length : 0; // Calculate model efficiency ranking const modelStats = new Map(); events.forEach(event => { const existing = modelStats.get(event.modelName) || { cost: 0, quality: 0, usage: 0 }; existing.cost += event.totalCost; existing.quality += event.qualityScore || 0.8; existing.usage += 1; modelStats.set(event.modelName, existing); }); const modelEfficiencyRanking = Array.from(modelStats.entries()) .map(([model, stats]) => ({ model, costEfficiency: stats.cost / (stats.quality / stats.usage), // Lower is better qualityScore: stats.quality / stats.usage, usage: stats.usage })) .sort((a, b) => a.costEfficiency - b.costEfficiency); return { costPerQualityPoint, avgTokensPerRequest, modelEfficiencyRanking }; } getEmptyCostMetrics(timeRange) { return { totalSpend: 0, costPerUser: 0, costPerToken: 0, projectedMonthly: 0, budgetUtilization: 0, costByModel: {}, costByUser: {}, costByProject: {}, costByTaskType: {}, trends: { daily: new Array(30).fill(0), hourly: new Array(24).fill(0), weekly: new Array(12).fill(0) }, efficiency: { costPerQualityPoint: 0, avgTokensPerRequest: 0, modelEfficiencyRanking: [] }, anomalies: [] }; } async findCheaperAlternatives(modelName, targetQuality) { const alternatives = []; const currentPricing = this.modelPricing.get(modelName); if (!currentPricing) return alternatives; const currentAvgCost = (currentPricing.input + currentPricing.output) / 2; for (const [altModel, altPricing] of this.modelPricing) { if (altModel === modelName) continue; const altAvgCost = (altPricing.input + altPricing.output) / 2; const costSavings = currentAvgCost - altAvgCost; if (costSavings > 0) { // Estimate quality impact (this would use actual quality data in production) const qualityImpact = this.estimateQualityImpact(modelName, altModel); const confidence = this.calculateAlternativeConfidence(modelName, altModel); alternatives.push({ model: altModel, costSavings, qualityImpact, confidence }); } } return alternatives.sort((a, b) => b.costSavings - a.costSavings); } estimateQualityImpact(currentModel, alternativeModel) { // Simplified quality impact estimation const qualityTiers = new Map([ ['claude-sonnet-4', 5], ['gpt-4-turbo', 5], ['gpt-4o', 4.5], ['gemini-2.5-pro', 4], ['claude-haiku-3', 3.5], ['deepseek-v3', 4.5], // High for coding tasks ]); const currentTier = qualityTiers.get(currentModel) || 3; const altTier = qualityTiers.get(alternativeModel) || 3; return Math.max(0, (currentTier - altTier) / currentTier); } calculateAlternativeConfidence(currentModel, alternativeModel) { // Confidence based on usage patterns and model characteristics const confidenceMap = new Map([ ['claude-sonnet-4_claude-haiku-3', 0.8], ['gpt-4-turbo_gpt-4o', 0.9], ['claude-sonnet-4_deepseek-v3', 0.7], // For coding tasks ]); const key = `${currentModel}_${alternativeModel}`; return confidenceMap.get(key) || 0.6; } async buildUserProfile(userId, events, timeframe) { const totalSpend = events.reduce((sum, e) => sum + e.totalCost, 0); const requestCount = events.length; const averageRequestCost = requestCount > 0 ? totalSpend / requestCount : 0; // Favorite models const modelUsage = new Map(); events.forEach(event => { const existing = modelUsage.get(event.modelName) || { usage: 0, cost: 0 }; existing.usage += 1; existing.cost += event.totalCost; modelUsage.set(event.modelName, existing); }); const favoriteModels = Array.from(modelUsage.entries()) .map(([model, stats]) => ({ model, ...stats })) .sort((a, b) => b.usage - a.usage) .slice(0, 5); // Spending patterns const hourlyUsage = new Array(24).fill(0); const dailyUsage = new Array(7).fill(0); events.forEach(event => { hourlyUsage[event.timestamp.getHours()]++; dailyUsage[event.timestamp.getDay()]++; }); const peakHours = hourlyUsage .map((count, hour) => ({ hour, count })) .sort((a, b) => b.count - a.count) .slice(0, 3) .map(item => item.hour); const peakDays = dailyUsage .map((count, day) => ({ day, count })) .sort((a, b) => b.count - a.count) .slice(0, 2) .map(item => item.day); // Efficiency metrics const qualityEvents = events.filter(e => e.qualityScore !== undefined); const avgQuality = qualityEvents.length > 0 ? qualityEvents.reduce((sum, e) => sum + e.qualityScore, 0) / qualityEvents.length : 0.8; const costPerQualityPoint = totalSpend / (avgQuality * requestCount); const tokensPerDollar = totalSpend > 0 ? events.reduce((sum, e) => sum + e.totalTokens, 0) / totalSpend : 0; const avgLatency = events.reduce((sum, e) => sum + e.latency, 0) / requestCount; return { userId, timeframe, totalSpend, averageRequestCost, requestCount, favoriteModels, spendingPattern: { peakHours, peakDays, seasonality: 'stable' // Would analyze historical data }, efficiency: { costPerQualityPoint, tokensPerDollar, avgLatency }, alerts: { budgetWarnings: 0, // Would track from budget system anomalies: Array.from(this.anomalies.values()) .filter(a => a.affectedEntity.id === userId && !a.resolved).length, lastAlertDate: undefined } }; } async buildProjectBreakdown(projectId, events, timeframe) { const totalCost = events.reduce((sum, e) => sum + e.totalCost, 0); // Model breakdown const modelBreakdown = {}; events.forEach(event => { if (!modelBreakdown[event.modelName]) { modelBreakdown[event.modelName] = { cost: 0, requests: 0, tokens: 0, avgCostPerRequest: 0 }; } const model = modelBreakdown[event.modelName]; model.cost += event.totalCost; model.requests += 1; model.tokens += event.totalTokens; model.avgCostPerRequest = model.cost / model.requests; }); // User breakdown const userCosts = new Map(); events.forEach(event => { const existing = userCosts.get(event.userId) || { cost: 0, requests: 0 }; existing.cost += event.totalCost; existing.requests += 1; userCosts.set(event.userId, existing); }); const userBreakdown = {}; userCosts.forEach((stats, userId) => { userBreakdown[userId] = { ...stats, percentage: (stats.cost / totalCost) * 100 }; }); // Task breakdown const taskBreakdown = {}; events.forEach(event => { if (!taskBreakdown[event.taskType]) { taskBreakdown[event.taskType] = { cost: 0, requests: 0, avgCost: 0 }; } const task = taskBreakdown[event.taskType]; task.cost += event.totalCost; task.requests += 1; task.avgCost = task.cost / task.requests; }); // Daily spending trend const dailySpend = new Array(30).fill(0); events.forEach(event => { const daysAgo = Math.floor((Date.now() - event.timestamp.getTime()) / (24 * 60 * 60 * 1000)); if (daysAgo < 30) { dailySpend[29 - daysAgo] += event.totalCost; } }); return { projectId, timeframe, totalCost, modelBreakdown, userBreakdown, taskBreakdown, trends: { dailySpend, growth: 0, // Would calculate from historical data forecast: totalCost * 1.1 // Simple 10% growth projection } }; } async updateUserProfiles() { // Update profiles for active users for (const [userId] of this.costEvents) { await this.getUserSpendingProfile(userId, '30d'); } } async detectAnomalies() { // System-wide anomaly detection const recentEvents = this.getAllEventsInRange(new Date(Date.now() - this.config.anomalyDetectionWindow)); // Detect spending spikes await this.detectSpendingSpikes(recentEvents); // Detect unusual model usage patterns await this.detectModelUsageAnomalies(recentEvents); // Detect user behavior anomalies await this.detectUserBehaviorAnomalies(recentEvents); } async detectSpendingSpikes(events) { // Implementation for system-wide spending spike detection const totalSpend = events.reduce((sum, e) => sum + e.totalCost, 0); const hourlySpend = totalSpend / (this.config.anomalyDetectionWindow / 3600000); // Would compare against historical hourly spend patterns shared_1.Logger.debug(`Current hourly spend rate: $${hourlySpend.toFixed(4)}`); } async detectModelUsageAnomalies(events) { // Implementation for model usage anomaly detection const modelUsage = new Map(); events.forEach(event => { modelUsage.set(event.modelName, (modelUsage.get(event.modelName) || 0) + 1); }); shared_1.Logger.debug(`Model usage distribution:`, Object.fromEntries(modelUsage)); } async detectUserBehaviorAnomalies(events) { // Implementation for user behavior anomaly detection const userActivity = new Map(); events.forEach(event => { userActivity.set(event.userId, (userActivity.get(event.userId) || 0) + event.totalCost); }); // Find users with unusually high activity const sortedUsers = Array.from(userActivity.entries()) .sort((a, b) => b[1] - a[1]); if (sortedUsers.length > 0) { const topUser = sortedUsers[0]; const totalSystemSpend = events.reduce((sum, e) => sum + e.totalCost, 0); if (topUser[1] / totalSystemSpend > 0.5) { // Single user > 50% of spend shared_1.Logger.debug(`High-spend user detected: ${topUser[0]} ($${topUser[1].toFixed(4)})`); } } } getProviderFromModel(modelName) { if (modelName.includes('claude')) return 'anthropic'; if (modelName.includes('gpt')) return 'openai'; if (modelName.includes('gemini')) return 'google'; if (modelName.includes('mistral')) return 'mistral'; if (modelName.includes('deepseek')) return 'deepseek'; if (modelName.includes('llama')) return 'ollama'; return 'unknown'; } } exports.AdvancedCostMonitor = AdvancedCostMonitor; // Export singleton instance exports.advancedCostMonitor = new AdvancedCostMonitor(); //# sourceMappingURL=advanced-cost-monitor.js.map