@loxia-labs/loxia-autopilot-one 1.0.1 → 1.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +44 -54
- package/bin/cli.js +1 -115
- package/bin/loxia-terminal-v2.js +3 -0
- package/bin/loxia-terminal.js +3 -0
- package/bin/start-with-terminal.js +3 -0
- package/package.json +15 -15
- package/scripts/install-scanners.js +1 -235
- package/src/analyzers/CSSAnalyzer.js +1 -297
- package/src/analyzers/ConfigValidator.js +1 -690
- package/src/analyzers/ESLintAnalyzer.js +1 -320
- package/src/analyzers/JavaScriptAnalyzer.js +1 -261
- package/src/analyzers/PrettierFormatter.js +1 -247
- package/src/analyzers/PythonAnalyzer.js +1 -266
- package/src/analyzers/SecurityAnalyzer.js +1 -729
- package/src/analyzers/TypeScriptAnalyzer.js +1 -247
- package/src/analyzers/codeCloneDetector/analyzer.js +1 -344
- package/src/analyzers/codeCloneDetector/detector.js +1 -203
- package/src/analyzers/codeCloneDetector/index.js +1 -160
- package/src/analyzers/codeCloneDetector/parser.js +1 -199
- package/src/analyzers/codeCloneDetector/reporter.js +1 -148
- package/src/analyzers/codeCloneDetector/scanner.js +1 -59
- package/src/core/agentPool.js +1 -1474
- package/src/core/agentScheduler.js +1 -2147
- package/src/core/contextManager.js +1 -709
- package/src/core/messageProcessor.js +1 -732
- package/src/core/orchestrator.js +1 -548
- package/src/core/stateManager.js +1 -877
- package/src/index.js +1 -631
- package/src/interfaces/cli.js +1 -549
- package/src/interfaces/terminal/__tests__/smoke/advancedFeatures.test.js +1 -0
- package/src/interfaces/terminal/__tests__/smoke/agentControl.test.js +1 -0
- package/src/interfaces/terminal/__tests__/smoke/agents.test.js +1 -0
- package/src/interfaces/terminal/__tests__/smoke/components.test.js +1 -0
- package/src/interfaces/terminal/__tests__/smoke/connection.test.js +1 -0
- package/src/interfaces/terminal/__tests__/smoke/enhancements.test.js +1 -0
- package/src/interfaces/terminal/__tests__/smoke/imports.test.js +1 -0
- package/src/interfaces/terminal/__tests__/smoke/messages.test.js +1 -0
- package/src/interfaces/terminal/__tests__/smoke/tools.test.js +1 -0
- package/src/interfaces/terminal/api/apiClient.js +1 -0
- package/src/interfaces/terminal/api/messageRouter.js +1 -0
- package/src/interfaces/terminal/api/session.js +1 -0
- package/src/interfaces/terminal/api/websocket.js +1 -0
- package/src/interfaces/terminal/components/AgentCreator.js +1 -0
- package/src/interfaces/terminal/components/AgentEditor.js +1 -0
- package/src/interfaces/terminal/components/AgentSwitcher.js +1 -0
- package/src/interfaces/terminal/components/ErrorBoundary.js +1 -0
- package/src/interfaces/terminal/components/ErrorPanel.js +1 -0
- package/src/interfaces/terminal/components/Header.js +1 -0
- package/src/interfaces/terminal/components/HelpPanel.js +1 -0
- package/src/interfaces/terminal/components/InputBox.js +1 -0
- package/src/interfaces/terminal/components/Layout.js +1 -0
- package/src/interfaces/terminal/components/LoadingSpinner.js +1 -0
- package/src/interfaces/terminal/components/MessageList.js +1 -0
- package/src/interfaces/terminal/components/MultilineTextInput.js +1 -0
- package/src/interfaces/terminal/components/SearchPanel.js +1 -0
- package/src/interfaces/terminal/components/SettingsPanel.js +1 -0
- package/src/interfaces/terminal/components/StatusBar.js +1 -0
- package/src/interfaces/terminal/components/TextInput.js +1 -0
- package/src/interfaces/terminal/config/agentEditorConstants.js +1 -0
- package/src/interfaces/terminal/config/constants.js +1 -0
- package/src/interfaces/terminal/index.js +1 -0
- package/src/interfaces/terminal/state/useAgentControl.js +1 -0
- package/src/interfaces/terminal/state/useAgents.js +1 -0
- package/src/interfaces/terminal/state/useConnection.js +1 -0
- package/src/interfaces/terminal/state/useMessages.js +1 -0
- package/src/interfaces/terminal/state/useTools.js +1 -0
- package/src/interfaces/terminal/utils/debugLogger.js +1 -0
- package/src/interfaces/terminal/utils/settingsStorage.js +1 -0
- package/src/interfaces/terminal/utils/theme.js +1 -0
- package/src/interfaces/webServer.js +1 -2162
- package/src/modules/fileExplorer/controller.js +1 -280
- package/src/modules/fileExplorer/index.js +1 -37
- package/src/modules/fileExplorer/middleware.js +1 -92
- package/src/modules/fileExplorer/routes.js +1 -125
- package/src/modules/fileExplorer/types.js +1 -44
- package/src/services/aiService.js +1 -1232
- package/src/services/apiKeyManager.js +1 -164
- package/src/services/benchmarkService.js +1 -366
- package/src/services/budgetService.js +1 -539
- package/src/services/contextInjectionService.js +1 -247
- package/src/services/conversationCompactionService.js +1 -637
- package/src/services/errorHandler.js +1 -810
- package/src/services/fileAttachmentService.js +1 -544
- package/src/services/modelRouterService.js +1 -366
- package/src/services/modelsService.js +1 -322
- package/src/services/qualityInspector.js +1 -796
- package/src/services/tokenCountingService.js +1 -536
- package/src/tools/agentCommunicationTool.js +1 -1344
- package/src/tools/agentDelayTool.js +1 -485
- package/src/tools/asyncToolManager.js +1 -604
- package/src/tools/baseTool.js +1 -800
- package/src/tools/browserTool.js +1 -920
- package/src/tools/cloneDetectionTool.js +1 -621
- package/src/tools/dependencyResolverTool.js +1 -1215
- package/src/tools/fileContentReplaceTool.js +1 -875
- package/src/tools/fileSystemTool.js +1 -1107
- package/src/tools/fileTreeTool.js +1 -853
- package/src/tools/imageTool.js +1 -901
- package/src/tools/importAnalyzerTool.js +1 -1060
- package/src/tools/jobDoneTool.js +1 -248
- package/src/tools/seekTool.js +1 -956
- package/src/tools/staticAnalysisTool.js +1 -1778
- package/src/tools/taskManagerTool.js +1 -2873
- package/src/tools/terminalTool.js +1 -2304
- package/src/tools/webTool.js +1 -1430
- package/src/types/agent.js +1 -519
- package/src/types/contextReference.js +1 -972
- package/src/types/conversation.js +1 -730
- package/src/types/toolCommand.js +1 -747
- package/src/utilities/attachmentValidator.js +1 -292
- package/src/utilities/configManager.js +1 -582
- package/src/utilities/constants.js +1 -722
- package/src/utilities/directoryAccessManager.js +1 -535
- package/src/utilities/fileProcessor.js +1 -307
- package/src/utilities/logger.js +1 -436
- package/src/utilities/tagParser.js +1 -1246
- package/src/utilities/toolConstants.js +1 -317
- package/web-ui/build/index.html +2 -2
- package/web-ui/build/static/{index-Dy2bYbOa.css → index-CClD1090.css} +1 -1
- package/web-ui/build/static/{index-CjkkcnFA.js → index-lCBai6dX.js} +66 -67
|
@@ -1,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();}
|