@loxia-labs/loxia-autopilot-one 1.0.1 → 1.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (120) hide show
  1. package/README.md +44 -54
  2. package/bin/cli.js +1 -115
  3. package/bin/loxia-terminal-v2.js +3 -0
  4. package/bin/loxia-terminal.js +3 -0
  5. package/bin/start-with-terminal.js +3 -0
  6. package/package.json +14 -15
  7. package/scripts/install-scanners.js +1 -235
  8. package/src/analyzers/CSSAnalyzer.js +1 -297
  9. package/src/analyzers/ConfigValidator.js +1 -690
  10. package/src/analyzers/ESLintAnalyzer.js +1 -320
  11. package/src/analyzers/JavaScriptAnalyzer.js +1 -261
  12. package/src/analyzers/PrettierFormatter.js +1 -247
  13. package/src/analyzers/PythonAnalyzer.js +1 -266
  14. package/src/analyzers/SecurityAnalyzer.js +1 -729
  15. package/src/analyzers/TypeScriptAnalyzer.js +1 -247
  16. package/src/analyzers/codeCloneDetector/analyzer.js +1 -344
  17. package/src/analyzers/codeCloneDetector/detector.js +1 -203
  18. package/src/analyzers/codeCloneDetector/index.js +1 -160
  19. package/src/analyzers/codeCloneDetector/parser.js +1 -199
  20. package/src/analyzers/codeCloneDetector/reporter.js +1 -148
  21. package/src/analyzers/codeCloneDetector/scanner.js +1 -59
  22. package/src/core/agentPool.js +1 -1474
  23. package/src/core/agentScheduler.js +1 -2147
  24. package/src/core/contextManager.js +1 -709
  25. package/src/core/messageProcessor.js +1 -732
  26. package/src/core/orchestrator.js +1 -548
  27. package/src/core/stateManager.js +1 -877
  28. package/src/index.js +1 -631
  29. package/src/interfaces/cli.js +1 -549
  30. package/src/interfaces/terminal/__tests__/smoke/advancedFeatures.test.js +1 -0
  31. package/src/interfaces/terminal/__tests__/smoke/agentControl.test.js +1 -0
  32. package/src/interfaces/terminal/__tests__/smoke/agents.test.js +1 -0
  33. package/src/interfaces/terminal/__tests__/smoke/components.test.js +1 -0
  34. package/src/interfaces/terminal/__tests__/smoke/connection.test.js +1 -0
  35. package/src/interfaces/terminal/__tests__/smoke/enhancements.test.js +1 -0
  36. package/src/interfaces/terminal/__tests__/smoke/imports.test.js +1 -0
  37. package/src/interfaces/terminal/__tests__/smoke/messages.test.js +1 -0
  38. package/src/interfaces/terminal/__tests__/smoke/tools.test.js +1 -0
  39. package/src/interfaces/terminal/api/apiClient.js +1 -0
  40. package/src/interfaces/terminal/api/messageRouter.js +1 -0
  41. package/src/interfaces/terminal/api/session.js +1 -0
  42. package/src/interfaces/terminal/api/websocket.js +1 -0
  43. package/src/interfaces/terminal/components/AgentCreator.js +1 -0
  44. package/src/interfaces/terminal/components/AgentEditor.js +1 -0
  45. package/src/interfaces/terminal/components/AgentSwitcher.js +1 -0
  46. package/src/interfaces/terminal/components/ErrorBoundary.js +1 -0
  47. package/src/interfaces/terminal/components/ErrorPanel.js +1 -0
  48. package/src/interfaces/terminal/components/Header.js +1 -0
  49. package/src/interfaces/terminal/components/HelpPanel.js +1 -0
  50. package/src/interfaces/terminal/components/InputBox.js +1 -0
  51. package/src/interfaces/terminal/components/Layout.js +1 -0
  52. package/src/interfaces/terminal/components/LoadingSpinner.js +1 -0
  53. package/src/interfaces/terminal/components/MessageList.js +1 -0
  54. package/src/interfaces/terminal/components/MultilineTextInput.js +1 -0
  55. package/src/interfaces/terminal/components/SearchPanel.js +1 -0
  56. package/src/interfaces/terminal/components/SettingsPanel.js +1 -0
  57. package/src/interfaces/terminal/components/StatusBar.js +1 -0
  58. package/src/interfaces/terminal/components/TextInput.js +1 -0
  59. package/src/interfaces/terminal/config/agentEditorConstants.js +1 -0
  60. package/src/interfaces/terminal/config/constants.js +1 -0
  61. package/src/interfaces/terminal/index.js +1 -0
  62. package/src/interfaces/terminal/state/useAgentControl.js +1 -0
  63. package/src/interfaces/terminal/state/useAgents.js +1 -0
  64. package/src/interfaces/terminal/state/useConnection.js +1 -0
  65. package/src/interfaces/terminal/state/useMessages.js +1 -0
  66. package/src/interfaces/terminal/state/useTools.js +1 -0
  67. package/src/interfaces/terminal/utils/debugLogger.js +1 -0
  68. package/src/interfaces/terminal/utils/settingsStorage.js +1 -0
  69. package/src/interfaces/terminal/utils/theme.js +1 -0
  70. package/src/interfaces/webServer.js +1 -2162
  71. package/src/modules/fileExplorer/controller.js +1 -280
  72. package/src/modules/fileExplorer/index.js +1 -37
  73. package/src/modules/fileExplorer/middleware.js +1 -92
  74. package/src/modules/fileExplorer/routes.js +1 -125
  75. package/src/modules/fileExplorer/types.js +1 -44
  76. package/src/services/aiService.js +1 -1232
  77. package/src/services/apiKeyManager.js +1 -164
  78. package/src/services/benchmarkService.js +1 -366
  79. package/src/services/budgetService.js +1 -539
  80. package/src/services/contextInjectionService.js +1 -247
  81. package/src/services/conversationCompactionService.js +1 -637
  82. package/src/services/errorHandler.js +1 -810
  83. package/src/services/fileAttachmentService.js +1 -544
  84. package/src/services/modelRouterService.js +1 -366
  85. package/src/services/modelsService.js +1 -322
  86. package/src/services/qualityInspector.js +1 -796
  87. package/src/services/tokenCountingService.js +1 -536
  88. package/src/tools/agentCommunicationTool.js +1 -1344
  89. package/src/tools/agentDelayTool.js +1 -485
  90. package/src/tools/asyncToolManager.js +1 -604
  91. package/src/tools/baseTool.js +1 -800
  92. package/src/tools/browserTool.js +1 -920
  93. package/src/tools/cloneDetectionTool.js +1 -621
  94. package/src/tools/dependencyResolverTool.js +1 -1215
  95. package/src/tools/fileContentReplaceTool.js +1 -875
  96. package/src/tools/fileSystemTool.js +1 -1107
  97. package/src/tools/fileTreeTool.js +1 -853
  98. package/src/tools/imageTool.js +1 -901
  99. package/src/tools/importAnalyzerTool.js +1 -1060
  100. package/src/tools/jobDoneTool.js +1 -248
  101. package/src/tools/seekTool.js +1 -956
  102. package/src/tools/staticAnalysisTool.js +1 -1778
  103. package/src/tools/taskManagerTool.js +1 -2873
  104. package/src/tools/terminalTool.js +1 -2304
  105. package/src/tools/webTool.js +1 -1430
  106. package/src/types/agent.js +1 -519
  107. package/src/types/contextReference.js +1 -972
  108. package/src/types/conversation.js +1 -730
  109. package/src/types/toolCommand.js +1 -747
  110. package/src/utilities/attachmentValidator.js +1 -292
  111. package/src/utilities/configManager.js +1 -582
  112. package/src/utilities/constants.js +1 -722
  113. package/src/utilities/directoryAccessManager.js +1 -535
  114. package/src/utilities/fileProcessor.js +1 -307
  115. package/src/utilities/logger.js +1 -436
  116. package/src/utilities/tagParser.js +1 -1246
  117. package/src/utilities/toolConstants.js +1 -317
  118. package/web-ui/build/index.html +2 -2
  119. package/web-ui/build/static/{index-Dy2bYbOa.css → index-CClD1090.css} +1 -1
  120. package/web-ui/build/static/{index-CjkkcnFA.js → index-lCBai6dX.js} +66 -67
@@ -1,1344 +1 @@
1
- /**
2
- * AgentCommunicationTool - Enables inter-agent communication with safety mechanisms
3
- *
4
- * Purpose:
5
- * - Allow agents to discover and communicate with other active agents
6
- * - Manage message threads with reply tracking
7
- * - Prevent conversation loops and exponential message growth
8
- * - Support file attachments for rich communication
9
- *
10
- * Design Principles:
11
- * - Loosely coupled with system components
12
- * - Message persistence for async communication
13
- * - Conversation limits to prevent runaway threads
14
- * - Agent lifecycle awareness
15
- */
16
-
17
- import { BaseTool } from './baseTool.js';
18
- import { promises as fs } from 'fs';
19
- import path from 'path';
20
- import crypto from 'crypto';
21
-
22
- class AgentCommunicationTool extends BaseTool {
23
- constructor(config = {}) {
24
- super('agentcommunication', 'Agent Communication', 'communication');
25
-
26
- // Configuration with safety defaults
27
- this.config = {
28
- maxConversationDepth: config.maxConversationDepth || 10,
29
- maxRecipientsPerMessage: config.maxRecipientsPerMessage || 3,
30
- maxAttachmentSize: config.maxAttachmentSize || 10 * 1024 * 1024, // 10MB
31
- maxAttachmentsPerMessage: config.maxAttachmentsPerMessage || 5,
32
- conversationTimeout: config.conversationTimeout || 3600000, // 1 hour
33
- messageRetentionPeriod: config.messageRetentionPeriod || 86400000, // 24 hours
34
- enableBroadcast: config.enableBroadcast || false,
35
- storageDir: config.storageDir || '.loxia-messages'
36
- };
37
-
38
- // Message storage - in production, this would be a database
39
- this.messages = new Map(); // messageId -> message object
40
- this.conversations = new Map(); // conversationId -> conversation metadata
41
- this.agentInboxes = new Map(); // agentId -> Set of messageIds
42
- this.agentConversations = new Map(); // agentId -> Set of conversationIds
43
-
44
- // Safety tracking
45
- this.conversationDepths = new Map(); // conversationId -> current depth
46
- this.lastActivityTimes = new Map(); // conversationId -> timestamp
47
- this.agentMessageCounts = new Map(); // agentId -> { sent: number, received: number }
48
-
49
- // Initialize storage directory
50
- this._initializeStorage();
51
- }
52
-
53
- /**
54
- * Get tool description for agent system prompts
55
- */
56
- getDescription() {
57
- return `
58
- Agent Communication Tool: Enables communication between active agents in the system.
59
-
60
- Available Actions:
61
- - get-available-agents: List all active agents you can communicate with
62
- - send-message: Send a message to another agent with optional attachments
63
- - reply-to-message: Reply to a received message
64
- - get-unreplied-messages: Get list of messages requiring your response
65
- - mark-conversation-ended: Mark a conversation as complete/disregarded
66
-
67
- Usage Examples (both XML and JSON formats supported):
68
-
69
- 1. Get available agents (XML format):
70
- [tool]
71
- <action>get-available-agents</action>
72
- [/tool]
73
-
74
- 1b. Get available agents (JSON format):
75
- {"actions": [{"type": "get-available-agents"}]}
76
-
77
- Both return a JSON response like:
78
- {
79
- "success": true,
80
- "agents": [
81
- {
82
- "id": "agent-alice-1755111616214",
83
- "name": "alice",
84
- "capabilities": ["terminal", "filesystem", ...],
85
- "status": "active"
86
- }
87
- ]
88
- }
89
-
90
- Look for the "id" field in each agent object - this is what you use as the recipient.
91
-
92
- 2. Send a message (XML format):
93
- [tool]
94
- <action>send-message</action>
95
- <recipient>agent-fullstack-developer-agent-1234567890123</recipient>
96
- <subject>Need assistance with code review</subject>
97
- <message>Could you review the authentication module I just implemented?</message>
98
- <priority>normal</priority>
99
- <requires-reply>true</requires-reply>
100
- [/tool]
101
-
102
- 2b. Send a message (JSON format):
103
- {"actions": [{"type": "send-message", "recipient": "agent-fullstack-developer-agent-1234567890123", "subject": "Need assistance with code review", "message": "Could you review the authentication module I just implemented?", "priority": "normal", "requires-reply": true}]}
104
-
105
- IMPORTANT: Always use the full agent ID (like "agent-fullstack-developer-agent-1234567890123") as the recipient, not just the name. Get the exact ID from get-available-agents first.
106
-
107
- 3. Send with attachments (XML format):
108
- [tool]
109
- <action>send-message</action>
110
- <recipient>agent-id-456</recipient>
111
- <subject>Analysis results</subject>
112
- <message>Here are the test results you requested</message>
113
- <attachments>[{"path": "/reports/test-results.pdf", "type": "pdf"}]</attachments>
114
- [/tool]
115
-
116
- 4. Reply to a message:
117
- [tool]
118
- <action>reply-to-message</action>
119
- <message-id>msg-789</message-id>
120
- <message>Thanks for the review. I've addressed all your comments.</message>
121
- <cc-recipients>["agent-id-111"]</cc-recipients>
122
- [/tool]
123
-
124
- 5. Get unreplied messages:
125
- [tool]
126
- <action>get-unreplied-messages</action>
127
- <include-low-priority>false</include-low-priority>
128
- [/tool]
129
-
130
- 6. End a conversation:
131
- [tool]
132
- <action>mark-conversation-ended</action>
133
- <conversation-id>conv-xyz</conversation-id>
134
- <reason>Task completed successfully</reason>
135
- [/tool]
136
-
137
- Safety Guidelines:
138
- - Maximum ${this.config.maxConversationDepth} replies per conversation thread
139
- - Maximum ${this.config.maxRecipientsPerMessage} recipients per message
140
- - Conversations auto-expire after ${this.config.conversationTimeout / 60000} minutes of inactivity
141
- - Avoid reply-all unless necessary to prevent message storms
142
- - Mark conversations as ended when goals are achieved
143
-
144
- Important Notes:
145
- - Messages are delivered asynchronously
146
- - Attachments must be readable files under ${this.config.maxAttachmentSize / 1024 / 1024}MB
147
- - Use clear subjects to help recipients prioritize
148
- - Check unreplied messages regularly to maintain communication flow
149
- `.trim();
150
- }
151
-
152
- /**
153
- * Parse tool parameters from command content
154
- */
155
- parseParameters(content) {
156
- // Handle JSON format (for direct tool calls)
157
- if (typeof content === 'object' && content !== null) {
158
- // If it's already an object, extract the parameters
159
- if (content.actions && Array.isArray(content.actions) && content.actions.length > 0) {
160
- // Handle format: {"actions": [{"type": "get-available-agents", ...}]}
161
- const action = content.actions[0];
162
- return {
163
- action: action.type,
164
- ...action
165
- };
166
- } else if (content.action || content.type) {
167
- // Handle format: {"action": "get-available-agents", ...}
168
- return {
169
- action: content.action || content.type,
170
- ...content
171
- };
172
- }
173
- return content;
174
- }
175
-
176
- // Handle string content (could be JSON string or XML)
177
- if (typeof content === 'string') {
178
- // Try parsing as JSON first
179
- if (content.trim().startsWith('{')) {
180
- try {
181
- const parsed = JSON.parse(content);
182
- return this.parseParameters(parsed); // Recursive call to handle the parsed object
183
- } catch (error) {
184
- // Not valid JSON, continue to XML parsing
185
- }
186
- }
187
-
188
- // Parse XML-style commands for agent communication
189
- const parameters = {};
190
-
191
- // Extract action parameter
192
- const actionMatch = content.match(/<action[^>]*>([^<]+)<\/action>/);
193
- if (actionMatch) {
194
- parameters.action = actionMatch[1].trim();
195
- }
196
-
197
- // Extract other parameters like recipient, subject, message, etc.
198
- const tags = [
199
- 'recipient', 'recipients', 'subject', 'message', 'attachments',
200
- 'priority', 'requires-reply', 'message-id', 'cc-recipients',
201
- 'include-low-priority', 'conversation-id', 'reason', 'mark-resolved'
202
- ];
203
-
204
- for (const tag of tags) {
205
- const regex = new RegExp(`<${tag.replace('-', '\\-')}[^>]*>(.*?)<\\/${tag.replace('-', '\\-')}>`, 's');
206
- const match = content.match(regex);
207
- if (match) {
208
- let value = match[1].trim();
209
- // Try to parse JSON values
210
- if (value.startsWith('[') || value.startsWith('{') || value === 'true' || value === 'false') {
211
- try {
212
- value = JSON.parse(value);
213
- } catch {
214
- // Keep as string if JSON parsing fails
215
- }
216
- }
217
- // Convert kebab-case to camelCase for parameter names
218
- const paramName = tag.replace(/-(.)/g, (_, char) => char.toUpperCase());
219
- parameters[paramName] = value;
220
- }
221
- }
222
-
223
- // Extract attributes from action tag if present
224
- const actionWithAttribs = content.match(/<action([^>]*)>([^<]+)<\/action>/);
225
- if (actionWithAttribs && actionWithAttribs[1]) {
226
- // Parse attributes like priority="high", requires-reply="true"
227
- const attribMatches = actionWithAttribs[1].matchAll(/([\w-]+)=["']([^"']+)["']/g);
228
- for (const match of attribMatches) {
229
- const key = match[1].replace(/-(.)/g, (_, char) => char.toUpperCase()); // Convert kebab-case to camelCase
230
- parameters[key] = match[2];
231
- }
232
- }
233
-
234
- return parameters;
235
- }
236
-
237
- // Fallback
238
- return content || {};
239
- }
240
-
241
- /**
242
- * Execute the tool action
243
- */
244
- async execute(parameters = {}, context = {}) {
245
- const { action } = parameters;
246
-
247
- if (!action) {
248
- throw new Error('Action parameter is required');
249
- }
250
-
251
- // Validate requesting agent exists
252
- const requestingAgentId = context.agentId;
253
- if (!requestingAgentId) {
254
- throw new Error('Agent ID is required in context');
255
- }
256
-
257
- // Route to appropriate action handler
258
- switch (action.toLowerCase()) {
259
- case 'get-available-agents':
260
- return await this.getAvailableAgents(requestingAgentId, parameters, context);
261
-
262
- case 'send-message':
263
- return await this.sendMessage(requestingAgentId, parameters, context);
264
-
265
- case 'reply-to-message':
266
- return await this.replyToMessage(requestingAgentId, parameters, context);
267
-
268
- case 'get-unreplied-messages':
269
- return await this.getUnrepliedMessages(requestingAgentId, parameters, context);
270
-
271
- case 'mark-conversation-ended':
272
- return await this.markConversationEnded(requestingAgentId, parameters, context);
273
-
274
- default:
275
- throw new Error(`Unknown action: ${action}`);
276
- }
277
- }
278
-
279
- /**
280
- * Get list of available agents
281
- */
282
- async getAvailableAgents(requestingAgentId, parameters, context) {
283
- try {
284
- // Get agent pool from context
285
- const agentPool = context.agentPool;
286
- if (!agentPool) {
287
- throw new Error('Agent pool not available in context');
288
- }
289
-
290
- // Get all active agents
291
- const agents = await agentPool.listActiveAgents();
292
-
293
- // Filter out requesting agent and format response
294
- const availableAgents = agents
295
- .filter(agent => agent.id !== requestingAgentId && !agent.isPaused)
296
- .map(agent => ({
297
- id: agent.id,
298
- name: agent.name,
299
- type: agent.type,
300
- capabilities: agent.capabilities,
301
- status: agent.status,
302
- messageStats: this.agentMessageCounts.get(agent.id) || { sent: 0, received: 0 },
303
- activeConversations: (this.agentConversations.get(agent.id) || new Set()).size
304
- }));
305
-
306
- return {
307
- success: true,
308
- agents: availableAgents,
309
- totalActive: availableAgents.length,
310
- timestamp: new Date().toISOString()
311
- };
312
-
313
- } catch (error) {
314
- return {
315
- success: false,
316
- error: error.message
317
- };
318
- }
319
- }
320
-
321
- /**
322
- * Send a message to another agent
323
- */
324
- async sendMessage(senderAgentId, parameters, context) {
325
- try {
326
- const {
327
- recipient,
328
- recipients, // Support both single and multiple
329
- subject,
330
- message,
331
- attachments,
332
- priority = 'normal',
333
- 'requires-reply': requiresReply = false
334
- } = parameters;
335
-
336
- // Validate required fields
337
- if (!subject || !message) {
338
- throw new Error('Subject and message are required');
339
- }
340
-
341
- // Determine recipients
342
- const recipientList = this._parseRecipients(recipient, recipients);
343
- if (recipientList.length === 0) {
344
- throw new Error('At least one recipient is required');
345
- }
346
-
347
- // Validate recipient count
348
- if (recipientList.length > this.config.maxRecipientsPerMessage) {
349
- throw new Error(`Maximum ${this.config.maxRecipientsPerMessage} recipients allowed`);
350
- }
351
-
352
- // Get agent pool and sender agent
353
- const agentPool = context.agentPool;
354
- const senderAgent = await agentPool.getAgent(senderAgentId);
355
- if (!senderAgent) {
356
- throw new Error('Sender agent not found');
357
- }
358
-
359
- // CRITICAL: Check if sender can send messages to recipients
360
- const blockedRecipients = [];
361
- for (const recipientId of recipientList) {
362
- const canSend = await this._canSendMessage(senderAgent, recipientId, context);
363
- if (!canSend.allowed) {
364
- blockedRecipients.push({
365
- recipientId,
366
- reason: canSend.reason,
367
- waitUntil: canSend.waitUntil
368
- });
369
- }
370
- }
371
-
372
- // If any recipients are blocked, apply delay and return
373
- if (blockedRecipients.length > 0) {
374
- const earliestAllowedTime = Math.max(...blockedRecipients.map(b => b.waitUntil || 0));
375
- const delayUntil = new Date(earliestAllowedTime);
376
-
377
- // Apply delay using existing infrastructure
378
- await agentPool.updateAgent(senderAgentId, {
379
- delayEndTime: delayUntil.toISOString()
380
- });
381
-
382
- const delaySeconds = Math.ceil((earliestAllowedTime - Date.now()) / 1000);
383
-
384
- return {
385
- success: true,
386
- delayed: true,
387
- delayUntil: delayUntil.toISOString(),
388
- delaySeconds,
389
- message: `Waiting ${delaySeconds}s before next message. Recipients need time to respond.`,
390
- blockedRecipients: blockedRecipients.map(b => ({
391
- recipientId: b.recipientId,
392
- reason: b.reason
393
- }))
394
- };
395
- }
396
-
397
- // Validate recipients exist and get their names
398
- const recipientAgents = {};
399
- const invalidRecipients = [];
400
-
401
- for (const recipientId of recipientList) {
402
- const agent = await agentPool.getAgent(recipientId);
403
- if (!agent) {
404
- invalidRecipients.push(recipientId);
405
- } else {
406
- recipientAgents[recipientId] = agent.name;
407
- }
408
- }
409
-
410
- // If any recipients are invalid, provide helpful error with suggestions
411
- if (invalidRecipients.length > 0) {
412
- const availableAgents = await agentPool.listActiveAgents();
413
- const suggestions = availableAgents
414
- .filter(agent => agent.id !== senderAgentId && !agent.isPaused)
415
- .map(agent => `- ${agent.name} (ID: ${agent.id})`)
416
- .join('\n');
417
-
418
- return {
419
- success: false,
420
- error: `Recipient agent(s) not found: ${invalidRecipients.join(', ')}`,
421
- suggestion: `Available agents you can message:\n${suggestions}`,
422
- availableAgents: availableAgents.map(agent => ({
423
- id: agent.id,
424
- name: agent.name,
425
- capabilities: agent.capabilities
426
- }))
427
- };
428
- }
429
-
430
- // Get sender agent name
431
- const senderName = senderAgent ? senderAgent.name : senderAgentId;
432
-
433
- // Process attachments if provided
434
- const processedAttachments = await this._processAttachments(attachments, senderAgentId);
435
-
436
- // Create message object
437
- const messageId = this._generateMessageId();
438
- const conversationId = this._generateConversationId();
439
- const timestamp = new Date().toISOString();
440
-
441
- const messageObj = {
442
- id: messageId,
443
- conversationId,
444
- sender: senderAgentId,
445
- senderName,
446
- recipients: recipientList,
447
- recipientNames: recipientAgents,
448
- subject,
449
- content: message,
450
- attachments: processedAttachments,
451
- priority,
452
- requiresReply,
453
- timestamp,
454
- status: 'sent',
455
- replies: [],
456
- metadata: {
457
- depth: 0,
458
- isRoot: true
459
- }
460
- };
461
-
462
- // Store message
463
- this.messages.set(messageId, messageObj);
464
-
465
- // Initialize conversation
466
- this.conversations.set(conversationId, {
467
- id: conversationId,
468
- rootMessageId: messageId,
469
- participants: [senderAgentId, ...recipientList],
470
- startTime: timestamp,
471
- lastActivity: timestamp,
472
- status: 'active',
473
- messageCount: 1
474
- });
475
-
476
- // Update inboxes
477
- for (const recipientId of recipientList) {
478
- if (!this.agentInboxes.has(recipientId)) {
479
- this.agentInboxes.set(recipientId, new Set());
480
- }
481
- this.agentInboxes.get(recipientId).add(messageId);
482
-
483
- // Track conversations
484
- if (!this.agentConversations.has(recipientId)) {
485
- this.agentConversations.set(recipientId, new Set());
486
- }
487
- this.agentConversations.get(recipientId).add(conversationId);
488
- }
489
-
490
- // Track sender's conversation
491
- if (!this.agentConversations.has(senderAgentId)) {
492
- this.agentConversations.set(senderAgentId, new Set());
493
- }
494
- this.agentConversations.get(senderAgentId).add(conversationId);
495
-
496
- // Update message counts
497
- this._updateMessageCounts(senderAgentId, 'sent');
498
- for (const recipientId of recipientList) {
499
- this._updateMessageCounts(recipientId, 'received');
500
- }
501
-
502
- // CRITICAL: Update inter-agent conversation tracking
503
- for (const recipientId of recipientList) {
504
- await this._updateConversationTracking(senderAgentId, recipientId, 'sent', context);
505
- }
506
-
507
- // Notify recipients through agent pool
508
- await this._notifyRecipients(messageObj, context);
509
-
510
- // Broadcast to WebSocket for UI visibility
511
- await this._broadcastToUI(messageObj, 'agent-message-sent', context);
512
-
513
- return {
514
- success: true,
515
- messageId,
516
- conversationId,
517
- recipients: recipientList,
518
- timestamp,
519
- message: 'Message sent successfully'
520
- };
521
-
522
- } catch (error) {
523
- return {
524
- success: false,
525
- error: error.message
526
- };
527
- }
528
- }
529
-
530
- /**
531
- * Reply to an existing message
532
- */
533
- async replyToMessage(senderAgentId, parameters, context) {
534
- try {
535
- const {
536
- 'message-id': originalMessageId,
537
- message,
538
- 'cc-recipients': ccRecipients,
539
- attachments,
540
- 'mark-resolved': markResolved = false
541
- } = parameters;
542
-
543
- // Validate required fields
544
- if (!originalMessageId || !message) {
545
- throw new Error('Original message ID and reply content are required');
546
- }
547
-
548
- // Get original message
549
- const originalMessage = this.messages.get(originalMessageId);
550
- if (!originalMessage) {
551
- throw new Error(`Original message not found: ${originalMessageId}`);
552
- }
553
-
554
- // Verify sender was a recipient or sender of original message
555
- const isParticipant = originalMessage.sender === senderAgentId ||
556
- originalMessage.recipients.includes(senderAgentId);
557
- if (!isParticipant) {
558
- throw new Error('You are not a participant in this conversation');
559
- }
560
-
561
- // Check conversation depth to prevent infinite loops
562
- const conversation = this.conversations.get(originalMessage.conversationId);
563
- const currentDepth = this._getConversationDepth(originalMessage.conversationId);
564
-
565
- if (currentDepth >= this.config.maxConversationDepth) {
566
- return {
567
- success: false,
568
- error: `Conversation depth limit reached (${this.config.maxConversationDepth}). Please start a new conversation.`,
569
- suggestion: 'Consider marking this conversation as ended and starting fresh if needed.'
570
- };
571
- }
572
-
573
- // Determine reply recipients
574
- let replyRecipients = [originalMessage.sender];
575
- if (originalMessage.sender === senderAgentId) {
576
- // If replying to own message, reply to original recipients
577
- replyRecipients = originalMessage.recipients;
578
- }
579
-
580
- // Add CC recipients if specified
581
- if (ccRecipients) {
582
- const ccList = this._parseRecipients(null, ccRecipients);
583
- replyRecipients = [...new Set([...replyRecipients, ...ccList])];
584
- }
585
-
586
- // Remove sender from recipients
587
- replyRecipients = replyRecipients.filter(id => id !== senderAgentId);
588
-
589
- // Validate recipient count
590
- if (replyRecipients.length > this.config.maxRecipientsPerMessage) {
591
- throw new Error(`Maximum ${this.config.maxRecipientsPerMessage} recipients allowed`);
592
- }
593
-
594
- // Get agent names
595
- const agentPool = context.agentPool;
596
- const senderAgent = await agentPool.getAgent(senderAgentId);
597
- const senderName = senderAgent ? senderAgent.name : senderAgentId;
598
-
599
- const recipientAgents = {};
600
- for (const recipientId of replyRecipients) {
601
- const agent = await agentPool.getAgent(recipientId);
602
- if (agent) {
603
- recipientAgents[recipientId] = agent.name;
604
- }
605
- }
606
-
607
- // Process attachments
608
- const processedAttachments = await this._processAttachments(attachments, senderAgentId);
609
-
610
- // Create reply message
611
- const replyMessageId = this._generateMessageId();
612
- const timestamp = new Date().toISOString();
613
-
614
- const replyMessage = {
615
- id: replyMessageId,
616
- conversationId: originalMessage.conversationId,
617
- sender: senderAgentId,
618
- senderName,
619
- recipients: replyRecipients,
620
- recipientNames: recipientAgents,
621
- subject: `Re: ${originalMessage.subject}`,
622
- content: message,
623
- attachments: processedAttachments,
624
- priority: originalMessage.priority,
625
- requiresReply: !markResolved,
626
- timestamp,
627
- status: 'sent',
628
- replies: [],
629
- metadata: {
630
- depth: currentDepth + 1,
631
- isRoot: false,
632
- inReplyTo: originalMessageId
633
- }
634
- };
635
-
636
- // Store reply
637
- this.messages.set(replyMessageId, replyMessage);
638
- originalMessage.replies.push(replyMessageId);
639
-
640
- // Update conversation
641
- conversation.lastActivity = timestamp;
642
- conversation.messageCount++;
643
- if (markResolved) {
644
- conversation.status = 'resolved';
645
- }
646
-
647
- // Update inboxes
648
- for (const recipientId of replyRecipients) {
649
- if (!this.agentInboxes.has(recipientId)) {
650
- this.agentInboxes.set(recipientId, new Set());
651
- }
652
- this.agentInboxes.get(recipientId).add(replyMessageId);
653
- }
654
-
655
- // Update message counts
656
- this._updateMessageCounts(senderAgentId, 'sent');
657
- for (const recipientId of replyRecipients) {
658
- this._updateMessageCounts(recipientId, 'received');
659
- }
660
-
661
- // CRITICAL: Update inter-agent conversation tracking for replies
662
- for (const recipientId of replyRecipients) {
663
- await this._updateConversationTracking(senderAgentId, recipientId, 'replied', context);
664
- }
665
-
666
- // Notify recipients
667
- await this._notifyRecipients(replyMessage, context);
668
-
669
- // Broadcast to WebSocket for UI visibility
670
- await this._broadcastToUI(replyMessage, 'agent-message-reply', context);
671
-
672
- return {
673
- success: true,
674
- messageId: replyMessageId,
675
- conversationId: originalMessage.conversationId,
676
- recipients: replyRecipients,
677
- depth: currentDepth + 1,
678
- timestamp,
679
- conversationStatus: conversation.status
680
- };
681
-
682
- } catch (error) {
683
- return {
684
- success: false,
685
- error: error.message
686
- };
687
- }
688
- }
689
-
690
- /**
691
- * Get unreplied messages for an agent
692
- */
693
- async getUnrepliedMessages(agentId, parameters, context) {
694
- try {
695
- const {
696
- 'include-low-priority': includeLowPriority = false,
697
- 'max-age-hours': maxAgeHours = 24
698
- } = parameters;
699
-
700
- const inbox = this.agentInboxes.get(agentId) || new Set();
701
- const unrepliedMessages = [];
702
- const maxAge = Date.now() - (maxAgeHours * 3600000);
703
-
704
- for (const messageId of inbox) {
705
- const message = this.messages.get(messageId);
706
- if (!message) continue;
707
-
708
- // Skip old messages
709
- if (new Date(message.timestamp).getTime() < maxAge) continue;
710
-
711
- // Skip low priority if not requested
712
- if (message.priority === 'low' && !includeLowPriority) continue;
713
-
714
- // Check if message requires reply and hasn't been replied to by this agent
715
- if (message.requiresReply) {
716
- const hasReplied = this._hasAgentReplied(agentId, message);
717
- if (!hasReplied) {
718
- const conversation = this.conversations.get(message.conversationId);
719
- unrepliedMessages.push({
720
- messageId: message.id,
721
- conversationId: message.conversationId,
722
- sender: message.sender,
723
- subject: message.subject,
724
- preview: message.content.substring(0, 100) + '...',
725
- priority: message.priority,
726
- timestamp: message.timestamp,
727
- hasAttachments: message.attachments.length > 0,
728
- conversationStatus: conversation?.status || 'unknown',
729
- depth: message.metadata.depth
730
- });
731
- }
732
- }
733
- }
734
-
735
- // Sort by priority and timestamp
736
- unrepliedMessages.sort((a, b) => {
737
- const priorityOrder = { high: 0, normal: 1, low: 2 };
738
- const priorityDiff = priorityOrder[a.priority] - priorityOrder[b.priority];
739
- if (priorityDiff !== 0) return priorityDiff;
740
- return new Date(b.timestamp) - new Date(a.timestamp);
741
- });
742
-
743
- return {
744
- success: true,
745
- messages: unrepliedMessages,
746
- total: unrepliedMessages.length,
747
- inbox: {
748
- total: inbox.size,
749
- activeConversations: (this.agentConversations.get(agentId) || new Set()).size
750
- }
751
- };
752
-
753
- } catch (error) {
754
- return {
755
- success: false,
756
- error: error.message
757
- };
758
- }
759
- }
760
-
761
- /**
762
- * Mark a conversation as ended
763
- */
764
- async markConversationEnded(agentId, parameters, context) {
765
- try {
766
- const {
767
- 'conversation-id': conversationId,
768
- reason = 'Conversation ended by agent'
769
- } = parameters;
770
-
771
- if (!conversationId) {
772
- throw new Error('Conversation ID is required');
773
- }
774
-
775
- const conversation = this.conversations.get(conversationId);
776
- if (!conversation) {
777
- throw new Error(`Conversation not found: ${conversationId}`);
778
- }
779
-
780
- // Verify agent is a participant
781
- if (!conversation.participants.includes(agentId)) {
782
- throw new Error('You are not a participant in this conversation');
783
- }
784
-
785
- // Update conversation status
786
- conversation.status = 'ended';
787
- conversation.endTime = new Date().toISOString();
788
- conversation.endReason = reason;
789
- conversation.endedBy = agentId;
790
-
791
- // Remove from active conversations for all participants
792
- for (const participantId of conversation.participants) {
793
- const agentConvs = this.agentConversations.get(participantId);
794
- if (agentConvs) {
795
- agentConvs.delete(conversationId);
796
- }
797
- }
798
-
799
- return {
800
- success: true,
801
- conversationId,
802
- status: 'ended',
803
- reason,
804
- timestamp: conversation.endTime
805
- };
806
-
807
- } catch (error) {
808
- return {
809
- success: false,
810
- error: error.message
811
- };
812
- }
813
- }
814
-
815
- /**
816
- * Initialize storage directory
817
- * @private
818
- */
819
- async _initializeStorage() {
820
- try {
821
- await fs.mkdir(this.config.storageDir, { recursive: true });
822
- const attachmentsDir = path.join(this.config.storageDir, 'attachments');
823
- await fs.mkdir(attachmentsDir, { recursive: true });
824
- } catch (error) {
825
- console.error('Failed to initialize message storage:', error);
826
- }
827
- }
828
-
829
- /**
830
- * Parse recipients from parameters
831
- * @private
832
- */
833
- _parseRecipients(recipient, recipients) {
834
- let recipientList = [];
835
-
836
- if (recipient) {
837
- recipientList.push(recipient);
838
- }
839
-
840
- if (recipients) {
841
- if (typeof recipients === 'string') {
842
- try {
843
- const parsed = JSON.parse(recipients);
844
- recipientList = [...recipientList, ...(Array.isArray(parsed) ? parsed : [parsed])];
845
- } catch {
846
- recipientList.push(recipients);
847
- }
848
- } else if (Array.isArray(recipients)) {
849
- recipientList = [...recipientList, ...recipients];
850
- }
851
- }
852
-
853
- // Remove duplicates
854
- return [...new Set(recipientList)];
855
- }
856
-
857
- /**
858
- * Process and validate attachments
859
- * @private
860
- */
861
- async _processAttachments(attachments, agentId) {
862
- if (!attachments) return [];
863
-
864
- let attachmentList = [];
865
- if (typeof attachments === 'string') {
866
- try {
867
- attachmentList = JSON.parse(attachments);
868
- } catch {
869
- return [];
870
- }
871
- } else {
872
- attachmentList = attachments;
873
- }
874
-
875
- if (!Array.isArray(attachmentList)) {
876
- attachmentList = [attachmentList];
877
- }
878
-
879
- // Validate attachment count
880
- if (attachmentList.length > this.config.maxAttachmentsPerMessage) {
881
- throw new Error(`Maximum ${this.config.maxAttachmentsPerMessage} attachments allowed`);
882
- }
883
-
884
- const processedAttachments = [];
885
-
886
- for (const attachment of attachmentList) {
887
- if (!attachment.path) continue;
888
-
889
- try {
890
- // Check file exists and size
891
- const stats = await fs.stat(attachment.path);
892
- if (stats.size > this.config.maxAttachmentSize) {
893
- throw new Error(`Attachment exceeds size limit: ${attachment.path}`);
894
- }
895
-
896
- // Copy to storage
897
- const attachmentId = this._generateAttachmentId();
898
- const ext = path.extname(attachment.path);
899
- const storagePath = path.join(this.config.storageDir, 'attachments', `${attachmentId}${ext}`);
900
-
901
- await fs.copyFile(attachment.path, storagePath);
902
-
903
- processedAttachments.push({
904
- id: attachmentId,
905
- originalPath: attachment.path,
906
- storagePath,
907
- type: attachment.type || 'file',
908
- size: stats.size,
909
- name: path.basename(attachment.path)
910
- });
911
-
912
- } catch (error) {
913
- console.error(`Failed to process attachment: ${attachment.path}`, error);
914
- }
915
- }
916
-
917
- return processedAttachments;
918
- }
919
-
920
- /**
921
- * Notify recipients of new message
922
- * @private
923
- */
924
- async _notifyRecipients(message, context) {
925
- const agentPool = context.agentPool;
926
- if (!agentPool) return;
927
-
928
- for (const recipientId of message.recipients) {
929
- try {
930
- // Send both a notification AND inject message into conversation
931
-
932
- // 1. Standard notification (for system awareness)
933
- await agentPool.notifyAgent(recipientId, {
934
- type: 'agent-communication',
935
- from: message.sender,
936
- conversationId: message.conversationId,
937
- content: `📨 New message from ${message.senderName}: "${message.subject}"`,
938
- messageId: message.id,
939
- priority: message.priority,
940
- requiresResponse: message.requiresReply
941
- });
942
-
943
- // 2. Inject the actual message content directly into recipient's conversation
944
- const recipient = await agentPool.getAgent(recipientId);
945
- if (recipient) {
946
- const messageContent = `📨 **Inter-Agent Message**
947
- **From:** ${message.senderName} (${message.sender})
948
- **Subject:** ${message.subject}
949
- **Priority:** ${message.priority}
950
- **Requires Reply:** ${message.requiresReply ? 'Yes' : 'No'}
951
-
952
- **Message:**
953
- ${message.content}
954
-
955
- ${message.attachments.length > 0 ? `**Attachments:** ${message.attachments.length} file(s)` : ''}
956
-
957
- *You can reply using the agentcommunication tool with action="reply-to-message" and message-id="${message.id}"*`;
958
-
959
- const directMessage = {
960
- id: `agent-comm-${message.id}`,
961
- conversationId: message.conversationId,
962
- agentId: message.sender,
963
- content: messageContent,
964
- role: 'system', // System message so it's clearly visible
965
- timestamp: message.timestamp,
966
- type: 'agent-communication',
967
- metadata: {
968
- originalMessageId: message.id,
969
- fromAgent: message.sender,
970
- requiresResponse: message.requiresReply,
971
- priority: message.priority
972
- }
973
- };
974
-
975
- // Add to full conversation
976
- recipient.conversations.full.messages.push(directMessage);
977
- recipient.conversations.full.lastUpdated = new Date().toISOString();
978
-
979
- // Add to current model conversation if active
980
- if (recipient.currentModel && recipient.conversations[recipient.currentModel]) {
981
- recipient.conversations[recipient.currentModel].messages.push(directMessage);
982
- recipient.conversations[recipient.currentModel].lastUpdated = new Date().toISOString();
983
- }
984
-
985
- // Persist the updated state
986
- await agentPool.persistAgentState(recipientId);
987
-
988
- // Queue message using new architecture
989
- console.log(`📬 Queueing inter-agent message for scheduler processing`, {
990
- recipientId,
991
- sender: message.sender,
992
- subject: message.subject,
993
- hasSessionId: !!context.sessionId
994
- });
995
-
996
- await agentPool.addInterAgentMessage(recipientId, {
997
- id: message.id,
998
- messageId: message.id,
999
- sender: message.sender,
1000
- senderName: message.senderName,
1001
- subject: message.subject,
1002
- content: message.content,
1003
- attachments: message.attachments,
1004
- priority: message.priority,
1005
- requiresReply: message.requiresReply,
1006
- conversationId: message.conversationId,
1007
- sessionId: context.sessionId,
1008
- timestamp: new Date().toISOString()
1009
- });
1010
-
1011
- console.log(`Direct message injected and queued for processing: ${recipientId}`, {
1012
- messageId: message.id,
1013
- fromAgent: message.sender,
1014
- subject: message.subject,
1015
- priority: message.priority
1016
- });
1017
- }
1018
-
1019
- } catch (error) {
1020
- console.error(`Failed to notify agent ${recipientId}:`, error);
1021
- }
1022
- }
1023
- }
1024
-
1025
- /**
1026
- * Check if agent has replied to a message
1027
- * @private
1028
- */
1029
- _hasAgentReplied(agentId, message) {
1030
- for (const replyId of message.replies) {
1031
- const reply = this.messages.get(replyId);
1032
- if (reply && reply.sender === agentId) {
1033
- return true;
1034
- }
1035
- // Recursively check nested replies
1036
- if (reply && this._hasAgentReplied(agentId, reply)) {
1037
- return true;
1038
- }
1039
- }
1040
- return false;
1041
- }
1042
-
1043
- /**
1044
- * Get conversation depth
1045
- * @private
1046
- */
1047
- _getConversationDepth(conversationId) {
1048
- const conversation = this.conversations.get(conversationId);
1049
- if (!conversation) return 0;
1050
-
1051
- let maxDepth = 0;
1052
- const rootMessage = this.messages.get(conversation.rootMessageId);
1053
- if (rootMessage) {
1054
- maxDepth = this._getMessageDepth(rootMessage);
1055
- }
1056
-
1057
- return maxDepth;
1058
- }
1059
-
1060
- /**
1061
- * Get message depth recursively
1062
- * @private
1063
- */
1064
- _getMessageDepth(message, currentDepth = 0) {
1065
- if (message.replies.length === 0) {
1066
- return currentDepth;
1067
- }
1068
-
1069
- let maxDepth = currentDepth;
1070
- for (const replyId of message.replies) {
1071
- const reply = this.messages.get(replyId);
1072
- if (reply) {
1073
- const depth = this._getMessageDepth(reply, currentDepth + 1);
1074
- maxDepth = Math.max(maxDepth, depth);
1075
- }
1076
- }
1077
-
1078
- return maxDepth;
1079
- }
1080
-
1081
- /**
1082
- * Update message counts for agent
1083
- * @private
1084
- */
1085
- _updateMessageCounts(agentId, type) {
1086
- if (!this.agentMessageCounts.has(agentId)) {
1087
- this.agentMessageCounts.set(agentId, { sent: 0, received: 0 });
1088
- }
1089
-
1090
- const counts = this.agentMessageCounts.get(agentId);
1091
- if (type === 'sent') {
1092
- counts.sent++;
1093
- } else {
1094
- counts.received++;
1095
- }
1096
- }
1097
-
1098
- /**
1099
- * Generate unique message ID
1100
- * @private
1101
- */
1102
- _generateMessageId() {
1103
- return `msg-${Date.now()}-${crypto.randomBytes(4).toString('hex')}`;
1104
- }
1105
-
1106
- /**
1107
- * Generate unique conversation ID
1108
- * @private
1109
- */
1110
- _generateConversationId() {
1111
- return `conv-${Date.now()}-${crypto.randomBytes(4).toString('hex')}`;
1112
- }
1113
-
1114
- /**
1115
- * Generate unique attachment ID
1116
- * @private
1117
- */
1118
- _generateAttachmentId() {
1119
- return `att-${Date.now()}-${crypto.randomBytes(4).toString('hex')}`;
1120
- }
1121
-
1122
- /**
1123
- * Cleanup old messages and conversations
1124
- * Called periodically to prevent memory growth
1125
- */
1126
- async cleanup() {
1127
- const now = Date.now();
1128
- const retentionCutoff = now - this.config.messageRetentionPeriod;
1129
-
1130
- // Clean up old messages
1131
- for (const [messageId, message] of this.messages.entries()) {
1132
- const messageTime = new Date(message.timestamp).getTime();
1133
- if (messageTime < retentionCutoff) {
1134
- // Clean up attachments
1135
- for (const attachment of message.attachments) {
1136
- try {
1137
- await fs.unlink(attachment.storagePath);
1138
- } catch (error) {
1139
- // Ignore errors for missing files
1140
- }
1141
- }
1142
-
1143
- // Remove from inboxes
1144
- for (const [agentId, inbox] of this.agentInboxes.entries()) {
1145
- inbox.delete(messageId);
1146
- }
1147
-
1148
- this.messages.delete(messageId);
1149
- }
1150
- }
1151
-
1152
- // Clean up old conversations
1153
- for (const [conversationId, conversation] of this.conversations.entries()) {
1154
- const lastActivity = new Date(conversation.lastActivity).getTime();
1155
- if (lastActivity < retentionCutoff || conversation.status === 'ended') {
1156
- // Remove from agent conversations
1157
- for (const [agentId, convs] of this.agentConversations.entries()) {
1158
- convs.delete(conversationId);
1159
- }
1160
-
1161
- this.conversations.delete(conversationId);
1162
- }
1163
- }
1164
- }
1165
-
1166
- /**
1167
- * Broadcast message to WebSocket for UI visibility
1168
- * @private
1169
- */
1170
- async _broadcastToUI(message, eventType, context) {
1171
- try {
1172
- // Build a formatted message for UI display
1173
- const uiMessage = {
1174
- type: 'agent-communication',
1175
- eventType,
1176
- timestamp: message.timestamp,
1177
- messageId: message.id,
1178
- conversationId: message.conversationId,
1179
- sender: {
1180
- id: message.sender,
1181
- name: message.senderName
1182
- },
1183
- recipients: Object.entries(message.recipientNames || {}).map(([id, name]) => ({
1184
- id,
1185
- name
1186
- })),
1187
- subject: message.subject,
1188
- content: message.content,
1189
- priority: message.priority,
1190
- requiresReply: message.requiresReply,
1191
- hasAttachments: message.attachments && message.attachments.length > 0,
1192
- attachmentCount: message.attachments ? message.attachments.length : 0,
1193
- metadata: message.metadata
1194
- };
1195
-
1196
- // Try multiple broadcast methods
1197
- // Method 1: Through agentPool if available
1198
- if (context.agentPool && context.agentPool.messageProcessor) {
1199
- const messageProcessor = context.agentPool.messageProcessor;
1200
- if (messageProcessor && messageProcessor.orchestrator && messageProcessor.orchestrator.webServer) {
1201
- // Use broadcastToSession - it will fallback to all connections if session not found
1202
- messageProcessor.orchestrator.webServer.broadcastToSession(context.sessionId || 'web-session', {
1203
- type: 'agent-communication',
1204
- action: 'agent-communication',
1205
- data: uiMessage
1206
- });
1207
- return;
1208
- }
1209
- }
1210
-
1211
- // Method 2: Direct orchestrator access
1212
- if (context.orchestrator && context.orchestrator.webServer) {
1213
- context.orchestrator.webServer.broadcastToSession(context.sessionId || 'web-session', {
1214
- type: 'agent-communication',
1215
- action: 'agent-communication',
1216
- data: uiMessage
1217
- });
1218
- return;
1219
- }
1220
-
1221
- // Method 3: Through global reference (if set during initialization)
1222
- if (global.loxiaWebServer) {
1223
- global.loxiaWebServer.broadcastToSession(context.sessionId || 'web-session', {
1224
- type: 'agent-communication',
1225
- action: 'agent-communication',
1226
- data: uiMessage
1227
- });
1228
- }
1229
- } catch (error) {
1230
- // Don't fail the operation if broadcast fails
1231
- console.error('Failed to broadcast agent message to UI:', error);
1232
- }
1233
- }
1234
-
1235
- /**
1236
- * Check if sender can send message to recipient
1237
- * @private
1238
- */
1239
- async _canSendMessage(senderAgent, recipientId, context) {
1240
- const agentPool = context.agentPool;
1241
- const tracking = senderAgent.interAgentTracking;
1242
-
1243
- // Initialize tracking for this recipient if needed
1244
- if (!tracking.has(recipientId)) {
1245
- tracking.set(recipientId, {
1246
- lastSent: null,
1247
- lastReceived: null,
1248
- lastType: null
1249
- });
1250
- }
1251
-
1252
- const recipientTracking = tracking.get(recipientId);
1253
- const now = Date.now();
1254
- const MIN_INTERVAL = 60 * 1000; // 1 minute
1255
-
1256
- // Rule 1: Always allow if recipient has replied since our last message
1257
- if (recipientTracking.lastType === 'received' ||
1258
- (recipientTracking.lastReceived && recipientTracking.lastReceived > recipientTracking.lastSent)) {
1259
- return { allowed: true };
1260
- }
1261
-
1262
- // Rule 2: Allow if minimum time has passed since last send
1263
- if (recipientTracking.lastSent) {
1264
- const timeSinceLastSend = now - recipientTracking.lastSent;
1265
- if (timeSinceLastSend >= MIN_INTERVAL) {
1266
- return { allowed: true };
1267
- }
1268
-
1269
- // Calculate when next send is allowed
1270
- const nextAllowedTime = recipientTracking.lastSent + MIN_INTERVAL;
1271
- return {
1272
- allowed: false,
1273
- reason: `Must wait ${Math.ceil((nextAllowedTime - now) / 1000)}s since last message`,
1274
- waitUntil: nextAllowedTime
1275
- };
1276
- }
1277
-
1278
- // Rule 3: First message to this recipient is always allowed
1279
- return { allowed: true };
1280
- }
1281
-
1282
- /**
1283
- * Update conversation tracking after message sent/received
1284
- * @private
1285
- */
1286
- async _updateConversationTracking(senderAgentId, recipientId, action, context) {
1287
- const agentPool = context.agentPool;
1288
- const senderAgent = await agentPool.getAgent(senderAgentId);
1289
- if (!senderAgent) return;
1290
-
1291
- const now = Date.now();
1292
-
1293
- // Update sender's tracking
1294
- if (!senderAgent.interAgentTracking.has(recipientId)) {
1295
- senderAgent.interAgentTracking.set(recipientId, {
1296
- lastSent: null,
1297
- lastReceived: null,
1298
- lastType: null
1299
- });
1300
- }
1301
-
1302
- const tracking = senderAgent.interAgentTracking.get(recipientId);
1303
-
1304
- if (action === 'sent') {
1305
- tracking.lastSent = now;
1306
- tracking.lastType = 'sent';
1307
- } else if (action === 'replied') {
1308
- tracking.lastSent = now;
1309
- tracking.lastType = 'sent'; // Reply is still a send action
1310
- }
1311
-
1312
- // Update recipient's tracking (they received a message)
1313
- const recipientAgent = await agentPool.getAgent(recipientId);
1314
- if (recipientAgent) {
1315
- if (!recipientAgent.interAgentTracking.has(senderAgentId)) {
1316
- recipientAgent.interAgentTracking.set(senderAgentId, {
1317
- lastSent: null,
1318
- lastReceived: null,
1319
- lastType: null
1320
- });
1321
- }
1322
-
1323
- const recipientTracking = recipientAgent.interAgentTracking.get(senderAgentId);
1324
- recipientTracking.lastReceived = now;
1325
- recipientTracking.lastType = 'received';
1326
-
1327
- // Persist recipient agent state
1328
- await agentPool.persistAgentState(recipientId);
1329
- }
1330
-
1331
- // Persist sender agent state
1332
- await agentPool.persistAgentState(senderAgentId);
1333
- }
1334
-
1335
- /**
1336
- * Set message processor for broadcasting
1337
- * Called during tool initialization
1338
- */
1339
- setMessageProcessor(messageProcessor) {
1340
- this.messageProcessor = messageProcessor;
1341
- }
1342
- }
1343
-
1344
- export default AgentCommunicationTool;
1
+ const a0_0x2966dd=a0_0x350f;function a0_0x1e73(){const _0x38dbb5=['ndKYnZaYm3feA0Tpva','CgfYC2u','rMfPBgvKihrVihbYB2nLC3mGyxr0ywnOBwvUDdOG','Bwf4qxr0ywnOBwvUDhnqzxjnzxnZywDL','ChjPB3jPDhK','q29UC2LKzxiGBwfYA2LUzYb0AgLZignVBNzLCNnHDgLVBIbHCYbLBMrLzcbHBMqGC3rHCNrPBMCGzNjLC2GGAwyGBMvLzgvKlG','CMvHC29U','DhjPBq','ww91igfYzsbUB3qGysbWyxj0AwnPCgfUDcbPBIb0AgLZignVBNzLCNnHDgLVBG','zxjYB3i','CMfUzg9TqNL0zxm','ywDLBNrnzxnZywDLq291BNrZ','D2vIu2vYDMvY','CMvJzwL2zwq','ywrK','BM90Awz5qwDLBNq','C3rVCMfNzurPCG','cKfNzw50ienVBw11BMLJyxrPB24Gvg9VBdOGrw5HyMXLCYbJB21TDw5Py2f0Aw9UigjLDhDLzw4Gywn0AxzLigfNzw50CYbPBIb0AguGC3LZDgvTlGOkqxzHAwXHyMXLiefJDgLVBNm6cI0Gz2v0lwf2ywLSywjSzs1Hz2vUDhm6ieXPC3qGywXSigfJDgL2zsbHz2vUDhmGEw91ignHBIbJB21TDw5Py2f0zsb3AxrOcI0GC2vUzc1TzxnZywDLoIbtzw5KigeGBwvZC2fNzsb0BYbHBM90AgvYigfNzw50ihDPDgGGB3b0Aw9UywWGyxr0ywnOBwvUDhmklsbYzxbSEs10BY1TzxnZywDLoIbszxbSEsb0BYbHihjLy2vPDMvKig1LC3nHz2uklsbNzxqTDw5YzxbSAwvKlw1LC3nHz2vZoIbhzxqGBgLZDcbVzIbTzxnZywDLCYbYzxf1AxjPBMCGEw91CIbYzxnWB25ZzqOTig1HCMSTy29UDMvYC2f0Aw9UlwvUzgvKoIbnyxjRigeGy29UDMvYC2f0Aw9UigfZignVBxbSzxrLl2rPC3jLz2fYzgvKcGPvC2fNzsbfEgfTCgXLCYaOyM90AcbytuWGyw5KiePtt04GzM9YBwf0CYbZDxbWB3j0zwqPoGOkms4Gr2v0igf2ywLSywjSzsbHz2vUDhmGkfHntcbMB3jTyxqPoGPBDg9VBf0kpgfJDgLVBJ5NzxqTyxzHAwXHyMXLlwfNzw50CZWVywn0Aw9UpGPBl3rVB2XDcGOXyI4Gr2v0igf2ywLSywjSzsbHz2vUDhmGkePtt04GzM9YBwf0ktOkEYjHy3rPB25ZiJOGw3SIDhLWzsi6icjNzxqTyxzHAwXHyMXLlwfNzw50CYj9xx0kcKjVDgGGCMv0DxjUigeGsLnptIbYzxnWB25ZzsbSAwTLoGP7cIaGiNn1y2nLC3mIoIb0CNvLlaOGicjHz2vUDhmIoIbBcIaGicb7cIaGicaGicjPzci6icjHz2vUDc1HBgLJzs0XnZu1mteXnJe2mJe0iIWkicaGicaGiM5HBwuIoIaIywXPy2uIlaOGicaGicaIy2fWywjPBgL0AwvZiJOGwYj0zxjTAw5HBciSicjMAwXLC3LZDgvTiIWGlI4UxsWkicaGicaGiNn0yxr1CYi6icjHy3rPDMuIcIaGicb9cIaGxqP9cGPmB29RigzVCIb0AguGiMLKiIbMAwvSzcbPBIbLywnOigfNzw50ig9IAMvJDcaTihrOAxmGAxmGD2HHDcb5B3uGDxnLigfZihrOzsbYzwnPCgLLBNqUcGOYlIbtzw5KigeGBwvZC2fNzsaOwe1migzVCM1HDcK6cLT0B29SxqO8ywn0Aw9UpNnLBMqTBwvZC2fNztWVywn0Aw9UpGO8CMvJAxbPzw50pMfNzw50lwz1BgXZDgfJAY1KzxzLBg9WzxiTywDLBNqTmtiZndu2nZG5mdeYmZWVCMvJAxbPzw50pGO8C3vIAMvJDd5ozwvKigfZC2LZDgfUy2uGD2L0AcbJB2rLihjLDMLLDZWVC3vIAMvJDd4kpg1LC3nHz2u+q291BgqGEw91ihjLDMLLDYb0AguGyxv0AgvUDgLJyxrPB24GBw9KDwXLieKGANvZDcbPBxbSzw1LBNrLzd88l21LC3nHz2u+cJXWCMLVCML0Et5UB3jTywW8l3bYAw9YAxr5pGO8CMvXDwLYzxmTCMvWBhK+Dhj1ztWVCMvXDwLYzxmTCMvWBhK+cLSVDg9VBf0kcJjIlIbtzw5KigeGBwvZC2fNzsaOsLnptIbMB3jTyxqPoGP7iMfJDgLVBNmIoIbBEYj0ExbLiJOGiNnLBMqTBwvZC2fNzsiSicjYzwnPCgLLBNqIoIaIywDLBNqTzNvSBhn0ywnRlwrLDMvSB3bLCI1Hz2vUDc0XmJm0nty3odKWmtiZiIWGiNn1yMPLy3qIoIaItMvLzcbHC3nPC3rHBMnLihDPDgGGy29KzsbYzxzPzxCIlcaIBwvZC2fNzsi6icjdB3vSzcb5B3uGCMv2Awv3ihrOzsbHDxrOzw50AwnHDgLVBIbTB2r1BguGssbQDxn0igLTCgXLBwvUDgvKpYiSicjWCMLVCML0Esi6icjUB3jTywWIlcaICMvXDwLYzxmTCMvWBhKIoIb0CNvLFv19cGPjtvbpuLrbtLq6iefSD2f5CYb1C2uGDgHLigz1BgWGywDLBNqGsuqGkgXPA2uGiMfNzw50lwz1BgXZDgfJAY1KzxzLBg9WzxiTywDLBNqTmtiZndu2nZG5mdeYmYiPigfZihrOzsbYzwnPCgLLBNqSig5VDcbQDxn0ihrOzsbUyw1LlIbhzxqGDgHLigv4ywn0ieLeigzYB20Gz2v0lwf2ywLSywjSzs1Hz2vUDhmGzMLYC3qUcGOZlIbtzw5KihDPDgGGyxr0ywnOBwvUDhmGkfHntcbMB3jTyxqPoGPBDg9VBf0kpgfJDgLVBJ5Zzw5Klw1LC3nHz2u8l2fJDgLVBJ4kphjLy2LWAwvUDd5Hz2vUDc1Pzc00nty8l3jLy2LWAwvUDd4kphn1yMPLy3q+qw5HBhLZAxmGCMvZDwX0CZWVC3vIAMvJDd4kpg1LC3nHz2u+sgvYzsbHCMuGDgHLihrLC3qGCMvZDwX0CYb5B3uGCMvXDwvZDgvKpc9TzxnZywDLpGO8yxr0ywnOBwvUDhm+w3SICgf0Aci6iciVCMvWB3j0CY90zxn0lxjLC3vSDhmUCgrMiIWGiNr5CguIoIaICgrMiN1Dpc9HDhrHy2HTzw50CZ4kwY90B29SxqOknc4GuMvWBhKGDg8GysbTzxnZywDLoGPBDg9VBf0kpgfJDgLVBJ5YzxbSEs10BY1TzxnZywDLpc9Hy3rPB24+cJXTzxnZywDLlwLKpM1ZzY03odK8l21LC3nHz2uTAwq+cJXTzxnZywDLpLrOyw5RCYbMB3iGDgHLihjLDMLLDY4GssD2zsbHzgrYzxnZzwqGywXSihLVDxiGy29TBwvUDhmUpc9TzxnZywDLpGO8y2mTCMvJAxbPzw50CZ5BiMfNzw50lwLKlteXmsjDpc9JyY1YzwnPCgLLBNrZpGPBl3rVB2XDcGO1lIbhzxqGDw5YzxbSAwvKig1LC3nHz2vZoGPBDg9VBf0kpgfJDgLVBJ5NzxqTDw5YzxbSAwvKlw1LC3nHz2vZpc9Hy3rPB24+cJXPBMnSDwrLlwXVDY1WCMLVCML0Et5MywXZztWVAw5JBhvKzs1SB3CTChjPB3jPDhK+cLSVDg9VBf0kcJyUievUzcbHignVBNzLCNnHDgLVBJOkw3rVB2XDcJXHy3rPB24+BwfYAY1JB252zxjZyxrPB24Tzw5Kzwq8l2fJDgLVBJ4kpgnVBNzLCNnHDgLVBI1Pzd5JB252lxH5EJWVy29UDMvYC2f0Aw9UlwLKpGO8CMvHC29UpLrHC2SGy29TCgXLDgvKihn1y2nLC3nMDwXSEtWVCMvHC29UpGPBl3rVB2XDcGPtywzLDhKGr3vPzgvSAw5LCZOklsbnyxHPBxvTia','BwfW','B3jJAgvZDhjHDg9Y','C2vUzgvY','C2vUzc1TzxnZywDL','C3rHCNrZv2L0Aa','CMvJAxbPzw50','C2v0','ig1PBNv0zxmGB2yGAw5Hy3rPDML0EqOTief2B2LKihjLCgX5lwfSBcb1BMXLC3mGBMvJzxnZyxj5ihrVihbYzxzLBNqGBwvZC2fNzsbZDg9YBxmklsbnyxjRignVBNzLCNnHDgLVBNmGyxmGzw5KzwqGD2HLBIbNB2fSCYbHCMuGywnOAwv2zwqkcKLTCg9YDgfUDcboB3rLCZOklsbnzxnZywDLCYbHCMuGzgvSAxzLCMvKigfZEw5JAhjVBM91C2X5cI0Gqxr0ywnOBwvUDhmGBxvZDcbIzsbYzwfKywjSzsbMAwXLCYb1BMrLCIa','C3rVCMfNzvbHDgG','x2DLDenVBNzLCNnHDgLVBKrLChrO','BwfYA0nVBNzLCNnHDgLVBKvUzgvK','t3jPz2LUywWGBwvZC2fNzsbUB3qGzM91BMq6ia','y2fWywjPBgL0AwvZ','ntGZmtGYnKjpwMHxzW','BwvZC2fNzunVDw50','CM9VDe1LC3nHz2vjza','AxnbCNjHEq','C2vUzgvYtMfTzq','kIPbDhrHy2HTzw50CZOQkIa','CMvWBgLLCW','CgvYC2LZDefNzw50u3rHDgu','y3vYCMvUDe1VzgvS','vw5RBM93BIbHy3rPB246ia','Cgf0Aa','BwvZC2fNzvbYB2nLC3nVCG','rMfPBgvKihrVigjYB2fKy2fZDcbHz2vUDcbTzxnZywDLihrVifvjoG','CMvXDwLYzxnszxbSEq','C29YDa','x3vWzgf0zu1LC3nHz2vdB3vUDhm','z2v0','y29UDI0','C2vUDa','z2v0vw5YzxbSAwvKtwvZC2fNzxm','lI4U','Bg93','x2DLDe1LC3nHz2vezxb0Aa','mtiYzNvswhLn','ywn0Aw9U','cIOQuMvXDwLYzxmGuMvWBhK6kIOG','DxbKyxrLqwDLBNq','x2DLBMvYyxrLqxr0ywnOBwvUDeLK','x25VDgLMEvjLy2LWAwvUDhm','zNvSBa','mZjJEvjhDMi','8j+tRcbrDwv1zwLUzYbPBNrLCI1Hz2vUDcbTzxnZywDLigzVCIbZy2HLzhvSzxiGChjVy2vZC2LUzW','BgfZDfnLBNq','rMfPBgvKihrVig5VDgLMEsbHz2vUDca','ihjLy2LWAwvUDhmGCgvYig1LC3nHz2uklsbdB252zxjZyxrPB25Zigf1Dg8TzxHWAxjLigfMDgvYia','twf4Aw11Bsa','ywDLBNrqB29S','z2v0vgLTzq','z2v0lwf2ywLSywjSzs1Hz2vUDhm','BwvZC2fNzxm','BgvUz3rO','CgfYC2vqyxjHBwv0zxjZ','CgfYDgLJAxbHBNrZ','Dw5SAw5R','zw5Kzwq','BgLZDefJDgL2zufNzw50CW','Bwf4','Bg9N','Bwf4q29UDMvYC2f0Aw9UrgvWDgG','x2DLBMvYyxrLtwvZC2fNzuLK','qxr0ywnOBwvUDcbLEgnLzwrZihnPEMuGBgLTAxq6ia','z2v0qxzHAwXHyMXLqwDLBNrZ','ywDLBNqTy29TBxvUAwnHDgLVBG','x3bHCNnLuMvJAxbPzw50CW','y29UDgvUDa','zw5KuMvHC29U','8j+tQcbozxCGBwvZC2fNzsbMCM9Tia','x2jYB2fKy2fZDfrVvuK','y29UDMvYC2f0Aw9UCW','CMvWBgfJzq','Dg9vChbLCKnHC2u','y29UzMLN','ntaWmZeZofnUu2rqvW','y29UDMvYC2f0Aw9UlwLK','x2LUAxrPywXPEMvtDg9YywDL','x2nHBLnLBMrnzxnZywDL','y2vPBa','q29UDMvYC2f0Aw9UigvUzgvKigj5igfNzw50','y29UDMvYC2f0Aw9UrgvWDgHZ','Dhj1zq','BxnNlq','qwDLBNqGq29TBxvUAwnHDgLVBG','q29UDMvYC2f0Aw9Uig5VDcbMB3vUzdOG','Dw5RBM93BG','mJeZotnNDwvZEu4','Bwf0y2G','zMLSDgvY','x3bYB2nLC3nbDhrHy2HTzw50CW','zMfSC2u','CMvWBhKTDg8TBwvZC2fNzq','BwvZC2fNzq','y29UDMvYC2f0Aw9Uswq','CMvJAxbPzw50tMfTzxm','AgfZ','C3rYAw5N','C2vUze1LC3nHz2u','BgfZDefJDgL2Axr5','D2vIlxnLC3nPB24','ihjLy2LWAwvUDhmGywXSB3DLza','uMu6ia','BgfZDfr5Cgu','cIOQuhjPB3jPDhK6kIOG','x2HHC0fNzw50uMvWBgLLza','tuiklsbvC2uGy2XLyxiGC3vIAMvJDhmGDg8GAgvSCcbYzwnPCgLLBNrZihbYAw9YAxrPEMuklsbdAgvJAYb1BNjLCgXPzwqGBwvZC2fNzxmGCMvNDwXHCMX5ihrVig1HAw50ywLUignVBw11BMLJyxrPB24GzMXVDWO','Dg9tDhjPBMC','BMfTzq','Aw50zxjbz2vUDfrYywnRAw5N','C2vZC2LVBKLK','kqOQkLn1yMPLy3q6kIOG','Bwf0y2HbBgW','yxr0ywnOBwvUDhm','B2jQzwn0','CMvJAxbPzw50CW','zw50CMLLCW','DgLTzxn0yw1W','z2v0qwDLBNq','BgfZDfjLy2vPDMvK','zgvSzxrL','BwfYAY1YzxnVBhzLza','ntCXnda1BuLqChPd','Bwf4uMvJAxbPzw50C1bLCK1LC3nHz2u','Aw5JBhvKzxm','DhLWzq','8j+tQcaQkKLUDgvYlufNzw50ie1LC3nHz2uQkGOQkKzYB206kIOG','ndq0ndy1nKThrxncEq','ywDLBNrdB252zxjZyxrPB25Z','ywn0Aw9UCW','CMvJAxbPzw50swq','x3vWzgf0zunVBNzLCNnHDgLVBLrYywnRAw5N','u2vUzgvYigfNzw50ig5VDcbMB3vUza','BM93','ywDLBNrjBMjVEgvZ','Dg9ju09tDhjPBMC','yNjVywrJyxn0vg9tzxnZAw9U','C3rHDa','rgLYzwn0ig1LC3nHz2uGAw5Qzwn0zwqGyw5Kihf1zxvLzcbMB3iGChjVy2vZC2LUzZOG','BwvZC2fNzvjLDgvUDgLVBLbLCMLVza','C3rHDhvZ','odqWotuXt1LICMHm','ChvZAa','BwfYAY1JB252zxjZyxrPB24Tzw5Kzwq','C2L6zq','zxH0BMfTzq','C3vIAMvJDa','Bwf4qxr0ywnOBwvUDfnPEMu','qwDLBNqGCg9VBcbUB3qGyxzHAwXHyMXLigLUignVBNrLEhq','AM9PBG','v2fPDgLUzYa','qwDLBNqGsuqGAxmGCMvXDwLYzwqGAw4Gy29UDgv4Da'];a0_0x1e73=function(){return _0x38dbb5;};return a0_0x1e73();}(function(_0x182388,_0x471e90){const _0x3082b6=a0_0x350f,_0x512d94=_0x182388();while(!![]){try{const _0x15de22=-parseInt(_0x3082b6(0x6c))/0x1+parseInt(_0x3082b6(0xad))/0x2*(parseInt(_0x3082b6(0xe0))/0x3)+-parseInt(_0x3082b6(0xb4))/0x4*(-parseInt(_0x3082b6(0x103))/0x5)+parseInt(_0x3082b6(0x96))/0x6+-parseInt(_0x3082b6(0xd4))/0x7+parseInt(_0x3082b6(0x108))/0x8+-parseInt(_0x3082b6(0x77))/0x9;if(_0x15de22===_0x471e90)break;else _0x512d94['push'](_0x512d94['shift']());}catch(_0x369ac9){_0x512d94['push'](_0x512d94['shift']());}}}(a0_0x1e73,0xbce1c));import{BaseTool}from'./baseTool.js';import{promises as a0_0x5a8f0d}from'fs';function a0_0x350f(_0x351a13,_0x108c2c){_0x351a13=_0x351a13-0x66;const _0x1e7330=a0_0x1e73();let _0x350f0e=_0x1e7330[_0x351a13];if(a0_0x350f['SQLuyn']===undefined){var _0x2be18e=function(_0x18c9e1){const _0x3c5224='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=';let _0x5a8f0d='',_0x1de5db='';for(let _0x565a6b=0x0,_0x1054c3,_0x508974,_0x54590a=0x0;_0x508974=_0x18c9e1['charAt'](_0x54590a++);~_0x508974&&(_0x1054c3=_0x565a6b%0x4?_0x1054c3*0x40+_0x508974:_0x508974,_0x565a6b++%0x4)?_0x5a8f0d+=String['fromCharCode'](0xff&_0x1054c3>>(-0x2*_0x565a6b&0x6)):0x0){_0x508974=_0x3c5224['indexOf'](_0x508974);}for(let _0x1e3277=0x0,_0x57f175=_0x5a8f0d['length'];_0x1e3277<_0x57f175;_0x1e3277++){_0x1de5db+='%'+('00'+_0x5a8f0d['charCodeAt'](_0x1e3277)['toString'](0x10))['slice'](-0x2);}return decodeURIComponent(_0x1de5db);};a0_0x350f['rkThQp']=_0x2be18e,a0_0x350f['yJprUr']={},a0_0x350f['SQLuyn']=!![];}const _0x24acaa=_0x1e7330[0x0],_0x9a2829=_0x351a13+_0x24acaa,_0x175013=a0_0x350f['yJprUr'][_0x9a2829];return!_0x175013?(_0x350f0e=a0_0x350f['rkThQp'](_0x350f0e),a0_0x350f['yJprUr'][_0x9a2829]=_0x350f0e):_0x350f0e=_0x175013,_0x350f0e;}import a0_0x1de5db from'path';import a0_0x565a6b from'crypto';class AgentCommunicationTool extends BaseTool{constructor(_0x1054c3={}){const _0x305fba=a0_0x350f;super('agentcommunication',_0x305fba(0xdd),'communication'),this['config']={'maxConversationDepth':_0x1054c3[_0x305fba(0xc6)]||0xa,'maxRecipientsPerMessage':_0x1054c3['maxRecipientsPerMessage']||0x3,'maxAttachmentSize':_0x1054c3[_0x305fba(0x72)]||0xa*0x400*0x400,'maxAttachmentsPerMessage':_0x1054c3[_0x305fba(0x7a)]||0x5,'conversationTimeout':_0x1054c3['conversationTimeout']||0x36ee80,'messageRetentionPeriod':_0x1054c3[_0x305fba(0x6a)]||0x5265c00,'enableBroadcast':_0x1054c3['enableBroadcast']||![],'storageDir':_0x1054c3['storageDir']||'.loxia-messages'},this[_0x305fba(0xbd)]=new Map(),this[_0x305fba(0xd0)]=new Map(),this[_0x305fba(0x10f)]=new Map(),this['agentConversations']=new Map(),this[_0x305fba(0xda)]=new Map(),this['lastActivityTimes']=new Map(),this['agentMessageCounts']=new Map(),this['_initializeStorage']();}['getDescription'](){const _0x4b8880=a0_0x350f;return(_0x4b8880(0x88)+this['config'][_0x4b8880(0xc6)]+'\x20replies\x20per\x20conversation\x20thread\x0a-\x20Maximum\x20'+this[_0x4b8880(0xd3)][_0x4b8880(0x104)]+_0x4b8880(0xb8)+this['config']['conversationTimeout']/0xea60+_0x4b8880(0x90)+this['config']['maxAttachmentSize']/0x400/0x400+_0x4b8880(0xf3))[_0x4b8880(0x7e)]();}[a0_0x2966dd(0xbf)](_0x508974){const _0x4580ab=a0_0x2966dd;if(typeof _0x508974===_0x4580ab(0xfb)&&_0x508974!==null){if(_0x508974['actions']&&Array[_0x4580ab(0x99)](_0x508974['actions'])&&_0x508974[_0x4580ab(0x10a)][_0x4580ab(0xbe)]>0x0){const _0x54590a=_0x508974[_0x4580ab(0x10a)][0x0];return{'action':_0x54590a[_0x4580ab(0x106)],..._0x54590a};}else{if(_0x508974['action']||_0x508974['type'])return{'action':_0x508974[_0x4580ab(0xae)]||_0x508974[_0x4580ab(0x106)],..._0x508974};}return _0x508974;}if(typeof _0x508974===_0x4580ab(0xea)){if(_0x508974['trim']()['startsWith']('{'))try{const _0x4a956b=JSON[_0x4580ab(0x78)](_0x508974);return this[_0x4580ab(0xbf)](_0x4a956b);}catch(_0x1cc630){}const _0x1e3277={},_0x57f175=_0x508974[_0x4580ab(0xe1)](/<action[^>]*>([^<]+)<\/action>/);_0x57f175&&(_0x1e3277[_0x4580ab(0xae)]=_0x57f175[0x1]['trim']());const _0x3c8b8b=[_0x4580ab(0x8e),_0x4580ab(0xfc),'subject',_0x4580ab(0xe6),'attachments',_0x4580ab(0x7b),'requires-reply','message-id','cc-recipients','include-low-priority',_0x4580ab(0xd5),'reason',_0x4580ab(0x102)];for(const _0x11df44 of _0x3c8b8b){const _0x4c9fed=new RegExp('<'+_0x11df44['replace']('-','\x5c-')+'[^>]*>(.*?)<\x5c/'+_0x11df44[_0x4580ab(0xd1)]('-','\x5c-')+'>','s'),_0x5a972f=_0x508974[_0x4580ab(0xe1)](_0x4c9fed);if(_0x5a972f){let _0x1c5ec2=_0x5a972f[0x1][_0x4580ab(0x7e)]();if(_0x1c5ec2[_0x4580ab(0x8d)]('[')||_0x1c5ec2['startsWith']('{')||_0x1c5ec2===_0x4580ab(0xdb)||_0x1c5ec2===_0x4580ab(0xe4))try{_0x1c5ec2=JSON['parse'](_0x1c5ec2);}catch{}const _0x3bacba=_0x11df44['replace'](/-(.)/g,(_0x22202e,_0x262dc0)=>_0x262dc0['toUpperCase']());_0x1e3277[_0x3bacba]=_0x1c5ec2;}}const _0x36b00b=_0x508974['match'](/<action([^>]*)>([^<]+)<\/action>/);if(_0x36b00b&&_0x36b00b[0x1]){const _0x1ba467=_0x36b00b[0x1][_0x4580ab(0xf9)](/([\w-]+)=["']([^"']+)["']/g);for(const _0x3cb7af of _0x1ba467){const _0x5ad7ad=_0x3cb7af[0x1][_0x4580ab(0xd1)](/-(.)/g,(_0x3186f0,_0x4d7160)=>_0x4d7160[_0x4580ab(0xd2)]());_0x1e3277[_0x5ad7ad]=_0x3cb7af[0x2];}}return _0x1e3277;}return _0x508974||{};}async['execute'](_0x1d203b={},_0x4ba86e={}){const _0x15806f=a0_0x2966dd,{action:_0x58d338}=_0x1d203b;if(!_0x58d338)throw new Error('Action\x20parameter\x20is\x20required');const _0x4e38a7=_0x4ba86e['agentId'];if(!_0x4e38a7)throw new Error(_0x15806f(0x76));switch(_0x58d338['toLowerCase']()){case _0x15806f(0xbc):return await this[_0x15806f(0xc9)](_0x4e38a7,_0x1d203b,_0x4ba86e);case _0x15806f(0x8c):return await this['sendMessage'](_0x4e38a7,_0x1d203b,_0x4ba86e);case _0x15806f(0xe5):return await this['replyToMessage'](_0x4e38a7,_0x1d203b,_0x4ba86e);case'get-unreplied-messages':return await this[_0x15806f(0xa9)](_0x4e38a7,_0x1d203b,_0x4ba86e);case _0x15806f(0x6e):return await this[_0x15806f(0x93)](_0x4e38a7,_0x1d203b,_0x4ba86e);default:throw new Error(_0x15806f(0x9f)+_0x58d338);}}async[a0_0x2966dd(0xc9)](_0x656dfc,_0x4e87a6,_0x403f2d){const _0x4894a5=a0_0x2966dd;try{const _0x14f30d=_0x403f2d[_0x4894a5(0xba)];if(!_0x14f30d)throw new Error(_0x4894a5(0x73));const _0x471067=await _0x14f30d[_0x4894a5(0xc3)](),_0x5302c5=_0x471067[_0x4894a5(0xe2)](_0x18fb55=>_0x18fb55['id']!==_0x656dfc&&!_0x18fb55['isPaused'])[_0x4894a5(0x89)](_0xb6ac32=>({'id':_0xb6ac32['id'],'name':_0xb6ac32['name'],'type':_0xb6ac32[_0x4894a5(0x106)],'capabilities':_0xb6ac32['capabilities'],'status':_0xb6ac32[_0x4894a5(0x6b)],'messageStats':this[_0x4894a5(0x82)][_0x4894a5(0xa6)](_0xb6ac32['id'])||{'sent':0x0,'received':0x0},'activeConversations':(this['agentConversations']['get'](_0xb6ac32['id'])||new Set())['size']}));return{'success':!![],'agents':_0x5302c5,'totalActive':_0x5302c5[_0x4894a5(0xbe)],'timestamp':new Date()[_0x4894a5(0x66)]()};}catch(_0xea9fa8){return{'success':![],'error':_0xea9fa8['message']};}}async[a0_0x2966dd(0xeb)](_0x9851ec,_0x4bcfdc,_0x246d96){const _0x311a60=a0_0x2966dd;try{const {recipient:_0x32b300,recipients:_0x1b2450,subject:_0x50682a,message:_0x1adbaf,attachments:_0xa690e1,priority:priority='normal','requires-reply':requiresReply=![]}=_0x4bcfdc;if(!_0x50682a||!_0x1adbaf)throw new Error('Subject\x20and\x20message\x20are\x20required');const _0x514c62=this[_0x311a60(0xcb)](_0x32b300,_0x1b2450);if(_0x514c62[_0x311a60(0xbe)]===0x0)throw new Error('At\x20least\x20one\x20recipient\x20is\x20required');if(_0x514c62['length']>this[_0x311a60(0xd3)][_0x311a60(0x104)])throw new Error('Maximum\x20'+this['config']['maxRecipientsPerMessage']+'\x20recipients\x20allowed');const _0x1312d6=_0x246d96[_0x311a60(0xba)],_0x107ebf=await _0x1312d6[_0x311a60(0xff)](_0x9851ec);if(!_0x107ebf)throw new Error(_0x311a60(0x10d));const _0x1210a2=[];for(const _0x32817f of _0x514c62){const _0xea5eb3=await this[_0x311a60(0xd7)](_0x107ebf,_0x32817f,_0x246d96);!_0xea5eb3['allowed']&&_0x1210a2['push']({'recipientId':_0x32817f,'reason':_0xea5eb3[_0x311a60(0x7d)],'waitUntil':_0xea5eb3['waitUntil']});}if(_0x1210a2[_0x311a60(0xbe)]>0x0){const _0x5a0a1b=Math['max'](..._0x1210a2[_0x311a60(0x89)](_0x54f665=>_0x54f665['waitUntil']||0x0)),_0x540ddf=new Date(_0x5a0a1b);await _0x1312d6[_0x311a60(0xb0)](_0x9851ec,{'delayEndTime':_0x540ddf['toISOString']()});const _0x1058c6=Math[_0x311a60(0xd8)]((_0x5a0a1b-Date['now']())/0x3e8);return{'success':!![],'delayed':!![],'delayUntil':_0x540ddf['toISOString'](),'delaySeconds':_0x1058c6,'message':_0x311a60(0x75)+_0x1058c6+'s\x20before\x20next\x20message.\x20Recipients\x20need\x20time\x20to\x20respond.','blockedRecipients':_0x1210a2['map'](_0x3515ac=>({'recipientId':_0x3515ac[_0x311a60(0x10b)],'reason':_0x3515ac['reason']}))};}const _0x3ab58c={},_0xdd5241=[];for(const _0x410907 of _0x514c62){const _0x5006a9=await _0x1312d6['getAgent'](_0x410907);!_0x5006a9?_0xdd5241[_0x311a60(0x6d)](_0x410907):_0x3ab58c[_0x410907]=_0x5006a9[_0x311a60(0xf5)];}if(_0xdd5241[_0x311a60(0xbe)]>0x0){const _0x504e93=await _0x1312d6['listActiveAgents'](),_0x333e60=_0x504e93['filter'](_0x41f050=>_0x41f050['id']!==_0x9851ec&&!_0x41f050['isPaused'])['map'](_0x313b3f=>'-\x20'+_0x313b3f['name']+'\x20(ID:\x20'+_0x313b3f['id']+')')['join']('\x0a');return{'success':![],'error':'Recipient\x20agent(s)\x20not\x20found:\x20'+_0xdd5241[_0x311a60(0x74)](',\x20'),'suggestion':'Available\x20agents\x20you\x20can\x20message:\x0a'+_0x333e60,'availableAgents':_0x504e93[_0x311a60(0x89)](_0x7ececb=>({'id':_0x7ececb['id'],'name':_0x7ececb['name'],'capabilities':_0x7ececb[_0x311a60(0x95)]}))};}const _0x532ec6=_0x107ebf?_0x107ebf['name']:_0x9851ec,processedAttachments=await this['_processAttachments'](_0xa690e1,_0x9851ec),_0x1bb1b5=this['_generateMessageId'](),_0x2d94cb=this['_generateConversationId'](),_0x3d8132=new Date()[_0x311a60(0x66)](),_0xe36366={'id':_0x1bb1b5,'conversationId':_0x2d94cb,'sender':_0x9851ec,'senderName':_0x532ec6,'recipients':_0x514c62,'recipientNames':_0x3ab58c,'subject':_0x50682a,'content':_0x1adbaf,'attachments':processedAttachments,'priority':priority,'requiresReply':requiresReply,'timestamp':_0x3d8132,'status':_0x311a60(0xa8),'replies':[],'metadata':{'depth':0x0,'isRoot':!![]}};this[_0x311a60(0xbd)][_0x311a60(0x8f)](_0x1bb1b5,_0xe36366),this['conversations']['set'](_0x2d94cb,{'id':_0x2d94cb,'rootMessageId':_0x1bb1b5,'participants':[_0x9851ec,..._0x514c62],'startTime':_0x3d8132,'lastActivity':_0x3d8132,'status':'active','messageCount':0x1});for(const _0x23af0e of _0x514c62){!this['agentInboxes'][_0x311a60(0xe9)](_0x23af0e)&&this['agentInboxes']['set'](_0x23af0e,new Set()),this[_0x311a60(0x10f)]['get'](_0x23af0e)[_0x311a60(0x85)](_0x1bb1b5),!this[_0x311a60(0x109)][_0x311a60(0xe9)](_0x23af0e)&&this[_0x311a60(0x109)][_0x311a60(0x8f)](_0x23af0e,new Set()),this['agentConversations']['get'](_0x23af0e)[_0x311a60(0x85)](_0x2d94cb);}!this['agentConversations']['has'](_0x9851ec)&&this['agentConversations']['set'](_0x9851ec,new Set());this[_0x311a60(0x109)][_0x311a60(0xa6)](_0x9851ec)['add'](_0x2d94cb),this[_0x311a60(0xa5)](_0x9851ec,'sent');for(const _0x40e66f of _0x514c62){this[_0x311a60(0xa5)](_0x40e66f,_0x311a60(0x84));}for(const _0x3ad7fa of _0x514c62){await this[_0x311a60(0x10c)](_0x9851ec,_0x3ad7fa,'sent',_0x246d96);}return await this[_0x311a60(0xb2)](_0xe36366,_0x246d96),await this[_0x311a60(0xcf)](_0xe36366,'agent-message-sent',_0x246d96),{'success':!![],'messageId':_0x1bb1b5,'conversationId':_0x2d94cb,'recipients':_0x514c62,'timestamp':_0x3d8132,'message':'Message\x20sent\x20successfully'};}catch(_0x4a23fa){return{'success':![],'error':_0x4a23fa[_0x311a60(0xe6)]};}}async['replyToMessage'](_0x523044,_0x5bbf1c,_0x22409c){const _0x1fcfae=a0_0x2966dd;try{const {'message-id':_0x4d027b,message:_0x4d5db6,'cc-recipients':_0x2ac547,attachments:_0xc4f456,'mark-resolved':_0x438d1a=![]}=_0x5bbf1c;if(!_0x4d027b||!_0x4d5db6)throw new Error('Original\x20message\x20ID\x20and\x20reply\x20content\x20are\x20required');const _0x99b74=this[_0x1fcfae(0xbd)][_0x1fcfae(0xa6)](_0x4d027b);if(!_0x99b74)throw new Error(_0x1fcfae(0x94)+_0x4d027b);const _0x4d6e74=_0x99b74['sender']===_0x523044||_0x99b74['recipients'][_0x1fcfae(0x105)](_0x523044);if(!_0x4d6e74)throw new Error(_0x1fcfae(0x7f));const _0x4ff8cc=this[_0x1fcfae(0xd0)][_0x1fcfae(0xa6)](_0x99b74['conversationId']),_0x3570cc=this['_getConversationDepth'](_0x99b74['conversationId']);if(_0x3570cc>=this[_0x1fcfae(0xd3)][_0x1fcfae(0xc6)])return{'success':![],'error':'Conversation\x20depth\x20limit\x20reached\x20('+this['config']['maxConversationDepth']+').\x20Please\x20start\x20a\x20new\x20conversation.','suggestion':_0x1fcfae(0x7c)};let _0x6b4627=[_0x99b74['sender']];_0x99b74['sender']===_0x523044&&(_0x6b4627=_0x99b74['recipients']);if(_0x2ac547){const _0x3276fb=this[_0x1fcfae(0xcb)](null,_0x2ac547);_0x6b4627=[...new Set([..._0x6b4627,..._0x3276fb])];}_0x6b4627=_0x6b4627['filter'](_0xf75bfc=>_0xf75bfc!==_0x523044);if(_0x6b4627[_0x1fcfae(0xbe)]>this['config']['maxRecipientsPerMessage'])throw new Error(_0x1fcfae(0xb9)+this[_0x1fcfae(0xd3)][_0x1fcfae(0x104)]+_0x1fcfae(0xee));const _0x347d8f=_0x22409c['agentPool'],_0x52c1f6=await _0x347d8f[_0x1fcfae(0xff)](_0x523044),_0x2d259f=_0x52c1f6?_0x52c1f6['name']:_0x523044,_0xf9d8b0={};for(const _0xb81217 of _0x6b4627){const _0x2d85fa=await _0x347d8f[_0x1fcfae(0xff)](_0xb81217);_0x2d85fa&&(_0xf9d8b0[_0xb81217]=_0x2d85fa[_0x1fcfae(0xf5)]);}const processedAttachments=await this[_0x1fcfae(0xe3)](_0xc4f456,_0x523044),_0x46b0f2=this[_0x1fcfae(0xc7)](),_0x3559f1=new Date()['toISOString'](),_0x251b58={'id':_0x46b0f2,'conversationId':_0x99b74['conversationId'],'sender':_0x523044,'senderName':_0x2d259f,'recipients':_0x6b4627,'recipientNames':_0xf9d8b0,'subject':_0x1fcfae(0xef)+_0x99b74[_0x1fcfae(0x71)],'content':_0x4d5db6,'attachments':processedAttachments,'priority':_0x99b74[_0x1fcfae(0x7b)],'requiresReply':!_0x438d1a,'timestamp':_0x3559f1,'status':'sent','replies':[],'metadata':{'depth':_0x3570cc+0x1,'isRoot':![],'inReplyTo':_0x4d027b}};this['messages']['set'](_0x46b0f2,_0x251b58),_0x99b74['replies'][_0x1fcfae(0x6d)](_0x46b0f2),_0x4ff8cc['lastActivity']=_0x3559f1,_0x4ff8cc[_0x1fcfae(0x97)]++;_0x438d1a&&(_0x4ff8cc[_0x1fcfae(0x6b)]='resolved');for(const _0x4eb556 of _0x6b4627){!this['agentInboxes'][_0x1fcfae(0xe9)](_0x4eb556)&&this['agentInboxes']['set'](_0x4eb556,new Set()),this[_0x1fcfae(0x10f)][_0x1fcfae(0xa6)](_0x4eb556)[_0x1fcfae(0x85)](_0x46b0f2);}this[_0x1fcfae(0xa5)](_0x523044,'sent');for(const _0x1590c0 of _0x6b4627){this[_0x1fcfae(0xa5)](_0x1590c0,'received');}for(const _0x5de577 of _0x6b4627){await this[_0x1fcfae(0x10c)](_0x523044,_0x5de577,'replied',_0x22409c);}return await this['_notifyRecipients'](_0x251b58,_0x22409c),await this['_broadcastToUI'](_0x251b58,'agent-message-reply',_0x22409c),{'success':!![],'messageId':_0x46b0f2,'conversationId':_0x99b74[_0x1fcfae(0xe7)],'recipients':_0x6b4627,'depth':_0x3570cc+0x1,'timestamp':_0x3559f1,'conversationStatus':_0x4ff8cc['status']};}catch(_0x5191e6){return{'success':![],'error':_0x5191e6['message']};}}async[a0_0x2966dd(0xa9)](_0x43e89a,_0x5578b0,_0x1b625e){const _0x1bdf57=a0_0x2966dd;try{const {'include-low-priority':_0x5adb3b=![],'max-age-hours':_0x5d2ff4=0x18}=_0x5578b0,_0x526203=this['agentInboxes'][_0x1bdf57(0xa6)](_0x43e89a)||new Set(),_0x1f818b=[],_0x2fb002=Date['now']()-_0x5d2ff4*0x36ee80;for(const _0x142001 of _0x526203){const _0x5a391d=this[_0x1bdf57(0xbd)]['get'](_0x142001);if(!_0x5a391d)continue;if(new Date(_0x5a391d['timestamp'])['getTime']()<_0x2fb002)continue;if(_0x5a391d[_0x1bdf57(0x7b)]===_0x1bdf57(0xab)&&!_0x5adb3b)continue;if(_0x5a391d[_0x1bdf57(0xa3)]){const _0x478600=this['_hasAgentReplied'](_0x43e89a,_0x5a391d);if(!_0x478600){const _0x3f0aae=this[_0x1bdf57(0xd0)][_0x1bdf57(0xa6)](_0x5a391d[_0x1bdf57(0xe7)]);_0x1f818b['push']({'messageId':_0x5a391d['id'],'conversationId':_0x5a391d['conversationId'],'sender':_0x5a391d[_0x1bdf57(0x8b)],'subject':_0x5a391d['subject'],'preview':_0x5a391d[_0x1bdf57(0xcc)]['substring'](0x0,0x64)+_0x1bdf57(0xaa),'priority':_0x5a391d['priority'],'timestamp':_0x5a391d['timestamp'],'hasAttachments':_0x5a391d[_0x1bdf57(0xfa)][_0x1bdf57(0xbe)]>0x0,'conversationStatus':_0x3f0aae?.['status']||_0x1bdf57(0xdf),'depth':_0x5a391d['metadata']['depth']});}}}return _0x1f818b[_0x1bdf57(0xa4)]((_0x212011,_0x2081ee)=>{const _0xe5ef8e=_0x1bdf57,_0x1f41e9={'high':0x0,'normal':0x1,'low':0x2},_0x189fc2=_0x1f41e9[_0x212011[_0xe5ef8e(0x7b)]]-_0x1f41e9[_0x2081ee['priority']];if(_0x189fc2!==0x0)return _0x189fc2;return new Date(_0x2081ee[_0xe5ef8e(0xfe)])-new Date(_0x212011['timestamp']);}),{'success':!![],'messages':_0x1f818b,'total':_0x1f818b[_0x1bdf57(0xbe)],'inbox':{'total':_0x526203[_0x1bdf57(0x6f)],'activeConversations':(this['agentConversations'][_0x1bdf57(0xa6)](_0x43e89a)||new Set())['size']}};}catch(_0x3fc3d7){return{'success':![],'error':_0x3fc3d7[_0x1bdf57(0xe6)]};}}async[a0_0x2966dd(0x93)](_0x512707,_0x2d5684,_0x1e0184){const _0x5f1f8b=a0_0x2966dd;try{const {'conversation-id':_0x3b3c48,reason:reason=_0x5f1f8b(0xd9)}=_0x2d5684;if(!_0x3b3c48)throw new Error('Conversation\x20ID\x20is\x20required');const _0xa4fc1d=this[_0x5f1f8b(0xd0)]['get'](_0x3b3c48);if(!_0xa4fc1d)throw new Error(_0x5f1f8b(0xde)+_0x3b3c48);if(!_0xa4fc1d[_0x5f1f8b(0xc0)][_0x5f1f8b(0x105)](_0x512707))throw new Error(_0x5f1f8b(0x7f));_0xa4fc1d[_0x5f1f8b(0x6b)]='ended',_0xa4fc1d['endTime']=new Date()['toISOString'](),_0xa4fc1d[_0x5f1f8b(0xcd)]=reason,_0xa4fc1d['endedBy']=_0x512707;for(const _0x4b0fd2 of _0xa4fc1d[_0x5f1f8b(0xc0)]){const _0x59e085=this['agentConversations']['get'](_0x4b0fd2);_0x59e085&&_0x59e085['delete'](_0x3b3c48);}return{'success':!![],'conversationId':_0x3b3c48,'status':'ended','reason':reason,'timestamp':_0xa4fc1d['endTime']};}catch(_0x95368d){return{'success':![],'error':_0x95368d[_0x5f1f8b(0xe6)]};}}async[a0_0x2966dd(0xd6)](){const _0x293bf9=a0_0x2966dd;try{await a0_0x5a8f0d['mkdir'](this['config'][_0x293bf9(0x87)],{'recursive':!![]});const _0x390cf6=a0_0x1de5db['join'](this[_0x293bf9(0xd3)][_0x293bf9(0x87)],'attachments');await a0_0x5a8f0d['mkdir'](_0x390cf6,{'recursive':!![]});}catch(_0x534dc3){console[_0x293bf9(0x80)]('Failed\x20to\x20initialize\x20message\x20storage:',_0x534dc3);}}[a0_0x2966dd(0xcb)](_0x354121,_0x6e97de){const _0x332eae=a0_0x2966dd;let _0x4840e5=[];_0x354121&&_0x4840e5['push'](_0x354121);if(_0x6e97de){if(typeof _0x6e97de===_0x332eae(0xea))try{const _0x119a93=JSON[_0x332eae(0x78)](_0x6e97de);_0x4840e5=[..._0x4840e5,...Array[_0x332eae(0x99)](_0x119a93)?_0x119a93:[_0x119a93]];}catch{_0x4840e5[_0x332eae(0x6d)](_0x6e97de);}else Array['isArray'](_0x6e97de)&&(_0x4840e5=[..._0x4840e5,..._0x6e97de]);}return[...new Set(_0x4840e5)];}async[a0_0x2966dd(0xe3)](_0x5e1381,_0x4929df){const _0x1e9c8d=a0_0x2966dd;if(!_0x5e1381)return[];let _0x24052f=[];if(typeof _0x5e1381===_0x1e9c8d(0xea))try{_0x24052f=JSON[_0x1e9c8d(0x78)](_0x5e1381);}catch{return[];}else _0x24052f=_0x5e1381;!Array['isArray'](_0x24052f)&&(_0x24052f=[_0x24052f]);if(_0x24052f['length']>this[_0x1e9c8d(0xd3)]['maxAttachmentsPerMessage'])throw new Error(_0x1e9c8d(0xb9)+this[_0x1e9c8d(0xd3)][_0x1e9c8d(0x7a)]+'\x20attachments\x20allowed');const processedAttachments=[];for(const _0x44faaf of _0x24052f){if(!_0x44faaf[_0x1e9c8d(0xa0)])continue;try{const _0x5c36d3=await a0_0x5a8f0d[_0x1e9c8d(0x68)](_0x44faaf['path']);if(_0x5c36d3['size']>this[_0x1e9c8d(0xd3)][_0x1e9c8d(0x72)])throw new Error(_0x1e9c8d(0xc8)+_0x44faaf[_0x1e9c8d(0xa0)]);const _0x1fd92c=this['_generateAttachmentId'](),_0x778e4d=a0_0x1de5db[_0x1e9c8d(0x70)](_0x44faaf[_0x1e9c8d(0xa0)]),_0x505c4f=a0_0x1de5db[_0x1e9c8d(0x74)](this[_0x1e9c8d(0xd3)]['storageDir'],'attachments',''+_0x1fd92c+_0x778e4d);await a0_0x5a8f0d['copyFile'](_0x44faaf['path'],_0x505c4f),processedAttachments['push']({'id':_0x1fd92c,'originalPath':_0x44faaf['path'],'storagePath':_0x505c4f,'type':_0x44faaf['type']||'file','size':_0x5c36d3[_0x1e9c8d(0x6f)],'name':a0_0x1de5db['basename'](_0x44faaf['path'])});}catch(_0x53eb73){console[_0x1e9c8d(0x80)](_0x1e9c8d(0x79)+_0x44faaf['path'],_0x53eb73);}}return processedAttachments;}async[a0_0x2966dd(0xb2)](_0x52d441,_0x7476fd){const _0x57ad66=a0_0x2966dd,_0x3ff73b=_0x7476fd['agentPool'];if(!_0x3ff73b)return;for(const _0x13bd97 of _0x52d441['recipients']){try{await _0x3ff73b[_0x57ad66(0x86)](_0x13bd97,{'type':'agent-communication','from':_0x52d441['sender'],'conversationId':_0x52d441[_0x57ad66(0xe7)],'content':_0x57ad66(0xce)+_0x52d441[_0x57ad66(0x9a)]+':\x20\x22'+_0x52d441['subject']+'\x22','messageId':_0x52d441['id'],'priority':_0x52d441[_0x57ad66(0x7b)],'requiresResponse':_0x52d441['requiresReply']});const _0x4719d5=await _0x3ff73b['getAgent'](_0x13bd97);if(_0x4719d5){const _0x39afbd=_0x57ad66(0x107)+_0x52d441['senderName']+'\x20('+_0x52d441[_0x57ad66(0x8b)]+_0x57ad66(0xf8)+_0x52d441[_0x57ad66(0x71)]+_0x57ad66(0xf1)+_0x52d441[_0x57ad66(0x7b)]+_0x57ad66(0xaf)+(_0x52d441['requiresReply']?'Yes':'No')+'\x0a\x0a**Message:**\x0a'+_0x52d441['content']+'\x0a\x0a'+(_0x52d441['attachments']['length']>0x0?_0x57ad66(0x9b)+_0x52d441['attachments'][_0x57ad66(0xbe)]+'\x20file(s)':'')+'\x0a\x0a*You\x20can\x20reply\x20using\x20the\x20agentcommunication\x20tool\x20with\x20action=\x22reply-to-message\x22\x20and\x20message-id=\x22'+_0x52d441['id']+'\x22*',_0x5ae3c2={'id':'agent-comm-'+_0x52d441['id'],'conversationId':_0x52d441['conversationId'],'agentId':_0x52d441[_0x57ad66(0x8b)],'content':_0x39afbd,'role':'system','timestamp':_0x52d441[_0x57ad66(0xfe)],'type':_0x57ad66(0xca),'metadata':{'originalMessageId':_0x52d441['id'],'fromAgent':_0x52d441['sender'],'requiresResponse':_0x52d441['requiresReply'],'priority':_0x52d441['priority']}};_0x4719d5['conversations'][_0x57ad66(0xb3)]['messages']['push'](_0x5ae3c2),_0x4719d5[_0x57ad66(0xd0)]['full']['lastUpdated']=new Date()['toISOString'](),_0x4719d5[_0x57ad66(0x9e)]&&_0x4719d5[_0x57ad66(0xd0)][_0x4719d5['currentModel']]&&(_0x4719d5[_0x57ad66(0xd0)][_0x4719d5['currentModel']][_0x57ad66(0xbd)]['push'](_0x5ae3c2),_0x4719d5['conversations'][_0x4719d5[_0x57ad66(0x9e)]]['lastUpdated']=new Date()[_0x57ad66(0x66)]()),await _0x3ff73b[_0x57ad66(0x9d)](_0x13bd97),console[_0x57ad66(0xc5)](_0x57ad66(0xb5),{'recipientId':_0x13bd97,'sender':_0x52d441['sender'],'subject':_0x52d441[_0x57ad66(0x71)],'hasSessionId':!!_0x7476fd['sessionId']}),await _0x3ff73b['addInterAgentMessage'](_0x13bd97,{'id':_0x52d441['id'],'messageId':_0x52d441['id'],'sender':_0x52d441['sender'],'senderName':_0x52d441[_0x57ad66(0x9a)],'subject':_0x52d441[_0x57ad66(0x71)],'content':_0x52d441[_0x57ad66(0xcc)],'attachments':_0x52d441[_0x57ad66(0xfa)],'priority':_0x52d441['priority'],'requiresReply':_0x52d441['requiresReply'],'conversationId':_0x52d441[_0x57ad66(0xe7)],'sessionId':_0x7476fd[_0x57ad66(0xf7)],'timestamp':new Date()[_0x57ad66(0x66)]()}),console[_0x57ad66(0xc5)](_0x57ad66(0x69)+_0x13bd97,{'messageId':_0x52d441['id'],'fromAgent':_0x52d441['sender'],'subject':_0x52d441[_0x57ad66(0x71)],'priority':_0x52d441[_0x57ad66(0x7b)]});}}catch(_0x3354f8){console['error'](_0x57ad66(0xb7)+_0x13bd97+':',_0x3354f8);}}}['_hasAgentReplied'](_0x5998c4,_0x38e155){const _0x4e8b61=a0_0x2966dd;for(const _0x186a10 of _0x38e155['replies']){const _0x41bb3b=this[_0x4e8b61(0xbd)]['get'](_0x186a10);if(_0x41bb3b&&_0x41bb3b['sender']===_0x5998c4)return!![];if(_0x41bb3b&&this[_0x4e8b61(0xf2)](_0x5998c4,_0x41bb3b))return!![];}return![];}[a0_0x2966dd(0x92)](_0x28ea88){const _0x3a8483=a0_0x2966dd,_0x4d7929=this[_0x3a8483(0xd0)]['get'](_0x28ea88);if(!_0x4d7929)return 0x0;let _0x46ac2f=0x0;const _0x350056=this['messages'][_0x3a8483(0xa6)](_0x4d7929[_0x3a8483(0x98)]);return _0x350056&&(_0x46ac2f=this['_getMessageDepth'](_0x350056)),_0x46ac2f;}[a0_0x2966dd(0xac)](_0x50bcc5,_0x42d69a=0x0){const _0xde7237=a0_0x2966dd;if(_0x50bcc5[_0xde7237(0x9c)][_0xde7237(0xbe)]===0x0)return _0x42d69a;let _0xc64a47=_0x42d69a;for(const _0x3693e1 of _0x50bcc5['replies']){const _0x6c1ac6=this[_0xde7237(0xbd)]['get'](_0x3693e1);if(_0x6c1ac6){const _0x1bb264=this[_0xde7237(0xac)](_0x6c1ac6,_0x42d69a+0x1);_0xc64a47=Math[_0xde7237(0xc4)](_0xc64a47,_0x1bb264);}}return _0xc64a47;}[a0_0x2966dd(0xa5)](_0x1b6483,_0x4ffce8){const _0x4901d4=a0_0x2966dd;!this['agentMessageCounts']['has'](_0x1b6483)&&this['agentMessageCounts'][_0x4901d4(0x8f)](_0x1b6483,{'sent':0x0,'received':0x0});const _0x4da0d8=this[_0x4901d4(0x82)][_0x4901d4(0xa6)](_0x1b6483);_0x4ffce8===_0x4901d4(0xa8)?_0x4da0d8[_0x4901d4(0xa8)]++:_0x4da0d8['received']++;}['_generateMessageId'](){const _0x27f9e5=a0_0x2966dd;return _0x27f9e5(0xdc)+Date[_0x27f9e5(0x10e)]()+'-'+a0_0x565a6b['randomBytes'](0x4)['toString']('hex');}['_generateConversationId'](){const _0x3ac746=a0_0x2966dd;return _0x3ac746(0xa7)+Date[_0x3ac746(0x10e)]()+'-'+a0_0x565a6b['randomBytes'](0x4)[_0x3ac746(0xf4)]('hex');}[a0_0x2966dd(0xb1)](){const _0x3a725a=a0_0x2966dd;return'att-'+Date['now']()+'-'+a0_0x565a6b[_0x3a725a(0x81)](0x4)[_0x3a725a(0xf4)]('hex');}async['cleanup'](){const _0x5fc850=a0_0x2966dd,_0x319498=Date['now'](),_0x2bb759=_0x319498-this[_0x5fc850(0xd3)]['messageRetentionPeriod'];for(const [_0x49e52a,_0x504091]of this[_0x5fc850(0xbd)]['entries']()){const _0x381aa2=new Date(_0x504091[_0x5fc850(0xfe)])[_0x5fc850(0xbb)]();if(_0x381aa2<_0x2bb759){for(const _0x136896 of _0x504091[_0x5fc850(0xfa)]){try{await a0_0x5a8f0d[_0x5fc850(0xc1)](_0x136896[_0x5fc850(0x91)]);}catch(_0x270044){}}for(const [_0xaa3be6,_0x410950]of this[_0x5fc850(0x10f)][_0x5fc850(0xfd)]()){_0x410950['delete'](_0x49e52a);}this[_0x5fc850(0xbd)]['delete'](_0x49e52a);}}for(const [_0x5e6810,_0x2ef042]of this['conversations']['entries']()){const _0x3b8208=new Date(_0x2ef042[_0x5fc850(0xec)])['getTime']();if(_0x3b8208<_0x2bb759||_0x2ef042[_0x5fc850(0x6b)]===_0x5fc850(0xc2)){for(const [_0x5d8a29,_0x1592b9]of this['agentConversations']['entries']()){_0x1592b9['delete'](_0x5e6810);}this['conversations'][_0x5fc850(0x101)](_0x5e6810);}}}async[a0_0x2966dd(0xcf)](_0x4893e2,_0x29542c,_0xa0d969){const _0xf1e8ae=a0_0x2966dd;try{const _0x3f5949={'type':'agent-communication','eventType':_0x29542c,'timestamp':_0x4893e2[_0xf1e8ae(0xfe)],'messageId':_0x4893e2['id'],'conversationId':_0x4893e2['conversationId'],'sender':{'id':_0x4893e2['sender'],'name':_0x4893e2[_0xf1e8ae(0x9a)]},'recipients':Object['entries'](_0x4893e2[_0xf1e8ae(0xe8)]||{})['map'](([_0x2ec554,_0x28c8c1])=>({'id':_0x2ec554,'name':_0x28c8c1})),'subject':_0x4893e2[_0xf1e8ae(0x71)],'content':_0x4893e2['content'],'priority':_0x4893e2[_0xf1e8ae(0x7b)],'requiresReply':_0x4893e2['requiresReply'],'hasAttachments':_0x4893e2['attachments']&&_0x4893e2['attachments']['length']>0x0,'attachmentCount':_0x4893e2[_0xf1e8ae(0xfa)]?_0x4893e2['attachments']['length']:0x0,'metadata':_0x4893e2['metadata']};if(_0xa0d969['agentPool']&&_0xa0d969[_0xf1e8ae(0xba)]['messageProcessor']){const _0x241dba=_0xa0d969['agentPool'][_0xf1e8ae(0xa1)];if(_0x241dba&&_0x241dba['orchestrator']&&_0x241dba[_0xf1e8ae(0x8a)]['webServer']){_0x241dba['orchestrator']['webServer'][_0xf1e8ae(0x67)](_0xa0d969['sessionId']||_0xf1e8ae(0xed),{'type':_0xf1e8ae(0xca),'action':'agent-communication','data':_0x3f5949});return;}}if(_0xa0d969['orchestrator']&&_0xa0d969[_0xf1e8ae(0x8a)][_0xf1e8ae(0x83)]){_0xa0d969['orchestrator']['webServer']['broadcastToSession'](_0xa0d969['sessionId']||'web-session',{'type':'agent-communication','action':'agent-communication','data':_0x3f5949});return;}global['loxiaWebServer']&&global['loxiaWebServer'][_0xf1e8ae(0x67)](_0xa0d969['sessionId']||_0xf1e8ae(0xed),{'type':'agent-communication','action':_0xf1e8ae(0xca),'data':_0x3f5949});}catch(_0x5277cc){console['error'](_0xf1e8ae(0xa2),_0x5277cc);}}async[a0_0x2966dd(0xd7)](_0x4f55f1,_0x81a7b8,_0x4cd0ce){const _0x5047b2=a0_0x2966dd,_0x3567bf=_0x4cd0ce['agentPool'],_0x147ce9=_0x4f55f1['interAgentTracking'];!_0x147ce9['has'](_0x81a7b8)&&_0x147ce9['set'](_0x81a7b8,{'lastSent':null,'lastReceived':null,'lastType':null});const _0xbbff64=_0x147ce9['get'](_0x81a7b8),_0x56247f=Date[_0x5047b2(0x10e)](),_0x292e1a=0x3c*0x3e8;if(_0xbbff64['lastType']==='received'||_0xbbff64[_0x5047b2(0x100)]&&_0xbbff64[_0x5047b2(0x100)]>_0xbbff64['lastSent'])return{'allowed':!![]};if(_0xbbff64['lastSent']){const _0x4862e3=_0x56247f-_0xbbff64[_0x5047b2(0xb6)];if(_0x4862e3>=_0x292e1a)return{'allowed':!![]};const _0x258a6c=_0xbbff64[_0x5047b2(0xb6)]+_0x292e1a;return{'allowed':![],'reason':'Must\x20wait\x20'+Math[_0x5047b2(0xd8)]((_0x258a6c-_0x56247f)/0x3e8)+'s\x20since\x20last\x20message','waitUntil':_0x258a6c};}return{'allowed':!![]};}async['_updateConversationTracking'](_0x1ed4f2,_0x5e4ffb,_0x475bfb,_0x104e21){const _0x311f29=a0_0x2966dd,_0x52d07a=_0x104e21[_0x311f29(0xba)],_0x2aa012=await _0x52d07a[_0x311f29(0xff)](_0x1ed4f2);if(!_0x2aa012)return;const _0x18d8ac=Date[_0x311f29(0x10e)]();!_0x2aa012[_0x311f29(0xf6)]['has'](_0x5e4ffb)&&_0x2aa012[_0x311f29(0xf6)]['set'](_0x5e4ffb,{'lastSent':null,'lastReceived':null,'lastType':null});const _0x11b2e5=_0x2aa012['interAgentTracking'][_0x311f29(0xa6)](_0x5e4ffb);if(_0x475bfb===_0x311f29(0xa8))_0x11b2e5[_0x311f29(0xb6)]=_0x18d8ac,_0x11b2e5['lastType']=_0x311f29(0xa8);else _0x475bfb==='replied'&&(_0x11b2e5['lastSent']=_0x18d8ac,_0x11b2e5[_0x311f29(0xf0)]='sent');const _0x22dd99=await _0x52d07a[_0x311f29(0xff)](_0x5e4ffb);if(_0x22dd99){!_0x22dd99[_0x311f29(0xf6)][_0x311f29(0xe9)](_0x1ed4f2)&&_0x22dd99['interAgentTracking']['set'](_0x1ed4f2,{'lastSent':null,'lastReceived':null,'lastType':null});const _0x4c30c3=_0x22dd99['interAgentTracking'][_0x311f29(0xa6)](_0x1ed4f2);_0x4c30c3[_0x311f29(0x100)]=_0x18d8ac,_0x4c30c3[_0x311f29(0xf0)]='received',await _0x52d07a['persistAgentState'](_0x5e4ffb);}await _0x52d07a['persistAgentState'](_0x1ed4f2);}['setMessageProcessor'](_0x479d46){const _0x1a47f3=a0_0x2966dd;this[_0x1a47f3(0xa1)]=_0x479d46;}}export default AgentCommunicationTool;