@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.
Files changed (120) hide show
  1. package/README.md +44 -54
  2. package/bin/cli.js +1 -115
  3. package/bin/loxia-terminal-v2.js +3 -0
  4. package/bin/loxia-terminal.js +3 -0
  5. package/bin/start-with-terminal.js +3 -0
  6. package/package.json +15 -15
  7. package/scripts/install-scanners.js +1 -235
  8. package/src/analyzers/CSSAnalyzer.js +1 -297
  9. package/src/analyzers/ConfigValidator.js +1 -690
  10. package/src/analyzers/ESLintAnalyzer.js +1 -320
  11. package/src/analyzers/JavaScriptAnalyzer.js +1 -261
  12. package/src/analyzers/PrettierFormatter.js +1 -247
  13. package/src/analyzers/PythonAnalyzer.js +1 -266
  14. package/src/analyzers/SecurityAnalyzer.js +1 -729
  15. package/src/analyzers/TypeScriptAnalyzer.js +1 -247
  16. package/src/analyzers/codeCloneDetector/analyzer.js +1 -344
  17. package/src/analyzers/codeCloneDetector/detector.js +1 -203
  18. package/src/analyzers/codeCloneDetector/index.js +1 -160
  19. package/src/analyzers/codeCloneDetector/parser.js +1 -199
  20. package/src/analyzers/codeCloneDetector/reporter.js +1 -148
  21. package/src/analyzers/codeCloneDetector/scanner.js +1 -59
  22. package/src/core/agentPool.js +1 -1474
  23. package/src/core/agentScheduler.js +1 -2147
  24. package/src/core/contextManager.js +1 -709
  25. package/src/core/messageProcessor.js +1 -732
  26. package/src/core/orchestrator.js +1 -548
  27. package/src/core/stateManager.js +1 -877
  28. package/src/index.js +1 -631
  29. package/src/interfaces/cli.js +1 -549
  30. package/src/interfaces/terminal/__tests__/smoke/advancedFeatures.test.js +1 -0
  31. package/src/interfaces/terminal/__tests__/smoke/agentControl.test.js +1 -0
  32. package/src/interfaces/terminal/__tests__/smoke/agents.test.js +1 -0
  33. package/src/interfaces/terminal/__tests__/smoke/components.test.js +1 -0
  34. package/src/interfaces/terminal/__tests__/smoke/connection.test.js +1 -0
  35. package/src/interfaces/terminal/__tests__/smoke/enhancements.test.js +1 -0
  36. package/src/interfaces/terminal/__tests__/smoke/imports.test.js +1 -0
  37. package/src/interfaces/terminal/__tests__/smoke/messages.test.js +1 -0
  38. package/src/interfaces/terminal/__tests__/smoke/tools.test.js +1 -0
  39. package/src/interfaces/terminal/api/apiClient.js +1 -0
  40. package/src/interfaces/terminal/api/messageRouter.js +1 -0
  41. package/src/interfaces/terminal/api/session.js +1 -0
  42. package/src/interfaces/terminal/api/websocket.js +1 -0
  43. package/src/interfaces/terminal/components/AgentCreator.js +1 -0
  44. package/src/interfaces/terminal/components/AgentEditor.js +1 -0
  45. package/src/interfaces/terminal/components/AgentSwitcher.js +1 -0
  46. package/src/interfaces/terminal/components/ErrorBoundary.js +1 -0
  47. package/src/interfaces/terminal/components/ErrorPanel.js +1 -0
  48. package/src/interfaces/terminal/components/Header.js +1 -0
  49. package/src/interfaces/terminal/components/HelpPanel.js +1 -0
  50. package/src/interfaces/terminal/components/InputBox.js +1 -0
  51. package/src/interfaces/terminal/components/Layout.js +1 -0
  52. package/src/interfaces/terminal/components/LoadingSpinner.js +1 -0
  53. package/src/interfaces/terminal/components/MessageList.js +1 -0
  54. package/src/interfaces/terminal/components/MultilineTextInput.js +1 -0
  55. package/src/interfaces/terminal/components/SearchPanel.js +1 -0
  56. package/src/interfaces/terminal/components/SettingsPanel.js +1 -0
  57. package/src/interfaces/terminal/components/StatusBar.js +1 -0
  58. package/src/interfaces/terminal/components/TextInput.js +1 -0
  59. package/src/interfaces/terminal/config/agentEditorConstants.js +1 -0
  60. package/src/interfaces/terminal/config/constants.js +1 -0
  61. package/src/interfaces/terminal/index.js +1 -0
  62. package/src/interfaces/terminal/state/useAgentControl.js +1 -0
  63. package/src/interfaces/terminal/state/useAgents.js +1 -0
  64. package/src/interfaces/terminal/state/useConnection.js +1 -0
  65. package/src/interfaces/terminal/state/useMessages.js +1 -0
  66. package/src/interfaces/terminal/state/useTools.js +1 -0
  67. package/src/interfaces/terminal/utils/debugLogger.js +1 -0
  68. package/src/interfaces/terminal/utils/settingsStorage.js +1 -0
  69. package/src/interfaces/terminal/utils/theme.js +1 -0
  70. package/src/interfaces/webServer.js +1 -2162
  71. package/src/modules/fileExplorer/controller.js +1 -280
  72. package/src/modules/fileExplorer/index.js +1 -37
  73. package/src/modules/fileExplorer/middleware.js +1 -92
  74. package/src/modules/fileExplorer/routes.js +1 -125
  75. package/src/modules/fileExplorer/types.js +1 -44
  76. package/src/services/aiService.js +1 -1232
  77. package/src/services/apiKeyManager.js +1 -164
  78. package/src/services/benchmarkService.js +1 -366
  79. package/src/services/budgetService.js +1 -539
  80. package/src/services/contextInjectionService.js +1 -247
  81. package/src/services/conversationCompactionService.js +1 -637
  82. package/src/services/errorHandler.js +1 -810
  83. package/src/services/fileAttachmentService.js +1 -544
  84. package/src/services/modelRouterService.js +1 -366
  85. package/src/services/modelsService.js +1 -322
  86. package/src/services/qualityInspector.js +1 -796
  87. package/src/services/tokenCountingService.js +1 -536
  88. package/src/tools/agentCommunicationTool.js +1 -1344
  89. package/src/tools/agentDelayTool.js +1 -485
  90. package/src/tools/asyncToolManager.js +1 -604
  91. package/src/tools/baseTool.js +1 -800
  92. package/src/tools/browserTool.js +1 -920
  93. package/src/tools/cloneDetectionTool.js +1 -621
  94. package/src/tools/dependencyResolverTool.js +1 -1215
  95. package/src/tools/fileContentReplaceTool.js +1 -875
  96. package/src/tools/fileSystemTool.js +1 -1107
  97. package/src/tools/fileTreeTool.js +1 -853
  98. package/src/tools/imageTool.js +1 -901
  99. package/src/tools/importAnalyzerTool.js +1 -1060
  100. package/src/tools/jobDoneTool.js +1 -248
  101. package/src/tools/seekTool.js +1 -956
  102. package/src/tools/staticAnalysisTool.js +1 -1778
  103. package/src/tools/taskManagerTool.js +1 -2873
  104. package/src/tools/terminalTool.js +1 -2304
  105. package/src/tools/webTool.js +1 -1430
  106. package/src/types/agent.js +1 -519
  107. package/src/types/contextReference.js +1 -972
  108. package/src/types/conversation.js +1 -730
  109. package/src/types/toolCommand.js +1 -747
  110. package/src/utilities/attachmentValidator.js +1 -292
  111. package/src/utilities/configManager.js +1 -582
  112. package/src/utilities/constants.js +1 -722
  113. package/src/utilities/directoryAccessManager.js +1 -535
  114. package/src/utilities/fileProcessor.js +1 -307
  115. package/src/utilities/logger.js +1 -436
  116. package/src/utilities/tagParser.js +1 -1246
  117. package/src/utilities/toolConstants.js +1 -317
  118. package/web-ui/build/index.html +2 -2
  119. package/web-ui/build/static/{index-Dy2bYbOa.css → index-CClD1090.css} +1 -1
  120. package/web-ui/build/static/{index-CjkkcnFA.js → index-lCBai6dX.js} +66 -67
@@ -1,2147 +1 @@
1
- /**
2
- * AgentScheduler - Manages cooperative execution of multiple agents
3
- *
4
- * Architecture:
5
- * - Iterates over all active agents in round-robin fashion
6
- * - For each agent, processes queued messages (toolResults, interAgentMessages, userMessages) in arrival order
7
- * - Sends conversation history to AI service for completion
8
- * - Handles agent mode differences (CHAT vs AGENT)
9
- * - Respects agent delays set by agentDelay tool
10
- */
11
-
12
- import {
13
- AGENT_MODES,
14
- AGENT_MODE_STATES,
15
- MESSAGE_ROLES,
16
- COMPACTION_CONFIG,
17
- COMPACTION_STATUS,
18
- COMPACTION_STRATEGIES,
19
- TOKEN_COUNTING_MODES
20
- } from '../utilities/constants.js';
21
- import ContextInjectionService from '../services/contextInjectionService.js';
22
- import TokenCountingService from '../services/tokenCountingService.js';
23
- import ConversationCompactionService from '../services/conversationCompactionService.js';
24
-
25
- class AgentScheduler {
26
- constructor(agentPool, messageProcessor, aiService, logger, webSocketManager = null, modelRouterService = null, modelsService = null) {
27
- this.agentPool = agentPool;
28
- this.messageProcessor = messageProcessor;
29
- this.aiService = aiService;
30
- this.logger = logger;
31
- this.webSocketManager = webSocketManager;
32
- this.modelRouterService = modelRouterService;
33
- this.modelsService = modelsService;
34
-
35
- // Initialize ContextInjectionService for file attachments
36
- this.contextInjectionService = new ContextInjectionService({}, logger);
37
-
38
- // Initialize compactization services
39
- this.tokenCountingService = new TokenCountingService(logger);
40
- this.compactionService = new ConversationCompactionService(
41
- this.tokenCountingService,
42
- aiService,
43
- logger
44
- );
45
-
46
- // Compactization state tracking
47
- this.compactionInProgress = new Map(); // Map of agentId to compaction status
48
-
49
- // Scheduler state
50
- this.isRunning = false;
51
- this.activeAgents = new Map(); // Map of agentId to context (includes sessionId)
52
- this.scheduleInterval = null;
53
-
54
- // Duplicate processing prevention
55
- this.processedStateHashes = new Map(); // Map of agentId to Set of processed state hashes
56
-
57
- // Concurrency control - prevent multiple processing cycles
58
- this.processingInProgress = false;
59
- this.agentProcessingLocks = new Map(); // Map of agentId to processing state
60
-
61
- // Configuration
62
- this.ITERATION_DELAY = 1000; // ms between agent iterations
63
- this.MAX_ITERATIONS_PER_CYCLE = 100000; // Safety limit
64
- }
65
-
66
- /**
67
- * Start the agent scheduler
68
- */
69
- start() {
70
- if (this.isRunning) {
71
- this.logger.info('Agent scheduler is already running');
72
- return;
73
- }
74
-
75
- this.isRunning = true;
76
- this.logger.info('Starting Agent Scheduler with T/M/U queue system');
77
-
78
- // Initialize existing AGENT mode agents
79
- this.initializeExistingAgents();
80
-
81
- // Start the main scheduler loop
82
- this.scheduleInterval = setInterval(() => {
83
- this.processingCycle().catch(error => {
84
- this.logger.error('Scheduler processing cycle failed:', error);
85
- });
86
- }, this.ITERATION_DELAY);
87
- }
88
-
89
- /**
90
- * Initialize existing AGENT mode agents into the scheduler
91
- * Called on scheduler startup to ensure all AGENT mode agents are active
92
- * @private
93
- */
94
- async initializeExistingAgents() {
95
- try {
96
- // Get all agents from the pool
97
- const allAgents = await this.agentPool.getAllAgents();
98
-
99
- let addedCount = 0;
100
- for (const agent of allAgents) {
101
- // Add AGENT mode agents to scheduler
102
- if (agent.mode === AGENT_MODES.AGENT) {
103
- this.logger.info(`Initializing existing AGENT mode agent: ${agent.id}`, {
104
- agentName: agent.name,
105
- sessionId: agent.sessionId
106
- });
107
-
108
- // Check if agent is already in scheduler with a sessionId
109
- const existingContext = this.activeAgents.get(agent.id);
110
- const sessionId = existingContext?.sessionId || agent.sessionId;
111
-
112
- await this.addAgent(agent.id, {
113
- sessionId: sessionId, // Preserve existing sessionId if available
114
- triggeredBy: 'scheduler-startup',
115
- reason: 'Agent was already in AGENT mode'
116
- });
117
-
118
- addedCount++;
119
- }
120
- }
121
-
122
- this.logger.info(`Initialized ${addedCount} existing AGENT mode agents into scheduler`);
123
-
124
- } catch (error) {
125
- this.logger.error('Failed to initialize existing agents', {
126
- error: error.message
127
- });
128
- }
129
- }
130
-
131
- /**
132
- * Stop the agent scheduler
133
- */
134
- stop() {
135
- if (!this.isRunning) return;
136
-
137
- this.isRunning = false;
138
- if (this.scheduleInterval) {
139
- clearInterval(this.scheduleInterval);
140
- this.scheduleInterval = null;
141
- }
142
-
143
- this.activeAgents.clear();
144
- this.compactionInProgress.clear();
145
-
146
- // Cleanup services
147
- if (this.tokenCountingService && this.tokenCountingService.cleanup) {
148
- this.tokenCountingService.cleanup();
149
- }
150
-
151
- this.logger.info('Agent Scheduler stopped');
152
- }
153
-
154
- /**
155
- * Add agent to scheduler for processing
156
- * @param {string} agentId - Agent ID to add
157
- * @param {Object} context - Processing context
158
- */
159
- async addAgent(agentId, context = {}) {
160
- const agent = await this.agentPool.getAgent(agentId);
161
- if (!agent) {
162
- this.logger.warn(`Cannot add agent to scheduler - agent not found: ${agentId}`);
163
- return;
164
- }
165
-
166
- if (agent.status !== 'active') {
167
- this.logger.debug(`Skipping inactive agent: ${agentId} (status: ${agent.status})`);
168
- return;
169
- }
170
-
171
- // Store agent with its context (including sessionId)
172
- // CRITICAL FIX: Don't use fallback session IDs that break API key resolution
173
- if (!context.sessionId) {
174
- this.logger.warn(`Agent ${agentId} added to scheduler without sessionId - API key resolution may fail`, {
175
- agentName: agent.name,
176
- triggeredBy: context.triggeredBy
177
- });
178
- }
179
-
180
- this.activeAgents.set(agentId, {
181
- sessionId: context.sessionId, // NO FALLBACK - preserve original session ID or undefined
182
- triggeredBy: context.triggeredBy || 'unknown',
183
- addedAt: new Date().toISOString()
184
- });
185
-
186
- // Initialize hash tracking for this agent if not exists
187
- if (!this.processedStateHashes.has(agentId)) {
188
- this.processedStateHashes.set(agentId, new Set());
189
- }
190
-
191
- this.logger.info(`Agent added to scheduler: ${agentId}`, {
192
- agentMode: agent.mode,
193
- activeAgents: this.activeAgents.size,
194
- sessionId: context.sessionId || 'NO_SESSION_ID',
195
- contextKeys: Object.keys(context),
196
- triggeredBy: context.triggeredBy || 'unknown'
197
- });
198
-
199
- // Start scheduler if not running
200
- if (!this.isRunning) {
201
- this.start();
202
- }
203
- }
204
-
205
- /**
206
- * Remove agent from scheduler
207
- * @param {string} agentId - Agent ID to remove
208
- * @param {string} reason - Reason for removal
209
- */
210
- removeAgent(agentId, reason = 'completed') {
211
- if (this.activeAgents.has(agentId)) {
212
- this.activeAgents.delete(agentId);
213
-
214
- // Clean up processed state hashes for this agent
215
- this.processedStateHashes.delete(agentId);
216
-
217
- this.logger.info(`Agent removed from scheduler: ${agentId}`, {
218
- reason,
219
- remainingAgents: this.activeAgents.size
220
- });
221
-
222
- // Stop scheduler if no active agents
223
- if (this.activeAgents.size === 0) {
224
- this.stop();
225
- }
226
- }
227
- }
228
-
229
- /**
230
- * Check if agent is currently in scheduler
231
- * @param {string} agentId - Agent ID to check
232
- * @returns {boolean} True if agent is in scheduler
233
- */
234
- isAgentInScheduler(agentId) {
235
- return this.activeAgents.has(agentId);
236
- }
237
-
238
- /**
239
- * Stop autonomous execution for a specific agent
240
- * @param {string} agentId - Agent ID to stop
241
- * @returns {Promise<Object>} Result with agent state
242
- */
243
- async stopAgentExecution(agentId) {
244
- try {
245
- const agent = await this.agentPool.getAgent(agentId);
246
- if (!agent) {
247
- return {
248
- success: false,
249
- error: 'Agent not found'
250
- };
251
- }
252
-
253
- // Set agent mode back to CHAT
254
- agent.mode = AGENT_MODES.CHAT;
255
- agent.modeState = AGENT_MODE_STATES.IDLE;
256
-
257
- // Clear any delays
258
- agent.delayEndTime = null;
259
-
260
- // Persist the change
261
- await this.agentPool.persistAgentState(agentId);
262
-
263
- // Remove from scheduler
264
- this.removeAgent(agentId, 'stopped-by-user');
265
-
266
- // Get session ID for broadcast
267
- const agentContext = this.activeAgents.get(agentId);
268
- const sessionId = agentContext?.sessionId || agent.sessionId;
269
-
270
- // Log warning if no session ID but continue with broadcast
271
- if (!sessionId) {
272
- this.logger.warn(`Agent ${agentId} stopped but has no session ID for broadcast`, {
273
- agentName: agent.name
274
- });
275
- }
276
-
277
- // Broadcast stop event only if we have a valid session ID
278
- if (sessionId && this.webSocketManager && this.webSocketManager.broadcastToSession) {
279
- this.webSocketManager.broadcastToSession(sessionId, {
280
- type: 'execution_stopped',
281
- data: {
282
- agentId,
283
- type: 'execution_stopped',
284
- modeState: 'stopped',
285
- timestamp: new Date().toISOString()
286
- }
287
- });
288
- }
289
-
290
- this.logger.info(`Agent execution stopped: ${agentId}`, {
291
- mode: agent.mode,
292
- modeState: agent.modeState
293
- });
294
-
295
- return {
296
- success: true,
297
- agent: {
298
- id: agent.id,
299
- name: agent.name,
300
- mode: agent.mode,
301
- modeState: agent.modeState
302
- }
303
- };
304
-
305
- } catch (error) {
306
- this.logger.error(`Failed to stop agent execution: ${agentId}`, {
307
- error: error.message
308
- });
309
-
310
- return {
311
- success: false,
312
- error: error.message
313
- };
314
- }
315
- }
316
-
317
- /**
318
- * Main processing cycle - iterates over all active agents
319
- * @private
320
- */
321
- async processingCycle() {
322
- // Prevent concurrent processing cycles
323
- if (this.processingInProgress) {
324
- this.logger.debug('Processing cycle already in progress, skipping');
325
- return;
326
- }
327
-
328
- if (this.activeAgents.size === 0) {
329
- return; // No agents to process
330
- }
331
-
332
- this.processingInProgress = true;
333
-
334
- try {
335
- const agentIds = Array.from(this.activeAgents.keys());
336
-
337
- for (const agentId of agentIds) {
338
- try {
339
- // Skip if agent was removed during this cycle
340
- if (!this.activeAgents.has(agentId)) continue;
341
-
342
- const shouldContinue = await this.processAgent(agentId);
343
-
344
- if (!shouldContinue) {
345
- this.removeAgent(agentId, 'completed');
346
- }
347
-
348
- } catch (error) {
349
- this.logger.error(`Agent processing failed: ${agentId}`, {
350
- error: error.message,
351
- stack: error.stack
352
- });
353
-
354
- this.removeAgent(agentId, 'error');
355
- }
356
- }
357
- } finally {
358
- this.processingInProgress = false;
359
- }
360
- }
361
-
362
- /**
363
- * Process a single agent - handle queues and get AI response
364
- * @param {string} agentId - Agent ID to process
365
- * @returns {Promise<boolean>} Whether agent should continue in scheduler
366
- * @private
367
- */
368
- async processAgent(agentId) {
369
- // Check if this agent is already being processed
370
- if (this.agentProcessingLocks.get(agentId)) {
371
- this.logger.debug(`Agent ${agentId} is already being processed, skipping`);
372
- return true; // Continue in scheduler but skip this iteration
373
- }
374
-
375
- const agent = await this.agentPool.getAgent(agentId);
376
- if (!agent) {
377
- return false; // Agent no longer exists
378
- }
379
-
380
- // Set processing lock
381
- this.agentProcessingLocks.set(agentId, true);
382
-
383
- try {
384
- // Check if agent is delayed
385
- if (agent.delayEndTime && new Date() < new Date(agent.delayEndTime)) {
386
- this.logger.debug(`Agent ${agentId} is delayed until ${agent.delayEndTime}`);
387
- return true; // Continue in scheduler but skip this iteration
388
- }
389
-
390
- // Check if agent is paused
391
- if (agent.status === 'paused' || agent.pausedUntil) {
392
- if (agent.pausedUntil && new Date() < new Date(agent.pausedUntil)) {
393
- this.logger.debug(`Agent ${agentId} is paused until ${agent.pausedUntil}`);
394
- return true; // Continue in scheduler but skip this iteration
395
- }
396
- }
397
-
398
- // Check stop request
399
- if (agent.stopRequested) {
400
- this.logger.info(`Agent ${agentId} stop requested - removing from scheduler`);
401
- return false;
402
- }
403
-
404
- // Generate current state hash
405
- const currentStateHash = this.generateAgentStateHash(agent);
406
-
407
- // Check if we've already processed this exact state
408
- if (this.hasProcessedState(agentId, currentStateHash)) {
409
- this.logger.debug(`Agent ${agentId} state already processed, skipping duplicate iteration`, {
410
- stateHash: currentStateHash,
411
- agentMode: agent.mode
412
- });
413
-
414
- // CRITICAL FIX: CHAT agents with no new messages should be removed, not kept in scheduler
415
- // Only AGENT agents should wait for backend responses with duplicate states
416
- if (agent.mode === AGENT_MODES.CHAT) {
417
- const hasNewMessages = agent.messageQueues.userMessages.length > 0 ||
418
- agent.messageQueues.interAgentMessages.length > 0;
419
-
420
- if (!hasNewMessages) {
421
- this.logger.debug(`CHAT agent ${agentId} has duplicate state with no new messages - removing from scheduler`);
422
- return false; // Remove CHAT agents with no new messages
423
- }
424
- }
425
-
426
- // AGENT agents: skip this iteration but keep in scheduler
427
- // Don't exit - backend responses might still arrive
428
- return true;
429
- }
430
-
431
- // REFACTORED: Unified processing path with priority handling
432
- // User messages are processed first by processAgentQueues (it sorts by priority)
433
- const queues = agent.messageQueues;
434
-
435
- // Log if user messages are present (highest priority)
436
- if (queues.userMessages.length > 0) {
437
- this.logger.info(`User message detected for agent ${agentId} - will be prioritized`, {
438
- userMessageCount: queues.userMessages.length,
439
- agentMode: agent.mode
440
- });
441
- }
442
-
443
- // Check if agent has any messages to process
444
- const totalMessages = queues.toolResults.length + queues.interAgentMessages.length + queues.userMessages.length;
445
-
446
- if (totalMessages === 0 && agent.mode === AGENT_MODES.CHAT) {
447
- // CHAT agents with no messages are removed from scheduler
448
- this.logger.debug(`CHAT agent ${agentId} has no queued messages - removing from scheduler`);
449
- return false;
450
- }
451
-
452
- if (totalMessages === 0 && agent.mode === AGENT_MODES.AGENT) {
453
- // Check if we should auto-create initial task for conversation
454
- await this.autoCreateInitialTaskIfNeeded(agentId);
455
-
456
- // AGENT agents need pending tasks or unprocessed messages to continue
457
- const hasPendingTasks = this.hasPendingTasks(agent);
458
- const hasUnprocessedMessages = this.hasUnprocessedMessages(agent);
459
-
460
- if (!hasPendingTasks && !hasUnprocessedMessages) {
461
- this.logger.info(`AGENT mode agent ${agentId} has no pending tasks or messages - removing from scheduler`, {
462
- agentName: agent.name,
463
- taskCount: agent.taskList?.tasks?.length || 0,
464
- completedTasks: agent.taskList?.tasks?.filter(t => t.status === 'completed').length || 0
465
- });
466
- return false; // Remove from scheduler when no work remaining
467
- }
468
-
469
- // Continue running autonomously if has work
470
- return await this.processAgentAutonomously(agentId);
471
- }
472
-
473
- // Process queued messages in arrival order
474
- const processedMessages = await this.processAgentQueues(agentId);
475
-
476
- if (processedMessages === 0) {
477
- // No messages processed
478
- if (agent.mode === AGENT_MODES.CHAT) {
479
- return false; // Remove CHAT agents with no messages
480
- } else {
481
- return await this.processAgentAutonomously(agentId); // Continue AGENT agents
482
- }
483
- }
484
-
485
- // Get AI response after processing queued messages
486
- const aiResponse = await this.getAgentAIResponse(agentId);
487
-
488
- if (!aiResponse) {
489
- this.logger.warn(`No AI response for agent ${agentId}`);
490
- return agent.mode === AGENT_MODES.AGENT; // Keep AGENT agents, remove CHAT agents
491
- }
492
-
493
- // Process AI response and execute any tools (broadcasts to UI, executes tools)
494
- await this.processAIResponse(agentId, aiResponse);
495
-
496
- // Mark this state as processed after successful completion
497
- this.markStateAsProcessed(agentId, currentStateHash);
498
-
499
- // Determine if agent should continue in scheduler
500
- return this.shouldAgentContinue(agentId, agent);
501
-
502
- } finally {
503
- // Always clear processing lock, even on errors
504
- this.agentProcessingLocks.delete(agentId);
505
- }
506
- }
507
-
508
- /**
509
- * Process agent's message queues with consolidated single-message approach
510
- * @param {string} agentId - Agent ID
511
- * @returns {Promise<number>} Number of messages processed
512
- * @private
513
- */
514
- async processAgentQueues(agentId) {
515
- const agent = await this.agentPool.getAgent(agentId);
516
- if (!agent) return 0;
517
-
518
- const queues = agent.messageQueues;
519
-
520
- // Collect all messages with timestamps for proper ordering
521
- const allMessages = [
522
- ...queues.toolResults.map(msg => ({ ...msg, queueType: 'toolResults' })),
523
- ...queues.interAgentMessages.map(msg => ({ ...msg, queueType: 'interAgentMessages' })),
524
- ...queues.userMessages.map(msg => ({ ...msg, queueType: 'userMessages' }))
525
- ];
526
-
527
- if (allMessages.length === 0) return 0;
528
-
529
- // Sort by arrival time (timestamp)
530
- allMessages.sort((a, b) => new Date(a.timestamp || a.queuedAt || 0) - new Date(b.timestamp || b.queuedAt || 0));
531
-
532
- // CRITICAL FIX: Consolidate all messages into single AI request
533
- let consolidatedContent = '';
534
- const hasUserMessages = allMessages.some(m => m.queueType === 'userMessages');
535
- const hasInterAgentMessages = allMessages.some(m => m.queueType === 'interAgentMessages');
536
- const hasToolResults = allMessages.some(m => m.queueType === 'toolResults');
537
-
538
- // Add user messages first (highest priority)
539
- const userMessages = allMessages.filter(m => m.queueType === 'userMessages');
540
- if (userMessages.length > 0) {
541
- userMessages.forEach(msg => {
542
- if (consolidatedContent) consolidatedContent += '\n\n';
543
- consolidatedContent += msg.content;
544
- });
545
- }
546
-
547
- // Add inter-agent messages as context (not as separate system messages)
548
- const interAgentMessages = allMessages.filter(m => m.queueType === 'interAgentMessages');
549
- if (interAgentMessages.length > 0) {
550
- if (consolidatedContent) consolidatedContent += '\n\n';
551
- consolidatedContent += '[Agent Messages]\n';
552
- interAgentMessages.forEach(msg => {
553
- const senderName = msg.senderName || msg.sender || 'Unknown Agent';
554
- consolidatedContent += `${senderName}: ${msg.content}\n`;
555
- });
556
- }
557
-
558
- // Add tool results as context
559
- const toolResults = allMessages.filter(m => m.queueType === 'toolResults');
560
- if (toolResults.length > 0) {
561
- if (consolidatedContent) consolidatedContent += '\n\n';
562
- consolidatedContent += '[Previous Tool Results]\n';
563
- toolResults.forEach(msg => {
564
- consolidatedContent += `${this.formatToolResult(msg)}\n`;
565
- });
566
- }
567
-
568
- // Add processing instructions only if needed
569
- if (hasInterAgentMessages) {
570
- consolidatedContent += '\nNote: Use the agentcommunication tool if you need to respond to other agents.';
571
- }
572
-
573
- // PHASE 2: Auto-create tasks for incoming messages
574
- await this.autoCreateTasksForMessages(agentId, userMessages, interAgentMessages);
575
-
576
- // Create single consolidated user message for AI processing
577
- const consolidatedMessage = {
578
- id: `consolidated-${Date.now()}`,
579
- role: MESSAGE_ROLES.USER,
580
- content: consolidatedContent.trim(),
581
- timestamp: new Date().toISOString(),
582
- type: 'consolidated-input',
583
- originalMessageCount: allMessages.length
584
- };
585
-
586
- // Add to conversation history (don't broadcast - this is internal)
587
- await this.addMessageToConversation(agentId, consolidatedMessage, false);
588
-
589
- // CRITICAL: Update conversation tracking when inter-agent messages are processed
590
- if (agent && interAgentMessages.length > 0) {
591
- for (const msg of interAgentMessages) {
592
- if (msg.sender) {
593
- // Mark that this agent received a message from the sender
594
- if (!agent.interAgentTracking.has(msg.sender)) {
595
- agent.interAgentTracking.set(msg.sender, {
596
- lastSent: null,
597
- lastReceived: null,
598
- lastType: null
599
- });
600
- }
601
-
602
- const tracking = agent.interAgentTracking.get(msg.sender);
603
- tracking.lastReceived = Date.now();
604
- tracking.lastType = 'received';
605
- }
606
- }
607
- // Persist updated tracking
608
- await this.agentPool.persistAgentState(agentId);
609
- }
610
-
611
- // Clear all processed queues
612
- queues.toolResults.length = 0;
613
- queues.interAgentMessages.length = 0;
614
- queues.userMessages.length = 0;
615
-
616
- // Persist updated agent state
617
- await this.agentPool.persistAgentState(agentId);
618
-
619
- this.logger.debug(`Consolidated ${allMessages.length} queued messages for agent ${agentId}`);
620
- return allMessages.length;
621
- }
622
-
623
- /**
624
- * Add message to agent's conversation history with proper formatting
625
- * @param {string} agentId - Agent ID
626
- * @param {Object} message - Message to add
627
- * @param {boolean} broadcast - Whether to broadcast message to UI (default true)
628
- * @private
629
- */
630
- async addMessageToConversation(agentId, message, broadcast = true) {
631
- const agent = await this.agentPool.getAgent(agentId);
632
- if (!agent) return;
633
-
634
- // Format message based on queue type
635
- let formattedMessage;
636
-
637
- switch (message.queueType) {
638
- case 'toolResults': // Tool results
639
- formattedMessage = {
640
- ...message,
641
- role: 'tool',
642
- content: this.formatToolResult(message)
643
- };
644
- break;
645
-
646
- case 'interAgentMessages': // Inter-agent messages
647
- formattedMessage = {
648
- ...message,
649
- role: MESSAGE_ROLES.SYSTEM,
650
- content: `Message from ${message.senderName || message.sender}: ${message.content}`
651
- };
652
- break;
653
-
654
- case 'userMessages': // User messages
655
- formattedMessage = {
656
- ...message,
657
- role: MESSAGE_ROLES.USER
658
- };
659
- break;
660
-
661
- default:
662
- formattedMessage = message;
663
- }
664
-
665
- // Add timestamp if not present
666
- if (!formattedMessage.timestamp) {
667
- formattedMessage.timestamp = new Date().toISOString();
668
- }
669
-
670
- // Add to conversation history
671
- agent.conversations.full.messages.push(formattedMessage);
672
- agent.conversations.full.lastUpdated = new Date().toISOString();
673
-
674
- // Add to current model conversation if exists
675
- if (agent.currentModel && agent.conversations[agent.currentModel]) {
676
- agent.conversations[agent.currentModel].messages.push(formattedMessage);
677
- agent.conversations[agent.currentModel].lastUpdated = new Date().toISOString();
678
- }
679
-
680
- // FIX: Only broadcast user-visible messages to UI (not internal system prompts)
681
- if (broadcast && this.shouldBroadcastMessage(formattedMessage)) {
682
- this.broadcastMessageUpdate(agentId, formattedMessage);
683
- }
684
- }
685
-
686
- /**
687
- * Process agent autonomously (for AGENT mode with no queued messages)
688
- * @param {string} agentId - Agent ID
689
- * @returns {Promise<boolean>} Whether agent should continue
690
- * @private
691
- */
692
- async processAgentAutonomously(agentId) {
693
- // PHASE 2: Auto-mark the highest priority pending task as in-progress
694
- await this.autoProgressHighestPriorityTask(agentId);
695
-
696
- // Get AI response without new messages
697
- const aiResponse = await this.getAgentAIResponse(agentId);
698
-
699
- if (!aiResponse) {
700
- return true; // Keep trying
701
- }
702
-
703
- // Process AI response and execute tools
704
- await this.processAIResponse(agentId, aiResponse);
705
-
706
- const agent = await this.agentPool.getAgent(agentId);
707
- return this.shouldAgentContinue(agentId, agent);
708
- }
709
-
710
- /**
711
- * Check if compaction is needed and perform it
712
- * @param {string} agentId - Agent ID
713
- * @param {string} targetModel - Target model for AI request
714
- * @param {string} sessionId - Session ID for context
715
- * @returns {Promise<Object>} Result with shouldContinue flag
716
- * @private
717
- */
718
- async checkAndPerformCompaction(agentId, targetModel, sessionId) {
719
- const ENABLE_COMPACT_DEBUG = process.env.COMPACT_DEBUG === 'true';
720
-
721
- if (ENABLE_COMPACT_DEBUG) {
722
- console.log('[COMPACT-CHECK-START]', {
723
- agentId,
724
- targetModel,
725
- sessionId,
726
- timestamp: new Date().toISOString()
727
- });
728
- }
729
-
730
- try {
731
- const agent = await this.agentPool.getAgent(agentId);
732
- if (!agent) {
733
- if (ENABLE_COMPACT_DEBUG) {
734
- console.log('[COMPACT-ERROR]', { agentId, reason: 'Agent not found' });
735
- }
736
- return { shouldContinue: false, error: 'Agent not found' };
737
- }
738
-
739
- // For model switching, check the current model's conversation, not the target model's
740
- // This handles scenarios where we're switching from a larger context to a smaller one
741
- let modelToCheck = agent.currentModel && agent.currentModel !== targetModel
742
- ? agent.currentModel
743
- : targetModel;
744
-
745
- // DEFENSIVE: If modelToCheck is undefined, try to find a valid conversation key
746
- if (!modelToCheck) {
747
- this.logger.warn(`Agent ${agentId} has no currentModel or targetModel set, attempting to use available conversation`, {
748
- agentId,
749
- currentModel: agent.currentModel,
750
- targetModel,
751
- preferredModel: agent.preferredModel,
752
- availableConversations: Object.keys(agent.conversations || {})
753
- });
754
-
755
- // Notify user via WebSocket
756
- this.broadcastCompactionEvent(agentId, sessionId, {
757
- status: 'warning',
758
- message: 'Agent model configuration issue detected - using fallback',
759
- details: `Agent has no currentModel set. Using fallback model for compaction check.`,
760
- agentName: agent.name
761
- });
762
-
763
- // Try preferredModel first
764
- if (agent.preferredModel && agent.conversations[agent.preferredModel]) {
765
- modelToCheck = agent.preferredModel;
766
- this.logger.info(`Using preferredModel as fallback for compaction check: ${modelToCheck}`);
767
- } else {
768
- // Find any non-'full' conversation key
769
- const conversationKeys = Object.keys(agent.conversations || {}).filter(key => key !== 'full');
770
- if (conversationKeys.length > 0) {
771
- modelToCheck = conversationKeys[0];
772
- this.logger.warn(`Using first available conversation key for compaction check: ${modelToCheck}`);
773
- } else {
774
- this.logger.error(`No valid conversation found for agent ${agentId}, skipping compaction`);
775
-
776
- // Notify user of critical error
777
- this.broadcastCompactionEvent(agentId, sessionId, {
778
- status: 'error',
779
- message: 'No valid conversation found for compaction',
780
- details: `Agent ${agent.name} has no valid conversation data. Compaction skipped.`,
781
- agentName: agent.name
782
- });
783
-
784
- return { shouldContinue: true, error: 'No valid conversation found' };
785
- }
786
- }
787
- }
788
-
789
- // Get conversation metadata
790
- const metadata = await this.agentPool.getCompactionMetadata(agentId, modelToCheck);
791
-
792
- if (ENABLE_COMPACT_DEBUG) {
793
- console.log('[COMPACT-METADATA]', {
794
- agentId,
795
- modelToCheck,
796
- hasMetadata: !!metadata,
797
- isCompacted: metadata?.isCompacted,
798
- originalMessageCount: metadata?.originalMessages?.length || 0,
799
- compactedMessageCount: metadata?.compactedMessages?.length || 0,
800
- lastCompactization: metadata?.lastCompactization || 'never',
801
- compactizationCount: metadata?.compactizationCount || 0,
802
- originalTokenCount: metadata?.originalTokenCount || 0,
803
- compactedTokenCount: metadata?.compactedTokenCount || 0
804
- });
805
- }
806
-
807
- // If no conversation exists for this model yet, return early
808
- if (!metadata || (!metadata.originalMessages && !metadata.compactedMessages)) {
809
- this.logger.debug(`Compaction skipped: no conversation metadata for agent ${agentId}, model ${modelToCheck}`);
810
- if (ENABLE_COMPACT_DEBUG) {
811
- console.log('[COMPACT-SKIPPED]', { agentId, reason: 'No conversation metadata' });
812
- }
813
- return { shouldContinue: true }; // No conversation to compact
814
- }
815
-
816
- // Determine which messages to use for token counting
817
- const messages = metadata.isCompacted
818
- ? metadata.compactedMessages
819
- : metadata.originalMessages;
820
-
821
- if (ENABLE_COMPACT_DEBUG) {
822
- console.log('[COMPACT-MESSAGES-SELECTED]', {
823
- agentId,
824
- selectedArray: metadata.isCompacted ? 'compactedMessages' : 'originalMessages',
825
- messageCount: messages?.length || 0,
826
- reason: metadata.isCompacted ? 'Compaction exists, using compacted version' : 'No compaction yet, using original'
827
- });
828
- }
829
-
830
- if (!messages || messages.length < COMPACTION_CONFIG.MIN_MESSAGES_FOR_COMPACTION) {
831
- this.logger.debug(`Compaction skipped: too few messages (${messages?.length || 0}) for agent ${agentId}`);
832
- if (ENABLE_COMPACT_DEBUG) {
833
- console.log('[COMPACT-SKIPPED]', { agentId, reason: 'Too few messages', messageCount: messages?.length || 0, minRequired: COMPACTION_CONFIG.MIN_MESSAGES_FOR_COMPACTION });
834
- }
835
- return { shouldContinue: true }; // Conversation too short to compact
836
- }
837
-
838
- // Count current tokens
839
- const currentTokens = await this.tokenCountingService.estimateConversationTokens(
840
- messages,
841
- targetModel,
842
- TOKEN_COUNTING_MODES.ACCURATE
843
- );
844
-
845
- // Get model specifications
846
- const contextWindow = this.tokenCountingService.getModelContextWindow(targetModel);
847
- const maxOutputTokens = this.tokenCountingService.getModelMaxOutputTokens(targetModel);
848
-
849
- if (ENABLE_COMPACT_DEBUG) {
850
- console.log('[COMPACT-TOKEN-COUNT]', {
851
- agentId,
852
- currentTokens,
853
- maxOutputTokens,
854
- contextWindow,
855
- model: targetModel,
856
- countingMode: 'ACCURATE'
857
- });
858
- }
859
-
860
- // Check if compaction is needed
861
- const threshold = agent.compactionThreshold || COMPACTION_CONFIG.DEFAULT_THRESHOLD;
862
- const shouldCompact = this.tokenCountingService.shouldTriggerCompaction(
863
- currentTokens,
864
- maxOutputTokens,
865
- contextWindow,
866
- threshold
867
- );
868
-
869
- if (ENABLE_COMPACT_DEBUG) {
870
- const requiredTokens = currentTokens + maxOutputTokens;
871
- const thresholdTokens = threshold * contextWindow;
872
- console.log('[COMPACT-TRIGGER-CHECK]', {
873
- agentId,
874
- currentTokens,
875
- maxOutputTokens,
876
- requiredTokens,
877
- contextWindow,
878
- threshold,
879
- thresholdTokens,
880
- shouldCompact,
881
- formula: `${currentTokens} + ${maxOutputTokens} = ${requiredTokens} ${shouldCompact ? '>=' : '<'} ${thresholdTokens} (${threshold * 100}% of ${contextWindow})`,
882
- decision: shouldCompact ? 'TRIGGER COMPACTION' : 'SKIP - below threshold'
883
- });
884
- }
885
-
886
- if (!shouldCompact) {
887
- if (ENABLE_COMPACT_DEBUG) {
888
- console.log('[COMPACT-SKIPPED]', { agentId, reason: 'Below threshold', utilizationPct: ((currentTokens + maxOutputTokens) / contextWindow * 100).toFixed(1) });
889
- }
890
- return { shouldContinue: true }; // No compaction needed
891
- }
892
-
893
- this.logger.info(`Compaction triggered for agent ${agentId}`, {
894
- currentTokens,
895
- contextWindow,
896
- threshold: `${(threshold * 100).toFixed(0)}%`,
897
- utilization: `${((currentTokens + maxOutputTokens) / contextWindow * 100).toFixed(1)}%`,
898
- targetModel
899
- });
900
-
901
- if (ENABLE_COMPACT_DEBUG) {
902
- console.log('[COMPACT-TRIGGERED]', {
903
- agentId,
904
- reason: 'Threshold exceeded',
905
- currentTokens,
906
- maxOutputTokens,
907
- requiredTokens: currentTokens + maxOutputTokens,
908
- contextWindow,
909
- threshold,
910
- utilizationPct: ((currentTokens + maxOutputTokens) / contextWindow * 100).toFixed(1)
911
- });
912
- }
913
-
914
- // Mark compaction in progress
915
- this.compactionInProgress.set(agentId, COMPACTION_STATUS.STARTING);
916
-
917
- // Broadcast compaction started event
918
- this.broadcastCompactionEvent(agentId, sessionId, {
919
- status: COMPACTION_STATUS.STARTING,
920
- currentTokens,
921
- targetTokens: this.tokenCountingService.calculateTargetTokenCount(contextWindow),
922
- contextWindow,
923
- model: targetModel
924
- });
925
-
926
- // Determine strategy: If model switching, use truncation; otherwise use summarization
927
- let strategy = COMPACTION_STRATEGIES.SUMMARIZATION;
928
- const currentModel = agent.currentModel;
929
-
930
- if (currentModel && currentModel !== targetModel) {
931
- strategy = COMPACTION_STRATEGIES.TRUNCATION;
932
- this.logger.info(`Using truncation strategy for model switch: ${currentModel} → ${targetModel}`);
933
- }
934
-
935
- // Update status to in-progress
936
- this.compactionInProgress.set(agentId, COMPACTION_STATUS.IN_PROGRESS);
937
- this.broadcastCompactionEvent(agentId, sessionId, {
938
- status: COMPACTION_STATUS.IN_PROGRESS,
939
- strategy,
940
- messageCount: messages.length
941
- });
942
-
943
- // Perform compaction (with retry logic)
944
- let compactionResult = null;
945
- let attempts = 0;
946
- const maxAttempts = COMPACTION_CONFIG.MAX_RETRY_ATTEMPTS;
947
-
948
- while (attempts < maxAttempts && !compactionResult) {
949
- attempts++;
950
-
951
- try {
952
- const currentStrategy = attempts === 1
953
- ? strategy
954
- : COMPACTION_STRATEGIES.AGGRESSIVE; // Use aggressive on retry
955
-
956
- compactionResult = await this.compactionService.compactConversation(
957
- messages,
958
- currentModel || targetModel,
959
- targetModel,
960
- {
961
- strategy: currentStrategy,
962
- targetTokenCount: this.tokenCountingService.calculateTargetTokenCount(contextWindow),
963
- sessionId
964
- }
965
- );
966
-
967
- // Validate compaction result
968
- const validation = this.tokenCountingService.validateCompaction(
969
- currentTokens,
970
- compactionResult.compactedTokenCount,
971
- contextWindow
972
- );
973
-
974
- if (!validation.valid) {
975
- this.logger.warn(`Compaction validation failed for agent ${agentId}`, {
976
- attempt: attempts,
977
- reason: validation.reason,
978
- reductionPercent: validation.reductionPercent
979
- });
980
-
981
- if (attempts < maxAttempts) {
982
- compactionResult = null; // Retry with aggressive strategy
983
- await new Promise(resolve => setTimeout(resolve, COMPACTION_CONFIG.RETRY_DELAY_MS));
984
- }
985
- }
986
-
987
- } catch (error) {
988
- this.logger.error(`Compaction attempt ${attempts} failed for agent ${agentId}`, {
989
- error: error.message
990
- });
991
-
992
- if (attempts >= maxAttempts) {
993
- throw error; // Final attempt failed
994
- }
995
-
996
- await new Promise(resolve => setTimeout(resolve, COMPACTION_CONFIG.RETRY_DELAY_MS));
997
- }
998
- }
999
-
1000
- if (!compactionResult) {
1001
- throw new Error('All compaction attempts failed');
1002
- }
1003
-
1004
- // For model switching, copy original messages to target model first
1005
- if (currentModel && currentModel !== targetModel && modelToCheck === currentModel) {
1006
- // Get the original messages from the current model
1007
- const sourceMetadata = await this.agentPool.getCompactionMetadata(agentId, currentModel);
1008
- if (sourceMetadata && sourceMetadata.originalMessages) {
1009
- // Copy original messages to target model's conversation
1010
- for (const message of sourceMetadata.originalMessages) {
1011
- await this.agentPool.addMessageToConversation(agentId, targetModel, message);
1012
- }
1013
- this.logger.debug(`Copied ${sourceMetadata.originalMessages.length} messages from ${currentModel} to ${targetModel} for model switching`);
1014
- }
1015
- }
1016
-
1017
- // Update AgentPool with compacted messages
1018
- await this.agentPool.updateCompactedMessages(agentId, targetModel, compactionResult);
1019
-
1020
- if (ENABLE_COMPACT_DEBUG) {
1021
- console.log('[COMPACT-COMPLETED]', {
1022
- agentId,
1023
- strategy: compactionResult.strategy,
1024
- originalMessageCount: compactionResult.originalMessages?.length || 0,
1025
- compactedMessageCount: compactionResult.compactedMessages?.length || 0,
1026
- originalTokens: compactionResult.originalTokenCount,
1027
- compactedTokens: compactionResult.compactedTokenCount,
1028
- reductionPercent: compactionResult.reductionPercent.toFixed(1),
1029
- executionTimeMs: compactionResult.executionTime,
1030
- model: targetModel
1031
- });
1032
- }
1033
-
1034
- this.logger.info(`Compaction completed for agent ${agentId}`, {
1035
- strategy: compactionResult.strategy,
1036
- originalTokens: compactionResult.originalTokenCount,
1037
- compactedTokens: compactionResult.compactedTokenCount,
1038
- reduction: `${compactionResult.reductionPercent.toFixed(1)}%`,
1039
- executionTime: `${compactionResult.executionTime}ms`
1040
- });
1041
-
1042
- // Update status to completed
1043
- this.compactionInProgress.delete(agentId);
1044
- this.broadcastCompactionEvent(agentId, sessionId, {
1045
- status: COMPACTION_STATUS.COMPLETED,
1046
- originalTokens: compactionResult.originalTokenCount,
1047
- compactedTokens: compactionResult.compactedTokenCount,
1048
- reductionPercent: compactionResult.reductionPercent,
1049
- strategy: compactionResult.strategy,
1050
- executionTime: compactionResult.executionTime
1051
- });
1052
-
1053
- return { shouldContinue: true, compactionPerformed: true };
1054
-
1055
- } catch (error) {
1056
- this.logger.error(`Compaction failed for agent ${agentId}`, {
1057
- error: error.message,
1058
- stack: error.stack
1059
- });
1060
-
1061
- // Update status to failed
1062
- this.compactionInProgress.delete(agentId);
1063
- this.broadcastCompactionEvent(agentId, sessionId, {
1064
- status: COMPACTION_STATUS.FAILED,
1065
- error: error.message
1066
- });
1067
-
1068
- // Don't block AI request on compaction failure
1069
- return { shouldContinue: true, error: error.message };
1070
- }
1071
- }
1072
-
1073
- /**
1074
- * Broadcast compaction event to UI
1075
- * @param {string} agentId - Agent ID
1076
- * @param {string} sessionId - Session ID
1077
- * @param {Object} data - Event data
1078
- * @private
1079
- */
1080
- broadcastCompactionEvent(agentId, sessionId, data) {
1081
- if (!this.webSocketManager || !this.webSocketManager.broadcastToSession) {
1082
- return;
1083
- }
1084
-
1085
- this.webSocketManager.broadcastToSession(sessionId, {
1086
- type: 'compaction_event',
1087
- data: {
1088
- agentId,
1089
- timestamp: new Date().toISOString(),
1090
- ...data
1091
- }
1092
- });
1093
- }
1094
-
1095
- /**
1096
- * Get AI response for agent with proper error handling
1097
- * @param {string} agentId - Agent ID
1098
- * @returns {Promise<Object|null>} AI response or null if failed
1099
- * @private
1100
- */
1101
- async getAgentAIResponse(agentId) {
1102
- try {
1103
- const agent = await this.agentPool.getAgent(agentId);
1104
- if (!agent) return null;
1105
-
1106
- const conversationHistory = agent.conversations?.full?.messages || [];
1107
-
1108
- // CRITICAL FIX: Get the session ID from the agent's context in the scheduler
1109
- const agentContext = this.activeAgents.get(agentId);
1110
- const sessionId = agentContext?.sessionId || agent.sessionId;
1111
-
1112
- if (!sessionId) {
1113
- this.logger.error(`Agent ${agentId} has no session ID - API key resolution will fail`, {
1114
- agentName: agent.name,
1115
- hasAgentContext: !!agentContext,
1116
- agentSessionId: agent.sessionId,
1117
- contextSessionId: agentContext?.sessionId
1118
- });
1119
- // Return null to avoid making requests that will fail
1120
- return null;
1121
- }
1122
-
1123
- // DYNAMIC ROUTING: Check if agent has dynamic model routing enabled
1124
- let targetModel = agent.currentModel;
1125
-
1126
- // DEFENSIVE: Ensure targetModel is set, fallback to preferredModel if currentModel is undefined
1127
- if (!targetModel) {
1128
- this.logger.warn(`Agent ${agentId} has no currentModel set, using preferredModel as fallback`, {
1129
- agentId,
1130
- preferredModel: agent.preferredModel,
1131
- availableConversations: Object.keys(agent.conversations || {})
1132
- });
1133
-
1134
- // Notify user via WebSocket
1135
- if (this.webSocketManager && sessionId) {
1136
- this.webSocketManager.broadcastToSession(sessionId, {
1137
- type: 'agent_warning',
1138
- agentId,
1139
- agentName: agent.name,
1140
- message: 'Agent model configuration restored',
1141
- details: `Agent "${agent.name}" had no currentModel set. Automatically restored to ${agent.preferredModel || 'default model'}.`,
1142
- severity: 'warning',
1143
- timestamp: new Date().toISOString()
1144
- });
1145
- }
1146
-
1147
- targetModel = agent.preferredModel;
1148
-
1149
- // Update agent's currentModel to preferredModel for future iterations
1150
- if (targetModel) {
1151
- agent.currentModel = targetModel;
1152
- await this.agentPool.persistAgentState(agentId);
1153
- this.logger.info(`Set agent currentModel to ${targetModel}`);
1154
- } else {
1155
- this.logger.error(`Agent ${agentId} has no preferredModel or currentModel, cannot continue`);
1156
-
1157
- // Notify user of critical error
1158
- if (this.webSocketManager && sessionId) {
1159
- this.webSocketManager.broadcastToSession(sessionId, {
1160
- type: 'agent_error',
1161
- agentId,
1162
- agentName: agent.name,
1163
- message: 'Agent model configuration error',
1164
- details: `Agent "${agent.name}" has no valid model configuration. Cannot process messages.`,
1165
- severity: 'error',
1166
- timestamp: new Date().toISOString()
1167
- });
1168
- }
1169
-
1170
- return null;
1171
- }
1172
- }
1173
-
1174
- if (agent.dynamicModelRouting && this.modelRouterService) {
1175
- try {
1176
- // Get the last user message for routing decision
1177
- const lastUserMessage = [...conversationHistory].reverse().find(m => m.role === 'user');
1178
-
1179
- if (lastUserMessage) {
1180
- // Get available models from ModelsService
1181
- let availableModels = [];
1182
- if (this.modelsService) {
1183
- try {
1184
- this.logger.debug('ModelsService type check', {
1185
- hasModelsService: !!this.modelsService,
1186
- type: typeof this.modelsService,
1187
- methods: Object.getOwnPropertyNames(Object.getPrototypeOf(this.modelsService))
1188
- });
1189
-
1190
- // Try to get models, if empty/stale, fetch with current sessionId
1191
- let allModels = this.modelsService.getModels();
1192
-
1193
- // Check if models need refresh (safer check)
1194
- const needsRefresh = !this.modelsService.lastFetched ||
1195
- (this.modelsService.lastFetched &&
1196
- (Date.now() - new Date(this.modelsService.lastFetched).getTime()) > (5 * 60 * 1000));
1197
-
1198
- if (!allModels || allModels.length === 0 || needsRefresh) {
1199
- this.logger.info('Models list empty or stale, fetching from backend with sessionId');
1200
- await this.modelsService.fetchModels({ sessionId });
1201
- allModels = this.modelsService.getModels();
1202
- }
1203
-
1204
- // Filter to only include models that are available (not router models)
1205
- availableModels = allModels
1206
- .filter(model => model.id !== 'autopilot-model-router' && model.name !== 'autopilot-model-router')
1207
- .map(model => model.id || model.name);
1208
-
1209
- this.logger.debug(`Available models for routing: ${availableModels.join(', ')}`);
1210
- } catch (error) {
1211
- this.logger.warn(`Failed to get available models for routing: ${error.message}`);
1212
- }
1213
- }
1214
-
1215
- const routingResult = await this.modelRouterService.routeMessage(
1216
- lastUserMessage.content,
1217
- conversationHistory.slice(-5), // Last 5 messages for context
1218
- agent.currentModel,
1219
- availableModels, // Pass actual available models
1220
- { agentId, sessionId }
1221
- );
1222
-
1223
- this.logger.info('Routing result analysis', {
1224
- selectedModel: routingResult.selectedModel,
1225
- currentModel: agent.currentModel,
1226
- areEqual: routingResult.selectedModel === agent.currentModel,
1227
- willSwitch: routingResult.selectedModel && routingResult.selectedModel !== agent.currentModel
1228
- });
1229
-
1230
- if (routingResult.selectedModel && routingResult.selectedModel !== agent.currentModel) {
1231
- this.logger.info(`Dynamic routing: switching from ${agent.currentModel} to ${routingResult.selectedModel}`, {
1232
- agentId,
1233
- reason: routingResult.reasoning
1234
- });
1235
-
1236
- targetModel = routingResult.selectedModel;
1237
-
1238
- // Update agent's current model
1239
- agent.currentModel = targetModel;
1240
- await this.agentPool.persistAgentState(agentId);
1241
-
1242
- this.logger.info(`Model updated: targetModel=${targetModel}, agent.currentModel=${agent.currentModel}`);
1243
- } else {
1244
- this.logger.info('No model switch needed', {
1245
- selectedModel: routingResult.selectedModel,
1246
- currentModel: agent.currentModel,
1247
- hasSelectedModel: !!routingResult.selectedModel
1248
- });
1249
- }
1250
- }
1251
- } catch (routingError) {
1252
- this.logger.warn(`Dynamic routing failed, using current model: ${routingError.message}`);
1253
- // Fall back to current model on routing failure
1254
- }
1255
- }
1256
-
1257
- this.logger.info(`About to send message to model: ${targetModel}`, {
1258
- agentId,
1259
- targetModel,
1260
- originalModel: agent.currentModel
1261
- });
1262
-
1263
- // PHASE 4: Check and perform compaction if needed BEFORE sending to AI
1264
- const compactionResult = await this.checkAndPerformCompaction(agentId, targetModel, sessionId);
1265
-
1266
- if (!compactionResult.shouldContinue) {
1267
- this.logger.warn(`Compaction check returned shouldContinue=false for agent ${agentId}`);
1268
- return null;
1269
- }
1270
-
1271
- if (compactionResult.compactionPerformed) {
1272
- this.logger.info(`Compaction performed for agent ${agentId}, proceeding with AI request`);
1273
- }
1274
-
1275
- // After compaction, retrieve messages from AgentPool (will use compacted if available)
1276
- const messagesToSend = await this.agentPool.getMessagesForAI(agentId, targetModel);
1277
-
1278
- // Inject TaskManager instructions for AGENT mode
1279
- let enhancedSystemPrompt = agent.systemPrompt;
1280
- if (agent.mode === AGENT_MODES.AGENT) {
1281
- const taskManagerInstruction = "\n\nIMPORTANT: You are in AGENT mode. The use of TaskManager tool is mandatory. Always create and update tasks to track your work progress. Update the user about task-list status periodically. Use the jobdone tool when your main task is complete.";
1282
- enhancedSystemPrompt = (agent.systemPrompt || '') + taskManagerInstruction;
1283
- }
1284
-
1285
- // Inject dynamic file attachment context
1286
- try {
1287
- const fileAttachmentContext = await this.contextInjectionService.buildDynamicContext(agentId);
1288
- if (fileAttachmentContext) {
1289
- enhancedSystemPrompt = (enhancedSystemPrompt || '') + fileAttachmentContext;
1290
- this.logger.debug(`Injected file attachment context for agent ${agentId}`, {
1291
- contextLength: fileAttachmentContext.length
1292
- });
1293
- }
1294
- } catch (error) {
1295
- this.logger.warn(`Failed to inject file attachment context for agent ${agentId}`, {
1296
- error: error.message
1297
- });
1298
- // Continue without file attachments if service fails
1299
- }
1300
-
1301
- const response = await this.aiService.sendMessage(
1302
- targetModel,
1303
- messagesToSend,
1304
- {
1305
- agentId: agentId,
1306
- systemPrompt: enhancedSystemPrompt,
1307
- sessionId: sessionId,
1308
- platformProvided: agent.platformProvided
1309
- }
1310
- );
1311
-
1312
- return response;
1313
-
1314
- } catch (error) {
1315
- this.logger.error(`AI response failed for agent ${agentId}:`, error);
1316
-
1317
- // Handle different types of AI service failures
1318
- await this.handleAIServiceFailure(agentId, error);
1319
-
1320
- return null;
1321
- }
1322
- }
1323
-
1324
- /**
1325
- * Handle AI service failures with appropriate recovery strategies
1326
- * @param {string} agentId - Agent ID that failed
1327
- * @param {Error} error - The error that occurred
1328
- * @private
1329
- */
1330
- async handleAIServiceFailure(agentId, error) {
1331
- const agent = await this.agentPool.getAgent(agentId);
1332
- if (!agent) return;
1333
-
1334
- // Determine failure type and response
1335
- const errorMessage = error.message?.toLowerCase() || '';
1336
-
1337
- if (errorMessage.includes('api key') || errorMessage.includes('authentication')) {
1338
- // API key issues - pause agent to prevent infinite retries
1339
- this.logger.warn(`Agent ${agentId} paused due to API key issue`);
1340
-
1341
- agent.delayEndTime = new Date(Date.now() + 5 * 60 * 1000).toISOString(); // 5 minute delay
1342
- await this.agentPool.persistAgentState(agentId);
1343
-
1344
- // Add error message to agent's queue
1345
- await this.agentPool.addToolResult(agentId, {
1346
- toolId: 'system-error',
1347
- status: 'failed',
1348
- error: 'API key authentication failed. Please check your API key configuration in Settings.',
1349
- timestamp: new Date().toISOString()
1350
- });
1351
-
1352
- } else if (errorMessage.includes('rate limit') || errorMessage.includes('too many requests')) {
1353
- // Rate limit - delay agent
1354
- this.logger.warn(`Agent ${agentId} delayed due to rate limiting`);
1355
-
1356
- agent.delayEndTime = new Date(Date.now() + 2 * 60 * 1000).toISOString(); // 2 minute delay
1357
- await this.agentPool.persistAgentState(agentId);
1358
-
1359
- } else if (errorMessage.includes('timeout') || errorMessage.includes('network')) {
1360
- // Network issues - shorter delay and retry
1361
- this.logger.warn(`Agent ${agentId} delayed due to network issues`);
1362
-
1363
- agent.delayEndTime = new Date(Date.now() + 30 * 1000).toISOString(); // 30 second delay
1364
- await this.agentPool.persistAgentState(agentId);
1365
-
1366
- } else {
1367
- // Unknown error - pause agent and notify
1368
- this.logger.error(`Agent ${agentId} paused due to unknown AI service error: ${error.message}`);
1369
-
1370
- agent.delayEndTime = new Date(Date.now() + 1 * 60 * 1000).toISOString(); // 1 minute delay
1371
- await this.agentPool.persistAgentState(agentId);
1372
-
1373
- // Add error message to agent's queue
1374
- await this.agentPool.addToolResult(agentId, {
1375
- toolId: 'system-error',
1376
- status: 'failed',
1377
- error: `AI service error: ${error.message}. Agent temporarily paused.`,
1378
- timestamp: new Date().toISOString()
1379
- });
1380
- }
1381
-
1382
- // Broadcast error to UI
1383
- if (this.webSocketManager && this.webSocketManager.broadcastToSession) {
1384
- const agentContext = this.activeAgents.get(agentId);
1385
- const sessionId = agentContext?.sessionId || 'scheduler-session';
1386
-
1387
- // FIX: Wrap payload in 'data' field to match UI expectations
1388
- this.webSocketManager.broadcastToSession(sessionId, {
1389
- type: 'agent_error',
1390
- data: {
1391
- agentId: agentId,
1392
- error: error.message,
1393
- recovery: 'Agent temporarily paused for recovery',
1394
- timestamp: new Date().toISOString()
1395
- }
1396
- });
1397
- }
1398
- }
1399
-
1400
- /**
1401
- * Process AI response and execute any tools
1402
- * @param {string} agentId - Agent ID
1403
- * @param {Object} aiResponse - AI service response
1404
- * @private
1405
- */
1406
- async processAIResponse(agentId, aiResponse) {
1407
- // Get the session ID from the agent's context BEFORE it might be removed
1408
- const agentContext = this.activeAgents.get(agentId);
1409
- const sessionId = agentContext?.sessionId || 'scheduler-session';
1410
-
1411
- // Add AI response to conversation (don't broadcast yet - wait for tool processing)
1412
- const responseMessage = {
1413
- id: `ai-response-${Date.now()}`,
1414
- agentId: agentId,
1415
- role: MESSAGE_ROLES.ASSISTANT,
1416
- content: aiResponse.content,
1417
- timestamp: new Date().toISOString(),
1418
- model: aiResponse.model,
1419
- tokenUsage: aiResponse.tokenUsage,
1420
- sessionId: sessionId // CRITICAL: Store sessionId in message for later broadcast
1421
- };
1422
-
1423
- await this.addMessageToConversation(agentId, responseMessage, false);
1424
-
1425
- // Extract and execute tools using MessageProcessor
1426
- let toolExecutions = [];
1427
- try {
1428
-
1429
- const toolResults = await this.messageProcessor.extractAndExecuteTools(
1430
- aiResponse.content,
1431
- agentId,
1432
- { sessionId: sessionId }
1433
- );
1434
-
1435
- // Queue tool results in T queue for next iteration
1436
- if (toolResults.length > 0) {
1437
- const agent = await this.agentPool.getAgent(agentId);
1438
- if (agent) {
1439
- for (const result of toolResults) {
1440
- agent.messageQueues.toolResults.push({
1441
- id: `tool-result-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,
1442
- toolId: result.toolId,
1443
- status: result.status,
1444
- result: result.result,
1445
- error: result.error,
1446
- executionTime: result.executionTime,
1447
- timestamp: new Date().toISOString(),
1448
- queuedAt: new Date().toISOString()
1449
- });
1450
-
1451
- // Collect tool execution info for UI display
1452
- toolExecutions.push({
1453
- toolId: result.toolId,
1454
- status: result.status,
1455
- error: result.error,
1456
- executionTime: result.executionTime
1457
- });
1458
- }
1459
-
1460
- await this.agentPool.persistAgentState(agentId);
1461
- }
1462
- }
1463
-
1464
- } catch (error) {
1465
- this.logger.error(`Tool execution failed for agent ${agentId}:`, error);
1466
- }
1467
-
1468
- // Add tool execution info to response message for UI
1469
- if (toolExecutions.length > 0) {
1470
- responseMessage.toolExecutions = toolExecutions;
1471
- responseMessage.hasToolExecutions = true;
1472
- }
1473
-
1474
- // Broadcast the final AI response to UI after all processing
1475
- if (this.shouldBroadcastMessage(responseMessage)) {
1476
- // Get updated agent info for UI sync
1477
- const updatedAgent = await this.agentPool.getAgent(agentId);
1478
-
1479
- // Broadcast with agent's current model (may have changed due to dynamic routing)
1480
- this.broadcastMessageUpdate(agentId, responseMessage, {
1481
- agentCurrentModel: updatedAgent?.currentModel
1482
- });
1483
- }
1484
- }
1485
-
1486
- /**
1487
- * Determine if agent should continue in scheduler
1488
- * @param {string} agentId - Agent ID
1489
- * @param {Object} agent - Agent object
1490
- * @returns {boolean} Whether agent should continue
1491
- * @private
1492
- */
1493
- shouldAgentContinue(agentId, agent) {
1494
- if (!agent) return false;
1495
-
1496
- // Check for jobdone tool execution
1497
- const hasJobDone = agent.messageQueues.toolResults.some(result =>
1498
- result.toolId === 'jobdone' ||
1499
- (result.result && String(result.result).toLowerCase().includes('task completed'))
1500
- );
1501
-
1502
- if (hasJobDone) {
1503
- this.logger.info(`Agent ${agentId} executed jobdone - removing from scheduler`);
1504
- return false;
1505
- }
1506
-
1507
- // CHAT agents are removed after processing messages
1508
- // CRITICAL FIX: Only continue if there are NEW user messages or inter-agent messages
1509
- // Tool results should NOT keep CHAT agents in scheduler
1510
- if (agent.mode === AGENT_MODES.CHAT) {
1511
- const hasNewMessages = agent.messageQueues.userMessages.length > 0 ||
1512
- agent.messageQueues.interAgentMessages.length > 0;
1513
-
1514
- if (!hasNewMessages) {
1515
- this.logger.debug(`CHAT agent ${agentId} has no new messages - removing from scheduler`, {
1516
- toolResults: agent.messageQueues.toolResults.length,
1517
- userMessages: agent.messageQueues.userMessages.length,
1518
- interAgentMessages: agent.messageQueues.interAgentMessages.length
1519
- });
1520
- }
1521
-
1522
- return hasNewMessages; // Only continue if there are NEW messages, not tool results
1523
- }
1524
-
1525
- // AGENT agents continue until jobdone
1526
- if (agent.mode === AGENT_MODES.AGENT) {
1527
- return !agent.stopRequested;
1528
- }
1529
-
1530
- return false;
1531
- }
1532
-
1533
- /**
1534
- * Format tool result for conversation
1535
- * @param {Object} toolResult - Tool result message
1536
- * @returns {string} Formatted content
1537
- * @private
1538
- */
1539
- formatToolResult(toolResult) {
1540
- if (toolResult.status === 'completed') {
1541
- if (typeof toolResult.result === 'object') {
1542
- return JSON.stringify(toolResult.result, null, 2);
1543
- }
1544
- return String(toolResult.result || 'Tool executed successfully');
1545
- } else if (toolResult.status === 'failed') {
1546
- return `Tool execution failed: ${toolResult.error || 'Unknown error'}`;
1547
- }
1548
- return `Tool status: ${toolResult.status}`;
1549
- }
1550
-
1551
- /**
1552
- * Check if message should be broadcast to UI
1553
- * @param {Object} message - Message to check
1554
- * @returns {boolean} Whether to broadcast
1555
- * @private
1556
- */
1557
- shouldBroadcastMessage(message) {
1558
- // Don't broadcast internal scheduler prompts
1559
- if (message.type === 'scheduler-prompt') {
1560
- return false;
1561
- }
1562
-
1563
- // Don't broadcast pure system instructions (but allow system messages from inter-agent communication)
1564
- if (message.role === MESSAGE_ROLES.SYSTEM && !message.queueType) {
1565
- return false;
1566
- }
1567
-
1568
- // Broadcast all other messages (user, assistant, tool, inter-agent)
1569
- return true;
1570
- }
1571
-
1572
- /**
1573
- * Broadcast message update to UI
1574
- * @param {string} agentId - Agent ID
1575
- * @param {Object} message - Message that was added
1576
- * @param {Object} agentInfo - Additional agent information for UI sync
1577
- * @private
1578
- */
1579
- broadcastMessageUpdate(agentId, message, agentInfo = {}) {
1580
- if (this.webSocketManager && this.webSocketManager.broadcastToSession) {
1581
- // Get the session ID from the agent's context or the message itself
1582
- const agentContext = this.activeAgents.get(agentId);
1583
- let sessionId = agentContext?.sessionId;
1584
-
1585
- // CRITICAL FIX: If no context (agent already removed), try to get sessionId from message
1586
- if (!sessionId && message.sessionId) {
1587
- sessionId = message.sessionId;
1588
- }
1589
-
1590
- // Final fallback
1591
- if (!sessionId) {
1592
- sessionId = 'scheduler-session';
1593
- }
1594
-
1595
- // DEBUG: Log session ID mapping
1596
- this.logger.info('Broadcasting message to session', {
1597
- agentId: agentId,
1598
- sessionId: sessionId,
1599
- hasAgentContext: !!agentContext,
1600
- agentContextSessionId: agentContext?.sessionId,
1601
- messageSessionId: message.sessionId,
1602
- messageRole: message.role,
1603
- messageType: message.type
1604
- });
1605
-
1606
- // FIX: Wrap payload in 'data' field to match UI expectations
1607
- this.webSocketManager.broadcastToSession(sessionId, {
1608
- type: 'message_added',
1609
- data: {
1610
- agentId: agentId,
1611
- message: message,
1612
- timestamp: new Date().toISOString(),
1613
- // Include agent current model for UI updates after dynamic routing
1614
- agentCurrentModel: agentInfo.agentCurrentModel
1615
- }
1616
- });
1617
- }
1618
- }
1619
-
1620
- /**
1621
- * Check if agent has pending tasks
1622
- * @param {Object} agent - Agent object
1623
- * @returns {boolean} Whether agent has pending tasks
1624
- * @private
1625
- */
1626
- hasPendingTasks(agent) {
1627
- if (!agent.taskList || !agent.taskList.tasks) {
1628
- return false;
1629
- }
1630
-
1631
- // Check for pending or in_progress tasks
1632
- return agent.taskList.tasks.some(task =>
1633
- task.status === 'pending' || task.status === 'in_progress'
1634
- );
1635
- }
1636
-
1637
- /**
1638
- * Check if agent has unprocessed messages (for task creation)
1639
- * @param {Object} agent - Agent object
1640
- * @returns {boolean} Whether agent has unprocessed messages
1641
- * @private
1642
- */
1643
- hasUnprocessedMessages(agent) {
1644
- // Check for incoming messages that should trigger task creation
1645
- if (agent.incomingMessages && agent.incomingMessages.length > 0) {
1646
- return true;
1647
- }
1648
-
1649
- // Check for recent inter-agent communication that might need follow-up
1650
- if (agent.interAgentTracking && agent.interAgentTracking.size > 0) {
1651
- const now = Date.now();
1652
- const RECENT_MESSAGE_THRESHOLD = 10 * 60 * 1000; // 10 minutes
1653
-
1654
- for (const tracking of agent.interAgentTracking.values()) {
1655
- if (tracking.lastReceived &&
1656
- (now - tracking.lastReceived) < RECENT_MESSAGE_THRESHOLD &&
1657
- tracking.lastType === 'received') {
1658
- return true;
1659
- }
1660
- }
1661
- }
1662
-
1663
- return false;
1664
- }
1665
-
1666
- /**
1667
- * Auto-create initial task if agent just switched to AGENT mode
1668
- * @param {string} agentId - Agent ID
1669
- * @private
1670
- */
1671
- async autoCreateInitialTaskIfNeeded(agentId) {
1672
- try {
1673
- const agent = await this.agentPool.getAgent(agentId);
1674
- if (!agent || agent.mode !== AGENT_MODES.AGENT) {
1675
- return;
1676
- }
1677
-
1678
- // Ensure taskList exists
1679
- if (!agent.taskList) {
1680
- agent.taskList = {
1681
- tasks: [],
1682
- lastUpdated: new Date().toISOString()
1683
- };
1684
- }
1685
-
1686
- // Check if we already have tasks
1687
- if (agent.taskList.tasks && agent.taskList.tasks.length > 0) {
1688
- return; // Already has tasks
1689
- }
1690
-
1691
- // Look for the last user message in conversation history
1692
- const conversations = agent.conversations?.full?.messages || [];
1693
- const lastUserMessage = [...conversations].reverse().find(m => m.role === MESSAGE_ROLES.USER);
1694
-
1695
- if (lastUserMessage) {
1696
- const taskTitle = `Process initial request: ${this.extractTaskTitle(lastUserMessage.content)}`;
1697
- const taskDescription = `Handle user request: "${this.truncateContent(lastUserMessage.content, 200)}"`;
1698
-
1699
- const task = {
1700
- id: `task-initial-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,
1701
- title: taskTitle,
1702
- description: taskDescription,
1703
- status: 'pending',
1704
- priority: 'high',
1705
- createdAt: new Date().toISOString(),
1706
- updatedAt: new Date().toISOString(),
1707
- source: 'auto-created-initial',
1708
- messageId: lastUserMessage.id
1709
- };
1710
-
1711
- agent.taskList.tasks.push(task);
1712
- agent.taskList.lastUpdated = new Date().toISOString();
1713
-
1714
- await this.agentPool.persistAgentState(agentId);
1715
-
1716
- this.logger.info(`Auto-created initial task for agent ${agentId}`, {
1717
- taskId: task.id,
1718
- title: task.title,
1719
- agentName: agent.name
1720
- });
1721
- }
1722
- } catch (error) {
1723
- this.logger.error(`Failed to auto-create initial task for agent ${agentId}`, {
1724
- error: error.message
1725
- });
1726
- }
1727
- }
1728
-
1729
- /**
1730
- * Auto-create tasks for incoming messages (Phase 2)
1731
- * @param {string} agentId - Agent ID
1732
- * @param {Array} userMessages - User messages to process
1733
- * @param {Array} interAgentMessages - Inter-agent messages to process
1734
- * @private
1735
- */
1736
- async autoCreateTasksForMessages(agentId, userMessages, interAgentMessages) {
1737
- try {
1738
- const agent = await this.agentPool.getAgent(agentId);
1739
- if (!agent || agent.mode !== AGENT_MODES.AGENT) {
1740
- return; // Only auto-create tasks for AGENT mode agents
1741
- }
1742
-
1743
- // Ensure taskList exists
1744
- if (!agent.taskList) {
1745
- agent.taskList = {
1746
- tasks: [],
1747
- lastUpdated: new Date().toISOString()
1748
- };
1749
- }
1750
-
1751
- // Create tasks for user messages
1752
- for (const msg of userMessages) {
1753
- const taskTitle = `Process user request: ${this.extractTaskTitle(msg.content)}`;
1754
- const taskDescription = `Handle user message: "${this.truncateContent(msg.content, 200)}"`;
1755
-
1756
- // Check if similar task already exists
1757
- const existingTask = agent.taskList.tasks.find(task =>
1758
- task.status === 'pending' &&
1759
- task.title.includes('Process user request') &&
1760
- this.calculateContentSimilarity(task.description, taskDescription) > 0.7
1761
- );
1762
-
1763
- if (!existingTask) {
1764
- const task = {
1765
- id: `task-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,
1766
- title: taskTitle,
1767
- description: taskDescription,
1768
- status: 'pending',
1769
- priority: 'high', // User messages get high priority
1770
- createdAt: new Date().toISOString(),
1771
- updatedAt: new Date().toISOString(),
1772
- source: 'auto-created',
1773
- messageId: msg.id
1774
- };
1775
-
1776
- agent.taskList.tasks.push(task);
1777
-
1778
- this.logger?.info(`Auto-created task for user message`, {
1779
- agentId,
1780
- taskId: task.id,
1781
- title: task.title
1782
- });
1783
- }
1784
- }
1785
-
1786
- // Create tasks for inter-agent messages
1787
- for (const msg of interAgentMessages) {
1788
- const senderName = msg.senderName || msg.sender || 'Unknown Agent';
1789
- const taskTitle = `Respond to ${senderName}: ${this.extractTaskTitle(msg.content)}`;
1790
- const taskDescription = `Handle message from ${senderName}: "${this.truncateContent(msg.content, 200)}"`;
1791
-
1792
- // Check if similar task already exists
1793
- const existingTask = agent.taskList.tasks.find(task =>
1794
- task.status === 'pending' &&
1795
- task.title.includes(`Respond to ${senderName}`) &&
1796
- this.calculateContentSimilarity(task.description, taskDescription) > 0.7
1797
- );
1798
-
1799
- if (!existingTask) {
1800
- const task = {
1801
- id: `task-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,
1802
- title: taskTitle,
1803
- description: taskDescription,
1804
- status: 'pending',
1805
- priority: 'medium', // Inter-agent messages get medium priority
1806
- createdAt: new Date().toISOString(),
1807
- updatedAt: new Date().toISOString(),
1808
- source: 'auto-created',
1809
- messageId: msg.id,
1810
- senderAgent: msg.sender
1811
- };
1812
-
1813
- agent.taskList.tasks.push(task);
1814
-
1815
- this.logger?.info(`Auto-created task for inter-agent message`, {
1816
- agentId,
1817
- taskId: task.id,
1818
- title: task.title,
1819
- sender: senderName
1820
- });
1821
- }
1822
- }
1823
-
1824
- // Update task list timestamp
1825
- if (userMessages.length > 0 || interAgentMessages.length > 0) {
1826
- agent.taskList.lastUpdated = new Date().toISOString();
1827
- await this.agentPool.persistAgentState(agentId);
1828
- }
1829
-
1830
- } catch (error) {
1831
- this.logger?.error(`Failed to auto-create tasks for agent ${agentId}`, {
1832
- error: error.message,
1833
- userMessageCount: userMessages.length,
1834
- interAgentMessageCount: interAgentMessages.length
1835
- });
1836
- }
1837
- }
1838
-
1839
- /**
1840
- * Extract a concise title from message content
1841
- * @param {string} content - Message content
1842
- * @returns {string} Extracted title
1843
- * @private
1844
- */
1845
- extractTaskTitle(content) {
1846
- // Extract first meaningful sentence or phrase, max 50 chars
1847
- const cleaned = content.trim().replace(/\n+/g, ' ').replace(/\s+/g, ' ');
1848
- const firstSentence = cleaned.split(/[.!?]/)[0].trim();
1849
-
1850
- if (firstSentence.length > 50) {
1851
- return firstSentence.substring(0, 47) + '...';
1852
- }
1853
-
1854
- return firstSentence || 'Process message';
1855
- }
1856
-
1857
- /**
1858
- * Truncate content to specified length
1859
- * @param {string} content - Content to truncate
1860
- * @param {number} maxLength - Maximum length
1861
- * @returns {string} Truncated content
1862
- * @private
1863
- */
1864
- truncateContent(content, maxLength) {
1865
- if (content.length <= maxLength) return content;
1866
- return content.substring(0, maxLength - 3) + '...';
1867
- }
1868
-
1869
- /**
1870
- * Calculate content similarity (simple implementation)
1871
- * @param {string} content1 - First content
1872
- * @param {string} content2 - Second content
1873
- * @returns {number} Similarity score (0-1)
1874
- * @private
1875
- */
1876
- calculateContentSimilarity(content1, content2) {
1877
- // Simple word-based similarity
1878
- const words1 = content1.toLowerCase().split(/\s+/);
1879
- const words2 = content2.toLowerCase().split(/\s+/);
1880
-
1881
- const commonWords = words1.filter(word => words2.includes(word));
1882
- const totalWords = new Set([...words1, ...words2]).size;
1883
-
1884
- return commonWords.length / totalWords;
1885
- }
1886
-
1887
- /**
1888
- * Auto-mark highest priority pending task as in-progress (Phase 2)
1889
- * @param {string} agentId - Agent ID
1890
- * @private
1891
- */
1892
- async autoProgressHighestPriorityTask(agentId) {
1893
- try {
1894
- const agent = await this.agentPool.getAgent(agentId);
1895
- if (!agent || !agent.taskList || !agent.taskList.tasks) {
1896
- return;
1897
- }
1898
-
1899
- // Find highest priority pending task that can be started (respecting dependencies)
1900
- const priorityOrder = { urgent: 0, high: 1, medium: 2, low: 3 };
1901
- let pendingTasks = agent.taskList.tasks.filter(task => task.status === 'pending');
1902
-
1903
- if (pendingTasks.length === 0) {
1904
- return; // No pending tasks
1905
- }
1906
-
1907
- // Phase 3: Filter out blocked tasks (dependencies not met)
1908
- pendingTasks = this.filterAvailableTasks(agent.taskList.tasks, pendingTasks);
1909
-
1910
- if (pendingTasks.length === 0) {
1911
- this.logger?.info(`All pending tasks are blocked by dependencies for agent ${agentId}`);
1912
- return; // All tasks are blocked
1913
- }
1914
-
1915
- // Phase 3.2: Sort by intelligent priority score, fallback to priority level, then creation date
1916
- pendingTasks.sort((a, b) => {
1917
- // Use priority score if available (higher score = higher priority)
1918
- if (a.priorityScore !== undefined && b.priorityScore !== undefined) {
1919
- const scoreDiff = b.priorityScore - a.priorityScore;
1920
- if (Math.abs(scoreDiff) > 0.1) return scoreDiff; // Use score if significantly different
1921
- }
1922
-
1923
- // Fallback to traditional priority ordering
1924
- const priorityDiff = priorityOrder[a.priority] - priorityOrder[b.priority];
1925
- if (priorityDiff !== 0) return priorityDiff;
1926
-
1927
- // Finally sort by creation date (older first)
1928
- return new Date(a.createdAt) - new Date(b.createdAt);
1929
- });
1930
-
1931
- const taskToProgress = pendingTasks[0];
1932
-
1933
- // Check if we already have a task in progress
1934
- const inProgressTasks = agent.taskList.tasks.filter(task => task.status === 'in_progress');
1935
-
1936
- if (inProgressTasks.length === 0) {
1937
- // Mark highest priority task as in-progress
1938
- taskToProgress.status = 'in_progress';
1939
- taskToProgress.updatedAt = new Date().toISOString();
1940
- taskToProgress.startedAt = new Date().toISOString();
1941
-
1942
- agent.taskList.lastUpdated = new Date().toISOString();
1943
- await this.agentPool.persistAgentState(agentId);
1944
-
1945
- this.logger?.info(`Auto-progressed task to in-progress`, {
1946
- agentId,
1947
- taskId: taskToProgress.id,
1948
- title: taskToProgress.title,
1949
- priority: taskToProgress.priority
1950
- });
1951
- }
1952
-
1953
- } catch (error) {
1954
- this.logger?.error(`Failed to auto-progress task for agent ${agentId}`, {
1955
- error: error.message
1956
- });
1957
- }
1958
- }
1959
-
1960
- /**
1961
- * Filter tasks to only include those that can be started (Phase 3)
1962
- * @param {Array} allTasks - All tasks for the agent
1963
- * @param {Array} pendingTasks - Tasks with pending status
1964
- * @returns {Array} Tasks that can be started (no blocking dependencies)
1965
- * @private
1966
- */
1967
- filterAvailableTasks(allTasks, pendingTasks) {
1968
- return pendingTasks.filter(task => {
1969
- // If task has no dependencies, it's available
1970
- if (!task.dependencies || task.dependencies.length === 0) {
1971
- return true;
1972
- }
1973
-
1974
- // Check all blocking dependencies
1975
- const blockingDeps = task.dependencies.filter(dep => dep.type === 'blocks');
1976
-
1977
- for (const dep of blockingDeps) {
1978
- const depTask = allTasks.find(t => t.id === dep.taskId);
1979
-
1980
- // If dependency task doesn't exist or isn't completed, task is blocked
1981
- if (!depTask || depTask.status !== 'completed') {
1982
- return false;
1983
- }
1984
- }
1985
-
1986
- return true; // All blocking dependencies are satisfied
1987
- });
1988
- }
1989
-
1990
- /**
1991
- * Update task statuses based on dependency completion (Phase 3)
1992
- * @param {Object} agent - Agent object
1993
- * @param {string} completedTaskId - ID of the task that was just completed
1994
- * @private
1995
- */
1996
- async updateDependentTasks(agent, completedTaskId) {
1997
- try {
1998
- if (!agent.taskList || !agent.taskList.tasks) {
1999
- return;
2000
- }
2001
-
2002
- let updated = false;
2003
-
2004
- // Find tasks that were blocked by the completed task
2005
- for (const task of agent.taskList.tasks) {
2006
- if (task.status === 'blocked' && task.dependencies) {
2007
- const blockingDep = task.dependencies.find(
2008
- dep => dep.type === 'blocks' && dep.taskId === completedTaskId
2009
- );
2010
-
2011
- if (blockingDep) {
2012
- // Check if all other blocking dependencies are also completed
2013
- const stillBlocked = task.dependencies.some(dep => {
2014
- if (dep.type !== 'blocks') return false;
2015
- const depTask = agent.taskList.tasks.find(t => t.id === dep.taskId);
2016
- return depTask && depTask.status !== 'completed';
2017
- });
2018
-
2019
- if (!stillBlocked) {
2020
- task.status = 'pending';
2021
- task.updatedAt = new Date().toISOString();
2022
- updated = true;
2023
-
2024
- this.logger?.info(`Task unblocked due to dependency completion`, {
2025
- taskId: task.id,
2026
- title: task.title,
2027
- completedDependency: completedTaskId
2028
- });
2029
- }
2030
- }
2031
- }
2032
- }
2033
-
2034
- if (updated) {
2035
- agent.taskList.lastUpdated = new Date().toISOString();
2036
- await this.agentPool.persistAgentState(agent.id);
2037
- }
2038
-
2039
- } catch (error) {
2040
- this.logger?.error(`Failed to update dependent tasks for agent ${agent.id}`, {
2041
- error: error.message,
2042
- completedTaskId
2043
- });
2044
- }
2045
- }
2046
-
2047
- /**
2048
- * Generate a hash representing the current agent state
2049
- * @param {Object} agent - Agent object
2050
- * @returns {string} Hash of the current state
2051
- * @private
2052
- */
2053
- generateAgentStateHash(agent) {
2054
- // Create a string representation of the relevant state
2055
- const stateComponents = [];
2056
-
2057
- // CRITICAL FIX: Only include INPUT messages (user and tool), NOT assistant responses
2058
- // This allows duplicate detection to work when agent generates same response repeatedly
2059
- // Assistant messages change every iteration, which previously prevented loop detection
2060
- const allMessages = agent.conversations?.full?.messages || [];
2061
- const inputMessages = allMessages
2062
- .filter(m => m.role === 'user' || m.role === 'tool')
2063
- .slice(-5); // Last 5 input messages for context
2064
-
2065
- const messagesSummary = inputMessages
2066
- .map(m => `${m.role}:${m.content?.substring(0, 100)}`)
2067
- .join('|');
2068
- stateComponents.push(`msgs:${messagesSummary}`);
2069
-
2070
- // Include pending and in-progress tasks
2071
- if (agent.taskList?.tasks) {
2072
- const activeTasks = agent.taskList.tasks
2073
- .filter(t => t.status === 'pending' || t.status === 'in_progress')
2074
- .map(t => `${t.id}:${t.status}`)
2075
- .sort()
2076
- .join(',');
2077
- stateComponents.push(`tasks:${activeTasks}`);
2078
- }
2079
-
2080
- // Include queued messages counts
2081
- const queues = agent.messageQueues || {};
2082
- stateComponents.push(`queues:T${queues.toolResults?.length || 0}:I${queues.interAgentMessages?.length || 0}:U${queues.userMessages?.length || 0}`);
2083
-
2084
- // Create a simple hash using string representation
2085
- // For production, consider using crypto.createHash('sha256')
2086
- const stateString = stateComponents.join('||');
2087
-
2088
- // Simple hash function (could be replaced with crypto hash)
2089
- let hash = 0;
2090
- for (let i = 0; i < stateString.length; i++) {
2091
- const char = stateString.charCodeAt(i);
2092
- hash = ((hash << 5) - hash) + char;
2093
- hash = hash & hash; // Convert to 32bit integer
2094
- }
2095
-
2096
- return `${hash}_${stateString.length}`;
2097
- }
2098
-
2099
- /**
2100
- * Check if this state has already been processed
2101
- * @param {string} agentId - Agent ID
2102
- * @param {string} stateHash - State hash to check
2103
- * @returns {boolean} True if already processed
2104
- * @private
2105
- */
2106
- hasProcessedState(agentId, stateHash) {
2107
- const agentHashes = this.processedStateHashes.get(agentId);
2108
- return agentHashes ? agentHashes.has(stateHash) : false;
2109
- }
2110
-
2111
- /**
2112
- * Mark state as processed
2113
- * @param {string} agentId - Agent ID
2114
- * @param {string} stateHash - State hash to mark
2115
- * @private
2116
- */
2117
- markStateAsProcessed(agentId, stateHash) {
2118
- if (!this.processedStateHashes.has(agentId)) {
2119
- this.processedStateHashes.set(agentId, new Set());
2120
- }
2121
-
2122
- const agentHashes = this.processedStateHashes.get(agentId);
2123
- agentHashes.add(stateHash);
2124
-
2125
- // Limit the size of stored hashes to prevent memory issues
2126
- if (agentHashes.size > 100) {
2127
- // Remove oldest entries (convert to array, slice, rebuild set)
2128
- const hashArray = Array.from(agentHashes);
2129
- const recentHashes = hashArray.slice(-50); // Keep last 50
2130
- this.processedStateHashes.set(agentId, new Set(recentHashes));
2131
- }
2132
- }
2133
-
2134
- /**
2135
- * Get scheduler status
2136
- * @returns {Object} Scheduler status
2137
- */
2138
- getStatus() {
2139
- return {
2140
- isRunning: this.isRunning,
2141
- activeAgents: Array.from(this.activeAgents),
2142
- agentCount: this.activeAgents.size
2143
- };
2144
- }
2145
- }
2146
-
2147
- export default AgentScheduler;
1
+ const a0_0x4735dd=a0_0x4da4;(function(_0x49dff0,_0x321975){const _0x473fe8=a0_0x4da4,_0x598041=_0x49dff0();while(!![]){try{const _0x3ab0cb=parseInt(_0x473fe8(0x25e))/0x1+parseInt(_0x473fe8(0x231))/0x2*(-parseInt(_0x473fe8(0x17e))/0x3)+parseInt(_0x473fe8(0x174))/0x4*(-parseInt(_0x473fe8(0x1f1))/0x5)+parseInt(_0x473fe8(0x166))/0x6*(parseInt(_0x473fe8(0x1f3))/0x7)+-parseInt(_0x473fe8(0x1c4))/0x8*(-parseInt(_0x473fe8(0x217))/0x9)+-parseInt(_0x473fe8(0x224))/0xa+parseInt(_0x473fe8(0x141))/0xb;if(_0x3ab0cb===_0x321975)break;else _0x598041['push'](_0x598041['shift']());}catch(_0x3bc19d){_0x598041['push'](_0x598041['shift']());}}}(a0_0x1fdd,0x2792a));import{AGENT_MODES,AGENT_MODE_STATES,MESSAGE_ROLES,COMPACTION_CONFIG,COMPACTION_STATUS,COMPACTION_STRATEGIES,TOKEN_COUNTING_MODES}from'../utilities/constants.js';import a0_0x4aa21e from'../services/contextInjectionService.js';import a0_0x252b65 from'../services/tokenCountingService.js';import a0_0x13b4e9 from'../services/conversationCompactionService.js';class AgentScheduler{constructor(_0x22d1a2,_0x27d4e5,_0x315e31,_0x41845d,_0x3e9410=null,_0xb1a0e1=null,_0x33f5a6=null){const _0x41fd4e=a0_0x4da4;this['agentPool']=_0x22d1a2,this['messageProcessor']=_0x27d4e5,this['aiService']=_0x315e31,this[_0x41fd4e(0x183)]=_0x41845d,this[_0x41fd4e(0x1cf)]=_0x3e9410,this[_0x41fd4e(0x239)]=_0xb1a0e1,this['modelsService']=_0x33f5a6,this[_0x41fd4e(0x1ce)]=new a0_0x4aa21e({},_0x41845d),this['tokenCountingService']=new a0_0x252b65(_0x41845d),this[_0x41fd4e(0x1a6)]=new a0_0x13b4e9(this[_0x41fd4e(0x1ba)],_0x315e31,_0x41845d),this['compactionInProgress']=new Map(),this['isRunning']=![],this[_0x41fd4e(0x243)]=new Map(),this['scheduleInterval']=null,this[_0x41fd4e(0x186)]=new Map(),this[_0x41fd4e(0x21c)]=![],this['agentProcessingLocks']=new Map(),this[_0x41fd4e(0x17a)]=0x3e8,this['MAX_ITERATIONS_PER_CYCLE']=0x186a0;}['start'](){const _0x3a7f91=a0_0x4da4;if(this['isRunning']){this['logger']['info']('Agent\x20scheduler\x20is\x20already\x20running');return;}this[_0x3a7f91(0x1ae)]=!![],this['logger']['info'](_0x3a7f91(0x175)),this['initializeExistingAgents'](),this['scheduleInterval']=setInterval(()=>{const _0x3d3feb=_0x3a7f91;this[_0x3d3feb(0x1fd)]()[_0x3d3feb(0x220)](_0x3f9413=>{const _0x18f1ed=_0x3d3feb;this['logger'][_0x18f1ed(0x1e2)]('Scheduler\x20processing\x20cycle\x20failed:',_0x3f9413);});},this[_0x3a7f91(0x17a)]);}async[a0_0x4735dd(0x189)](){const _0x4f58dc=a0_0x4735dd;try{const _0x2e7ee3=await this['agentPool'][_0x4f58dc(0x1f8)]();let _0x5c3537=0x0;for(const _0xd2ae50 of _0x2e7ee3){if(_0xd2ae50[_0x4f58dc(0x235)]===AGENT_MODES['AGENT']){this[_0x4f58dc(0x183)]['info'](_0x4f58dc(0x252)+_0xd2ae50['id'],{'agentName':_0xd2ae50[_0x4f58dc(0x219)],'sessionId':_0xd2ae50[_0x4f58dc(0x1aa)]});const _0x1d5f23=this[_0x4f58dc(0x243)]['get'](_0xd2ae50['id']),_0x2b4f38=_0x1d5f23?.[_0x4f58dc(0x1aa)]||_0xd2ae50[_0x4f58dc(0x1aa)];await this['addAgent'](_0xd2ae50['id'],{'sessionId':_0x2b4f38,'triggeredBy':_0x4f58dc(0x208),'reason':_0x4f58dc(0x21b)}),_0x5c3537++;}}this[_0x4f58dc(0x183)]['info'](_0x4f58dc(0x19e)+_0x5c3537+_0x4f58dc(0x1ab));}catch(_0x240cef){this['logger']['error']('Failed\x20to\x20initialize\x20existing\x20agents',{'error':_0x240cef['message']});}}['stop'](){const _0x413246=a0_0x4735dd;if(!this['isRunning'])return;this[_0x413246(0x1ae)]=![],this['scheduleInterval']&&(clearInterval(this['scheduleInterval']),this['scheduleInterval']=null),this[_0x413246(0x243)]['clear'](),this[_0x413246(0x1f5)][_0x413246(0x226)](),this[_0x413246(0x1ba)]&&this[_0x413246(0x1ba)]['cleanup']&&this[_0x413246(0x1ba)]['cleanup'](),this['logger']['info']('Agent\x20Scheduler\x20stopped');}async[a0_0x4735dd(0x1f2)](_0x2657ab,_0x2d888d={}){const _0x13c0e1=a0_0x4735dd,_0x191892=await this[_0x13c0e1(0x177)]['getAgent'](_0x2657ab);if(!_0x191892){this[_0x13c0e1(0x183)][_0x13c0e1(0x262)]('Cannot\x20add\x20agent\x20to\x20scheduler\x20-\x20agent\x20not\x20found:\x20'+_0x2657ab);return;}if(_0x191892['status']!=='active'){this['logger']['debug']('Skipping\x20inactive\x20agent:\x20'+_0x2657ab+_0x13c0e1(0x248)+_0x191892['status']+')');return;}!_0x2d888d['sessionId']&&this[_0x13c0e1(0x183)]['warn'](_0x13c0e1(0x18e)+_0x2657ab+'\x20added\x20to\x20scheduler\x20without\x20sessionId\x20-\x20API\x20key\x20resolution\x20may\x20fail',{'agentName':_0x191892['name'],'triggeredBy':_0x2d888d['triggeredBy']}),this['activeAgents'][_0x13c0e1(0x15c)](_0x2657ab,{'sessionId':_0x2d888d[_0x13c0e1(0x1aa)],'triggeredBy':_0x2d888d[_0x13c0e1(0x13f)]||'unknown','addedAt':new Date()[_0x13c0e1(0x176)]()}),!this[_0x13c0e1(0x186)][_0x13c0e1(0x222)](_0x2657ab)&&this[_0x13c0e1(0x186)]['set'](_0x2657ab,new Set()),this['logger'][_0x13c0e1(0x160)](_0x13c0e1(0x14b)+_0x2657ab,{'agentMode':_0x191892[_0x13c0e1(0x235)],'activeAgents':this[_0x13c0e1(0x243)][_0x13c0e1(0x181)],'sessionId':_0x2d888d[_0x13c0e1(0x1aa)]||'NO_SESSION_ID','contextKeys':Object[_0x13c0e1(0x1b3)](_0x2d888d),'triggeredBy':_0x2d888d[_0x13c0e1(0x13f)]||_0x13c0e1(0x1c7)}),!this['isRunning']&&this['start']();}[a0_0x4735dd(0x249)](_0x4a3d0c,_0x4000fb=a0_0x4735dd(0x247)){const _0x451bdb=a0_0x4735dd;this[_0x451bdb(0x243)]['has'](_0x4a3d0c)&&(this[_0x451bdb(0x243)]['delete'](_0x4a3d0c),this['processedStateHashes']['delete'](_0x4a3d0c),this['logger']['info']('Agent\x20removed\x20from\x20scheduler:\x20'+_0x4a3d0c,{'reason':_0x4000fb,'remainingAgents':this['activeAgents']['size']}),this[_0x451bdb(0x243)]['size']===0x0&&this[_0x451bdb(0x1d3)]());}[a0_0x4735dd(0x1bb)](_0x40b4de){const _0x1bd23a=a0_0x4735dd;return this[_0x1bd23a(0x243)][_0x1bd23a(0x222)](_0x40b4de);}async['stopAgentExecution'](_0xdf6f4){const _0x81cad=a0_0x4735dd;try{const _0x43e07a=await this[_0x81cad(0x177)]['getAgent'](_0xdf6f4);if(!_0x43e07a)return{'success':![],'error':_0x81cad(0x25a)};_0x43e07a['mode']=AGENT_MODES[_0x81cad(0x1bf)],_0x43e07a[_0x81cad(0x172)]=AGENT_MODE_STATES[_0x81cad(0x206)],_0x43e07a[_0x81cad(0x225)]=null,await this['agentPool']['persistAgentState'](_0xdf6f4),this['removeAgent'](_0xdf6f4,_0x81cad(0x1ca));const _0x5473af=this[_0x81cad(0x243)][_0x81cad(0x179)](_0xdf6f4),_0x1c1020=_0x5473af?.['sessionId']||_0x43e07a['sessionId'];return!_0x1c1020&&this[_0x81cad(0x183)]['warn'](_0x81cad(0x18e)+_0xdf6f4+_0x81cad(0x205),{'agentName':_0x43e07a[_0x81cad(0x219)]}),_0x1c1020&&this['webSocketManager']&&this['webSocketManager']['broadcastToSession']&&this[_0x81cad(0x1cf)]['broadcastToSession'](_0x1c1020,{'type':'execution_stopped','data':{'agentId':_0xdf6f4,'type':_0x81cad(0x1a9),'modeState':'stopped','timestamp':new Date()[_0x81cad(0x176)]()}}),this['logger']['info']('Agent\x20execution\x20stopped:\x20'+_0xdf6f4,{'mode':_0x43e07a['mode'],'modeState':_0x43e07a[_0x81cad(0x172)]}),{'success':!![],'agent':{'id':_0x43e07a['id'],'name':_0x43e07a[_0x81cad(0x219)],'mode':_0x43e07a['mode'],'modeState':_0x43e07a[_0x81cad(0x172)]}};}catch(_0x27050d){return this['logger'][_0x81cad(0x1e2)](_0x81cad(0x1e3)+_0xdf6f4,{'error':_0x27050d[_0x81cad(0x1fc)]}),{'success':![],'error':_0x27050d['message']};}}async['processingCycle'](){const _0x366d75=a0_0x4735dd;if(this[_0x366d75(0x21c)]){this[_0x366d75(0x183)][_0x366d75(0x1c5)](_0x366d75(0x1a1));return;}if(this[_0x366d75(0x243)][_0x366d75(0x181)]===0x0)return;this[_0x366d75(0x21c)]=!![];try{const _0x49127f=Array['from'](this['activeAgents'][_0x366d75(0x1b3)]());for(const _0x1c52b2 of _0x49127f){try{if(!this['activeAgents']['has'](_0x1c52b2))continue;const _0x3f1b5d=await this[_0x366d75(0x169)](_0x1c52b2);!_0x3f1b5d&&this[_0x366d75(0x249)](_0x1c52b2,_0x366d75(0x247));}catch(_0x28078c){this[_0x366d75(0x183)]['error'](_0x366d75(0x1af)+_0x1c52b2,{'error':_0x28078c['message'],'stack':_0x28078c[_0x366d75(0x1e1)]}),this['removeAgent'](_0x1c52b2,_0x366d75(0x1e2));}}}finally{this[_0x366d75(0x21c)]=![];}}async['processAgent'](_0x2c0628){const _0x73905f=a0_0x4735dd;if(this[_0x73905f(0x215)][_0x73905f(0x179)](_0x2c0628))return this[_0x73905f(0x183)]['debug'](_0x73905f(0x18e)+_0x2c0628+'\x20is\x20already\x20being\x20processed,\x20skipping'),!![];const _0x5930ee=await this[_0x73905f(0x177)]['getAgent'](_0x2c0628);if(!_0x5930ee)return![];this['agentProcessingLocks']['set'](_0x2c0628,!![]);try{if(_0x5930ee['delayEndTime']&&new Date()<new Date(_0x5930ee[_0x73905f(0x225)]))return this['logger'][_0x73905f(0x1c5)]('Agent\x20'+_0x2c0628+'\x20is\x20delayed\x20until\x20'+_0x5930ee['delayEndTime']),!![];if(_0x5930ee['status']==='paused'||_0x5930ee['pausedUntil']){if(_0x5930ee['pausedUntil']&&new Date()<new Date(_0x5930ee['pausedUntil']))return this[_0x73905f(0x183)][_0x73905f(0x1c5)](_0x73905f(0x18e)+_0x2c0628+_0x73905f(0x19d)+_0x5930ee[_0x73905f(0x16a)]),!![];}if(_0x5930ee['stopRequested'])return this[_0x73905f(0x183)][_0x73905f(0x160)](_0x73905f(0x18e)+_0x2c0628+'\x20stop\x20requested\x20-\x20removing\x20from\x20scheduler'),![];const _0xd014b3=this['generateAgentStateHash'](_0x5930ee);if(this[_0x73905f(0x184)](_0x2c0628,_0xd014b3)){this['logger'][_0x73905f(0x1c5)](_0x73905f(0x18e)+_0x2c0628+'\x20state\x20already\x20processed,\x20skipping\x20duplicate\x20iteration',{'stateHash':_0xd014b3,'agentMode':_0x5930ee['mode']});if(_0x5930ee['mode']===AGENT_MODES['CHAT']){const _0x27898c=_0x5930ee[_0x73905f(0x1b6)][_0x73905f(0x1d1)][_0x73905f(0x16c)]>0x0||_0x5930ee['messageQueues'][_0x73905f(0x1c9)]['length']>0x0;if(!_0x27898c)return this[_0x73905f(0x183)]['debug'](_0x73905f(0x15b)+_0x2c0628+_0x73905f(0x22b)),![];}return!![];}const _0xb92832=_0x5930ee['messageQueues'];_0xb92832['userMessages'][_0x73905f(0x16c)]>0x0&&this[_0x73905f(0x183)][_0x73905f(0x160)](_0x73905f(0x187)+_0x2c0628+_0x73905f(0x178),{'userMessageCount':_0xb92832['userMessages']['length'],'agentMode':_0x5930ee[_0x73905f(0x235)]});const _0x4678a6=_0xb92832[_0x73905f(0x168)][_0x73905f(0x16c)]+_0xb92832[_0x73905f(0x1c9)][_0x73905f(0x16c)]+_0xb92832['userMessages'][_0x73905f(0x16c)];if(_0x4678a6===0x0&&_0x5930ee['mode']===AGENT_MODES['CHAT'])return this[_0x73905f(0x183)][_0x73905f(0x1c5)](_0x73905f(0x15b)+_0x2c0628+_0x73905f(0x1e0)),![];if(_0x4678a6===0x0&&_0x5930ee[_0x73905f(0x235)]===AGENT_MODES['AGENT']){await this[_0x73905f(0x251)](_0x2c0628);const _0x4dda9e=this[_0x73905f(0x196)](_0x5930ee),hasUnprocessedMessages=this[_0x73905f(0x260)](_0x5930ee);if(!_0x4dda9e&&!hasUnprocessedMessages)return this[_0x73905f(0x183)][_0x73905f(0x160)](_0x73905f(0x1a5)+_0x2c0628+_0x73905f(0x22a),{'agentName':_0x5930ee['name'],'taskCount':_0x5930ee[_0x73905f(0x1d6)]?.['tasks']?.['length']||0x0,'completedTasks':_0x5930ee[_0x73905f(0x1d6)]?.[_0x73905f(0x1d4)]?.['filter'](_0x624937=>_0x624937['status']===_0x73905f(0x247))['length']||0x0}),![];return await this[_0x73905f(0x20a)](_0x2c0628);}const processedMessages=await this['processAgentQueues'](_0x2c0628);if(processedMessages===0x0)return _0x5930ee[_0x73905f(0x235)]===AGENT_MODES[_0x73905f(0x1bf)]?![]:await this[_0x73905f(0x20a)](_0x2c0628);const _0x1e3170=await this[_0x73905f(0x1fb)](_0x2c0628);if(!_0x1e3170)return this['logger'][_0x73905f(0x262)]('No\x20AI\x20response\x20for\x20agent\x20'+_0x2c0628),_0x5930ee['mode']===AGENT_MODES[_0x73905f(0x1c2)];return await this[_0x73905f(0x24d)](_0x2c0628,_0x1e3170),this['markStateAsProcessed'](_0x2c0628,_0xd014b3),this[_0x73905f(0x23e)](_0x2c0628,_0x5930ee);}finally{this[_0x73905f(0x215)]['delete'](_0x2c0628);}}async[a0_0x4735dd(0x1a7)](_0x58a4f0){const _0x3dff6e=a0_0x4735dd,_0x3e1d7f=await this['agentPool']['getAgent'](_0x58a4f0);if(!_0x3e1d7f)return 0x0;const _0x5e1c88=_0x3e1d7f[_0x3dff6e(0x1b6)],_0x32cedd=[..._0x5e1c88[_0x3dff6e(0x168)][_0x3dff6e(0x21f)](_0x3cd65c=>({..._0x3cd65c,'queueType':'toolResults'})),..._0x5e1c88['interAgentMessages'][_0x3dff6e(0x21f)](_0x1e7715=>({..._0x1e7715,'queueType':'interAgentMessages'})),..._0x5e1c88['userMessages']['map'](_0x88c9a9=>({..._0x88c9a9,'queueType':_0x3dff6e(0x1d1)}))];if(_0x32cedd['length']===0x0)return 0x0;_0x32cedd[_0x3dff6e(0x180)]((_0x4786be,_0x30f69d)=>new Date(_0x4786be['timestamp']||_0x4786be[_0x3dff6e(0x162)]||0x0)-new Date(_0x30f69d[_0x3dff6e(0x182)]||_0x30f69d['queuedAt']||0x0));let _0x45b301='';const _0x217b89=_0x32cedd[_0x3dff6e(0x155)](_0x214976=>_0x214976['queueType']===_0x3dff6e(0x1d1)),_0x264017=_0x32cedd['some'](_0x22ccc9=>_0x22ccc9[_0x3dff6e(0x212)]===_0x3dff6e(0x1c9)),_0x6054f8=_0x32cedd[_0x3dff6e(0x155)](_0x134d57=>_0x134d57['queueType']===_0x3dff6e(0x168)),_0x2ab93c=_0x32cedd[_0x3dff6e(0x170)](_0x158bcb=>_0x158bcb[_0x3dff6e(0x212)]==='userMessages');_0x2ab93c[_0x3dff6e(0x16c)]>0x0&&_0x2ab93c['forEach'](_0xfd75df=>{if(_0x45b301)_0x45b301+='\x0a\x0a';_0x45b301+=_0xfd75df['content'];});const _0x217bdd=_0x32cedd['filter'](_0x80da62=>_0x80da62[_0x3dff6e(0x212)]===_0x3dff6e(0x1c9));if(_0x217bdd['length']>0x0){if(_0x45b301)_0x45b301+='\x0a\x0a';_0x45b301+=_0x3dff6e(0x16b),_0x217bdd['forEach'](_0x5e2a24=>{const _0x28360b=_0x3dff6e,_0x48f4a0=_0x5e2a24['senderName']||_0x5e2a24['sender']||_0x28360b(0x191);_0x45b301+=_0x48f4a0+':\x20'+_0x5e2a24['content']+'\x0a';});}const _0x3b21e3=_0x32cedd['filter'](_0x27fc3f=>_0x27fc3f['queueType']==='toolResults');if(_0x3b21e3[_0x3dff6e(0x16c)]>0x0){if(_0x45b301)_0x45b301+='\x0a\x0a';_0x45b301+='[Previous\x20Tool\x20Results]\x0a',_0x3b21e3[_0x3dff6e(0x214)](_0x1b2416=>{_0x45b301+=this['formatToolResult'](_0x1b2416)+'\x0a';});}_0x264017&&(_0x45b301+=_0x3dff6e(0x1d2));await this[_0x3dff6e(0x1d0)](_0x58a4f0,_0x2ab93c,_0x217bdd);const _0x3dce97={'id':_0x3dff6e(0x143)+Date[_0x3dff6e(0x20c)](),'role':MESSAGE_ROLES[_0x3dff6e(0x1a2)],'content':_0x45b301[_0x3dff6e(0x228)](),'timestamp':new Date()[_0x3dff6e(0x176)](),'type':_0x3dff6e(0x157),'originalMessageCount':_0x32cedd[_0x3dff6e(0x16c)]};await this['addMessageToConversation'](_0x58a4f0,_0x3dce97,![]);if(_0x3e1d7f&&_0x217bdd[_0x3dff6e(0x16c)]>0x0){for(const _0x4913e6 of _0x217bdd){if(_0x4913e6['sender']){!_0x3e1d7f[_0x3dff6e(0x22e)][_0x3dff6e(0x222)](_0x4913e6['sender'])&&_0x3e1d7f[_0x3dff6e(0x22e)][_0x3dff6e(0x15c)](_0x4913e6['sender'],{'lastSent':null,'lastReceived':null,'lastType':null});const _0x11a3a5=_0x3e1d7f['interAgentTracking'][_0x3dff6e(0x179)](_0x4913e6['sender']);_0x11a3a5['lastReceived']=Date['now'](),_0x11a3a5['lastType']=_0x3dff6e(0x245);}}await this['agentPool']['persistAgentState'](_0x58a4f0);}return _0x5e1c88['toolResults'][_0x3dff6e(0x16c)]=0x0,_0x5e1c88['interAgentMessages']['length']=0x0,_0x5e1c88['userMessages'][_0x3dff6e(0x16c)]=0x0,await this[_0x3dff6e(0x177)][_0x3dff6e(0x1fa)](_0x58a4f0),this['logger']['debug'](_0x3dff6e(0x144)+_0x32cedd['length']+_0x3dff6e(0x142)+_0x58a4f0),_0x32cedd[_0x3dff6e(0x16c)];}async[a0_0x4735dd(0x195)](_0x460c7c,_0x3372d8,_0x23862a=!![]){const _0x4d4646=a0_0x4735dd,_0x11a629=await this[_0x4d4646(0x177)]['getAgent'](_0x460c7c);if(!_0x11a629)return;let _0xd15157;switch(_0x3372d8['queueType']){case'toolResults':_0xd15157={..._0x3372d8,'role':_0x4d4646(0x1fe),'content':this['formatToolResult'](_0x3372d8)};break;case _0x4d4646(0x1c9):_0xd15157={..._0x3372d8,'role':MESSAGE_ROLES['SYSTEM'],'content':'Message\x20from\x20'+(_0x3372d8[_0x4d4646(0x1be)]||_0x3372d8[_0x4d4646(0x20b)])+':\x20'+_0x3372d8['content']};break;case'userMessages':_0xd15157={..._0x3372d8,'role':MESSAGE_ROLES[_0x4d4646(0x1a2)]};break;default:_0xd15157=_0x3372d8;}!_0xd15157[_0x4d4646(0x182)]&&(_0xd15157['timestamp']=new Date()[_0x4d4646(0x176)]()),_0x11a629['conversations']['full']['messages']['push'](_0xd15157),_0x11a629['conversations'][_0x4d4646(0x198)][_0x4d4646(0x19b)]=new Date()[_0x4d4646(0x176)](),_0x11a629[_0x4d4646(0x152)]&&_0x11a629[_0x4d4646(0x1c6)][_0x11a629[_0x4d4646(0x152)]]&&(_0x11a629['conversations'][_0x11a629[_0x4d4646(0x152)]]['messages']['push'](_0xd15157),_0x11a629['conversations'][_0x11a629[_0x4d4646(0x152)]]['lastUpdated']=new Date()['toISOString']()),_0x23862a&&this['shouldBroadcastMessage'](_0xd15157)&&this[_0x4d4646(0x165)](_0x460c7c,_0xd15157);}async['processAgentAutonomously'](_0x4000b6){const _0x58f751=a0_0x4735dd;await this[_0x58f751(0x188)](_0x4000b6);const _0x55252b=await this[_0x58f751(0x1fb)](_0x4000b6);if(!_0x55252b)return!![];await this['processAIResponse'](_0x4000b6,_0x55252b);const _0x220779=await this[_0x58f751(0x177)][_0x58f751(0x1db)](_0x4000b6);return this['shouldAgentContinue'](_0x4000b6,_0x220779);}async['checkAndPerformCompaction'](_0x594571,_0xeef836,_0x164b22){const _0x1c0293=a0_0x4735dd,_0xa36d13=process['env']['COMPACT_DEBUG']===_0x1c0293(0x1c3);_0xa36d13&&console['log'](_0x1c0293(0x18c),{'agentId':_0x594571,'targetModel':_0xeef836,'sessionId':_0x164b22,'timestamp':new Date()[_0x1c0293(0x176)]()});try{const _0x15288b=await this[_0x1c0293(0x177)]['getAgent'](_0x594571);if(!_0x15288b)return _0xa36d13&&console[_0x1c0293(0x192)](_0x1c0293(0x18f),{'agentId':_0x594571,'reason':_0x1c0293(0x25a)}),{'shouldContinue':![],'error':'Agent\x20not\x20found'};let _0x7976b0=_0x15288b[_0x1c0293(0x152)]&&_0x15288b[_0x1c0293(0x152)]!==_0xeef836?_0x15288b[_0x1c0293(0x152)]:_0xeef836;if(!_0x7976b0){this['logger'][_0x1c0293(0x262)]('Agent\x20'+_0x594571+_0x1c0293(0x14a),{'agentId':_0x594571,'currentModel':_0x15288b[_0x1c0293(0x152)],'targetModel':_0xeef836,'preferredModel':_0x15288b['preferredModel'],'availableConversations':Object['keys'](_0x15288b['conversations']||{})}),this[_0x1c0293(0x22d)](_0x594571,_0x164b22,{'status':'warning','message':_0x1c0293(0x17c),'details':_0x1c0293(0x1b9),'agentName':_0x15288b[_0x1c0293(0x219)]});if(_0x15288b[_0x1c0293(0x18a)]&&_0x15288b[_0x1c0293(0x1c6)][_0x15288b[_0x1c0293(0x18a)]])_0x7976b0=_0x15288b['preferredModel'],this[_0x1c0293(0x183)][_0x1c0293(0x160)](_0x1c0293(0x242)+_0x7976b0);else{const _0xe24d7c=Object['keys'](_0x15288b[_0x1c0293(0x1c6)]||{})[_0x1c0293(0x170)](_0x4664f5=>_0x4664f5!=='full');if(_0xe24d7c[_0x1c0293(0x16c)]>0x0)_0x7976b0=_0xe24d7c[0x0],this['logger']['warn']('Using\x20first\x20available\x20conversation\x20key\x20for\x20compaction\x20check:\x20'+_0x7976b0);else return this['logger'][_0x1c0293(0x1e2)](_0x1c0293(0x216)+_0x594571+_0x1c0293(0x1ee)),this[_0x1c0293(0x22d)](_0x594571,_0x164b22,{'status':'error','message':_0x1c0293(0x25b),'details':_0x1c0293(0x18e)+_0x15288b[_0x1c0293(0x219)]+'\x20has\x20no\x20valid\x20conversation\x20data.\x20Compaction\x20skipped.','agentName':_0x15288b['name']}),{'shouldContinue':!![],'error':_0x1c0293(0x1ff)};}}const _0x174f4a=await this[_0x1c0293(0x177)][_0x1c0293(0x265)](_0x594571,_0x7976b0);_0xa36d13&&console[_0x1c0293(0x192)]('[COMPACT-METADATA]',{'agentId':_0x594571,'modelToCheck':_0x7976b0,'hasMetadata':!!_0x174f4a,'isCompacted':_0x174f4a?.[_0x1c0293(0x25f)],'originalMessageCount':_0x174f4a?.['originalMessages']?.['length']||0x0,'compactedMessageCount':_0x174f4a?.['compactedMessages']?.[_0x1c0293(0x16c)]||0x0,'lastCompactization':_0x174f4a?.['lastCompactization']||_0x1c0293(0x261),'compactizationCount':_0x174f4a?.['compactizationCount']||0x0,'originalTokenCount':_0x174f4a?.[_0x1c0293(0x200)]||0x0,'compactedTokenCount':_0x174f4a?.['compactedTokenCount']||0x0});if(!_0x174f4a||!_0x174f4a['originalMessages']&&!_0x174f4a['compactedMessages'])return this['logger'][_0x1c0293(0x1c5)]('Compaction\x20skipped:\x20no\x20conversation\x20metadata\x20for\x20agent\x20'+_0x594571+',\x20model\x20'+_0x7976b0),_0xa36d13&&console[_0x1c0293(0x192)]('[COMPACT-SKIPPED]',{'agentId':_0x594571,'reason':_0x1c0293(0x1e9)}),{'shouldContinue':!![]};const _0x492fd4=_0x174f4a['isCompacted']?_0x174f4a[_0x1c0293(0x236)]:_0x174f4a['originalMessages'];_0xa36d13&&console[_0x1c0293(0x192)]('[COMPACT-MESSAGES-SELECTED]',{'agentId':_0x594571,'selectedArray':_0x174f4a[_0x1c0293(0x25f)]?_0x1c0293(0x236):_0x1c0293(0x24a),'messageCount':_0x492fd4?.['length']||0x0,'reason':_0x174f4a[_0x1c0293(0x25f)]?_0x1c0293(0x15f):'No\x20compaction\x20yet,\x20using\x20original'});if(!_0x492fd4||_0x492fd4[_0x1c0293(0x16c)]<COMPACTION_CONFIG[_0x1c0293(0x227)])return this[_0x1c0293(0x183)]['debug'](_0x1c0293(0x23b)+(_0x492fd4?.['length']||0x0)+')\x20for\x20agent\x20'+_0x594571),_0xa36d13&&console[_0x1c0293(0x192)]('[COMPACT-SKIPPED]',{'agentId':_0x594571,'reason':_0x1c0293(0x1f4),'messageCount':_0x492fd4?.['length']||0x0,'minRequired':COMPACTION_CONFIG[_0x1c0293(0x227)]}),{'shouldContinue':!![]};const _0x515485=await this['tokenCountingService']['estimateConversationTokens'](_0x492fd4,_0xeef836,TOKEN_COUNTING_MODES['ACCURATE']),_0xc32558=this['tokenCountingService']['getModelContextWindow'](_0xeef836),_0x4442d2=this['tokenCountingService']['getModelMaxOutputTokens'](_0xeef836);_0xa36d13&&console[_0x1c0293(0x192)]('[COMPACT-TOKEN-COUNT]',{'agentId':_0x594571,'currentTokens':_0x515485,'maxOutputTokens':_0x4442d2,'contextWindow':_0xc32558,'model':_0xeef836,'countingMode':_0x1c0293(0x16e)});const _0xfdc1b3=_0x15288b['compactionThreshold']||COMPACTION_CONFIG['DEFAULT_THRESHOLD'],_0x59cf19=this[_0x1c0293(0x1ba)]['shouldTriggerCompaction'](_0x515485,_0x4442d2,_0xc32558,_0xfdc1b3);if(_0xa36d13){const requiredTokens=_0x515485+_0x4442d2,_0x535a63=_0xfdc1b3*_0xc32558;console[_0x1c0293(0x192)]('[COMPACT-TRIGGER-CHECK]',{'agentId':_0x594571,'currentTokens':_0x515485,'maxOutputTokens':_0x4442d2,'requiredTokens':requiredTokens,'contextWindow':_0xc32558,'threshold':_0xfdc1b3,'thresholdTokens':_0x535a63,'shouldCompact':_0x59cf19,'formula':_0x515485+_0x1c0293(0x1b4)+_0x4442d2+_0x1c0293(0x234)+requiredTokens+'\x20'+(_0x59cf19?'>=':'<')+'\x20'+_0x535a63+'\x20('+_0xfdc1b3*0x64+'%\x20of\x20'+_0xc32558+')','decision':_0x59cf19?_0x1c0293(0x223):_0x1c0293(0x147)});}if(!_0x59cf19)return _0xa36d13&&console[_0x1c0293(0x192)]('[COMPACT-SKIPPED]',{'agentId':_0x594571,'reason':_0x1c0293(0x145),'utilizationPct':((_0x515485+_0x4442d2)/_0xc32558*0x64)[_0x1c0293(0x1d5)](0x1)}),{'shouldContinue':!![]};this['logger'][_0x1c0293(0x160)](_0x1c0293(0x154)+_0x594571,{'currentTokens':_0x515485,'contextWindow':_0xc32558,'threshold':(_0xfdc1b3*0x64)[_0x1c0293(0x1d5)](0x0)+'%','utilization':((_0x515485+_0x4442d2)/_0xc32558*0x64)[_0x1c0293(0x1d5)](0x1)+'%','targetModel':_0xeef836});_0xa36d13&&console['log']('[COMPACT-TRIGGERED]',{'agentId':_0x594571,'reason':_0x1c0293(0x1b0),'currentTokens':_0x515485,'maxOutputTokens':_0x4442d2,'requiredTokens':_0x515485+_0x4442d2,'contextWindow':_0xc32558,'threshold':_0xfdc1b3,'utilizationPct':((_0x515485+_0x4442d2)/_0xc32558*0x64)['toFixed'](0x1)});this['compactionInProgress']['set'](_0x594571,COMPACTION_STATUS[_0x1c0293(0x1a4)]),this['broadcastCompactionEvent'](_0x594571,_0x164b22,{'status':COMPACTION_STATUS['STARTING'],'currentTokens':_0x515485,'targetTokens':this[_0x1c0293(0x1ba)][_0x1c0293(0x1da)](_0xc32558),'contextWindow':_0xc32558,'model':_0xeef836});let _0xe10d32=COMPACTION_STRATEGIES['SUMMARIZATION'];const _0x269792=_0x15288b['currentModel'];_0x269792&&_0x269792!==_0xeef836&&(_0xe10d32=COMPACTION_STRATEGIES['TRUNCATION'],this['logger'][_0x1c0293(0x160)](_0x1c0293(0x246)+_0x269792+'\x20→\x20'+_0xeef836));this[_0x1c0293(0x1f5)][_0x1c0293(0x15c)](_0x594571,COMPACTION_STATUS['IN_PROGRESS']),this['broadcastCompactionEvent'](_0x594571,_0x164b22,{'status':COMPACTION_STATUS['IN_PROGRESS'],'strategy':_0xe10d32,'messageCount':_0x492fd4['length']});let _0x2213d8=null,_0x455bf2=0x0;const _0x476d96=COMPACTION_CONFIG['MAX_RETRY_ATTEMPTS'];while(_0x455bf2<_0x476d96&&!_0x2213d8){_0x455bf2++;try{const _0x2932e8=_0x455bf2===0x1?_0xe10d32:COMPACTION_STRATEGIES[_0x1c0293(0x1bc)];_0x2213d8=await this[_0x1c0293(0x1a6)]['compactConversation'](_0x492fd4,_0x269792||_0xeef836,_0xeef836,{'strategy':_0x2932e8,'targetTokenCount':this[_0x1c0293(0x1ba)]['calculateTargetTokenCount'](_0xc32558),'sessionId':_0x164b22});const _0x3d171e=this[_0x1c0293(0x1ba)]['validateCompaction'](_0x515485,_0x2213d8['compactedTokenCount'],_0xc32558);!_0x3d171e['valid']&&(this[_0x1c0293(0x183)]['warn']('Compaction\x20validation\x20failed\x20for\x20agent\x20'+_0x594571,{'attempt':_0x455bf2,'reason':_0x3d171e[_0x1c0293(0x266)],'reductionPercent':_0x3d171e[_0x1c0293(0x1b7)]}),_0x455bf2<_0x476d96&&(_0x2213d8=null,await new Promise(_0x52c59e=>setTimeout(_0x52c59e,COMPACTION_CONFIG[_0x1c0293(0x255)]))));}catch(_0x264af3){this[_0x1c0293(0x183)][_0x1c0293(0x1e2)](_0x1c0293(0x1f7)+_0x455bf2+'\x20failed\x20for\x20agent\x20'+_0x594571,{'error':_0x264af3[_0x1c0293(0x1fc)]});if(_0x455bf2>=_0x476d96)throw _0x264af3;await new Promise(_0x1058ae=>setTimeout(_0x1058ae,COMPACTION_CONFIG['RETRY_DELAY_MS']));}}if(!_0x2213d8)throw new Error('All\x20compaction\x20attempts\x20failed');if(_0x269792&&_0x269792!==_0xeef836&&_0x7976b0===_0x269792){const _0x27e1aa=await this[_0x1c0293(0x177)][_0x1c0293(0x265)](_0x594571,_0x269792);if(_0x27e1aa&&_0x27e1aa[_0x1c0293(0x24a)]){for(const _0x328036 of _0x27e1aa[_0x1c0293(0x24a)]){await this['agentPool'][_0x1c0293(0x195)](_0x594571,_0xeef836,_0x328036);}this['logger'][_0x1c0293(0x1c5)]('Copied\x20'+_0x27e1aa[_0x1c0293(0x24a)][_0x1c0293(0x16c)]+'\x20messages\x20from\x20'+_0x269792+'\x20to\x20'+_0xeef836+_0x1c0293(0x22f));}}return await this['agentPool'][_0x1c0293(0x202)](_0x594571,_0xeef836,_0x2213d8),_0xa36d13&&console['log']('[COMPACT-COMPLETED]',{'agentId':_0x594571,'strategy':_0x2213d8['strategy'],'originalMessageCount':_0x2213d8[_0x1c0293(0x24a)]?.['length']||0x0,'compactedMessageCount':_0x2213d8[_0x1c0293(0x236)]?.[_0x1c0293(0x16c)]||0x0,'originalTokens':_0x2213d8[_0x1c0293(0x200)],'compactedTokens':_0x2213d8['compactedTokenCount'],'reductionPercent':_0x2213d8['reductionPercent']['toFixed'](0x1),'executionTimeMs':_0x2213d8['executionTime'],'model':_0xeef836}),this['logger'][_0x1c0293(0x160)](_0x1c0293(0x15d)+_0x594571,{'strategy':_0x2213d8['strategy'],'originalTokens':_0x2213d8['originalTokenCount'],'compactedTokens':_0x2213d8[_0x1c0293(0x24e)],'reduction':_0x2213d8[_0x1c0293(0x1b7)]['toFixed'](0x1)+'%','executionTime':_0x2213d8[_0x1c0293(0x16d)]+'ms'}),this[_0x1c0293(0x1f5)][_0x1c0293(0x264)](_0x594571),this[_0x1c0293(0x22d)](_0x594571,_0x164b22,{'status':COMPACTION_STATUS[_0x1c0293(0x171)],'originalTokens':_0x2213d8[_0x1c0293(0x200)],'compactedTokens':_0x2213d8['compactedTokenCount'],'reductionPercent':_0x2213d8[_0x1c0293(0x1b7)],'strategy':_0x2213d8[_0x1c0293(0x1df)],'executionTime':_0x2213d8[_0x1c0293(0x16d)]}),{'shouldContinue':!![],'compactionPerformed':!![]};}catch(_0x59a8df){return this['logger'][_0x1c0293(0x1e2)](_0x1c0293(0x22c)+_0x594571,{'error':_0x59a8df[_0x1c0293(0x1fc)],'stack':_0x59a8df['stack']}),this[_0x1c0293(0x1f5)][_0x1c0293(0x264)](_0x594571),this[_0x1c0293(0x22d)](_0x594571,_0x164b22,{'status':COMPACTION_STATUS[_0x1c0293(0x15e)],'error':_0x59a8df['message']}),{'shouldContinue':!![],'error':_0x59a8df[_0x1c0293(0x1fc)]};}}['broadcastCompactionEvent'](_0x5345e6,_0x291d50,_0x5e8122){const _0x2c1a01=a0_0x4735dd;if(!this['webSocketManager']||!this[_0x2c1a01(0x1cf)]['broadcastToSession'])return;this[_0x2c1a01(0x1cf)]['broadcastToSession'](_0x291d50,{'type':'compaction_event','data':{'agentId':_0x5345e6,'timestamp':new Date()['toISOString'](),..._0x5e8122}});}async[a0_0x4735dd(0x1fb)](_0x196916){const _0x5062b5=a0_0x4735dd;try{const _0x339e7f=await this['agentPool'][_0x5062b5(0x1db)](_0x196916);if(!_0x339e7f)return null;const _0x13c630=_0x339e7f[_0x5062b5(0x1c6)]?.['full']?.[_0x5062b5(0x1f0)]||[],_0x2ca6dd=this['activeAgents']['get'](_0x196916),_0x3a48b3=_0x2ca6dd?.['sessionId']||_0x339e7f[_0x5062b5(0x1aa)];if(!_0x3a48b3)return this['logger'][_0x5062b5(0x1e2)](_0x5062b5(0x18e)+_0x196916+_0x5062b5(0x1ac),{'agentName':_0x339e7f[_0x5062b5(0x219)],'hasAgentContext':!!_0x2ca6dd,'agentSessionId':_0x339e7f[_0x5062b5(0x1aa)],'contextSessionId':_0x2ca6dd?.['sessionId']}),null;let _0x41042c=_0x339e7f[_0x5062b5(0x152)];if(!_0x41042c){this[_0x5062b5(0x183)][_0x5062b5(0x262)](_0x5062b5(0x18e)+_0x196916+'\x20has\x20no\x20currentModel\x20set,\x20using\x20preferredModel\x20as\x20fallback',{'agentId':_0x196916,'preferredModel':_0x339e7f['preferredModel'],'availableConversations':Object['keys'](_0x339e7f['conversations']||{})});this['webSocketManager']&&_0x3a48b3&&this['webSocketManager'][_0x5062b5(0x13e)](_0x3a48b3,{'type':_0x5062b5(0x253),'agentId':_0x196916,'agentName':_0x339e7f[_0x5062b5(0x219)],'message':'Agent\x20model\x20configuration\x20restored','details':_0x5062b5(0x19c)+_0x339e7f[_0x5062b5(0x219)]+'\x22\x20had\x20no\x20currentModel\x20set.\x20Automatically\x20restored\x20to\x20'+(_0x339e7f['preferredModel']||'default model')+'.','severity':'warning','timestamp':new Date()[_0x5062b5(0x176)]()});_0x41042c=_0x339e7f['preferredModel'];if(_0x41042c)_0x339e7f[_0x5062b5(0x152)]=_0x41042c,await this['agentPool'][_0x5062b5(0x1fa)](_0x196916),this['logger'][_0x5062b5(0x160)](_0x5062b5(0x1eb)+_0x41042c);else return this[_0x5062b5(0x183)][_0x5062b5(0x1e2)](_0x5062b5(0x18e)+_0x196916+'\x20has\x20no\x20preferredModel\x20or\x20currentModel,\x20cannot\x20continue'),this['webSocketManager']&&_0x3a48b3&&this[_0x5062b5(0x1cf)][_0x5062b5(0x13e)](_0x3a48b3,{'type':'agent_error','agentId':_0x196916,'agentName':_0x339e7f[_0x5062b5(0x219)],'message':'Agent\x20model\x20configuration\x20error','details':'Agent\x20\x22'+_0x339e7f['name']+'\x22\x20has\x20no\x20valid\x20model\x20configuration.\x20Cannot\x20process\x20messages.','severity':'error','timestamp':new Date()[_0x5062b5(0x176)]()}),null;}if(_0x339e7f['dynamicModelRouting']&&this['modelRouterService'])try{const _0x2a5bfe=[..._0x13c630]['reverse']()[_0x5062b5(0x1dc)](_0x1de22d=>_0x1de22d['role']==='user');if(_0x2a5bfe){let _0xa975e2=[];if(this['modelsService'])try{this['logger']['debug']('ModelsService\x20type\x20check',{'hasModelsService':!!this[_0x5062b5(0x1c8)],'type':typeof this[_0x5062b5(0x1c8)],'methods':Object[_0x5062b5(0x163)](Object['getPrototypeOf'](this['modelsService']))});let _0x27c848=this[_0x5062b5(0x1c8)]['getModels']();const _0x265b09=!this[_0x5062b5(0x1c8)][_0x5062b5(0x21e)]||this['modelsService'][_0x5062b5(0x21e)]&&Date['now']()-new Date(this['modelsService']['lastFetched'])['getTime']()>0x5*0x3c*0x3e8;(!_0x27c848||_0x27c848[_0x5062b5(0x16c)]===0x0||_0x265b09)&&(this[_0x5062b5(0x183)]['info']('Models list empty or stale, fetching from backend with sessionId'),await this['modelsService']['fetchModels']({'sessionId':_0x3a48b3}),_0x27c848=this[_0x5062b5(0x1c8)]['getModels']()),_0xa975e2=_0x27c848['filter'](_0x4170a4=>_0x4170a4['id']!==_0x5062b5(0x1ea)&&_0x4170a4['name']!==_0x5062b5(0x1ea))['map'](_0x11b214=>_0x11b214['id']||_0x11b214['name']),this[_0x5062b5(0x183)]['debug']('Available\x20models\x20for\x20routing:\x20'+_0xa975e2[_0x5062b5(0x259)](',\x20'));}catch(_0x424363){this['logger']['warn'](_0x5062b5(0x17d)+_0x424363['message']);}const _0x4fd1e1=await this[_0x5062b5(0x239)][_0x5062b5(0x244)](_0x2a5bfe['content'],_0x13c630['slice'](-0x5),_0x339e7f['currentModel'],_0xa975e2,{'agentId':_0x196916,'sessionId':_0x3a48b3});this[_0x5062b5(0x183)][_0x5062b5(0x160)](_0x5062b5(0x241),{'selectedModel':_0x4fd1e1['selectedModel'],'currentModel':_0x339e7f['currentModel'],'areEqual':_0x4fd1e1['selectedModel']===_0x339e7f['currentModel'],'willSwitch':_0x4fd1e1[_0x5062b5(0x21d)]&&_0x4fd1e1[_0x5062b5(0x21d)]!==_0x339e7f['currentModel']}),_0x4fd1e1['selectedModel']&&_0x4fd1e1['selectedModel']!==_0x339e7f[_0x5062b5(0x152)]?(this[_0x5062b5(0x183)][_0x5062b5(0x160)]('Dynamic\x20routing:\x20switching\x20from\x20'+_0x339e7f['currentModel']+_0x5062b5(0x15a)+_0x4fd1e1[_0x5062b5(0x21d)],{'agentId':_0x196916,'reason':_0x4fd1e1['reasoning']}),_0x41042c=_0x4fd1e1[_0x5062b5(0x21d)],_0x339e7f['currentModel']=_0x41042c,await this['agentPool'][_0x5062b5(0x1fa)](_0x196916),this[_0x5062b5(0x183)]['info'](_0x5062b5(0x204)+_0x41042c+',\x20agent.currentModel='+_0x339e7f[_0x5062b5(0x152)])):this[_0x5062b5(0x183)][_0x5062b5(0x160)]('No\x20model\x20switch\x20needed',{'selectedModel':_0x4fd1e1[_0x5062b5(0x21d)],'currentModel':_0x339e7f['currentModel'],'hasSelectedModel':!!_0x4fd1e1[_0x5062b5(0x21d)]});}}catch(_0x17a3c7){this['logger']['warn']('Dynamic\x20routing\x20failed,\x20using\x20current\x20model:\x20'+_0x17a3c7[_0x5062b5(0x1fc)]);}this[_0x5062b5(0x183)]['info'](_0x5062b5(0x23f)+_0x41042c,{'agentId':_0x196916,'targetModel':_0x41042c,'originalModel':_0x339e7f['currentModel']});const _0xe54d3b=await this['checkAndPerformCompaction'](_0x196916,_0x41042c,_0x3a48b3);if(!_0xe54d3b[_0x5062b5(0x218)])return this[_0x5062b5(0x183)]['warn']('Compaction\x20check\x20returned\x20shouldContinue=false\x20for\x20agent\x20'+_0x196916),null;_0xe54d3b[_0x5062b5(0x267)]&&this['logger']['info']('Compaction\x20performed\x20for\x20agent\x20'+_0x196916+_0x5062b5(0x148));const _0x216a60=await this[_0x5062b5(0x177)]['getMessagesForAI'](_0x196916,_0x41042c);let _0x2013cf=_0x339e7f[_0x5062b5(0x1cb)];if(_0x339e7f['mode']===AGENT_MODES[_0x5062b5(0x1c2)]){const _0xc913b=_0x5062b5(0x229);_0x2013cf=(_0x339e7f[_0x5062b5(0x1cb)]||'')+_0xc913b;}try{const _0x353dfb=await this[_0x5062b5(0x1ce)][_0x5062b5(0x1c0)](_0x196916);_0x353dfb&&(_0x2013cf=(_0x2013cf||'')+_0x353dfb,this[_0x5062b5(0x183)]['debug'](_0x5062b5(0x232)+_0x196916,{'contextLength':_0x353dfb['length']}));}catch(_0x278f9d){this['logger'][_0x5062b5(0x262)]('Failed\x20to\x20inject\x20file\x20attachment\x20context\x20for\x20agent\x20'+_0x196916,{'error':_0x278f9d['message']});}const _0x2c6feb=await this[_0x5062b5(0x18b)]['sendMessage'](_0x41042c,_0x216a60,{'agentId':_0x196916,'systemPrompt':_0x2013cf,'sessionId':_0x3a48b3,'platformProvided':_0x339e7f[_0x5062b5(0x24b)]});return _0x2c6feb;}catch(_0x345f2d){return this[_0x5062b5(0x183)]['error']('AI\x20response\x20failed\x20for\x20agent\x20'+_0x196916+':',_0x345f2d),await this['handleAIServiceFailure'](_0x196916,_0x345f2d),null;}}async['handleAIServiceFailure'](_0xdc98fc,_0x145523){const _0x532d9f=a0_0x4735dd,_0x359fa3=await this[_0x532d9f(0x177)]['getAgent'](_0xdc98fc);if(!_0x359fa3)return;const _0x3b5bb1=_0x145523[_0x532d9f(0x1fc)]?.[_0x532d9f(0x1d9)]()||'';if(_0x3b5bb1[_0x532d9f(0x1f6)]('api\x20key')||_0x3b5bb1[_0x532d9f(0x1f6)]('authentication'))this['logger'][_0x532d9f(0x262)]('Agent\x20'+_0xdc98fc+_0x532d9f(0x25c)),_0x359fa3['delayEndTime']=new Date(Date['now']()+0x5*0x3c*0x3e8)[_0x532d9f(0x176)](),await this['agentPool']['persistAgentState'](_0xdc98fc),await this['agentPool'][_0x532d9f(0x16f)](_0xdc98fc,{'toolId':_0x532d9f(0x1d7),'status':_0x532d9f(0x1ad),'error':_0x532d9f(0x1d8),'timestamp':new Date()['toISOString']()});else{if(_0x3b5bb1[_0x532d9f(0x1f6)](_0x532d9f(0x1ed))||_0x3b5bb1['includes']('too\x20many\x20requests'))this[_0x532d9f(0x183)][_0x532d9f(0x262)]('Agent\x20'+_0xdc98fc+'\x20delayed\x20due\x20to\x20rate\x20limiting'),_0x359fa3[_0x532d9f(0x225)]=new Date(Date[_0x532d9f(0x20c)]()+0x2*0x3c*0x3e8)[_0x532d9f(0x176)](),await this['agentPool'][_0x532d9f(0x1fa)](_0xdc98fc);else _0x3b5bb1[_0x532d9f(0x1f6)](_0x532d9f(0x23a))||_0x3b5bb1[_0x532d9f(0x1f6)]('network')?(this['logger']['warn'](_0x532d9f(0x18e)+_0xdc98fc+'\x20delayed\x20due\x20to\x20network\x20issues'),_0x359fa3[_0x532d9f(0x225)]=new Date(Date[_0x532d9f(0x20c)]()+0x1e*0x3e8)['toISOString'](),await this[_0x532d9f(0x177)][_0x532d9f(0x1fa)](_0xdc98fc)):(this[_0x532d9f(0x183)]['error']('Agent\x20'+_0xdc98fc+'\x20paused\x20due\x20to\x20unknown\x20AI\x20service\x20error:\x20'+_0x145523['message']),_0x359fa3['delayEndTime']=new Date(Date['now']()+0x1*0x3c*0x3e8)['toISOString'](),await this[_0x532d9f(0x177)][_0x532d9f(0x1fa)](_0xdc98fc),await this[_0x532d9f(0x177)]['addToolResult'](_0xdc98fc,{'toolId':_0x532d9f(0x1d7),'status':_0x532d9f(0x1ad),'error':'AI\x20service\x20error:\x20'+_0x145523[_0x532d9f(0x1fc)]+_0x532d9f(0x24c),'timestamp':new Date()[_0x532d9f(0x176)]()}));}if(this[_0x532d9f(0x1cf)]&&this['webSocketManager'][_0x532d9f(0x13e)]){const _0x2bc33c=this[_0x532d9f(0x243)]['get'](_0xdc98fc),_0x59415d=_0x2bc33c?.['sessionId']||_0x532d9f(0x254);this['webSocketManager']['broadcastToSession'](_0x59415d,{'type':_0x532d9f(0x19a),'data':{'agentId':_0xdc98fc,'error':_0x145523['message'],'recovery':'Agent\x20temporarily\x20paused\x20for\x20recovery','timestamp':new Date()[_0x532d9f(0x176)]()}});}}async[a0_0x4735dd(0x24d)](_0x370642,_0x542a3c){const _0x200f29=a0_0x4735dd,_0x7ac63e=this['activeAgents'][_0x200f29(0x179)](_0x370642),_0x402ac3=_0x7ac63e?.['sessionId']||'scheduler-session',_0xaa4de6={'id':_0x200f29(0x25d)+Date['now'](),'agentId':_0x370642,'role':MESSAGE_ROLES[_0x200f29(0x159)],'content':_0x542a3c['content'],'timestamp':new Date()[_0x200f29(0x176)](),'model':_0x542a3c[_0x200f29(0x238)],'tokenUsage':_0x542a3c['tokenUsage'],'sessionId':_0x402ac3};await this['addMessageToConversation'](_0x370642,_0xaa4de6,![]);let _0x35b287=[];try{const _0x46ee27=await this[_0x200f29(0x190)]['extractAndExecuteTools'](_0x542a3c[_0x200f29(0x197)],_0x370642,{'sessionId':_0x402ac3});if(_0x46ee27[_0x200f29(0x16c)]>0x0){const _0x568a5b=await this['agentPool'][_0x200f29(0x1db)](_0x370642);if(_0x568a5b){for(const _0x528edb of _0x46ee27){_0x568a5b[_0x200f29(0x1b6)][_0x200f29(0x168)][_0x200f29(0x185)]({'id':_0x200f29(0x1b8)+Date['now']()+'-'+Math[_0x200f29(0x1b1)]()[_0x200f29(0x24f)](0x24)[_0x200f29(0x257)](0x2,0x9),'toolId':_0x528edb['toolId'],'status':_0x528edb[_0x200f29(0x203)],'result':_0x528edb[_0x200f29(0x19f)],'error':_0x528edb['error'],'executionTime':_0x528edb[_0x200f29(0x16d)],'timestamp':new Date()['toISOString'](),'queuedAt':new Date()['toISOString']()}),_0x35b287[_0x200f29(0x185)]({'toolId':_0x528edb[_0x200f29(0x1b2)],'status':_0x528edb['status'],'error':_0x528edb['error'],'executionTime':_0x528edb[_0x200f29(0x16d)]});}await this['agentPool']['persistAgentState'](_0x370642);}}}catch(_0xc3a25b){this[_0x200f29(0x183)][_0x200f29(0x1e2)](_0x200f29(0x210)+_0x370642+':',_0xc3a25b);}_0x35b287['length']>0x0&&(_0xaa4de6[_0x200f29(0x211)]=_0x35b287,_0xaa4de6['hasToolExecutions']=!![]);if(this[_0x200f29(0x1cc)](_0xaa4de6)){const _0x1ade2d=await this[_0x200f29(0x177)]['getAgent'](_0x370642);this[_0x200f29(0x165)](_0x370642,_0xaa4de6,{'agentCurrentModel':_0x1ade2d?.[_0x200f29(0x152)]});}}[a0_0x4735dd(0x23e)](_0x5200f8,_0xa5c00){const _0x34397a=a0_0x4735dd;if(!_0xa5c00)return![];const _0x1616cf=_0xa5c00['messageQueues'][_0x34397a(0x168)]['some'](_0x469072=>_0x469072['toolId']==='jobdone'||_0x469072['result']&&String(_0x469072[_0x34397a(0x19f)])[_0x34397a(0x1d9)]()[_0x34397a(0x1f6)]('task\x20completed'));if(_0x1616cf)return this['logger']['info']('Agent\x20'+_0x5200f8+'\x20executed\x20jobdone\x20-\x20removing\x20from\x20scheduler'),![];if(_0xa5c00['mode']===AGENT_MODES['CHAT']){const _0x51598a=_0xa5c00['messageQueues'][_0x34397a(0x1d1)][_0x34397a(0x16c)]>0x0||_0xa5c00['messageQueues'][_0x34397a(0x1c9)]['length']>0x0;return!_0x51598a&&this[_0x34397a(0x183)]['debug']('CHAT\x20agent\x20'+_0x5200f8+'\x20has\x20no\x20new\x20messages\x20-\x20removing\x20from\x20scheduler',{'toolResults':_0xa5c00['messageQueues'][_0x34397a(0x168)]['length'],'userMessages':_0xa5c00[_0x34397a(0x1b6)][_0x34397a(0x1d1)][_0x34397a(0x16c)],'interAgentMessages':_0xa5c00[_0x34397a(0x1b6)]['interAgentMessages']['length']}),_0x51598a;}if(_0xa5c00[_0x34397a(0x235)]===AGENT_MODES[_0x34397a(0x1c2)])return!_0xa5c00[_0x34397a(0x207)];return![];}[a0_0x4735dd(0x14d)](_0x61ff04){const _0x3a66ba=a0_0x4735dd;if(_0x61ff04['status']===_0x3a66ba(0x247)){if(typeof _0x61ff04['result']===_0x3a66ba(0x140))return JSON[_0x3a66ba(0x1bd)](_0x61ff04[_0x3a66ba(0x19f)],null,0x2);return String(_0x61ff04['result']||_0x3a66ba(0x1dd));}else{if(_0x61ff04['status']==='failed')return _0x3a66ba(0x161)+(_0x61ff04['error']||'Unknown\x20error');}return'Tool\x20status:\x20'+_0x61ff04['status'];}['shouldBroadcastMessage'](_0x4536d8){const _0xf1b372=a0_0x4735dd;if(_0x4536d8['type']==='scheduler-prompt')return![];if(_0x4536d8[_0xf1b372(0x150)]===MESSAGE_ROLES[_0xf1b372(0x21a)]&&!_0x4536d8[_0xf1b372(0x212)])return![];return!![];}['broadcastMessageUpdate'](_0x39d5a4,_0x307f61,_0x131e18={}){const _0x3f3b38=a0_0x4735dd;if(this['webSocketManager']&&this[_0x3f3b38(0x1cf)]['broadcastToSession']){const _0xe0d403=this[_0x3f3b38(0x243)]['get'](_0x39d5a4);let _0x58e226=_0xe0d403?.['sessionId'];!_0x58e226&&_0x307f61[_0x3f3b38(0x1aa)]&&(_0x58e226=_0x307f61[_0x3f3b38(0x1aa)]),!_0x58e226&&(_0x58e226=_0x3f3b38(0x254)),this[_0x3f3b38(0x183)][_0x3f3b38(0x160)]('Broadcasting\x20message\x20to\x20session',{'agentId':_0x39d5a4,'sessionId':_0x58e226,'hasAgentContext':!!_0xe0d403,'agentContextSessionId':_0xe0d403?.['sessionId'],'messageSessionId':_0x307f61[_0x3f3b38(0x1aa)],'messageRole':_0x307f61[_0x3f3b38(0x150)],'messageType':_0x307f61['type']}),this['webSocketManager'][_0x3f3b38(0x13e)](_0x58e226,{'type':_0x3f3b38(0x1ef),'data':{'agentId':_0x39d5a4,'message':_0x307f61,'timestamp':new Date()['toISOString'](),'agentCurrentModel':_0x131e18['agentCurrentModel']}});}}['hasPendingTasks'](_0x1c6333){const _0x5ceba8=a0_0x4735dd;if(!_0x1c6333[_0x5ceba8(0x1d6)]||!_0x1c6333[_0x5ceba8(0x1d6)][_0x5ceba8(0x1d4)])return![];return _0x1c6333[_0x5ceba8(0x1d6)]['tasks']['some'](_0x790cf7=>_0x790cf7['status']==='pending'||_0x790cf7[_0x5ceba8(0x203)]===_0x5ceba8(0x256));}[a0_0x4735dd(0x260)](_0x3d4527){const _0x3a30cd=a0_0x4735dd;if(_0x3d4527['incomingMessages']&&_0x3d4527[_0x3a30cd(0x1ec)]['length']>0x0)return!![];if(_0x3d4527['interAgentTracking']&&_0x3d4527[_0x3a30cd(0x22e)]['size']>0x0){const _0x40382d=Date[_0x3a30cd(0x20c)](),_0x4707db=0xa*0x3c*0x3e8;for(const _0x1a3a5c of _0x3d4527[_0x3a30cd(0x22e)][_0x3a30cd(0x158)]()){if(_0x1a3a5c[_0x3a30cd(0x233)]&&_0x40382d-_0x1a3a5c['lastReceived']<_0x4707db&&_0x1a3a5c[_0x3a30cd(0x237)]==='received')return!![];}}return![];}async[a0_0x4735dd(0x251)](_0x22f325){const _0x3749ae=a0_0x4735dd;try{const _0x148a22=await this[_0x3749ae(0x177)]['getAgent'](_0x22f325);if(!_0x148a22||_0x148a22[_0x3749ae(0x235)]!==AGENT_MODES[_0x3749ae(0x1c2)])return;!_0x148a22[_0x3749ae(0x1d6)]&&(_0x148a22[_0x3749ae(0x1d6)]={'tasks':[],'lastUpdated':new Date()['toISOString']()});if(_0x148a22['taskList']['tasks']&&_0x148a22['taskList'][_0x3749ae(0x1d4)][_0x3749ae(0x16c)]>0x0)return;const _0x4c36ba=_0x148a22[_0x3749ae(0x1c6)]?.['full']?.[_0x3749ae(0x1f0)]||[],_0x5c6925=[..._0x4c36ba][_0x3749ae(0x230)]()['find'](_0x45c7f6=>_0x45c7f6[_0x3749ae(0x150)]===MESSAGE_ROLES['USER']);if(_0x5c6925){const _0x2f419e=_0x3749ae(0x240)+this['extractTaskTitle'](_0x5c6925['content']),_0x5577f1=_0x3749ae(0x1f9)+this[_0x3749ae(0x14e)](_0x5c6925[_0x3749ae(0x197)],0xc8)+'\x22',_0x18144c={'id':'task-initial-'+Date['now']()+'-'+Math[_0x3749ae(0x1b1)]()[_0x3749ae(0x24f)](0x24)[_0x3749ae(0x257)](0x2,0x9),'title':_0x2f419e,'description':_0x5577f1,'status':'pending','priority':_0x3749ae(0x221),'createdAt':new Date()['toISOString'](),'updatedAt':new Date()['toISOString'](),'source':'auto-created-initial','messageId':_0x5c6925['id']};_0x148a22['taskList'][_0x3749ae(0x1d4)]['push'](_0x18144c),_0x148a22['taskList']['lastUpdated']=new Date()[_0x3749ae(0x176)](),await this['agentPool'][_0x3749ae(0x1fa)](_0x22f325),this[_0x3749ae(0x183)]['info'](_0x3749ae(0x149)+_0x22f325,{'taskId':_0x18144c['id'],'title':_0x18144c['title'],'agentName':_0x148a22[_0x3749ae(0x219)]});}}catch(_0x4c999c){this['logger'][_0x3749ae(0x1e2)]('Failed\x20to\x20auto-create\x20initial\x20task\x20for\x20agent\x20'+_0x22f325,{'error':_0x4c999c[_0x3749ae(0x1fc)]});}}async['autoCreateTasksForMessages'](_0x9cb077,_0x1798aa,_0x15d16f){const _0x487065=a0_0x4735dd;try{const _0x1ed683=await this['agentPool']['getAgent'](_0x9cb077);if(!_0x1ed683||_0x1ed683[_0x487065(0x235)]!==AGENT_MODES['AGENT'])return;!_0x1ed683[_0x487065(0x1d6)]&&(_0x1ed683['taskList']={'tasks':[],'lastUpdated':new Date()[_0x487065(0x176)]()});for(const _0x2ce38b of _0x1798aa){const _0x5b3ea3=_0x487065(0x1a0)+this[_0x487065(0x173)](_0x2ce38b['content']),_0x8fa22f=_0x487065(0x1a3)+this['truncateContent'](_0x2ce38b[_0x487065(0x197)],0xc8)+'\x22',_0x24093f=_0x1ed683[_0x487065(0x1d6)][_0x487065(0x1d4)][_0x487065(0x1dc)](_0x1ac2cb=>_0x1ac2cb[_0x487065(0x203)]==='pending'&&_0x1ac2cb[_0x487065(0x23c)]['includes'](_0x487065(0x199))&&this[_0x487065(0x17f)](_0x1ac2cb[_0x487065(0x209)],_0x8fa22f)>0.7);if(!_0x24093f){const _0x590d29={'id':'task-'+Date['now']()+'-'+Math['random']()['toString'](0x24)[_0x487065(0x257)](0x2,0x9),'title':_0x5b3ea3,'description':_0x8fa22f,'status':'pending','priority':_0x487065(0x221),'createdAt':new Date()['toISOString'](),'updatedAt':new Date()[_0x487065(0x176)](),'source':'auto-created','messageId':_0x2ce38b['id']};_0x1ed683['taskList'][_0x487065(0x1d4)]['push'](_0x590d29),this[_0x487065(0x183)]?.['info']('Auto-created\x20task\x20for\x20user\x20message',{'agentId':_0x9cb077,'taskId':_0x590d29['id'],'title':_0x590d29[_0x487065(0x23c)]});}}for(const _0x4506f8 of _0x15d16f){const _0xd019dc=_0x4506f8['senderName']||_0x4506f8['sender']||_0x487065(0x191),_0xf4c0a8='Respond\x20to\x20'+_0xd019dc+':\x20'+this['extractTaskTitle'](_0x4506f8['content']),_0x201b85=_0x487065(0x156)+_0xd019dc+_0x487065(0x18d)+this[_0x487065(0x14e)](_0x4506f8[_0x487065(0x197)],0xc8)+'\x22',_0x5b5989=_0x1ed683['taskList'][_0x487065(0x1d4)][_0x487065(0x1dc)](_0x370b7b=>_0x370b7b[_0x487065(0x203)]==='pending'&&_0x370b7b[_0x487065(0x23c)]['includes'](_0x487065(0x164)+_0xd019dc)&&this['calculateContentSimilarity'](_0x370b7b[_0x487065(0x209)],_0x201b85)>0.7);if(!_0x5b5989){const _0x76fca5={'id':_0x487065(0x13c)+Date[_0x487065(0x20c)]()+'-'+Math['random']()['toString'](0x24)[_0x487065(0x257)](0x2,0x9),'title':_0xf4c0a8,'description':_0x201b85,'status':'pending','priority':_0x487065(0x146),'createdAt':new Date()['toISOString'](),'updatedAt':new Date()['toISOString'](),'source':'auto-created','messageId':_0x4506f8['id'],'senderAgent':_0x4506f8[_0x487065(0x20b)]};_0x1ed683['taskList']['tasks'][_0x487065(0x185)](_0x76fca5),this['logger']?.[_0x487065(0x160)](_0x487065(0x258),{'agentId':_0x9cb077,'taskId':_0x76fca5['id'],'title':_0x76fca5[_0x487065(0x23c)],'sender':_0xd019dc});}}(_0x1798aa[_0x487065(0x16c)]>0x0||_0x15d16f['length']>0x0)&&(_0x1ed683[_0x487065(0x1d6)]['lastUpdated']=new Date()[_0x487065(0x176)](),await this[_0x487065(0x177)]['persistAgentState'](_0x9cb077));}catch(_0x59acd4){this['logger']?.[_0x487065(0x1e2)](_0x487065(0x1e6)+_0x9cb077,{'error':_0x59acd4['message'],'userMessageCount':_0x1798aa['length'],'interAgentMessageCount':_0x15d16f['length']});}}['extractTaskTitle'](_0x288b3f){const _0x46a980=a0_0x4735dd,_0x65b191=_0x288b3f[_0x46a980(0x228)]()['replace'](/\n+/g,'\x20')['replace'](/\s+/g,'\x20'),_0xe7441d=_0x65b191[_0x46a980(0x14c)](/[.!?]/)[0x0][_0x46a980(0x228)]();if(_0xe7441d[_0x46a980(0x16c)]>0x32)return _0xe7441d['substring'](0x0,0x2f)+_0x46a980(0x201);return _0xe7441d||'Process\x20message';}['truncateContent'](_0x594684,_0x291c76){const _0x52db66=a0_0x4735dd;if(_0x594684[_0x52db66(0x16c)]<=_0x291c76)return _0x594684;return _0x594684[_0x52db66(0x193)](0x0,_0x291c76-0x3)+'...';}[a0_0x4735dd(0x17f)](_0x5032e3,_0x159c4b){const _0x1b770a=a0_0x4735dd,_0x533ed3=_0x5032e3[_0x1b770a(0x1d9)]()['split'](/\s+/),_0x33567b=_0x159c4b[_0x1b770a(0x1d9)]()['split'](/\s+/),_0x20123a=_0x533ed3[_0x1b770a(0x170)](_0x2a64ec=>_0x33567b[_0x1b770a(0x1f6)](_0x2a64ec)),_0x204e40=new Set([..._0x533ed3,..._0x33567b])['size'];return _0x20123a[_0x1b770a(0x16c)]/_0x204e40;}async[a0_0x4735dd(0x188)](_0x5b4dea){const _0x2bef2b=a0_0x4735dd;try{const _0x354c91=await this[_0x2bef2b(0x177)]['getAgent'](_0x5b4dea);if(!_0x354c91||!_0x354c91[_0x2bef2b(0x1d6)]||!_0x354c91[_0x2bef2b(0x1d6)]['tasks'])return;const _0x3c63af={'urgent':0x0,'high':0x1,'medium':0x2,'low':0x3};let _0x536f51=_0x354c91['taskList'][_0x2bef2b(0x1d4)][_0x2bef2b(0x170)](_0x437a5e=>_0x437a5e[_0x2bef2b(0x203)]==='pending');if(_0x536f51['length']===0x0)return;_0x536f51=this[_0x2bef2b(0x20f)](_0x354c91[_0x2bef2b(0x1d6)]['tasks'],_0x536f51);if(_0x536f51['length']===0x0){this[_0x2bef2b(0x183)]?.['info'](_0x2bef2b(0x263)+_0x5b4dea);return;}_0x536f51[_0x2bef2b(0x180)]((_0x1bd84d,_0x3235df)=>{const _0x508957=_0x2bef2b;if(_0x1bd84d[_0x508957(0x17b)]!==undefined&&_0x3235df['priorityScore']!==undefined){const _0x9273fa=_0x3235df[_0x508957(0x17b)]-_0x1bd84d['priorityScore'];if(Math['abs'](_0x9273fa)>0.1)return _0x9273fa;}const _0x1719dd=_0x3c63af[_0x1bd84d[_0x508957(0x14f)]]-_0x3c63af[_0x3235df[_0x508957(0x14f)]];if(_0x1719dd!==0x0)return _0x1719dd;return new Date(_0x1bd84d[_0x508957(0x1cd)])-new Date(_0x3235df[_0x508957(0x1cd)]);});const _0x19e5be=_0x536f51[0x0],_0x234402=_0x354c91[_0x2bef2b(0x1d6)][_0x2bef2b(0x1d4)][_0x2bef2b(0x170)](_0x4eb1d1=>_0x4eb1d1[_0x2bef2b(0x203)]==='in_progress');_0x234402['length']===0x0&&(_0x19e5be[_0x2bef2b(0x203)]='in_progress',_0x19e5be[_0x2bef2b(0x1e8)]=new Date()['toISOString'](),_0x19e5be['startedAt']=new Date()[_0x2bef2b(0x176)](),_0x354c91['taskList'][_0x2bef2b(0x19b)]=new Date()['toISOString'](),await this['agentPool']['persistAgentState'](_0x5b4dea),this['logger']?.['info']('Auto-progressed\x20task\x20to\x20in-progress',{'agentId':_0x5b4dea,'taskId':_0x19e5be['id'],'title':_0x19e5be[_0x2bef2b(0x23c)],'priority':_0x19e5be['priority']}));}catch(_0x3f3e39){this[_0x2bef2b(0x183)]?.['error'](_0x2bef2b(0x23d)+_0x5b4dea,{'error':_0x3f3e39['message']});}}['filterAvailableTasks'](_0x50b2d3,_0x13738d){return _0x13738d['filter'](_0x566817=>{const _0x33b329=a0_0x4da4;if(!_0x566817['dependencies']||_0x566817['dependencies'][_0x33b329(0x16c)]===0x0)return!![];const _0x1674f7=_0x566817[_0x33b329(0x153)][_0x33b329(0x170)](_0x18e25d=>_0x18e25d['type']===_0x33b329(0x1e7));for(const _0x428beb of _0x1674f7){const _0x225df2=_0x50b2d3['find'](_0x2a9c34=>_0x2a9c34['id']===_0x428beb[_0x33b329(0x1e4)]);if(!_0x225df2||_0x225df2[_0x33b329(0x203)]!==_0x33b329(0x247))return![];}return!![];});}async['updateDependentTasks'](_0x5b2ca8,_0x307599){const _0x43b564=a0_0x4735dd;try{if(!_0x5b2ca8[_0x43b564(0x1d6)]||!_0x5b2ca8['taskList'][_0x43b564(0x1d4)])return;let _0x582eeb=![];for(const _0x335f5a of _0x5b2ca8['taskList'][_0x43b564(0x1d4)]){if(_0x335f5a[_0x43b564(0x203)]===_0x43b564(0x1b5)&&_0x335f5a['dependencies']){const _0x5b81d4=_0x335f5a[_0x43b564(0x153)][_0x43b564(0x1dc)](_0x2d45ce=>_0x2d45ce['type']==='blocks'&&_0x2d45ce['taskId']===_0x307599);if(_0x5b81d4){const _0x4e2ac8=_0x335f5a[_0x43b564(0x153)]['some'](_0xfc056d=>{const _0x58c6d9=_0x43b564;if(_0xfc056d[_0x58c6d9(0x1a8)]!==_0x58c6d9(0x1e7))return![];const _0x5bc676=_0x5b2ca8['taskList']['tasks']['find'](_0x4659ff=>_0x4659ff['id']===_0xfc056d['taskId']);return _0x5bc676&&_0x5bc676['status']!=='completed';});!_0x4e2ac8&&(_0x335f5a['status']=_0x43b564(0x213),_0x335f5a[_0x43b564(0x1e8)]=new Date()['toISOString'](),_0x582eeb=!![],this[_0x43b564(0x183)]?.['info'](_0x43b564(0x1e5),{'taskId':_0x335f5a['id'],'title':_0x335f5a[_0x43b564(0x23c)],'completedDependency':_0x307599}));}}}_0x582eeb&&(_0x5b2ca8[_0x43b564(0x1d6)]['lastUpdated']=new Date()['toISOString'](),await this[_0x43b564(0x177)]['persistAgentState'](_0x5b2ca8['id']));}catch(_0x3b3415){this['logger']?.['error'](_0x43b564(0x250)+_0x5b2ca8['id'],{'error':_0x3b3415[_0x43b564(0x1fc)],'completedTaskId':_0x307599});}}[a0_0x4735dd(0x194)](_0x4900a4){const _0x555cdd=a0_0x4735dd,_0x2c6925=[],_0x227eca=_0x4900a4['conversations']?.['full']?.['messages']||[],_0x2ba0c9=_0x227eca[_0x555cdd(0x170)](_0x7bdcc8=>_0x7bdcc8['role']===_0x555cdd(0x20e)||_0x7bdcc8['role']==='tool')['slice'](-0x5),_0x103456=_0x2ba0c9['map'](_0x533c4e=>_0x533c4e[_0x555cdd(0x150)]+':'+_0x533c4e[_0x555cdd(0x197)]?.[_0x555cdd(0x193)](0x0,0x64))[_0x555cdd(0x259)]('|');_0x2c6925['push']('msgs:'+_0x103456);if(_0x4900a4['taskList']?.['tasks']){const _0x10f0e7=_0x4900a4['taskList']['tasks'][_0x555cdd(0x170)](_0x215ff8=>_0x215ff8[_0x555cdd(0x203)]==='pending'||_0x215ff8['status']===_0x555cdd(0x256))['map'](_0x477993=>_0x477993['id']+':'+_0x477993['status'])[_0x555cdd(0x180)]()[_0x555cdd(0x259)](',');_0x2c6925[_0x555cdd(0x185)](_0x555cdd(0x1de)+_0x10f0e7);}const _0x5c576a=_0x4900a4[_0x555cdd(0x1b6)]||{};_0x2c6925['push'](_0x555cdd(0x1c1)+(_0x5c576a['toolResults']?.[_0x555cdd(0x16c)]||0x0)+':I'+(_0x5c576a[_0x555cdd(0x1c9)]?.[_0x555cdd(0x16c)]||0x0)+':U'+(_0x5c576a[_0x555cdd(0x1d1)]?.[_0x555cdd(0x16c)]||0x0));const _0x4409c7=_0x2c6925[_0x555cdd(0x259)]('||');let _0x5c09dc=0x0;for(let _0x18efc3=0x0;_0x18efc3<_0x4409c7['length'];_0x18efc3++){const _0x859aed=_0x4409c7['charCodeAt'](_0x18efc3);_0x5c09dc=(_0x5c09dc<<0x5)-_0x5c09dc+_0x859aed,_0x5c09dc=_0x5c09dc&_0x5c09dc;}return _0x5c09dc+'_'+_0x4409c7['length'];}[a0_0x4735dd(0x184)](_0x468c27,_0x6bbc39){const _0x107c9b=a0_0x4735dd,_0x2f60cd=this[_0x107c9b(0x186)]['get'](_0x468c27);return _0x2f60cd?_0x2f60cd['has'](_0x6bbc39):![];}[a0_0x4735dd(0x20d)](_0x3a7193,_0xb01b0f){const _0x4025b9=a0_0x4735dd;!this['processedStateHashes'][_0x4025b9(0x222)](_0x3a7193)&&this[_0x4025b9(0x186)]['set'](_0x3a7193,new Set());const _0x122505=this['processedStateHashes'][_0x4025b9(0x179)](_0x3a7193);_0x122505[_0x4025b9(0x13d)](_0xb01b0f);if(_0x122505['size']>0x64){const _0x4f9c6e=Array[_0x4025b9(0x167)](_0x122505),_0x280c12=_0x4f9c6e['slice'](-0x32);this['processedStateHashes']['set'](_0x3a7193,new Set(_0x280c12));}}[a0_0x4735dd(0x151)](){const _0x3a4d90=a0_0x4735dd;return{'isRunning':this['isRunning'],'activeAgents':Array['from'](this['activeAgents']),'agentCount':this[_0x3a4d90(0x243)][_0x3a4d90(0x181)]};}}export default AgentScheduler;function a0_0x4da4(_0x12b3c6,_0x726537){_0x12b3c6=_0x12b3c6-0x13c;const _0x1fddbc=a0_0x1fdd();let _0x4da45e=_0x1fddbc[_0x12b3c6];if(a0_0x4da4['ybQPsv']===undefined){var _0x41fdbe=function(_0xf5af31){const _0x11fbd7='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=';let _0x4aa21e='',_0x252b65='';for(let _0x13b4e9=0x0,_0x22d1a2,_0x27d4e5,_0x315e31=0x0;_0x27d4e5=_0xf5af31['charAt'](_0x315e31++);~_0x27d4e5&&(_0x22d1a2=_0x13b4e9%0x4?_0x22d1a2*0x40+_0x27d4e5:_0x27d4e5,_0x13b4e9++%0x4)?_0x4aa21e+=String['fromCharCode'](0xff&_0x22d1a2>>(-0x2*_0x13b4e9&0x6)):0x0){_0x27d4e5=_0x11fbd7['indexOf'](_0x27d4e5);}for(let _0x41845d=0x0,_0x3e9410=_0x4aa21e['length'];_0x41845d<_0x3e9410;_0x41845d++){_0x252b65+='%'+('00'+_0x4aa21e['charCodeAt'](_0x41845d)['toString'](0x10))['slice'](-0x2);}return decodeURIComponent(_0x252b65);};a0_0x4da4['axyiTa']=_0x41fdbe,a0_0x4da4['hXkgXK']={},a0_0x4da4['ybQPsv']=!![];}const _0xded39a=_0x1fddbc[0x0],_0x1978c6=_0x12b3c6+_0xded39a,_0x47e955=a0_0x4da4['hXkgXK'][_0x1978c6];return!_0x47e955?(_0x4da45e=a0_0x4da4['axyiTa'](_0x4da45e),a0_0x4da4['hXkgXK'][_0x1978c6]=_0x4da45e):_0x4da45e=_0x47e955,_0x4da45e;}function a0_0x1fdd(){const _0xa3ac8=['ChjVy2vZC2LUz0n5y2XL','Dg9VBa','tM8GDMfSAwqGy29UDMvYC2f0Aw9UigzVDw5K','B3jPz2LUywXuB2TLBKnVDw50','lI4U','DxbKyxrLq29TCgfJDgvKtwvZC2fNzxm','C3rHDhvZ','tw9KzwWGDxbKyxrLzdOGDgfYz2v0tw9KzwW9','ihn0B3bWzwqGyNv0igHHCYbUBYbZzxnZAw9UieLeigzVCIbICM9HzgnHC3q','surmrq','C3rVCfjLCxvLC3rLza','C2nOzwr1BgvYlxn0yxj0Dxa','zgvZy3jPChrPB24','ChjVy2vZC0fNzw50qxv0B25VBw91C2X5','C2vUzgvY','BM93','BwfYA1n0yxrLqxnqCM9JzxnZzwq','DxnLCG','zMLSDgvYqxzHAwXHyMXLvgfZA3m','vg9VBcbLEgvJDxrPB24GzMfPBgvKigzVCIbHz2vUDca','Dg9VBev4zwn1DgLVBNm','CxvLDwvuExbL','CgvUzgLUzW','zM9YrwfJAa','ywDLBNrqCM9JzxnZAw5Ntg9JA3m','tM8GDMfSAwqGy29UDMvYC2f0Aw9UigzVDw5KigzVCIbHz2vUDca','mtaWmtCWoxDItgfMrq','C2HVDwXKq29UDgLUDwu','BMfTzq','u1Ltvevn','qwDLBNqGD2fZigfSCMvHzhKGAw4GquDftLqGBw9Kzq','ChjVy2vZC2LUz0LUuhjVz3jLC3m','C2vSzwn0zwrnB2rLBa','BgfZDezLDgnOzwq','BwfW','y2f0y2G','AgLNAa','AgfZ','vfjjr0DfuIbdt01qqunusu9o','nZCWnZGWD1nID1bZ','zgvSyxLfBMruAw1L','y2XLyxi','tuLox01fu1nbr0vtx0zpuL9dt01qqunusu9o','DhjPBq','cGPjtvbpuLrbtLq6ifLVDsbHCMuGAw4GquDftLqGBw9Kzs4GvgHLihvZzsbVzIbuyxnRtwfUywDLCIb0B29SigLZig1HBMrHDg9YEs4GqwX3yxLZignYzwf0zsbHBMqGDxbKyxrLihrHC2TZihrVihrYywnRihLVDxiGD29YAYbWCM9NCMvZCY4GvxbKyxrLihrOzsb1C2vYigfIB3v0ihrHC2STBgLZDcbZDgf0DxmGCgvYAw9KAwnHBgX5lIbvC2uGDgHLigPVyMrVBMuGDg9VBcb3AgvUihLVDxiGBwfPBIb0yxnRigLZignVBxbSzxrLlG','igHHCYbUBYbWzw5KAw5NihrHC2TZig9Yig1LC3nHz2vZic0GCMvTB3zPBMCGzNjVBsbZy2HLzhvSzxi','igHHCYbKDxbSAwnHDguGC3rHDguGD2L0AcbUBYbUzxCGBwvZC2fNzxmGlsbYzw1VDMLUzYbMCM9TihnJAgvKDwXLCG','q29TCgfJDgLVBIbMywLSzwqGzM9YigfNzw50ia','yNjVywrJyxn0q29TCgfJDgLVBKv2zw50','Aw50zxjbz2vUDfrYywnRAw5N','igzVCIbTB2rLBcbZD2L0y2HPBMC','CMv2zxjZzq','nefsyu5cvW','sw5Qzwn0zwqGzMLSzsbHDhrHy2HTzw50ignVBNrLEhqGzM9YigfNzw50ia','BgfZDfjLy2vPDMvK','id0G','Bw9Kzq','y29TCgfJDgvKtwvZC2fNzxm','BgfZDfr5Cgu','Bw9KzwW','Bw9KzwXsB3v0zxjtzxj2AwnL','DgLTzw91Da','q29TCgfJDgLVBIbZA2LWCgvKoIb0B28GzMv3ig1LC3nHz2vZicG','DgL0Bgu','rMfPBgvKihrVigf1Dg8TChjVz3jLC3mGDgfZAYbMB3iGywDLBNqG','C2HVDwXKqwDLBNrdB250Aw51zq','qwjVDxqGDg8GC2vUzcbTzxnZywDLihrVig1VzgvSoIa','uhjVy2vZCYbPBML0AwfSihjLCxvLC3q6ia','uM91DgLUzYbYzxn1BhqGyw5HBhLZAxm','vxnPBMCGChjLzMvYCMvKtw9KzwWGyxmGzMfSBgjHy2SGzM9YignVBxbHy3rPB24Gy2HLy2S6ia','ywn0AxzLqwDLBNrZ','CM91DgvnzxnZywDL','CMvJzwL2zwq','vxnPBMCGDhj1BMnHDgLVBIbZDhjHDgvNEsbMB3iGBw9KzwWGC3DPDgnOoIa','y29TCgXLDgvK','icHZDgf0Dxm6ia','CMvTB3zLqwDLBNq','B3jPz2LUywXnzxnZywDLCW','CgXHDgzVCM1qCM92AwrLza','lIbbz2vUDcb0zw1WB3jHCMLSEsbWyxvZzwqU','ChjVy2vZC0fjuMvZCg9UC2u','y29TCgfJDgvKvg9Rzw5dB3vUDa','Dg9tDhjPBMC','rMfPBgvKihrVihvWzgf0zsbKzxbLBMrLBNqGDgfZA3mGzM9YigfNzw50ia','yxv0B0nYzwf0zuLUAxrPywXuyxnRswzozwvKzwq','sw5PDgLHBgL6Aw5Nigv4Axn0Aw5Niefhru5uig1VzguGywDLBNq6ia','ywDLBNrFD2fYBMLUzW','C2nOzwr1BgvYlxnLC3nPB24','uKvuuLLFrevmqvLFtvm','Aw5FChjVz3jLC3m','C3vIC3rY','qxv0BY1JCMvHDgvKihrHC2SGzM9YigLUDgvYlwfNzw50ig1LC3nHz2u','AM9PBG','qwDLBNqGBM90igzVDw5K','tM8GDMfSAwqGy29UDMvYC2f0Aw9UigzVDw5KigzVCIbJB21Wywn0Aw9U','ihbHDxnLzcbKDwuGDg8GqvbjigTLEsbPC3n1zq','ywKTCMvZCg9UC2uT','mJGXmZCYwwHIyuTf','AxndB21Wywn0zwq','AgfZvw5WCM9JzxnZzwrnzxnZywDLCW','BMv2zxi','D2fYBG','qwXSihbLBMrPBMCGDgfZA3mGyxjLigjSB2nRzwqGyNKGzgvWzw5Kzw5JAwvZigzVCIbHz2vUDca','zgvSzxrL','z2v0q29TCgfJDgLVBK1LDgfKyxrH','CMvHC29U','y29TCgfJDgLVBLbLCMzVCM1Lza','DgfZAY0','ywrK','yNjVywrJyxn0vg9tzxnZAw9U','DhjPz2DLCMvKqNK','B2jQzwn0','mte5ntqZnM9Nu3LLuW','ihf1zxvLzcbTzxnZywDLCYbMB3iGywDLBNqG','y29UC29SAwrHDgvKlq','q29UC29SAwrHDgvKia','qMvSB3CGDgHYzxnOB2XK','BwvKAxvT','u0TjucaTigjLBg93ihrOCMvZAg9Sza','lcbWCM9JzwvKAw5NihDPDgGGquKGCMvXDwvZDa','qxv0BY1JCMvHDgvKigLUAxrPywWGDgfZAYbMB3iGywDLBNqG','igHHCYbUBYbJDxjYzw50tw9KzwWGB3iGDgfYz2v0tw9KzwWGC2v0lcbHDhrLBxb0Aw5NihrVihvZzsbHDMfPBgfIBguGy29UDMvYC2f0Aw9U','qwDLBNqGywrKzwqGDg8GC2nOzwr1BgvYoIa','C3bSAxq','zM9YBwf0vg9VBfjLC3vSDa','Dhj1BMnHDgvdB250zw50','ChjPB3jPDhK','CM9Szq','z2v0u3rHDhvZ','y3vYCMvUDe1VzgvS','zgvWzw5Kzw5JAwvZ','q29TCgfJDgLVBIb0CMLNz2vYzwqGzM9YigfNzw50ia','C29Tzq','sgfUzgXLig1LC3nHz2uGzNjVBsa','y29UC29SAwrHDgvKlwLUChv0','DMfSDwvZ','qvntsvnuqu5u','ihrVia','q0HbvcbHz2vUDca','C2v0','q29TCgfJDgLVBIbJB21WBgv0zwqGzM9YigfNzw50ia','rKfjteve','q29TCgfJDgLVBIbLEgLZDhmSihvZAw5NignVBxbHy3rLzcb2zxjZAw9U','Aw5MBW','vg9VBcbLEgvJDxrPB24GzMfPBgvKoIa','CxvLDwvKqxq','z2v0t3DUuhjVCgvYDhLoyw1LCW','uMvZCg9Uzcb0BYa','yNjVywrJyxn0twvZC2fNzvvWzgf0zq','nMziqvjxrG','zNjVBq','Dg9VBfjLC3vSDhm','ChjVy2vZC0fNzw50','Cgf1C2vKvw50AwW','w0fNzw50ie1LC3nHz2vZxqO','BgvUz3rO','zxHLy3v0Aw9UvgLTzq','qundvvjbveu','ywrKvg9VBfjLC3vSDa','zMLSDgvY','q09nueXfveve','Bw9Kzvn0yxrL','zxH0CMfJDfrHC2TuAxrSzq','mZu5mLPNC3LmCG','u3rHCNrPBMCGqwDLBNqGu2nOzwr1BgvYihDPDgGGvc9nl1uGCxvLDwuGC3LZDgvT','Dg9ju09tDhjPBMC','ywDLBNrqB29S','ic0GD2LSBcbIzsbWCMLVCML0AxPLza','z2v0','svrfuKfusu9ox0rftefz','ChjPB3jPDhLty29Yzq','qwDLBNqGBw9KzwWGy29UzMLNDxjHDgLVBIbPC3n1zsbKzxrLy3rLzcaTihvZAw5NigzHBgXIywnR','rMfPBgvKihrVigDLDcbHDMfPBgfIBguGBw9KzwXZigzVCIbYB3v0Aw5NoIa','mZyZnde3AKX0Ag1q','y2fSy3vSyxrLq29UDgvUDfnPBwLSyxjPDhK','C29YDa','C2L6zq','DgLTzxn0yw1W','Bg9Nz2vY','AgfZuhjVy2vZC2vKu3rHDgu','ChvZAa','ChjVy2vZC2vKu3rHDgviyxnOzxm','vxnLCIbTzxnZywDLigrLDgvJDgvKigzVCIbHz2vUDca','yxv0B1bYB2DYzxnZsgLNAgvZDfbYAw9YAxr5vgfZAW','Aw5PDgLHBgL6zuv4Axn0Aw5NqwDLBNrZ','ChjLzMvYCMvKtw9KzwW','ywLtzxj2AwnL','w0nptvbbq1qTq0Hfq0STu1rbuLrD','oIaI','qwDLBNqG','w0nptvbbq1qTrvjst1jD','BwvZC2fNzvbYB2nLC3nVCG','vw5RBM93BIbbz2vUDa','Bg9N','C3vIC3rYAw5N','z2vUzxjHDgvbz2vUDfn0yxrLsgfZAa','ywrKtwvZC2fNzvrVq29UDMvYC2f0Aw9U','AgfZugvUzgLUz1rHC2TZ','y29UDgvUDa','zNvSBa','uhjVy2vZCYb1C2vYihjLCxvLC3q','ywDLBNrFzxjYB3i','BgfZDfvWzgf0zwq','qwDLBNqGiG','igLZihbHDxnLzcb1BNrPBca','sw5PDgLHBgL6zwqG','CMvZDwX0','uhjVy2vZCYb1C2vYihjLCxvLC3q6ia','uhjVy2vZC2LUzYbJEwnSzsbHBhjLywr5igLUihbYB2DYzxnZlcbZA2LWCgLUzW','vvnfuG','sgfUzgXLihvZzxiGBwvZC2fNztOGiG','u1rbuLrjtKC','quDftLqGBw9KzsbHz2vUDca','y29TCgfJDgLVBLnLCNzPy2u','ChjVy2vZC0fNzw50uxvLDwvZ','DhLWzq','zxHLy3v0Aw9Ux3n0B3bWzwq','C2vZC2LVBKLK','igv4Axn0Aw5Niefhru5uig1VzguGywDLBNrZigLUDg8GC2nOzwr1BgvY','igHHCYbUBYbZzxnZAw9UieLeic0GqvbjigTLEsbYzxnVBhv0Aw9UihDPBgWGzMfPBa','zMfPBgvK','AxnsDw5UAw5N','qwDLBNqGChjVy2vZC2LUzYbMywLSzwq6ia','vgHYzxnOB2XKigv4y2vLzgvK','CMfUzg9T','Dg9VBeLK','A2v5CW','icSG','yMXVy2TLza','BwvZC2fNzvf1zxvLCW','CMvKDwn0Aw9UugvYy2vUDa','Dg9VBc1Yzxn1BhqT','qwDLBNqGAgfZig5Vign1CNjLBNrnB2rLBcbZzxqUifvZAw5NigzHBgXIywnRig1VzgvSigzVCIbJB21Wywn0Aw9UignOzwnRlG','Dg9Rzw5dB3vUDgLUz1nLCNzPy2u','Axnbz2vUDeLUu2nOzwr1BgvY','quDhuKvtu0Lwrq','C3rYAw5NAwz5','C2vUzgvYtMfTzq','q0Hbva','yNvPBgreEw5HBwLJq29UDgv4Da','CxvLDwvZoLq','quDftLq','Dhj1zq','oevXA3jjvW','zgvIDwC','y29UDMvYC2f0Aw9UCW','Dw5RBM93BG','Bw9KzwXZu2vYDMLJzq','Aw50zxjbz2vUDe1LC3nHz2vZ','C3rVChbLzc1IEs11C2vY','C3LZDgvTuhjVBxb0','C2HVDwXKqNjVywrJyxn0twvZC2fNzq','y3jLyxrLzef0','y29UDgv4DeLUAMvJDgLVBLnLCNzPy2u','D2vIu29JA2v0twfUywDLCG','yxv0B0nYzwf0zvrHC2TZrM9YtwvZC2fNzxm','DxnLCK1LC3nHz2vZ','cK5VDgu6ifvZzsb0AguGywDLBNrJB21TDw5Py2f0Aw9UihrVB2WGAwyGEw91ig5LzwqGDg8GCMvZCg9Uzcb0BYbVDgHLCIbHz2vUDhmU','C3rVCa','DgfZA3m','Dg9gAxHLza','DgfZA0XPC3q','C3LZDgvTlwvYCM9Y','qvbjigTLEsbHDxrOzw50AwnHDgLVBIbMywLSzwqUifbSzwfZzsbJAgvJAYb5B3vYiefqssbRzxKGy29UzMLNDxjHDgLVBIbPBIbtzxr0Aw5NCY4','Dg9mB3DLCKnHC2u','y2fSy3vSyxrLvgfYz2v0vg9Rzw5dB3vUDa','z2v0qwDLBNq','zMLUza','vg9VBcbLEgvJDxrLzcbZDwnJzxnZzNvSBhK','DgfZA3m6','C3rYyxrLz3K','igHHCYbUBYbXDwv1zwqGBwvZC2fNzxmGlsbYzw1VDMLUzYbMCM9TihnJAgvKDwXLCG','C3rHy2S','zxjYB3i','rMfPBgvKihrVihn0B3aGywDLBNqGzxHLy3v0Aw9UoIa','DgfZA0LK','vgfZAYb1BMjSB2nRzwqGzhvLihrVigrLCgvUzgvUy3KGy29TCgXLDgLVBG','rMfPBgvKihrVigf1Dg8Ty3jLyxrLihrHC2TZigzVCIbHz2vUDca','yMXVy2TZ','DxbKyxrLzef0','tM8Gy29UDMvYC2f0Aw9Uig1LDgfKyxrH','yxv0B3bPBg90lw1VzgvSlxjVDxrLCG','u2v0igfNzw50ign1CNjLBNrnB2rLBcb0BYa','Aw5JB21PBMDnzxnZywDLCW','CMf0zsbSAw1PDa','lcbZA2LWCgLUzYbJB21Wywn0Aw9U','BwvZC2fNzv9HzgrLza','BwvZC2fNzxm','nZq1BenkrgDl','ywrKqwDLBNq','nZK3mJKZELjWquXo','vg9VigzLDYbTzxnZywDLCW','y29TCgfJDgLVBKLUuhjVz3jLC3m','Aw5JBhvKzxm','q29TCgfJDgLVBIbHDhrLBxb0ia','z2v0qwXSqwDLBNrZ','sgfUzgXLihvZzxiGCMvXDwvZDdOGiG','CgvYC2LZDefNzw50u3rHDgu','z2v0qwDLBNrbsvjLC3bVBNnL','BwvZC2fNzq'];a0_0x1fdd=function(){return _0xa3ac8;};return a0_0x1fdd();}