@loxia-labs/loxia-autopilot-one 1.0.1 → 1.0.4
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 +15 -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,322 +1 @@
|
|
|
1
|
-
|
|
2
|
-
* ModelsService - Manages available models from the backend API
|
|
3
|
-
*
|
|
4
|
-
* Purpose:
|
|
5
|
-
* - Fetch available models from /llm/models endpoint
|
|
6
|
-
* - Cache models for the session
|
|
7
|
-
* - Provide model names for routing
|
|
8
|
-
* - Handle fallback when API is unavailable
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
class ModelsService {
|
|
12
|
-
constructor(config, logger) {
|
|
13
|
-
this.config = config;
|
|
14
|
-
this.logger = logger;
|
|
15
|
-
|
|
16
|
-
this.models = null;
|
|
17
|
-
this.lastFetched = null;
|
|
18
|
-
this.isLoading = false;
|
|
19
|
-
this.cacheExpiry = 5 * 60 * 1000; // 5 minutes cache
|
|
20
|
-
|
|
21
|
-
this.backendUrl = 'https://autopilot-api.azurewebsites.net';
|
|
22
|
-
|
|
23
|
-
// API Key Manager reference (will be set by LoxiaSystem)
|
|
24
|
-
this.apiKeyManager = null;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
/**
|
|
28
|
-
* Set API key manager instance
|
|
29
|
-
* @param {ApiKeyManager} apiKeyManager - API key manager instance
|
|
30
|
-
*/
|
|
31
|
-
setApiKeyManager(apiKeyManager) {
|
|
32
|
-
this.apiKeyManager = apiKeyManager;
|
|
33
|
-
|
|
34
|
-
this.logger?.info('API key manager set for models service', {
|
|
35
|
-
hasManager: !!apiKeyManager
|
|
36
|
-
});
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
/**
|
|
40
|
-
* Initialize the models service and fetch initial data
|
|
41
|
-
*/
|
|
42
|
-
async initialize() {
|
|
43
|
-
try {
|
|
44
|
-
await this.fetchModels();
|
|
45
|
-
this.logger.info('Models service initialized', {
|
|
46
|
-
modelCount: this.models?.length || 0
|
|
47
|
-
});
|
|
48
|
-
} catch (error) {
|
|
49
|
-
this.logger.error('Failed to initialize models service', {
|
|
50
|
-
error: error.message
|
|
51
|
-
});
|
|
52
|
-
// Use fallback models on initialization failure
|
|
53
|
-
this.models = this._getFallbackModels();
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
/**
|
|
58
|
-
* Get available model names for routing
|
|
59
|
-
*/
|
|
60
|
-
getAvailableModelNames() {
|
|
61
|
-
if (!this.models || this.models.length === 0) {
|
|
62
|
-
this.logger.warn('No models available, using fallback');
|
|
63
|
-
return this._getFallbackModelNames();
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
return this.models.map(model => model.name);
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
/**
|
|
70
|
-
* Get all model information
|
|
71
|
-
*/
|
|
72
|
-
getModels() {
|
|
73
|
-
return this.models || this._getFallbackModels();
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
/**
|
|
77
|
-
* Fetch models from backend API
|
|
78
|
-
* @param {Object} context - Optional context with API key
|
|
79
|
-
*/
|
|
80
|
-
async fetchModels(context = null) {
|
|
81
|
-
if (this.isLoading) {
|
|
82
|
-
this.logger.debug('Models fetch already in progress');
|
|
83
|
-
return;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
this.isLoading = true;
|
|
87
|
-
|
|
88
|
-
try {
|
|
89
|
-
const url = `${this.backendUrl}/llm/models`;
|
|
90
|
-
|
|
91
|
-
// Get API key from multiple sources
|
|
92
|
-
let apiKey = null;
|
|
93
|
-
|
|
94
|
-
// First try to get from API key manager using session ID
|
|
95
|
-
if (this.apiKeyManager && context && context.sessionId) {
|
|
96
|
-
const keys = this.apiKeyManager.getKeysForRequest(context.sessionId, {
|
|
97
|
-
platformProvided: true, // Models endpoint uses platform key
|
|
98
|
-
vendor: null
|
|
99
|
-
});
|
|
100
|
-
|
|
101
|
-
apiKey = keys.loxiaApiKey;
|
|
102
|
-
|
|
103
|
-
this.logger?.info('Retrieved API key from session manager for models fetch', {
|
|
104
|
-
sessionId: context.sessionId,
|
|
105
|
-
hasLoxiaKey: !!apiKey
|
|
106
|
-
});
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
// Fallback to context, config, then environment
|
|
110
|
-
if (!apiKey && context && context.apiKey) {
|
|
111
|
-
apiKey = context.apiKey;
|
|
112
|
-
} else if (!apiKey && this.config.apiKey) {
|
|
113
|
-
apiKey = this.config.apiKey;
|
|
114
|
-
} else if (!apiKey && process.env.LOXIA_API_KEY) {
|
|
115
|
-
apiKey = process.env.LOXIA_API_KEY;
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
const fetchOptions = {
|
|
119
|
-
method: 'GET',
|
|
120
|
-
headers: {
|
|
121
|
-
'Content-Type': 'application/json',
|
|
122
|
-
...(apiKey && { 'Authorization': `Bearer ${apiKey}` })
|
|
123
|
-
},
|
|
124
|
-
timeout: 10000 // 10 second timeout
|
|
125
|
-
};
|
|
126
|
-
|
|
127
|
-
this.logger.debug('Fetching models from backend', {
|
|
128
|
-
url,
|
|
129
|
-
hasApiKey: !!apiKey,
|
|
130
|
-
apiKeySource: context?.apiKey ? 'context' : this.config.apiKey ? 'config' : process.env.LOXIA_API_KEY ? 'env' : 'none'
|
|
131
|
-
});
|
|
132
|
-
|
|
133
|
-
const response = await fetch(url, fetchOptions);
|
|
134
|
-
|
|
135
|
-
if (!response.ok) {
|
|
136
|
-
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
const data = await response.json();
|
|
140
|
-
|
|
141
|
-
if (data.models && Array.isArray(data.models)) {
|
|
142
|
-
this.models = data.models;
|
|
143
|
-
this.lastFetched = new Date();
|
|
144
|
-
this.needsRefresh = false;
|
|
145
|
-
|
|
146
|
-
this.logger.info('Models fetched from backend', {
|
|
147
|
-
modelCount: this.models.length,
|
|
148
|
-
models: this.models.map(m => m.name)
|
|
149
|
-
});
|
|
150
|
-
} else {
|
|
151
|
-
throw new Error('Invalid response format from models API');
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
} catch (error) {
|
|
155
|
-
this.logger.warn('Failed to fetch models from backend, using fallback', {
|
|
156
|
-
error: error.message
|
|
157
|
-
});
|
|
158
|
-
|
|
159
|
-
// Use fallback data on fetch error
|
|
160
|
-
if (!this.models) {
|
|
161
|
-
this.models = this._getFallbackModels();
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
} finally {
|
|
165
|
-
this.isLoading = false;
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
/**
|
|
170
|
-
* Check if models cache needs refresh
|
|
171
|
-
*/
|
|
172
|
-
needsRefresh() {
|
|
173
|
-
if (!this.lastFetched) return true;
|
|
174
|
-
|
|
175
|
-
const timeSinceUpdate = Date.now() - this.lastFetched.getTime();
|
|
176
|
-
return timeSinceUpdate > this.cacheExpiry;
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
/**
|
|
180
|
-
* Force refresh models from backend
|
|
181
|
-
* @param {Object} context - Optional context with API key
|
|
182
|
-
*/
|
|
183
|
-
async refresh(context = null) {
|
|
184
|
-
this.logger.info('Force refreshing models');
|
|
185
|
-
await this.fetchModels(context);
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
/**
|
|
189
|
-
* Refresh models with API key context if needed
|
|
190
|
-
* @param {Object} context - Context with API key
|
|
191
|
-
*/
|
|
192
|
-
async refreshWithContext(context) {
|
|
193
|
-
// Only refresh if we haven't successfully fetched or if we need a refresh
|
|
194
|
-
if (this.needsRefresh || !this.lastFetched) {
|
|
195
|
-
this.logger.debug('Refreshing models with API key context');
|
|
196
|
-
await this.fetchModels(context);
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
/**
|
|
201
|
-
* Get fallback models when API is unavailable
|
|
202
|
-
* @private
|
|
203
|
-
*/
|
|
204
|
-
_getFallbackModels() {
|
|
205
|
-
return [
|
|
206
|
-
{
|
|
207
|
-
name: 'anthropic-sonnet',
|
|
208
|
-
category: 'anthropic',
|
|
209
|
-
type: 'chat',
|
|
210
|
-
maxTokens: 10000,
|
|
211
|
-
supportsVision: true,
|
|
212
|
-
supportsSystem: true,
|
|
213
|
-
pricing: { input: 0.003, output: 0.015, unit: '1K tokens' }
|
|
214
|
-
},
|
|
215
|
-
{
|
|
216
|
-
name: 'anthropic-opus',
|
|
217
|
-
category: 'anthropic',
|
|
218
|
-
type: 'chat',
|
|
219
|
-
maxTokens: 10000,
|
|
220
|
-
supportsVision: true,
|
|
221
|
-
supportsSystem: true,
|
|
222
|
-
pricing: { input: 0.015, output: 0.075, unit: '1K tokens' }
|
|
223
|
-
},
|
|
224
|
-
{
|
|
225
|
-
name: 'anthropic-haiku',
|
|
226
|
-
category: 'anthropic',
|
|
227
|
-
type: 'chat',
|
|
228
|
-
maxTokens: 10000,
|
|
229
|
-
supportsVision: true,
|
|
230
|
-
supportsSystem: true,
|
|
231
|
-
pricing: { input: 0.00025, output: 0.00125, unit: '1K tokens' }
|
|
232
|
-
},
|
|
233
|
-
{
|
|
234
|
-
name: 'gpt-4',
|
|
235
|
-
category: 'openai',
|
|
236
|
-
type: 'chat',
|
|
237
|
-
maxTokens: 4096,
|
|
238
|
-
supportsVision: false,
|
|
239
|
-
supportsSystem: true,
|
|
240
|
-
pricing: { input: 0.030, output: 0.060, unit: '1K tokens' }
|
|
241
|
-
},
|
|
242
|
-
{
|
|
243
|
-
name: 'gpt-4-mini',
|
|
244
|
-
category: 'openai',
|
|
245
|
-
type: 'chat',
|
|
246
|
-
maxTokens: 16384,
|
|
247
|
-
supportsVision: false,
|
|
248
|
-
supportsSystem: true,
|
|
249
|
-
pricing: { input: 0.00015, output: 0.0006, unit: '1K tokens' }
|
|
250
|
-
},
|
|
251
|
-
{
|
|
252
|
-
name: 'deepseek-r1',
|
|
253
|
-
category: 'deepseek',
|
|
254
|
-
type: 'chat',
|
|
255
|
-
maxTokens: 8192,
|
|
256
|
-
supportsVision: false,
|
|
257
|
-
supportsSystem: true,
|
|
258
|
-
pricing: { input: 0.014, output: 0.028, unit: '1K tokens' }
|
|
259
|
-
},
|
|
260
|
-
{
|
|
261
|
-
name: 'azure-ai-grok3',
|
|
262
|
-
category: 'azure',
|
|
263
|
-
type: 'chat',
|
|
264
|
-
maxTokens: 4096,
|
|
265
|
-
supportsVision: false,
|
|
266
|
-
supportsSystem: true,
|
|
267
|
-
pricing: { input: 0.01, output: 0.02, unit: '1K tokens' }
|
|
268
|
-
},
|
|
269
|
-
{
|
|
270
|
-
name: 'phi-4',
|
|
271
|
-
category: 'microsoft',
|
|
272
|
-
type: 'chat',
|
|
273
|
-
maxTokens: 2048,
|
|
274
|
-
supportsVision: false,
|
|
275
|
-
supportsSystem: true,
|
|
276
|
-
pricing: { input: 0.010, output: 0.020, unit: '1K tokens' }
|
|
277
|
-
},
|
|
278
|
-
{
|
|
279
|
-
name: 'autopilot-model-router',
|
|
280
|
-
category: 'azure',
|
|
281
|
-
type: 'chat',
|
|
282
|
-
maxTokens: 2048,
|
|
283
|
-
supportsVision: false,
|
|
284
|
-
supportsSystem: true,
|
|
285
|
-
pricing: { input: 0.001, output: 0.002, unit: '1K tokens' }
|
|
286
|
-
}
|
|
287
|
-
];
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
/**
|
|
291
|
-
* Get fallback model names only
|
|
292
|
-
* @private
|
|
293
|
-
*/
|
|
294
|
-
_getFallbackModelNames() {
|
|
295
|
-
return [
|
|
296
|
-
'anthropic-sonnet',
|
|
297
|
-
'anthropic-opus',
|
|
298
|
-
'anthropic-haiku',
|
|
299
|
-
'gpt-4',
|
|
300
|
-
'gpt-4-mini',
|
|
301
|
-
'deepseek-r1',
|
|
302
|
-
'azure-ai-grok3',
|
|
303
|
-
'phi-4',
|
|
304
|
-
'autopilot-model-router'
|
|
305
|
-
];
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
/**
|
|
309
|
-
* Get service status
|
|
310
|
-
*/
|
|
311
|
-
getStatus() {
|
|
312
|
-
return {
|
|
313
|
-
initialized: !!this.models,
|
|
314
|
-
lastFetched: this.lastFetched?.toISOString() || null,
|
|
315
|
-
modelCount: this.models?.length || 0,
|
|
316
|
-
isLoading: this.isLoading,
|
|
317
|
-
needsRefresh: this.needsRefresh()
|
|
318
|
-
};
|
|
319
|
-
}
|
|
320
|
-
}
|
|
321
|
-
|
|
322
|
-
export default ModelsService;
|
|
1
|
+
const a0_0x2f8032=a0_0x3592;function a0_0x211d(){const _0x49c0c1=['mte5nJK2n1jizK5rvq','y29UDgv4Da','l2fWAs9SBg0VBw9KzwXZ','D2fYBG','sfruuca','mJG5nJC4ovLgwhLlrq','x3nJAgvKDwXLuMv0CNK','y29UzMLN','yMfJA2vUzfvYBa','BMfTzq','BgvUz3rO','ofzItfLXEG','qvbjigTLEsbTyw5Hz2vYihnLDcbMB3iGBw9KzwXZihnLCNzPy2u','Dg9ju09tDhjPBMC','mtaXmZm1oevfCNriwq','tM8GBw9KzwXZigf2ywLSywjSzsaTiefqssbMzxrJAcbMywLSzwq','yxbPs2v5twfUywDLCG','BgfZDevYCM9Y','x2nHBMnLBfjLDhj5','z2v0vgLTzq','zxjYB3i','CMv0CNLbDhrLBxb0CW','BMvLzhnszwzYzxnO','AxnbCNjHEq','z2v0qxzHAwXHyMXLtw9KzwXoyw1LCW','BwfW','CMvMCMvZAfDPDgHdB250zxH0','BgfZDezLDgnOzwq','uMv0CNKGyxr0zw1WDcbMywLSzwq','twf4ihjLDhj5igf0DgvTChrZihjLywnOzwqGzM9Yig1VzgvSigzLDgnO','Bw9KzwXZ','Bwf4uMv0CMLLCW','zw52','y2fJAgvfEhbPCNK','BwvZC2fNzq','q2fUy2vSBgvKihbLBMrPBMCGBw9KzwWGzMv0y2GGCMv0CNK','ntq4ndy5mfrdv2rxqW','tw9KzwXZihnLCNzPy2uGAw5PDgLHBgL6zwq','C2vZC2LVBKLK','AxnmB2fKAw5N','yxbPs2v5','z2v0u3rHDhvZ','mJe3nJK3nZzmuKTVz2m','Ahr0CdOVl2XVy2fSAg9ZDdO4mdGW','zgvIDwC','Aw5MBW','ofH5Ce9nvq','CMv0CNLuAw1LCG','zMv0y2HnB2rLBhm','nZqXndq2D1r1v0nV','Bg9Nz2vY','mtaZnJqXoeXRAw5Uta','te9ysufFqvbjx0Tfwq','Cg93','Bg94AwfbCgLlzxK'];a0_0x211d=function(){return _0x49c0c1;};return a0_0x211d();}function a0_0x3592(_0x57ca20,_0x18b3c8){_0x57ca20=_0x57ca20-0xbe;const _0x211d17=a0_0x211d();let _0x3592fa=_0x211d17[_0x57ca20];if(a0_0x3592['AgEGbk']===undefined){var _0x52c20d=function(_0x676a7){const _0x563855='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=';let _0x5e9339='',_0x574980='';for(let _0x222e08=0x0,_0x43de57,_0x54aba9,_0x2c3860=0x0;_0x54aba9=_0x676a7['charAt'](_0x2c3860++);~_0x54aba9&&(_0x43de57=_0x222e08%0x4?_0x43de57*0x40+_0x54aba9:_0x54aba9,_0x222e08++%0x4)?_0x5e9339+=String['fromCharCode'](0xff&_0x43de57>>(-0x2*_0x222e08&0x6)):0x0){_0x54aba9=_0x563855['indexOf'](_0x54aba9);}for(let _0x26e8f1=0x0,_0x289e71=_0x5e9339['length'];_0x26e8f1<_0x289e71;_0x26e8f1++){_0x574980+='%'+('00'+_0x5e9339['charCodeAt'](_0x26e8f1)['toString'](0x10))['slice'](-0x2);}return decodeURIComponent(_0x574980);};a0_0x3592['lBWVpw']=_0x52c20d,a0_0x3592['PcHPqY']={},a0_0x3592['AgEGbk']=!![];}const _0x39a70d=_0x211d17[0x0],_0x24b563=_0x57ca20+_0x39a70d,_0x21b196=a0_0x3592['PcHPqY'][_0x24b563];return!_0x21b196?(_0x3592fa=a0_0x3592['lBWVpw'](_0x3592fa),a0_0x3592['PcHPqY'][_0x24b563]=_0x3592fa):_0x3592fa=_0x21b196,_0x3592fa;}(function(_0x28b7b3,_0xa2d502){const _0x15d007=a0_0x3592,_0x26bec0=_0x28b7b3();while(!![]){try{const _0x272af5=-parseInt(_0x15d007(0xdf))/0x1+-parseInt(_0x15d007(0xe1))/0x2+parseInt(_0x15d007(0xe5))/0x3*(parseInt(_0x15d007(0xf0))/0x4)+-parseInt(_0x15d007(0xd2))/0x5+parseInt(_0x15d007(0xf3))/0x6+parseInt(_0x15d007(0xea))/0x7*(-parseInt(_0x15d007(0xdc))/0x8)+parseInt(_0x15d007(0xd8))/0x9;if(_0x272af5===_0xa2d502)break;else _0x26bec0['push'](_0x26bec0['shift']());}catch(_0x3e8f6d){_0x26bec0['push'](_0x26bec0['shift']());}}}(a0_0x211d,0x96393));class ModelsService{constructor(_0x5e9339,_0x574980){const _0x31bc92=a0_0x3592;this['config']=_0x5e9339,this[_0x31bc92(0xe0)]=_0x574980,this['models']=null,this[_0x31bc92(0xc9)]=null,this[_0x31bc92(0xd5)]=![],this[_0x31bc92(0xcf)]=0x5*0x3c*0x3e8,this['backendUrl']=_0x5e9339[_0x31bc92(0xed)]||_0x31bc92(0xd9),this['retryAttempts']=0x0,this['maxRetries']=0x3,this['retryDelay']=0x7d0,this[_0x31bc92(0xdd)]=null,this[_0x31bc92(0xbf)]=null,this['apiKeyManager']=null;}['setApiKeyManager'](_0x222e08){const _0x2b0906=a0_0x3592;this[_0x2b0906(0xbe)]=_0x222e08,this['logger']?.[_0x2b0906(0xdb)](_0x2b0906(0xf1),{'hasManager':!!_0x222e08});}async['initialize'](){const _0x4a3f8e=a0_0x3592;try{await this['fetchModels'](),this[_0x4a3f8e(0xe0)][_0x4a3f8e(0xdb)](_0x4a3f8e(0xd3),{'modelCount':this['models']?.[_0x4a3f8e(0xef)]||0x0});}catch(_0x43de57){this['lastError']=_0x43de57[_0x4a3f8e(0xd0)],this[_0x4a3f8e(0xe0)]['error']('Failed\x20to\x20initialize\x20models\x20service\x20-\x20NO\x20FALLBACK\x20AVAILABLE',{'error':_0x43de57['message'],'endpoint':this['backendUrl']+_0x4a3f8e(0xe7),'willRetry':!![]}),this[_0x4a3f8e(0xeb)]();}}[a0_0x2f8032(0xc6)](){const _0x103c74=a0_0x2f8032;if(!this['models']||this['models'][_0x103c74(0xef)]===0x0)return this[_0x103c74(0xe0)]['error'](_0x103c74(0xf4),{'lastError':this[_0x103c74(0xbf)],'endpoint':this['backendUrl']+'/api/llm/models','retryAttempt':this[_0x103c74(0xc3)],'maxRetries':this[_0x103c74(0xcd)]}),[];return this[_0x103c74(0xcc)][_0x103c74(0xc7)](_0x54aba9=>_0x54aba9['name']);}['getModels'](){const _0x1169fb=a0_0x2f8032;if(!this[_0x1169fb(0xcc)]||this[_0x1169fb(0xcc)][_0x1169fb(0xef)]===0x0)return this[_0x1169fb(0xe0)][_0x1169fb(0xc2)](_0x1169fb(0xf4),{'lastError':this[_0x1169fb(0xbf)],'endpoint':this[_0x1169fb(0xed)]+_0x1169fb(0xe7)}),[];return this[_0x1169fb(0xcc)];}async[a0_0x2f8032(0xde)](_0x2c3860=null){const _0x282b19=a0_0x2f8032;if(this[_0x282b19(0xd5)]){this['logger'][_0x282b19(0xda)]('Models\x20fetch\x20already\x20in\x20progress');return;}this['isLoading']=!![];try{const _0x26e8f1=this[_0x282b19(0xed)]+'/api/llm/models';let _0x289e71=null;if(this['apiKeyManager']&&_0x2c3860&&_0x2c3860['sessionId']){const _0x4269b7=this['apiKeyManager']['getKeysForRequest'](_0x2c3860[_0x282b19(0xd4)],{'platformProvided':!![],'vendor':null});_0x289e71=_0x4269b7[_0x282b19(0xe4)],this['logger']?.['info']('Retrieved API key from session manager for models fetch',{'sessionId':_0x2c3860[_0x282b19(0xd4)],'hasLoxiaKey':!!_0x289e71});}if(!_0x289e71&&_0x2c3860&&_0x2c3860[_0x282b19(0xd6)])_0x289e71=_0x2c3860[_0x282b19(0xd6)];else{if(!_0x289e71&&this['config'][_0x282b19(0xd6)])_0x289e71=this[_0x282b19(0xec)]['apiKey'];else!_0x289e71&&process['env']['LOXIA_API_KEY']&&(_0x289e71=process['env'][_0x282b19(0xe2)]);}const _0x17988e={'method':'GET','headers':{'Content-Type':'application/json',..._0x289e71&&{'Authorization':'Bearer\x20'+_0x289e71}},'timeout':0x2710};this['logger']['debug']('Fetching models from backend',{'url':_0x26e8f1,'hasApiKey':!!_0x289e71,'apiKeySource':_0x2c3860?.[_0x282b19(0xd6)]?_0x282b19(0xe6):this[_0x282b19(0xec)][_0x282b19(0xd6)]?'config':process['env']['LOXIA_API_KEY']?_0x282b19(0xce):'none'});const _0x2dce73=await fetch(_0x26e8f1,_0x17988e);if(!_0x2dce73['ok'])throw new Error(_0x282b19(0xe9)+_0x2dce73['status']+':\x20'+_0x2dce73['statusText']);const _0x4bef77=await _0x2dce73['json']();if(_0x4bef77[_0x282b19(0xcc)]&&Array[_0x282b19(0xc5)](_0x4bef77[_0x282b19(0xcc)]))this[_0x282b19(0xcc)]=_0x4bef77['models'],this['lastFetched']=new Date(),this['needsRefresh']=![],this[_0x282b19(0xe0)][_0x282b19(0xdb)]('Models fetched from backend',{'modelCount':this[_0x282b19(0xcc)][_0x282b19(0xef)],'models':this['models'][_0x282b19(0xc7)](_0xec495=>_0xec495[_0x282b19(0xee)])});else throw new Error('Invalid response format from models API');}catch(_0x2274df){this['lastError']=_0x2274df[_0x282b19(0xd0)],this[_0x282b19(0xe0)]['error']('Failed to fetch models from backend - NO FALLBACK',{'error':_0x2274df['message'],'endpoint':url,'retryAttempt':this[_0x282b19(0xc3)],'maxRetries':this[_0x282b19(0xcd)]}),this[_0x282b19(0xeb)](_0x2c3860);if(!this['models'])throw _0x2274df;}finally{this['isLoading']=![];}}[a0_0x2f8032(0xc4)](){const _0x5eb053=a0_0x2f8032;if(!this[_0x5eb053(0xc9)])return!![];const _0x183390=Date['now']()-this[_0x5eb053(0xc9)][_0x5eb053(0xc1)]();return _0x183390>this[_0x5eb053(0xcf)];}async['refresh'](_0x26eab3=null){const _0x5361f2=a0_0x2f8032;this['logger'][_0x5361f2(0xdb)]('Force\x20refreshing\x20models'),await this['fetchModels'](_0x26eab3);}async[a0_0x2f8032(0xc8)](_0xdc1053){const _0x4232bb=a0_0x2f8032;(this['needsRefresh']||!this['lastFetched'])&&(this[_0x4232bb(0xe0)][_0x4232bb(0xda)]('Refreshing\x20models\x20with\x20API\x20key\x20context'),await this[_0x4232bb(0xde)](_0xdc1053));}[a0_0x2f8032(0xeb)](_0x1590cb=null){const _0x5410b2=a0_0x2f8032;this['retryTimer']&&(clearTimeout(this[_0x5410b2(0xdd)]),this[_0x5410b2(0xdd)]=null);if(this['retryAttempts']>=this[_0x5410b2(0xcd)]){this['logger'][_0x5410b2(0xc2)](_0x5410b2(0xcb),{'attempts':this['retryAttempts'],'maxRetries':this[_0x5410b2(0xcd)],'lastError':this['lastError']});return;}const _0x505a2a=this['retryDelay']*Math[_0x5410b2(0xe3)](0x2,this[_0x5410b2(0xc3)]);this[_0x5410b2(0xc3)]++,this['logger'][_0x5410b2(0xdb)]('Scheduling\x20model\x20fetch\x20retry',{'attempt':this[_0x5410b2(0xc3)],'maxRetries':this['maxRetries'],'delayMs':_0x505a2a}),this['retryTimer']=setTimeout(async()=>{const _0x16e28f=_0x5410b2;this[_0x16e28f(0xe0)][_0x16e28f(0xdb)]('Executing\x20scheduled\x20model\x20fetch\x20retry',{'attempt':this['retryAttempts']});try{await this[_0x16e28f(0xde)](_0x1590cb),this[_0x16e28f(0xc3)]=0x0,this[_0x16e28f(0xbf)]=null;}catch(_0x372b2c){this['logger'][_0x16e28f(0xe8)](_0x16e28f(0xca),{'attempt':this[_0x16e28f(0xc3)],'error':_0x372b2c[_0x16e28f(0xd0)]});}},_0x505a2a);}[a0_0x2f8032(0xc0)](){const _0x184e89=a0_0x2f8032;this[_0x184e89(0xdd)]&&(clearTimeout(this['retryTimer']),this[_0x184e89(0xdd)]=null,this['logger']['debug'](_0x184e89(0xd1)));}[a0_0x2f8032(0xd7)](){const _0x47ec4f=a0_0x2f8032;return{'initialized':!!this['models'],'lastFetched':this[_0x47ec4f(0xc9)]?.[_0x47ec4f(0xf2)]()||null,'modelCount':this['models']?.['length']||0x0,'isLoading':this['isLoading'],'needsRefresh':this[_0x47ec4f(0xc4)](),'error':this[_0x47ec4f(0xbf)]||null,'retryAttempts':this['retryAttempts'],'maxRetries':this[_0x47ec4f(0xcd)],'hasError':!!this[_0x47ec4f(0xbf)]};}}export default ModelsService;
|