@loxia-labs/loxia-autopilot-one 1.0.1 → 1.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +44 -54
- package/bin/cli.js +1 -115
- package/bin/loxia-terminal-v2.js +3 -0
- package/bin/loxia-terminal.js +3 -0
- package/bin/start-with-terminal.js +3 -0
- package/package.json +14 -15
- package/scripts/install-scanners.js +1 -235
- package/src/analyzers/CSSAnalyzer.js +1 -297
- package/src/analyzers/ConfigValidator.js +1 -690
- package/src/analyzers/ESLintAnalyzer.js +1 -320
- package/src/analyzers/JavaScriptAnalyzer.js +1 -261
- package/src/analyzers/PrettierFormatter.js +1 -247
- package/src/analyzers/PythonAnalyzer.js +1 -266
- package/src/analyzers/SecurityAnalyzer.js +1 -729
- package/src/analyzers/TypeScriptAnalyzer.js +1 -247
- package/src/analyzers/codeCloneDetector/analyzer.js +1 -344
- package/src/analyzers/codeCloneDetector/detector.js +1 -203
- package/src/analyzers/codeCloneDetector/index.js +1 -160
- package/src/analyzers/codeCloneDetector/parser.js +1 -199
- package/src/analyzers/codeCloneDetector/reporter.js +1 -148
- package/src/analyzers/codeCloneDetector/scanner.js +1 -59
- package/src/core/agentPool.js +1 -1474
- package/src/core/agentScheduler.js +1 -2147
- package/src/core/contextManager.js +1 -709
- package/src/core/messageProcessor.js +1 -732
- package/src/core/orchestrator.js +1 -548
- package/src/core/stateManager.js +1 -877
- package/src/index.js +1 -631
- package/src/interfaces/cli.js +1 -549
- package/src/interfaces/terminal/__tests__/smoke/advancedFeatures.test.js +1 -0
- package/src/interfaces/terminal/__tests__/smoke/agentControl.test.js +1 -0
- package/src/interfaces/terminal/__tests__/smoke/agents.test.js +1 -0
- package/src/interfaces/terminal/__tests__/smoke/components.test.js +1 -0
- package/src/interfaces/terminal/__tests__/smoke/connection.test.js +1 -0
- package/src/interfaces/terminal/__tests__/smoke/enhancements.test.js +1 -0
- package/src/interfaces/terminal/__tests__/smoke/imports.test.js +1 -0
- package/src/interfaces/terminal/__tests__/smoke/messages.test.js +1 -0
- package/src/interfaces/terminal/__tests__/smoke/tools.test.js +1 -0
- package/src/interfaces/terminal/api/apiClient.js +1 -0
- package/src/interfaces/terminal/api/messageRouter.js +1 -0
- package/src/interfaces/terminal/api/session.js +1 -0
- package/src/interfaces/terminal/api/websocket.js +1 -0
- package/src/interfaces/terminal/components/AgentCreator.js +1 -0
- package/src/interfaces/terminal/components/AgentEditor.js +1 -0
- package/src/interfaces/terminal/components/AgentSwitcher.js +1 -0
- package/src/interfaces/terminal/components/ErrorBoundary.js +1 -0
- package/src/interfaces/terminal/components/ErrorPanel.js +1 -0
- package/src/interfaces/terminal/components/Header.js +1 -0
- package/src/interfaces/terminal/components/HelpPanel.js +1 -0
- package/src/interfaces/terminal/components/InputBox.js +1 -0
- package/src/interfaces/terminal/components/Layout.js +1 -0
- package/src/interfaces/terminal/components/LoadingSpinner.js +1 -0
- package/src/interfaces/terminal/components/MessageList.js +1 -0
- package/src/interfaces/terminal/components/MultilineTextInput.js +1 -0
- package/src/interfaces/terminal/components/SearchPanel.js +1 -0
- package/src/interfaces/terminal/components/SettingsPanel.js +1 -0
- package/src/interfaces/terminal/components/StatusBar.js +1 -0
- package/src/interfaces/terminal/components/TextInput.js +1 -0
- package/src/interfaces/terminal/config/agentEditorConstants.js +1 -0
- package/src/interfaces/terminal/config/constants.js +1 -0
- package/src/interfaces/terminal/index.js +1 -0
- package/src/interfaces/terminal/state/useAgentControl.js +1 -0
- package/src/interfaces/terminal/state/useAgents.js +1 -0
- package/src/interfaces/terminal/state/useConnection.js +1 -0
- package/src/interfaces/terminal/state/useMessages.js +1 -0
- package/src/interfaces/terminal/state/useTools.js +1 -0
- package/src/interfaces/terminal/utils/debugLogger.js +1 -0
- package/src/interfaces/terminal/utils/settingsStorage.js +1 -0
- package/src/interfaces/terminal/utils/theme.js +1 -0
- package/src/interfaces/webServer.js +1 -2162
- package/src/modules/fileExplorer/controller.js +1 -280
- package/src/modules/fileExplorer/index.js +1 -37
- package/src/modules/fileExplorer/middleware.js +1 -92
- package/src/modules/fileExplorer/routes.js +1 -125
- package/src/modules/fileExplorer/types.js +1 -44
- package/src/services/aiService.js +1 -1232
- package/src/services/apiKeyManager.js +1 -164
- package/src/services/benchmarkService.js +1 -366
- package/src/services/budgetService.js +1 -539
- package/src/services/contextInjectionService.js +1 -247
- package/src/services/conversationCompactionService.js +1 -637
- package/src/services/errorHandler.js +1 -810
- package/src/services/fileAttachmentService.js +1 -544
- package/src/services/modelRouterService.js +1 -366
- package/src/services/modelsService.js +1 -322
- package/src/services/qualityInspector.js +1 -796
- package/src/services/tokenCountingService.js +1 -536
- package/src/tools/agentCommunicationTool.js +1 -1344
- package/src/tools/agentDelayTool.js +1 -485
- package/src/tools/asyncToolManager.js +1 -604
- package/src/tools/baseTool.js +1 -800
- package/src/tools/browserTool.js +1 -920
- package/src/tools/cloneDetectionTool.js +1 -621
- package/src/tools/dependencyResolverTool.js +1 -1215
- package/src/tools/fileContentReplaceTool.js +1 -875
- package/src/tools/fileSystemTool.js +1 -1107
- package/src/tools/fileTreeTool.js +1 -853
- package/src/tools/imageTool.js +1 -901
- package/src/tools/importAnalyzerTool.js +1 -1060
- package/src/tools/jobDoneTool.js +1 -248
- package/src/tools/seekTool.js +1 -956
- package/src/tools/staticAnalysisTool.js +1 -1778
- package/src/tools/taskManagerTool.js +1 -2873
- package/src/tools/terminalTool.js +1 -2304
- package/src/tools/webTool.js +1 -1430
- package/src/types/agent.js +1 -519
- package/src/types/contextReference.js +1 -972
- package/src/types/conversation.js +1 -730
- package/src/types/toolCommand.js +1 -747
- package/src/utilities/attachmentValidator.js +1 -292
- package/src/utilities/configManager.js +1 -582
- package/src/utilities/constants.js +1 -722
- package/src/utilities/directoryAccessManager.js +1 -535
- package/src/utilities/fileProcessor.js +1 -307
- package/src/utilities/logger.js +1 -436
- package/src/utilities/tagParser.js +1 -1246
- package/src/utilities/toolConstants.js +1 -317
- package/web-ui/build/index.html +2 -2
- package/web-ui/build/static/{index-Dy2bYbOa.css → index-CClD1090.css} +1 -1
- package/web-ui/build/static/{index-CjkkcnFA.js → index-lCBai6dX.js} +66 -67
|
@@ -1,539 +1 @@
|
|
|
1
|
-
import { BUDGET_LIMITS, COST_PER_TOKEN, USAGE_ALERTS } from '../utilities/constants.js';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Budget and usage tracking service for monitoring AI model costs and token usage
|
|
5
|
-
*/
|
|
6
|
-
export class BudgetService {
|
|
7
|
-
constructor(config, logger) {
|
|
8
|
-
this.config = config || {};
|
|
9
|
-
this.logger = logger;
|
|
10
|
-
this.usage = {
|
|
11
|
-
daily: new Map(),
|
|
12
|
-
weekly: new Map(),
|
|
13
|
-
monthly: new Map(),
|
|
14
|
-
total: {
|
|
15
|
-
tokens: 0,
|
|
16
|
-
cost: 0,
|
|
17
|
-
requests: 0
|
|
18
|
-
}
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
this.budgets = {
|
|
22
|
-
daily: BUDGET_LIMITS.DAILY,
|
|
23
|
-
weekly: BUDGET_LIMITS.WEEKLY,
|
|
24
|
-
monthly: BUDGET_LIMITS.MONTHLY
|
|
25
|
-
};
|
|
26
|
-
|
|
27
|
-
this.alerts = {
|
|
28
|
-
enabled: true,
|
|
29
|
-
thresholds: USAGE_ALERTS.THRESHOLDS,
|
|
30
|
-
lastAlertTimes: new Map()
|
|
31
|
-
};
|
|
32
|
-
|
|
33
|
-
this.loadUsageData();
|
|
34
|
-
this.setupPeriodicSave();
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* Track token usage for a specific model and agent
|
|
39
|
-
* @param {string} agentId - Agent identifier
|
|
40
|
-
* @param {string} modelId - Model identifier
|
|
41
|
-
* @param {Object} tokenUsage - Token usage data
|
|
42
|
-
* @param {number} tokenUsage.prompt_tokens - Input tokens used
|
|
43
|
-
* @param {number} tokenUsage.completion_tokens - Output tokens used
|
|
44
|
-
* @param {number} tokenUsage.total_tokens - Total tokens used
|
|
45
|
-
* @returns {Object} Updated usage statistics and cost
|
|
46
|
-
*/
|
|
47
|
-
trackUsage(agentId, modelId, tokenUsage) {
|
|
48
|
-
try {
|
|
49
|
-
const cost = this.calculateCost(modelId, tokenUsage);
|
|
50
|
-
const now = new Date();
|
|
51
|
-
const dayKey = this.getDayKey(now);
|
|
52
|
-
const weekKey = this.getWeekKey(now);
|
|
53
|
-
const monthKey = this.getMonthKey(now);
|
|
54
|
-
|
|
55
|
-
// Initialize usage entries if they don't exist
|
|
56
|
-
this.initializeUsageEntry(this.usage.daily, dayKey);
|
|
57
|
-
this.initializeUsageEntry(this.usage.weekly, weekKey);
|
|
58
|
-
this.initializeUsageEntry(this.usage.monthly, monthKey);
|
|
59
|
-
|
|
60
|
-
// Update usage statistics
|
|
61
|
-
const usageData = {
|
|
62
|
-
agentId,
|
|
63
|
-
modelId,
|
|
64
|
-
tokens: tokenUsage.total_tokens,
|
|
65
|
-
cost,
|
|
66
|
-
timestamp: now.toISOString()
|
|
67
|
-
};
|
|
68
|
-
|
|
69
|
-
this.updateUsageEntry(this.usage.daily.get(dayKey), usageData);
|
|
70
|
-
this.updateUsageEntry(this.usage.weekly.get(weekKey), usageData);
|
|
71
|
-
this.updateUsageEntry(this.usage.monthly.get(monthKey), usageData);
|
|
72
|
-
|
|
73
|
-
// Update total usage
|
|
74
|
-
this.usage.total.tokens += tokenUsage.total_tokens;
|
|
75
|
-
this.usage.total.cost += cost;
|
|
76
|
-
this.usage.total.requests += 1;
|
|
77
|
-
|
|
78
|
-
// Check budget limits and send alerts if necessary
|
|
79
|
-
this.checkBudgetLimits(dayKey, weekKey, monthKey);
|
|
80
|
-
|
|
81
|
-
this.logger.info('Usage tracked', {
|
|
82
|
-
agentId,
|
|
83
|
-
modelId,
|
|
84
|
-
tokens: tokenUsage.total_tokens,
|
|
85
|
-
cost,
|
|
86
|
-
totalCost: this.usage.total.cost
|
|
87
|
-
});
|
|
88
|
-
|
|
89
|
-
return {
|
|
90
|
-
cost,
|
|
91
|
-
totalCost: this.usage.total.cost,
|
|
92
|
-
totalTokens: this.usage.total.tokens,
|
|
93
|
-
dailyUsage: this.usage.daily.get(dayKey),
|
|
94
|
-
budgetRemaining: this.getRemainingBudget()
|
|
95
|
-
};
|
|
96
|
-
|
|
97
|
-
} catch (error) {
|
|
98
|
-
this.logger.error('Failed to track usage', { error: error.message, agentId, modelId });
|
|
99
|
-
throw error;
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
/**
|
|
104
|
-
* Calculate cost based on model and token usage
|
|
105
|
-
* @param {string} modelId - Model identifier
|
|
106
|
-
* @param {Object} tokenUsage - Token usage data
|
|
107
|
-
* @returns {number} Cost in USD
|
|
108
|
-
*/
|
|
109
|
-
calculateCost(modelId, tokenUsage) {
|
|
110
|
-
const modelCosts = COST_PER_TOKEN[modelId];
|
|
111
|
-
|
|
112
|
-
if (!modelCosts) {
|
|
113
|
-
this.logger.warn('Unknown model for cost calculation', { modelId });
|
|
114
|
-
return 0;
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
const inputCost = (tokenUsage.prompt_tokens || 0) * modelCosts.input;
|
|
118
|
-
const outputCost = (tokenUsage.completion_tokens || 0) * modelCosts.output;
|
|
119
|
-
|
|
120
|
-
return inputCost + outputCost;
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
/**
|
|
124
|
-
* Get current usage statistics
|
|
125
|
-
* @param {string} period - 'daily', 'weekly', 'monthly', or 'total'
|
|
126
|
-
* @param {Date} date - Date for the period (optional, defaults to now)
|
|
127
|
-
* @returns {Object} Usage statistics
|
|
128
|
-
*/
|
|
129
|
-
getUsage(period = 'daily', date = new Date()) {
|
|
130
|
-
switch (period) {
|
|
131
|
-
case 'daily':
|
|
132
|
-
return this.usage.daily.get(this.getDayKey(date)) || this.createEmptyUsage();
|
|
133
|
-
case 'weekly':
|
|
134
|
-
return this.usage.weekly.get(this.getWeekKey(date)) || this.createEmptyUsage();
|
|
135
|
-
case 'monthly':
|
|
136
|
-
return this.usage.monthly.get(this.getMonthKey(date)) || this.createEmptyUsage();
|
|
137
|
-
case 'total':
|
|
138
|
-
return { ...this.usage.total };
|
|
139
|
-
default:
|
|
140
|
-
throw new Error(`Invalid period: ${period}`);
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
/**
|
|
145
|
-
* Get usage by agent
|
|
146
|
-
* @param {string} agentId - Agent identifier
|
|
147
|
-
* @param {string} period - 'daily', 'weekly', 'monthly', or 'total'
|
|
148
|
-
* @returns {Object} Agent-specific usage statistics
|
|
149
|
-
*/
|
|
150
|
-
getAgentUsage(agentId, period = 'daily') {
|
|
151
|
-
const usage = this.getUsage(period);
|
|
152
|
-
return usage.byAgent?.[agentId] || this.createEmptyUsage();
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
/**
|
|
156
|
-
* Get usage by model
|
|
157
|
-
* @param {string} modelId - Model identifier
|
|
158
|
-
* @param {string} period - 'daily', 'weekly', 'monthly', or 'total'
|
|
159
|
-
* @returns {Object} Model-specific usage statistics
|
|
160
|
-
*/
|
|
161
|
-
getModelUsage(modelId, period = 'daily') {
|
|
162
|
-
const usage = this.getUsage(period);
|
|
163
|
-
return usage.byModel?.[modelId] || this.createEmptyUsage();
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
/**
|
|
167
|
-
* Set budget limits
|
|
168
|
-
* @param {Object} budgets - Budget configuration
|
|
169
|
-
* @param {number} budgets.daily - Daily budget limit in USD
|
|
170
|
-
* @param {number} budgets.weekly - Weekly budget limit in USD
|
|
171
|
-
* @param {number} budgets.monthly - Monthly budget limit in USD
|
|
172
|
-
*/
|
|
173
|
-
setBudgets(budgets) {
|
|
174
|
-
if (budgets.daily !== undefined) this.budgets.daily = budgets.daily;
|
|
175
|
-
if (budgets.weekly !== undefined) this.budgets.weekly = budgets.weekly;
|
|
176
|
-
if (budgets.monthly !== undefined) this.budgets.monthly = budgets.monthly;
|
|
177
|
-
|
|
178
|
-
this.logger.info('Budget limits updated', this.budgets);
|
|
179
|
-
this.saveUsageData();
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
/**
|
|
183
|
-
* Get remaining budget for each period
|
|
184
|
-
* @returns {Object} Remaining budget amounts
|
|
185
|
-
*/
|
|
186
|
-
getRemainingBudget() {
|
|
187
|
-
const now = new Date();
|
|
188
|
-
const dailyUsage = this.getUsage('daily', now);
|
|
189
|
-
const weeklyUsage = this.getUsage('weekly', now);
|
|
190
|
-
const monthlyUsage = this.getUsage('monthly', now);
|
|
191
|
-
|
|
192
|
-
return {
|
|
193
|
-
daily: Math.max(0, this.budgets.daily - dailyUsage.cost),
|
|
194
|
-
weekly: Math.max(0, this.budgets.weekly - weeklyUsage.cost),
|
|
195
|
-
monthly: Math.max(0, this.budgets.monthly - monthlyUsage.cost)
|
|
196
|
-
};
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
/**
|
|
200
|
-
* Check if usage is within budget limits
|
|
201
|
-
* @param {string} period - 'daily', 'weekly', or 'monthly'
|
|
202
|
-
* @returns {boolean} True if within budget
|
|
203
|
-
*/
|
|
204
|
-
isWithinBudget(period = 'daily') {
|
|
205
|
-
const usage = this.getUsage(period);
|
|
206
|
-
const budget = this.budgets[period];
|
|
207
|
-
return usage.cost <= budget;
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
/**
|
|
211
|
-
* Get usage trends and analytics
|
|
212
|
-
* @param {number} days - Number of days to analyze
|
|
213
|
-
* @returns {Object} Usage trends and analytics
|
|
214
|
-
*/
|
|
215
|
-
getUsageTrends(days = 30) {
|
|
216
|
-
const trends = {
|
|
217
|
-
dailyAverages: {
|
|
218
|
-
cost: 0,
|
|
219
|
-
tokens: 0,
|
|
220
|
-
requests: 0
|
|
221
|
-
},
|
|
222
|
-
topAgents: [],
|
|
223
|
-
topModels: [],
|
|
224
|
-
costByDay: [],
|
|
225
|
-
tokensByDay: []
|
|
226
|
-
};
|
|
227
|
-
|
|
228
|
-
const now = new Date();
|
|
229
|
-
let totalCost = 0;
|
|
230
|
-
let totalTokens = 0;
|
|
231
|
-
let totalRequests = 0;
|
|
232
|
-
const agentUsage = new Map();
|
|
233
|
-
const modelUsage = new Map();
|
|
234
|
-
|
|
235
|
-
// Analyze daily usage for the specified period
|
|
236
|
-
for (let i = 0; i < days; i++) {
|
|
237
|
-
const date = new Date(now);
|
|
238
|
-
date.setDate(date.getDate() - i);
|
|
239
|
-
const dayKey = this.getDayKey(date);
|
|
240
|
-
const dayUsage = this.usage.daily.get(dayKey);
|
|
241
|
-
|
|
242
|
-
if (dayUsage) {
|
|
243
|
-
totalCost += dayUsage.cost;
|
|
244
|
-
totalTokens += dayUsage.tokens;
|
|
245
|
-
totalRequests += dayUsage.requests;
|
|
246
|
-
|
|
247
|
-
trends.costByDay.unshift({ date: dayKey, cost: dayUsage.cost });
|
|
248
|
-
trends.tokensByDay.unshift({ date: dayKey, tokens: dayUsage.tokens });
|
|
249
|
-
|
|
250
|
-
// Aggregate agent usage
|
|
251
|
-
Object.entries(dayUsage.byAgent || {}).forEach(([agentId, usage]) => {
|
|
252
|
-
if (!agentUsage.has(agentId)) {
|
|
253
|
-
agentUsage.set(agentId, { cost: 0, tokens: 0, requests: 0 });
|
|
254
|
-
}
|
|
255
|
-
const current = agentUsage.get(agentId);
|
|
256
|
-
current.cost += usage.cost;
|
|
257
|
-
current.tokens += usage.tokens;
|
|
258
|
-
current.requests += usage.requests;
|
|
259
|
-
});
|
|
260
|
-
|
|
261
|
-
// Aggregate model usage
|
|
262
|
-
Object.entries(dayUsage.byModel || {}).forEach(([modelId, usage]) => {
|
|
263
|
-
if (!modelUsage.has(modelId)) {
|
|
264
|
-
modelUsage.set(modelId, { cost: 0, tokens: 0, requests: 0 });
|
|
265
|
-
}
|
|
266
|
-
const current = modelUsage.get(modelId);
|
|
267
|
-
current.cost += usage.cost;
|
|
268
|
-
current.tokens += usage.tokens;
|
|
269
|
-
current.requests += usage.requests;
|
|
270
|
-
});
|
|
271
|
-
} else {
|
|
272
|
-
trends.costByDay.unshift({ date: dayKey, cost: 0 });
|
|
273
|
-
trends.tokensByDay.unshift({ date: dayKey, tokens: 0 });
|
|
274
|
-
}
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
// Calculate averages
|
|
278
|
-
trends.dailyAverages.cost = totalCost / days;
|
|
279
|
-
trends.dailyAverages.tokens = totalTokens / days;
|
|
280
|
-
trends.dailyAverages.requests = totalRequests / days;
|
|
281
|
-
|
|
282
|
-
// Sort and get top agents and models
|
|
283
|
-
trends.topAgents = Array.from(agentUsage.entries())
|
|
284
|
-
.map(([id, usage]) => ({ id, ...usage }))
|
|
285
|
-
.sort((a, b) => b.cost - a.cost)
|
|
286
|
-
.slice(0, 10);
|
|
287
|
-
|
|
288
|
-
trends.topModels = Array.from(modelUsage.entries())
|
|
289
|
-
.map(([id, usage]) => ({ id, ...usage }))
|
|
290
|
-
.sort((a, b) => b.cost - a.cost)
|
|
291
|
-
.slice(0, 10);
|
|
292
|
-
|
|
293
|
-
return trends;
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
/**
|
|
297
|
-
* Export usage data for reporting
|
|
298
|
-
* @param {string} format - 'json' or 'csv'
|
|
299
|
-
* @param {Date} startDate - Start date for export
|
|
300
|
-
* @param {Date} endDate - End date for export
|
|
301
|
-
* @returns {string} Exported data
|
|
302
|
-
*/
|
|
303
|
-
exportUsageData(format = 'json', startDate = null, endDate = null) {
|
|
304
|
-
const data = {
|
|
305
|
-
budgets: this.budgets,
|
|
306
|
-
total: this.usage.total,
|
|
307
|
-
daily: {},
|
|
308
|
-
weekly: {},
|
|
309
|
-
monthly: {}
|
|
310
|
-
};
|
|
311
|
-
|
|
312
|
-
// Filter data by date range if specified
|
|
313
|
-
const filterByDateRange = (entries, keyFormatter) => {
|
|
314
|
-
const filtered = {};
|
|
315
|
-
entries.forEach((usage, key) => {
|
|
316
|
-
const date = keyFormatter(key);
|
|
317
|
-
if ((!startDate || date >= startDate) && (!endDate || date <= endDate)) {
|
|
318
|
-
filtered[key] = usage;
|
|
319
|
-
}
|
|
320
|
-
});
|
|
321
|
-
return filtered;
|
|
322
|
-
};
|
|
323
|
-
|
|
324
|
-
if (startDate || endDate) {
|
|
325
|
-
data.daily = filterByDateRange(this.usage.daily, key => new Date(key));
|
|
326
|
-
data.weekly = filterByDateRange(this.usage.weekly, key => new Date(key));
|
|
327
|
-
data.monthly = filterByDateRange(this.usage.monthly, key => new Date(key + '-01'));
|
|
328
|
-
} else {
|
|
329
|
-
this.usage.daily.forEach((usage, key) => data.daily[key] = usage);
|
|
330
|
-
this.usage.weekly.forEach((usage, key) => data.weekly[key] = usage);
|
|
331
|
-
this.usage.monthly.forEach((usage, key) => data.monthly[key] = usage);
|
|
332
|
-
}
|
|
333
|
-
|
|
334
|
-
if (format === 'csv') {
|
|
335
|
-
return this.convertToCSV(data);
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
return JSON.stringify(data, null, 2);
|
|
339
|
-
}
|
|
340
|
-
|
|
341
|
-
// Private helper methods
|
|
342
|
-
|
|
343
|
-
initializeUsageEntry(usageMap, key) {
|
|
344
|
-
if (!usageMap.has(key)) {
|
|
345
|
-
usageMap.set(key, this.createEmptyUsage());
|
|
346
|
-
}
|
|
347
|
-
}
|
|
348
|
-
|
|
349
|
-
createEmptyUsage() {
|
|
350
|
-
return {
|
|
351
|
-
cost: 0,
|
|
352
|
-
tokens: 0,
|
|
353
|
-
requests: 0,
|
|
354
|
-
byAgent: {},
|
|
355
|
-
byModel: {}
|
|
356
|
-
};
|
|
357
|
-
}
|
|
358
|
-
|
|
359
|
-
updateUsageEntry(entry, usageData) {
|
|
360
|
-
entry.cost += usageData.cost;
|
|
361
|
-
entry.tokens += usageData.tokens;
|
|
362
|
-
entry.requests += 1;
|
|
363
|
-
|
|
364
|
-
// Update by agent
|
|
365
|
-
if (!entry.byAgent[usageData.agentId]) {
|
|
366
|
-
entry.byAgent[usageData.agentId] = this.createEmptyUsage();
|
|
367
|
-
}
|
|
368
|
-
entry.byAgent[usageData.agentId].cost += usageData.cost;
|
|
369
|
-
entry.byAgent[usageData.agentId].tokens += usageData.tokens;
|
|
370
|
-
entry.byAgent[usageData.agentId].requests += 1;
|
|
371
|
-
|
|
372
|
-
// Update by model
|
|
373
|
-
if (!entry.byModel[usageData.modelId]) {
|
|
374
|
-
entry.byModel[usageData.modelId] = this.createEmptyUsage();
|
|
375
|
-
}
|
|
376
|
-
entry.byModel[usageData.modelId].cost += usageData.cost;
|
|
377
|
-
entry.byModel[usageData.modelId].tokens += usageData.tokens;
|
|
378
|
-
entry.byModel[usageData.modelId].requests += 1;
|
|
379
|
-
}
|
|
380
|
-
|
|
381
|
-
checkBudgetLimits(dayKey, weekKey, monthKey) {
|
|
382
|
-
const dailyUsage = this.usage.daily.get(dayKey);
|
|
383
|
-
const weeklyUsage = this.usage.weekly.get(weekKey);
|
|
384
|
-
const monthlyUsage = this.usage.monthly.get(monthKey);
|
|
385
|
-
|
|
386
|
-
// Check daily budget
|
|
387
|
-
if (dailyUsage.cost > this.budgets.daily) {
|
|
388
|
-
this.sendBudgetAlert('daily', dailyUsage.cost, this.budgets.daily);
|
|
389
|
-
}
|
|
390
|
-
|
|
391
|
-
// Check weekly budget
|
|
392
|
-
if (weeklyUsage.cost > this.budgets.weekly) {
|
|
393
|
-
this.sendBudgetAlert('weekly', weeklyUsage.cost, this.budgets.weekly);
|
|
394
|
-
}
|
|
395
|
-
|
|
396
|
-
// Check monthly budget
|
|
397
|
-
if (monthlyUsage.cost > this.budgets.monthly) {
|
|
398
|
-
this.sendBudgetAlert('monthly', monthlyUsage.cost, this.budgets.monthly);
|
|
399
|
-
}
|
|
400
|
-
|
|
401
|
-
// Check threshold alerts
|
|
402
|
-
this.checkThresholdAlerts(dailyUsage, weeklyUsage, monthlyUsage);
|
|
403
|
-
}
|
|
404
|
-
|
|
405
|
-
checkThresholdAlerts(dailyUsage, weeklyUsage, monthlyUsage) {
|
|
406
|
-
const thresholds = this.alerts.thresholds;
|
|
407
|
-
|
|
408
|
-
this.checkThreshold('daily', dailyUsage.cost, this.budgets.daily, thresholds);
|
|
409
|
-
this.checkThreshold('weekly', weeklyUsage.cost, this.budgets.weekly, thresholds);
|
|
410
|
-
this.checkThreshold('monthly', monthlyUsage.cost, this.budgets.monthly, thresholds);
|
|
411
|
-
}
|
|
412
|
-
|
|
413
|
-
checkThreshold(period, usage, budget, thresholds) {
|
|
414
|
-
const percentage = (usage / budget) * 100;
|
|
415
|
-
|
|
416
|
-
for (const threshold of thresholds) {
|
|
417
|
-
if (percentage >= threshold) {
|
|
418
|
-
const alertKey = `${period}_${threshold}`;
|
|
419
|
-
const lastAlert = this.alerts.lastAlertTimes.get(alertKey);
|
|
420
|
-
const now = Date.now();
|
|
421
|
-
|
|
422
|
-
// Only send alert if we haven't sent one in the last hour
|
|
423
|
-
if (!lastAlert || (now - lastAlert) > 3600000) {
|
|
424
|
-
this.sendThresholdAlert(period, percentage, threshold, usage, budget);
|
|
425
|
-
this.alerts.lastAlertTimes.set(alertKey, now);
|
|
426
|
-
}
|
|
427
|
-
break; // Only send the highest threshold alert
|
|
428
|
-
}
|
|
429
|
-
}
|
|
430
|
-
}
|
|
431
|
-
|
|
432
|
-
sendBudgetAlert(period, currentUsage, budgetLimit) {
|
|
433
|
-
this.logger.warn('Budget limit exceeded', {
|
|
434
|
-
period,
|
|
435
|
-
currentUsage,
|
|
436
|
-
budgetLimit,
|
|
437
|
-
excess: currentUsage - budgetLimit
|
|
438
|
-
});
|
|
439
|
-
|
|
440
|
-
// Emit event for external handling
|
|
441
|
-
if (typeof process !== 'undefined' && process.emit) {
|
|
442
|
-
process.emit('budgetAlert', {
|
|
443
|
-
type: 'budget_exceeded',
|
|
444
|
-
period,
|
|
445
|
-
currentUsage,
|
|
446
|
-
budgetLimit,
|
|
447
|
-
excess: currentUsage - budgetLimit
|
|
448
|
-
});
|
|
449
|
-
}
|
|
450
|
-
}
|
|
451
|
-
|
|
452
|
-
sendThresholdAlert(period, percentage, threshold, usage, budget) {
|
|
453
|
-
this.logger.warn('Budget threshold reached', {
|
|
454
|
-
period,
|
|
455
|
-
percentage: Math.round(percentage),
|
|
456
|
-
threshold,
|
|
457
|
-
usage,
|
|
458
|
-
budget
|
|
459
|
-
});
|
|
460
|
-
|
|
461
|
-
// Emit event for external handling
|
|
462
|
-
if (typeof process !== 'undefined' && process.emit) {
|
|
463
|
-
process.emit('budgetAlert', {
|
|
464
|
-
type: 'threshold_reached',
|
|
465
|
-
period,
|
|
466
|
-
percentage: Math.round(percentage),
|
|
467
|
-
threshold,
|
|
468
|
-
usage,
|
|
469
|
-
budget
|
|
470
|
-
});
|
|
471
|
-
}
|
|
472
|
-
}
|
|
473
|
-
|
|
474
|
-
getDayKey(date) {
|
|
475
|
-
return date.toISOString().split('T')[0];
|
|
476
|
-
}
|
|
477
|
-
|
|
478
|
-
getWeekKey(date) {
|
|
479
|
-
const year = date.getFullYear();
|
|
480
|
-
const weekNum = this.getWeekNumber(date);
|
|
481
|
-
return `${year}-W${weekNum.toString().padStart(2, '0')}`;
|
|
482
|
-
}
|
|
483
|
-
|
|
484
|
-
getMonthKey(date) {
|
|
485
|
-
const year = date.getFullYear();
|
|
486
|
-
const month = date.getMonth() + 1;
|
|
487
|
-
return `${year}-${month.toString().padStart(2, '0')}`;
|
|
488
|
-
}
|
|
489
|
-
|
|
490
|
-
getWeekNumber(date) {
|
|
491
|
-
const firstDayOfYear = new Date(date.getFullYear(), 0, 1);
|
|
492
|
-
const pastDaysOfYear = (date - firstDayOfYear) / 86400000;
|
|
493
|
-
return Math.ceil((pastDaysOfYear + firstDayOfYear.getDay() + 1) / 7);
|
|
494
|
-
}
|
|
495
|
-
|
|
496
|
-
convertToCSV(data) {
|
|
497
|
-
const rows = [];
|
|
498
|
-
rows.push(['Period', 'Date', 'Cost', 'Tokens', 'Requests', 'Agent', 'Model']);
|
|
499
|
-
|
|
500
|
-
// Convert daily data
|
|
501
|
-
Object.entries(data.daily).forEach(([date, usage]) => {
|
|
502
|
-
rows.push(['Daily', date, usage.cost, usage.tokens, usage.requests, '', '']);
|
|
503
|
-
|
|
504
|
-
Object.entries(usage.byAgent || {}).forEach(([agentId, agentUsage]) => {
|
|
505
|
-
rows.push(['Daily', date, agentUsage.cost, agentUsage.tokens, agentUsage.requests, agentId, '']);
|
|
506
|
-
});
|
|
507
|
-
});
|
|
508
|
-
|
|
509
|
-
return rows.map(row => row.join(',')).join('\n');
|
|
510
|
-
}
|
|
511
|
-
|
|
512
|
-
loadUsageData() {
|
|
513
|
-
try {
|
|
514
|
-
// In a real implementation, this would load from persistent storage
|
|
515
|
-
// For now, we'll just initialize with empty data
|
|
516
|
-
this.logger.info('Budget service initialized');
|
|
517
|
-
} catch (error) {
|
|
518
|
-
this.logger.error('Failed to load usage data', { error: error.message });
|
|
519
|
-
}
|
|
520
|
-
}
|
|
521
|
-
|
|
522
|
-
saveUsageData() {
|
|
523
|
-
try {
|
|
524
|
-
// In a real implementation, this would save to persistent storage
|
|
525
|
-
this.logger.debug('Usage data saved');
|
|
526
|
-
} catch (error) {
|
|
527
|
-
this.logger.error('Failed to save usage data', { error: error.message });
|
|
528
|
-
}
|
|
529
|
-
}
|
|
530
|
-
|
|
531
|
-
setupPeriodicSave() {
|
|
532
|
-
// Save usage data every 5 minutes
|
|
533
|
-
setInterval(() => {
|
|
534
|
-
this.saveUsageData();
|
|
535
|
-
}, 300000);
|
|
536
|
-
}
|
|
537
|
-
}
|
|
538
|
-
|
|
539
|
-
export default BudgetService;
|
|
1
|
+
const a0_0x16c752=a0_0x390e;function a0_0x390e(_0x4f6201,_0x25f7a1){_0x4f6201=_0x4f6201-0x1ef;const _0x3a69d2=a0_0x3a69();let _0x390e05=_0x3a69d2[_0x4f6201];if(a0_0x390e['bIiSjs']===undefined){var _0x1b39c9=function(_0x4f79ca){const _0x134808='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=';let _0xb28a82='',_0x891055='';for(let _0x5ea8e7=0x0,_0x413429,_0x5242e6,_0x2ce437=0x0;_0x5242e6=_0x4f79ca['charAt'](_0x2ce437++);~_0x5242e6&&(_0x413429=_0x5ea8e7%0x4?_0x413429*0x40+_0x5242e6:_0x5242e6,_0x5ea8e7++%0x4)?_0xb28a82+=String['fromCharCode'](0xff&_0x413429>>(-0x2*_0x5ea8e7&0x6)):0x0){_0x5242e6=_0x134808['indexOf'](_0x5242e6);}for(let _0x37b542=0x0,_0x2ed13a=_0xb28a82['length'];_0x37b542<_0x2ed13a;_0x37b542++){_0x891055+='%'+('00'+_0xb28a82['charCodeAt'](_0x37b542)['toString'](0x10))['slice'](-0x2);}return decodeURIComponent(_0x891055);};a0_0x390e['WHJpZg']=_0x1b39c9,a0_0x390e['mOEYDe']={},a0_0x390e['bIiSjs']=!![];}const _0x45ad71=_0x3a69d2[0x0],_0x5b2c0e=_0x4f6201+_0x45ad71,_0x3be9b5=a0_0x390e['mOEYDe'][_0x5b2c0e];return!_0x3be9b5?(_0x390e05=a0_0x390e['WHJpZg'](_0x390e05),a0_0x390e['mOEYDe'][_0x5b2c0e]=_0x390e05):_0x390e05=_0x3be9b5,_0x390e05;}(function(_0x43683d,_0x260c97){const _0x3fc20a=a0_0x390e,_0x319079=_0x43683d();while(!![]){try{const _0x318615=parseInt(_0x3fc20a(0x24a))/0x1+-parseInt(_0x3fc20a(0x219))/0x2+-parseInt(_0x3fc20a(0x237))/0x3+-parseInt(_0x3fc20a(0x250))/0x4+-parseInt(_0x3fc20a(0x1f3))/0x5*(-parseInt(_0x3fc20a(0x218))/0x6)+-parseInt(_0x3fc20a(0x248))/0x7+parseInt(_0x3fc20a(0x202))/0x8;if(_0x318615===_0x260c97)break;else _0x319079['push'](_0x319079['shift']());}catch(_0x14a3ee){_0x319079['push'](_0x319079['shift']());}}}(a0_0x3a69,0x7a26a));import{BUDGET_LIMITS,COST_PER_TOKEN,USAGE_ALERTS}from'../utilities/constants.js';export class BudgetService{constructor(_0xb28a82,_0x891055){const _0x20b009=a0_0x390e;this[_0x20b009(0x21e)]=_0xb28a82||{},this['logger']=_0x891055,this['usage']={'daily':new Map(),'weekly':new Map(),'monthly':new Map(),'total':{'tokens':0x0,'cost':0x0,'requests':0x0}},this['budgets']={'daily':BUDGET_LIMITS['DAILY'],'weekly':BUDGET_LIMITS[_0x20b009(0x1f6)],'monthly':BUDGET_LIMITS[_0x20b009(0x1fc)]},this[_0x20b009(0x227)]={'enabled':!![],'thresholds':USAGE_ALERTS[_0x20b009(0x206)],'lastAlertTimes':new Map()},this['loadUsageData'](),this['setupPeriodicSave']();}[a0_0x16c752(0x214)](_0x5ea8e7,_0x413429,_0x5242e6){const _0x181969=a0_0x16c752;try{const _0x2ce437=this[_0x181969(0x205)](_0x413429,_0x5242e6),_0x37b542=new Date(),_0x2ed13a=this[_0x181969(0x246)](_0x37b542),_0x1a64b1=this[_0x181969(0x228)](_0x37b542),_0x112695=this[_0x181969(0x1f1)](_0x37b542);this['initializeUsageEntry'](this['usage']['daily'],_0x2ed13a),this[_0x181969(0x23b)](this['usage']['weekly'],_0x1a64b1),this['initializeUsageEntry'](this[_0x181969(0x229)][_0x181969(0x1f0)],_0x112695);const _0x5dea44={'agentId':_0x5ea8e7,'modelId':_0x413429,'tokens':_0x5242e6[_0x181969(0x247)],'cost':_0x2ce437,'timestamp':_0x37b542['toISOString']()};return this[_0x181969(0x211)](this[_0x181969(0x229)][_0x181969(0x23e)]['get'](_0x2ed13a),_0x5dea44),this[_0x181969(0x211)](this['usage']['weekly']['get'](_0x1a64b1),_0x5dea44),this['updateUsageEntry'](this['usage'][_0x181969(0x1f0)][_0x181969(0x1fa)](_0x112695),_0x5dea44),this['usage'][_0x181969(0x215)][_0x181969(0x203)]+=_0x5242e6['total_tokens'],this[_0x181969(0x229)]['total'][_0x181969(0x225)]+=_0x2ce437,this['usage'][_0x181969(0x215)]['requests']+=0x1,this['checkBudgetLimits'](_0x2ed13a,_0x1a64b1,_0x112695),this['logger'][_0x181969(0x1f9)](_0x181969(0x21d),{'agentId':_0x5ea8e7,'modelId':_0x413429,'tokens':_0x5242e6['total_tokens'],'cost':_0x2ce437,'totalCost':this['usage'][_0x181969(0x215)]['cost']}),{'cost':_0x2ce437,'totalCost':this[_0x181969(0x229)]['total'][_0x181969(0x225)],'totalTokens':this['usage'][_0x181969(0x215)][_0x181969(0x203)],'dailyUsage':this[_0x181969(0x229)]['daily'][_0x181969(0x1fa)](_0x2ed13a),'budgetRemaining':this[_0x181969(0x216)]()};}catch(_0xc9fddb){this['logger']['error'](_0x181969(0x24d),{'error':_0xc9fddb[_0x181969(0x22c)],'agentId':_0x5ea8e7,'modelId':_0x413429});throw _0xc9fddb;}}['calculateCost'](_0x27645c,_0x309d8e){const _0x4b70ff=a0_0x16c752,_0x742b34=COST_PER_TOKEN[_0x27645c];if(!_0x742b34)return this[_0x4b70ff(0x209)][_0x4b70ff(0x21b)](_0x4b70ff(0x1fd),{'modelId':_0x27645c}),0x0;const _0x36bc01=(_0x309d8e[_0x4b70ff(0x241)]||0x0)*_0x742b34['input'],_0x4c88f6=(_0x309d8e['completion_tokens']||0x0)*_0x742b34[_0x4b70ff(0x1fe)];return _0x36bc01+_0x4c88f6;}['getUsage'](_0xd82055=a0_0x16c752(0x23e),_0x9e1020=new Date()){const _0x15c0ae=a0_0x16c752;switch(_0xd82055){case'daily':return this['usage']['daily'][_0x15c0ae(0x1fa)](this[_0x15c0ae(0x246)](_0x9e1020))||this[_0x15c0ae(0x22b)]();case'weekly':return this['usage'][_0x15c0ae(0x22e)]['get'](this[_0x15c0ae(0x228)](_0x9e1020))||this['createEmptyUsage']();case'monthly':return this[_0x15c0ae(0x229)][_0x15c0ae(0x1f0)][_0x15c0ae(0x1fa)](this[_0x15c0ae(0x1f1)](_0x9e1020))||this['createEmptyUsage']();case _0x15c0ae(0x215):return{...this['usage']['total']};default:throw new Error(_0x15c0ae(0x226)+_0xd82055);}}[a0_0x16c752(0x1f2)](_0x38cbfd,_0x909784='daily'){const _0x5d314b=a0_0x16c752,_0x13249a=this['getUsage'](_0x909784);return _0x13249a[_0x5d314b(0x212)]?.[_0x38cbfd]||this[_0x5d314b(0x22b)]();}[a0_0x16c752(0x245)](_0x1d5d71,_0x28b572=a0_0x16c752(0x23e)){const _0x18a6d6=a0_0x16c752,_0x384c76=this[_0x18a6d6(0x208)](_0x28b572);return _0x384c76['byModel']?.[_0x1d5d71]||this['createEmptyUsage']();}['setBudgets'](_0x22bf27){const _0x57e0f0=a0_0x16c752;if(_0x22bf27[_0x57e0f0(0x23e)]!==undefined)this['budgets']['daily']=_0x22bf27['daily'];if(_0x22bf27['weekly']!==undefined)this['budgets']['weekly']=_0x22bf27['weekly'];if(_0x22bf27[_0x57e0f0(0x1f0)]!==undefined)this['budgets'][_0x57e0f0(0x1f0)]=_0x22bf27[_0x57e0f0(0x1f0)];this[_0x57e0f0(0x209)][_0x57e0f0(0x1f9)]('Budget\x20limits\x20updated',this[_0x57e0f0(0x23a)]),this['saveUsageData']();}[a0_0x16c752(0x216)](){const _0x59ff9c=a0_0x16c752,_0x1dcb9f=new Date(),_0x3cb77f=this['getUsage'](_0x59ff9c(0x23e),_0x1dcb9f),_0x531532=this['getUsage'](_0x59ff9c(0x22e),_0x1dcb9f),_0x35f499=this[_0x59ff9c(0x208)]('monthly',_0x1dcb9f);return{'daily':Math['max'](0x0,this['budgets'][_0x59ff9c(0x23e)]-_0x3cb77f['cost']),'weekly':Math[_0x59ff9c(0x1f4)](0x0,this['budgets'][_0x59ff9c(0x22e)]-_0x531532['cost']),'monthly':Math['max'](0x0,this['budgets'][_0x59ff9c(0x1f0)]-_0x35f499[_0x59ff9c(0x225)])};}['isWithinBudget'](_0xaffcd='daily'){const _0x4a9086=this['getUsage'](_0xaffcd),_0x574bbb=this['budgets'][_0xaffcd];return _0x4a9086['cost']<=_0x574bbb;}[a0_0x16c752(0x1ff)](_0x1ff05c=0x1e){const _0x44d813=a0_0x16c752,_0x18f15a={'dailyAverages':{'cost':0x0,'tokens':0x0,'requests':0x0},'topAgents':[],'topModels':[],'costByDay':[],'tokensByDay':[]},_0x2ac997=new Date();let _0x5ad5a8=0x0,_0x3a6821=0x0,_0x4231e1=0x0;const _0x4caf45=new Map(),_0x41e91b=new Map();for(let _0x12dd2d=0x0;_0x12dd2d<_0x1ff05c;_0x12dd2d++){const _0x5b018d=new Date(_0x2ac997);_0x5b018d[_0x44d813(0x24f)](_0x5b018d['getDate']()-_0x12dd2d);const _0x4b8fa6=this['getDayKey'](_0x5b018d),_0x325a96=this['usage'][_0x44d813(0x23e)][_0x44d813(0x1fa)](_0x4b8fa6);_0x325a96?(_0x5ad5a8+=_0x325a96[_0x44d813(0x225)],_0x3a6821+=_0x325a96[_0x44d813(0x203)],_0x4231e1+=_0x325a96[_0x44d813(0x20f)],_0x18f15a[_0x44d813(0x20d)]['unshift']({'date':_0x4b8fa6,'cost':_0x325a96['cost']}),_0x18f15a[_0x44d813(0x21c)][_0x44d813(0x21f)]({'date':_0x4b8fa6,'tokens':_0x325a96[_0x44d813(0x203)]}),Object['entries'](_0x325a96['byAgent']||{})[_0x44d813(0x21a)](([_0x5674c8,_0x3c3415])=>{const _0x2414a3=_0x44d813;!_0x4caf45[_0x2414a3(0x22d)](_0x5674c8)&&_0x4caf45['set'](_0x5674c8,{'cost':0x0,'tokens':0x0,'requests':0x0});const _0x233e94=_0x4caf45['get'](_0x5674c8);_0x233e94[_0x2414a3(0x225)]+=_0x3c3415[_0x2414a3(0x225)],_0x233e94['tokens']+=_0x3c3415['tokens'],_0x233e94[_0x2414a3(0x20f)]+=_0x3c3415[_0x2414a3(0x20f)];}),Object['entries'](_0x325a96['byModel']||{})['forEach'](([_0x33d2c2,_0x45c487])=>{const _0x504985=_0x44d813;!_0x41e91b[_0x504985(0x22d)](_0x33d2c2)&&_0x41e91b[_0x504985(0x236)](_0x33d2c2,{'cost':0x0,'tokens':0x0,'requests':0x0});const _0x262f03=_0x41e91b['get'](_0x33d2c2);_0x262f03['cost']+=_0x45c487['cost'],_0x262f03['tokens']+=_0x45c487['tokens'],_0x262f03['requests']+=_0x45c487[_0x504985(0x20f)];})):(_0x18f15a[_0x44d813(0x20d)][_0x44d813(0x21f)]({'date':_0x4b8fa6,'cost':0x0}),_0x18f15a['tokensByDay']['unshift']({'date':_0x4b8fa6,'tokens':0x0}));}return _0x18f15a['dailyAverages']['cost']=_0x5ad5a8/_0x1ff05c,_0x18f15a[_0x44d813(0x243)]['tokens']=_0x3a6821/_0x1ff05c,_0x18f15a['dailyAverages'][_0x44d813(0x20f)]=_0x4231e1/_0x1ff05c,_0x18f15a[_0x44d813(0x213)]=Array[_0x44d813(0x231)](_0x4caf45['entries']())[_0x44d813(0x24b)](([_0x300226,_0x4b72af])=>({'id':_0x300226,..._0x4b72af}))[_0x44d813(0x20a)]((_0x1c2a8c,_0x30ea0e)=>_0x30ea0e['cost']-_0x1c2a8c[_0x44d813(0x225)])[_0x44d813(0x233)](0x0,0xa),_0x18f15a['topModels']=Array[_0x44d813(0x231)](_0x41e91b[_0x44d813(0x238)]())['map'](([_0x4eb478,_0x3091bb])=>({'id':_0x4eb478,..._0x3091bb}))['sort']((_0x18dd49,_0xf6a556)=>_0xf6a556[_0x44d813(0x225)]-_0x18dd49['cost'])[_0x44d813(0x233)](0x0,0xa),_0x18f15a;}[a0_0x16c752(0x23d)](_0x45b10f=a0_0x16c752(0x235),_0x5f584c=null,_0x5b7b22=null){const _0x5d410d=a0_0x16c752,_0x23c270={'budgets':this['budgets'],'total':this['usage'][_0x5d410d(0x215)],'daily':{},'weekly':{},'monthly':{}},_0x505378=(_0x24bc4d,_0x3a5fde)=>{const _0x5250c8={};return _0x24bc4d['forEach']((_0x566b36,_0x1900c2)=>{const _0xa1cd43=_0x3a5fde(_0x1900c2);(!_0x5f584c||_0xa1cd43>=_0x5f584c)&&(!_0x5b7b22||_0xa1cd43<=_0x5b7b22)&&(_0x5250c8[_0x1900c2]=_0x566b36);}),_0x5250c8;};_0x5f584c||_0x5b7b22?(_0x23c270['daily']=_0x505378(this['usage'][_0x5d410d(0x23e)],_0x58e290=>new Date(_0x58e290)),_0x23c270[_0x5d410d(0x22e)]=_0x505378(this['usage']['weekly'],_0x13c6d6=>new Date(_0x13c6d6)),_0x23c270['monthly']=_0x505378(this[_0x5d410d(0x229)][_0x5d410d(0x1f0)],_0x516477=>new Date(_0x516477+_0x5d410d(0x20b)))):(this[_0x5d410d(0x229)]['daily']['forEach']((_0x277d2e,_0x4b4931)=>_0x23c270[_0x5d410d(0x23e)][_0x4b4931]=_0x277d2e),this['usage']['weekly']['forEach']((_0x543572,_0x514095)=>_0x23c270['weekly'][_0x514095]=_0x543572),this[_0x5d410d(0x229)][_0x5d410d(0x1f0)]['forEach']((_0x322b80,_0x397b15)=>_0x23c270['monthly'][_0x397b15]=_0x322b80));if(_0x45b10f===_0x5d410d(0x244))return this['convertToCSV'](_0x23c270);return JSON['stringify'](_0x23c270,null,0x2);}['initializeUsageEntry'](_0x45fc9a,_0x465191){const _0x113abf=a0_0x16c752;!_0x45fc9a['has'](_0x465191)&&_0x45fc9a['set'](_0x465191,this[_0x113abf(0x22b)]());}[a0_0x16c752(0x22b)](){return{'cost':0x0,'tokens':0x0,'requests':0x0,'byAgent':{},'byModel':{}};}[a0_0x16c752(0x211)](_0x423079,_0x22fa18){const _0x580714=a0_0x16c752;_0x423079[_0x580714(0x225)]+=_0x22fa18[_0x580714(0x225)],_0x423079[_0x580714(0x203)]+=_0x22fa18['tokens'],_0x423079[_0x580714(0x20f)]+=0x1,!_0x423079['byAgent'][_0x22fa18[_0x580714(0x230)]]&&(_0x423079['byAgent'][_0x22fa18[_0x580714(0x230)]]=this['createEmptyUsage']()),_0x423079['byAgent'][_0x22fa18[_0x580714(0x230)]][_0x580714(0x225)]+=_0x22fa18['cost'],_0x423079['byAgent'][_0x22fa18['agentId']][_0x580714(0x203)]+=_0x22fa18[_0x580714(0x203)],_0x423079['byAgent'][_0x22fa18[_0x580714(0x230)]][_0x580714(0x20f)]+=0x1,!_0x423079[_0x580714(0x217)][_0x22fa18[_0x580714(0x242)]]&&(_0x423079['byModel'][_0x22fa18[_0x580714(0x242)]]=this['createEmptyUsage']()),_0x423079[_0x580714(0x217)][_0x22fa18['modelId']]['cost']+=_0x22fa18['cost'],_0x423079[_0x580714(0x217)][_0x22fa18['modelId']][_0x580714(0x203)]+=_0x22fa18['tokens'],_0x423079['byModel'][_0x22fa18['modelId']][_0x580714(0x20f)]+=0x1;}['checkBudgetLimits'](_0x4312b9,_0x235d7a,_0x2479d1){const _0xa5f2eb=a0_0x16c752,_0x85e80f=this[_0xa5f2eb(0x229)]['daily']['get'](_0x4312b9),_0x10468c=this[_0xa5f2eb(0x229)]['weekly'][_0xa5f2eb(0x1fa)](_0x235d7a),_0x143b15=this['usage']['monthly'][_0xa5f2eb(0x1fa)](_0x2479d1);_0x85e80f[_0xa5f2eb(0x225)]>this['budgets']['daily']&&this['sendBudgetAlert'](_0xa5f2eb(0x23e),_0x85e80f['cost'],this['budgets']['daily']),_0x10468c['cost']>this[_0xa5f2eb(0x23a)]['weekly']&&this['sendBudgetAlert'](_0xa5f2eb(0x22e),_0x10468c['cost'],this[_0xa5f2eb(0x23a)]['weekly']),_0x143b15[_0xa5f2eb(0x225)]>this['budgets']['monthly']&&this['sendBudgetAlert']('monthly',_0x143b15['cost'],this[_0xa5f2eb(0x23a)]['monthly']),this['checkThresholdAlerts'](_0x85e80f,_0x10468c,_0x143b15);}[a0_0x16c752(0x20e)](_0xccacaa,_0xdfe6b8,_0x54923a){const _0x233748=a0_0x16c752,_0x4f9b23=this['alerts'][_0x233748(0x222)];this['checkThreshold'](_0x233748(0x23e),_0xccacaa['cost'],this[_0x233748(0x23a)]['daily'],_0x4f9b23),this[_0x233748(0x224)](_0x233748(0x22e),_0xdfe6b8[_0x233748(0x225)],this[_0x233748(0x23a)]['weekly'],_0x4f9b23),this[_0x233748(0x224)](_0x233748(0x1f0),_0x54923a[_0x233748(0x225)],this[_0x233748(0x23a)][_0x233748(0x1f0)],_0x4f9b23);}[a0_0x16c752(0x224)](_0x1cf39d,_0x49866c,_0x450909,_0x3fe17d){const _0x2ee4af=a0_0x16c752,_0x5022fb=_0x49866c/_0x450909*0x64;for(const _0xdc5f6f of _0x3fe17d){if(_0x5022fb>=_0xdc5f6f){const _0x3e8869=_0x1cf39d+'_'+_0xdc5f6f,_0x4316b9=this[_0x2ee4af(0x227)]['lastAlertTimes']['get'](_0x3e8869),_0x42a7b7=Date[_0x2ee4af(0x23f)]();(!_0x4316b9||_0x42a7b7-_0x4316b9>0x36ee80)&&(this[_0x2ee4af(0x251)](_0x1cf39d,_0x5022fb,_0xdc5f6f,_0x49866c,_0x450909),this['alerts'][_0x2ee4af(0x239)][_0x2ee4af(0x236)](_0x3e8869,_0x42a7b7));break;}}}['sendBudgetAlert'](_0x3a1357,_0x4d2154,_0x598fba){const _0x4b24ab=a0_0x16c752;this[_0x4b24ab(0x209)]['warn'](_0x4b24ab(0x24c),{'period':_0x3a1357,'currentUsage':_0x4d2154,'budgetLimit':_0x598fba,'excess':_0x4d2154-_0x598fba}),typeof process!=='undefined'&&process['emit']&&process['emit'](_0x4b24ab(0x240),{'type':_0x4b24ab(0x210),'period':_0x3a1357,'currentUsage':_0x4d2154,'budgetLimit':_0x598fba,'excess':_0x4d2154-_0x598fba});}['sendThresholdAlert'](_0x5c1b3b,_0x55d7b9,_0x587673,_0x25e076,_0x3648dc){const _0x2ba884=a0_0x16c752;this['logger'][_0x2ba884(0x21b)]('Budget\x20threshold\x20reached',{'period':_0x5c1b3b,'percentage':Math['round'](_0x55d7b9),'threshold':_0x587673,'usage':_0x25e076,'budget':_0x3648dc}),typeof process!=='undefined'&&process[_0x2ba884(0x22a)]&&process['emit']('budgetAlert',{'type':_0x2ba884(0x232),'period':_0x5c1b3b,'percentage':Math[_0x2ba884(0x223)](_0x55d7b9),'threshold':_0x587673,'usage':_0x25e076,'budget':_0x3648dc});}[a0_0x16c752(0x246)](_0x521589){const _0x154667=a0_0x16c752;return _0x521589[_0x154667(0x220)]()[_0x154667(0x200)]('T')[0x0];}['getWeekKey'](_0xdd24f8){const _0x4ed6b5=a0_0x16c752,_0x49c35a=_0xdd24f8['getFullYear'](),_0x3985cb=this['getWeekNumber'](_0xdd24f8);return _0x49c35a+'-W'+_0x3985cb[_0x4ed6b5(0x1f5)]()['padStart'](0x2,'0');}['getMonthKey'](_0x2ef0c1){const _0x5d4897=a0_0x16c752,_0x1eb889=_0x2ef0c1[_0x5d4897(0x22f)](),_0x347c7f=_0x2ef0c1['getMonth']()+0x1;return _0x1eb889+'-'+_0x347c7f[_0x5d4897(0x1f5)]()[_0x5d4897(0x207)](0x2,'0');}[a0_0x16c752(0x1f7)](_0x1986cc){const _0x337753=a0_0x16c752,_0x377b82=new Date(_0x1986cc['getFullYear'](),0x0,0x1),_0x1142e1=(_0x1986cc-_0x377b82)/0x5265c00;return Math[_0x337753(0x201)]((_0x1142e1+_0x377b82['getDay']()+0x1)/0x7);}['convertToCSV'](_0x269fdc){const _0x407b73=a0_0x16c752,_0x42f6f3=[];return _0x42f6f3['push']([_0x407b73(0x24e),'Date','Cost','Tokens',_0x407b73(0x23c),_0x407b73(0x221),_0x407b73(0x249)]),Object[_0x407b73(0x238)](_0x269fdc['daily'])[_0x407b73(0x21a)](([_0x5d5ba1,_0x2627de])=>{const _0x1e5527=_0x407b73;_0x42f6f3['push']([_0x1e5527(0x20c),_0x5d5ba1,_0x2627de[_0x1e5527(0x225)],_0x2627de['tokens'],_0x2627de[_0x1e5527(0x20f)],'','']),Object['entries'](_0x2627de['byAgent']||{})[_0x1e5527(0x21a)](([_0x1adfc3,_0xaef986])=>{const _0x1c693f=_0x1e5527;_0x42f6f3['push']([_0x1c693f(0x20c),_0x5d5ba1,_0xaef986[_0x1c693f(0x225)],_0xaef986['tokens'],_0xaef986[_0x1c693f(0x20f)],_0x1adfc3,'']);});}),_0x42f6f3[_0x407b73(0x24b)](_0x59abf9=>_0x59abf9['join'](','))['join']('\x0a');}['loadUsageData'](){const _0x11648c=a0_0x16c752;try{this['logger']['info'](_0x11648c(0x204));}catch(_0x23dc44){this['logger']['error'](_0x11648c(0x1ef),{'error':_0x23dc44['message']});}}[a0_0x16c752(0x1f8)](){const _0x1e552d=a0_0x16c752;try{this['logger']['debug'](_0x1e552d(0x234));}catch(_0x5c3534){this[_0x1e552d(0x209)]['error'](_0x1e552d(0x1fb),{'error':_0x5c3534[_0x1e552d(0x22c)]});}}['setupPeriodicSave'](){setInterval(()=>{const _0x5d8b1f=a0_0x390e;this[_0x5d8b1f(0x1f8)]();},0x493e0);}}function a0_0x3a69(){const _0x4cc5b1=['Dg9Rzw5Z','qNvKz2v0ihnLCNzPy2uGAw5PDgLHBgL6zwq','y2fSy3vSyxrLq29ZDa','veHsrvnit0XeuW','CgfKu3rHCNq','z2v0vxnHz2u','Bg9Nz2vY','C29YDa','ltaX','rgfPBhK','y29ZDej5rgf5','y2HLy2TuAhjLC2HVBgrbBgvYDhm','CMvXDwvZDhm','yNvKz2v0x2v4y2vLzgvK','DxbKyxrLvxnHz2vfBNrYEq','yNLbz2vUDa','Dg9WqwDLBNrZ','DhjHy2TvC2fNzq','Dg90ywW','z2v0uMvTywLUAw5NqNvKz2v0','yNLnB2rLBa','nKrns01gzW','mta3ntCZog1IC2ztsq','zM9YrwfJAa','D2fYBG','Dg9Rzw5ZqNLeyxK','vxnHz2uGDhjHy2TLza','y29UzMLN','Dw5ZAgLMDa','Dg9ju09tDhjPBMC','qwDLBNq','DgHYzxnOB2XKCW','CM91BMq','y2HLy2TuAhjLC2HVBgq','y29ZDa','sw52ywXPzcbWzxjPB2q6ia','ywXLCNrZ','z2v0v2vLA0TLEq','DxnHz2u','zw1PDa','y3jLyxrLrw1WDhLvC2fNzq','BwvZC2fNzq','AgfZ','D2vLA2X5','z2v0rNvSBfLLyxi','ywDLBNrjza','zNjVBq','DgHYzxnOB2XKx3jLywnOzwq','C2XPy2u','vxnHz2uGzgf0ysbZyxzLza','ANnVBG','C2v0','mJaZmZu0mujUwKnnBq','zw50CMLLCW','BgfZDefSzxj0vgLTzxm','yNvKz2v0CW','Aw5PDgLHBgL6zvvZywDLrw50CNK','uMvXDwvZDhm','zxHWB3j0vxnHz2veyxrH','zgfPBhK','BM93','yNvKz2v0qwXLCNq','ChjVBxb0x3rVA2vUCW','Bw9KzwXjza','zgfPBhLbDMvYywDLCW','y3n2','z2v0tw9KzwXvC2fNzq','z2v0rgf5s2v5','Dg90ywXFDg9Rzw5Z','ntuZmtKXogfwugXIBq','tw9KzwW','ndmYntr3q1zkCfm','BwfW','qNvKz2v0igXPBwL0igv4y2vLzgvK','rMfPBgvKihrVihrYywnRihvZywDL','ugvYAw9K','C2v0rgf0zq','nZC2otqWs0Puuw1I','C2vUzfrOCMvZAg9SzefSzxj0','rMfPBgvKihrVigXVywqGDxnHz2uGzgf0yq','Bw9UDgHSEq','z2v0tw9UDgHlzxK','z2v0qwDLBNrvC2fNzq','mtK4mdy3meftB09cAG','Bwf4','Dg9tDhjPBMC','v0vfs0Xz','z2v0v2vLA051BwjLCG','C2f2zvvZywDLrgf0yq','Aw5MBW','z2v0','rMfPBgvKihrVihnHDMuGDxnHz2uGzgf0yq','tu9oveHmwq','vw5RBM93BIbTB2rLBcbMB3iGy29ZDcbJywXJDwXHDgLVBG','B3v0Chv0','z2v0vxnHz2vuCMvUzhm','C3bSAxq','y2vPBa','mtGWodKZmZzoq0vvBNq'];a0_0x3a69=function(){return _0x4cc5b1;};return a0_0x3a69();}export default BudgetService;
|