@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,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_0x320a88=a0_0x13f9;(function(_0x189421,_0x3c7b19){const _0x466127=a0_0x13f9,_0x46709c=_0x189421();while(!![]){try{const _0x807645=-parseInt(_0x466127(0x1f4))/0x1+-parseInt(_0x466127(0x1f0))/0x2+-parseInt(_0x466127(0x231))/0x3+-parseInt(_0x466127(0x227))/0x4*(parseInt(_0x466127(0x243))/0x5)+-parseInt(_0x466127(0x1e5))/0x6+-parseInt(_0x466127(0x23f))/0x7*(-parseInt(_0x466127(0x212))/0x8)+parseInt(_0x466127(0x256))/0x9*(parseInt(_0x466127(0x1e0))/0xa);if(_0x807645===_0x3c7b19)break;else _0x46709c['push'](_0x46709c['shift']());}catch(_0x46e873){_0x46709c['push'](_0x46709c['shift']());}}}(a0_0x8ed5,0xc0617));import{BaseTool}from'./baseTool.js';function a0_0x13f9(_0x59b683,_0x10e010){_0x59b683=_0x59b683-0x1b5;const _0x8ed5af=a0_0x8ed5();let _0x13f900=_0x8ed5af[_0x59b683];if(a0_0x13f9['AZBZhG']===undefined){var _0xb1b848=function(_0x3d1dfc){const _0x69ea1='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=';let _0x48309c='',_0x2675b8='';for(let _0x10416b=0x0,_0x370efa,_0x1b16ef,_0xa900d3=0x0;_0x1b16ef=_0x3d1dfc['charAt'](_0xa900d3++);~_0x1b16ef&&(_0x370efa=_0x10416b%0x4?_0x370efa*0x40+_0x1b16ef:_0x1b16ef,_0x10416b++%0x4)?_0x48309c+=String['fromCharCode'](0xff&_0x370efa>>(-0x2*_0x10416b&0x6)):0x0){_0x1b16ef=_0x69ea1['indexOf'](_0x1b16ef);}for(let _0x581d31=0x0,_0x5c0a72=_0x48309c['length'];_0x581d31<_0x5c0a72;_0x581d31++){_0x2675b8+='%'+('00'+_0x48309c['charCodeAt'](_0x581d31)['toString'](0x10))['slice'](-0x2);}return decodeURIComponent(_0x2675b8);};a0_0x13f9['FEYkoh']=_0xb1b848,a0_0x13f9['ALnPid']={},a0_0x13f9['AZBZhG']=!![];}const _0x3cb189=_0x8ed5af[0x0],_0x35f512=_0x59b683+_0x3cb189,_0x374910=a0_0x13f9['ALnPid'][_0x35f512];return!_0x374910?(_0x13f900=a0_0x13f9['FEYkoh'](_0x13f900),a0_0x13f9['ALnPid'][_0x35f512]=_0x13f900):_0x13f900=_0x374910,_0x13f900;}import{promises as a0_0x48309c}from'fs';function a0_0x8ed5(){const _0x4c4c1e=['C3rHCNrZv2L0Aa','zxH0BMfTzq','uMvJAxbPzw50igfNzw50khmPig5VDcbMB3vUzdOG','ywDLBNrqB29S','rMfPBgvKihrVig5VDgLMEsbHz2vUDca','C2L6zq','Agv4','mJe1odq4DMD5vvDo','x3vWzgf0zu1LC3nHz2vdB3vUDhm','x2DLBMvYyxrLqxr0ywnOBwvUDeLK','qxqGBgvHC3qGB25LihjLy2LWAwvUDcbPCYbYzxf1AxjLza','ywDLBNrJB21TDw5Py2f0Aw9U','yxr0lq','ywn0Aw9UCW','y29UDMvYC2f0Aw9UCW','C2vZC2LVBKLK','zMLSDgvY','mZy4mtK3ogLqu3ncBW','z2v0qxzHAwXHyMXLqwDLBNrZ','y29UDMvYC2f0Aw9UlwLK','CMvWBgLLza','BwfYA0nVBNzLCNnHDgLVBKvUzgvK','yxr0ywnOBwvUDhm','x2LUAxrPywXPEMvtDg9YywDL','AM9PBG','igf0DgfJAg1LBNrZigfSBg93zwq','y2mTCMvJAxbPzw50CW','BM93','rMfPBgvKihrVigjYB2fKy2fZDcbHz2vUDcbTzxnZywDLihrVifvjoG','C2vUzgvYtMfTzq','zMfSC2u','nZmZntuZmwXgquHPCG','z2v0','CYbZAw5JzsbSyxn0ig1LC3nHz2u','twvZC2fNzsbZzw50ihn1y2nLC3nMDwXSEq','mtvyB25Uwvq','zxjYB3i','y2XLyw51Ca','y2vPBa','BwfYAY1JB252zxjZyxrPB24Tzw5Kzwq','ywDLBNqTy29TBxvUAwnHDgLVBG','BgfZDfnLBNq','x25VDgLMEvjLy2LWAwvUDhm','ChvZAa','ywn0AxzL','qwDLBNqGq29TBxvUAwnHDgLVBG','w14+xsO+kc4QpYK8xc8','Bwv0ywrHDge','Dg9ju09tDhjPBMC','zgvWDgG','Bwf4q29UDMvYC2f0Aw9UrgvWDgG','z2v0vw5YzxbSAwvKtwvZC2fNzxm','C3vIAMvJDa','D2vIu2vYDMvY','mJe2uhbmswLl','ywDLBNrjBMjVEgvZ','CgfYC2u','y29UDMvYC2f0Aw9Uswq','cGOQww91ignHBIbYzxbSEsb1C2LUzYb0AguGywDLBNrJB21TDw5Py2f0Aw9UihrVB2WGD2L0AcbHy3rPB249iNjLCgX5lxrVlw1LC3nHz2uIigfUzcbTzxnZywDLlwLKpsi','qwDLBNqGCg9VBcbUB3qGyxzHAwXHyMXLigLUignVBNrLEhq','x2HHC0fNzw50uMvWBgLLza','BgfZDfvWzgf0zwq','Bwf4uMvJAxbPzw50C1bLCK1LC3nHz2u','Aw50zxjbz2vUDfrYywnRAw5N','y29TBxvUAwnHDgLVBG','y29UDMvYC2f0Aw9UvgLTzw91Da','x3bHCNnLuMvJAxbPzw50CW','BwvZC2fNzq','CMvHC29U','CMvZB2X2zwq','zNvSBa','x2DLBMvYyxrLq29UDMvYC2f0Aw9Uswq','u2vUzgvYigfNzw50ig5VDcbMB3vUza','BwTKAxi','BgfZDfjLy2vPDMvK','CMvWBgLLCW','C3vIC3rYAw5N','AxnbCNjHEq','zw5Kzwq','D2fPDfvUDgLS','Dg9vChbLCKnHC2u','CMvXDwLYzxnszxbSEq','BM9YBwfS','CgvYC2LZDefNzw50u3rHDgu','ywn0Aw9U','BwvZC2fNzvjLDgvUDgLVBLbLCMLVza','C2vUzgvY','CMvWBgfJzq','8j+tRcbrDwv1zwLUzYbPBNrLCI1Hz2vUDcbTzxnZywDLigzVCIbZy2HLzhvSzxiGChjVy2vZC2LUzW','DgLTzxn0yw1W','Dhj1zq','x3vWzgf0zunVBNzLCNnHDgLVBLrYywnRAw5N','x2nHBLnLBMrnzxnZywDL','Aw5JBhvKzs1SB3CTChjPB3jPDhK','C3rVCMfNzurPCG','CMvJzwL2zwq','DhjPBq','C2vUDa','Bg94Awfxzwjtzxj2zxi','y3vYCMvUDe1VzgvS','ywrK','ig1PBNv0zxmGB2yGAw5Hy3rPDML0EqOTief2B2LKihjLCgX5lwfSBcb1BMXLC3mGBMvJzxnZyxj5ihrVihbYzxzLBNqGBwvZC2fNzsbZDg9YBxmklsbnyxjRignVBNzLCNnHDgLVBNmGyxmGzw5KzwqGD2HLBIbNB2fSCYbHCMuGywnOAwv2zwqkcKLTCg9YDgfUDcboB3rLCZOklsbnzxnZywDLCYbHCMuGzgvSAxzLCMvKigfZEw5JAhjVBM91C2X5cI0Gqxr0ywnOBwvUDhmGBxvZDcbIzsbYzwfKywjSzsbMAwXLCYb1BMrLCIa','qwn0Aw9UihbHCMfTzxrLCIbPCYbYzxf1AxjLza','BgLZDefJDgL2zufNzw50CW','8j+tQcbozxCGBwvZC2fNzsbMCM9Tia','CMvJAxbPzw50','Bg9N','vw5RBM93BIbHy3rPB246ia','cIOQuhjPB3jPDhK6kIOG','Cgf0Aa','oIaI','twf4Aw11Bsa','lMXVEgLHlw1LC3nHz2vZ','ywDLBNrdB252zxjZyxrPB25Z','CMvXDwLYzxmTCMvWBhK','odGWmtGWseTdzxfH','q29UDMvYC2f0Aw9Uig5VDcbMB3vUzdOG','C3rHDhvZ','zw5HyMXLqNjVywrJyxn0','Bwf0y2G','nJyWndyYr3D4tKPY','ChjPB3jPDhK','zw5KvgLTzq','AgfZ','AxnqyxvZzwq','C3rYAw5N','B2jQzwn0','C2vUze1LC3nHz2u','C2v0','q29UDMvYC2f0Aw9UieLeigLZihjLCxvPCMvK','B3jJAgvZDhjHDg9Y','mtqYmdm1nMnAu0jdEG','cKfNzw50ienVBw11BMLJyxrPB24Gvg9VBdOGrw5HyMXLCYbJB21TDw5Py2f0Aw9UigjLDhDLzw4Gywn0AxzLigfNzw50CYbPBIb0AguGC3LZDgvTlGOkqxzHAwXHyMXLiefJDgLVBNm6cI0Gz2v0lwf2ywLSywjSzs1Hz2vUDhm6ieXPC3qGywXSigfJDgL2zsbHz2vUDhmGEw91ignHBIbJB21TDw5Py2f0zsb3AxrOcI0GC2vUzc1TzxnZywDLoIbtzw5KigeGBwvZC2fNzsb0BYbHBM90AgvYigfNzw50ihDPDgGGB3b0Aw9UywWGyxr0ywnOBwvUDhmklsbYzxbSEs10BY1TzxnZywDLoIbszxbSEsb0BYbHihjLy2vPDMvKig1LC3nHz2uklsbNzxqTDw5YzxbSAwvKlw1LC3nHz2vZoIbhzxqGBgLZDcbVzIbTzxnZywDLCYbYzxf1AxjPBMCGEw91CIbYzxnWB25ZzqOTig1HCMSTy29UDMvYC2f0Aw9UlwvUzgvKoIbnyxjRigeGy29UDMvYC2f0Aw9UigfZignVBxbSzxrLl2rPC3jLz2fYzgvKcGPvC2fNzsbfEgfTCgXLCYaOyM90AcbytuWGyw5KiePtt04GzM9YBwf0CYbZDxbWB3j0zwqPoGOkms4Gr2v0igf2ywLSywjSzsbHz2vUDhmGkfHntcbMB3jTyxqPoGPBDg9VBf0kpgfJDgLVBJ5NzxqTyxzHAwXHyMXLlwfNzw50CZWVywn0Aw9UpGPBl3rVB2XDcGOXyI4Gr2v0igf2ywLSywjSzsbHz2vUDhmGkePtt04GzM9YBwf0ktOkEYjHy3rPB25ZiJOGw3SIDhLWzsi6icjNzxqTyxzHAwXHyMXLlwfNzw50CYj9xx0kcKjVDgGGCMv0DxjUigeGsLnptIbYzxnWB25ZzsbSAwTLoGP7cIaGiNn1y2nLC3mIoIb0CNvLlaOGicjHz2vUDhmIoIbBcIaGicb7cIaGicaGicjPzci6icjHz2vUDc1HBgLJzs0XnZu1mteXnJe2mJe0iIWkicaGicaGiM5HBwuIoIaIywXPy2uIlaOGicaGicaIy2fWywjPBgL0AwvZiJOGwYj0zxjTAw5HBciSicjMAwXLC3LZDgvTiIWGlI4UxsWkicaGicaGiNn0yxr1CYi6icjHy3rPDMuIcIaGicb9cIaGxqP9cGPmB29RigzVCIb0AguGiMLKiIbMAwvSzcbPBIbLywnOigfNzw50ig9IAMvJDcaTihrOAxmGAxmGD2HHDcb5B3uGDxnLigfZihrOzsbYzwnPCgLLBNqUcGOYlIbtzw5KigeGBwvZC2fNzsaOwe1migzVCM1HDcK6cLT0B29SxqO8ywn0Aw9UpNnLBMqTBwvZC2fNztWVywn0Aw9UpGO8CMvJAxbPzw50pMfNzw50lwz1BgXZDgfJAY1KzxzLBg9WzxiTywDLBNqTmtiZndu2nZG5mdeYmZWVCMvJAxbPzw50pGO8C3vIAMvJDd5ozwvKigfZC2LZDgfUy2uGD2L0AcbJB2rLihjLDMLLDZWVC3vIAMvJDd4kpg1LC3nHz2u+q291BgqGEw91ihjLDMLLDYb0AguGyxv0AgvUDgLJyxrPB24GBw9KDwXLieKGANvZDcbPBxbSzw1LBNrLzd88l21LC3nHz2u+cJXWCMLVCML0Et5UB3jTywW8l3bYAw9YAxr5pGO8CMvXDwLYzxmTCMvWBhK+Dhj1ztWVCMvXDwLYzxmTCMvWBhK+cLSVDg9VBf0kcJjIlIbtzw5KigeGBwvZC2fNzsaOsLnptIbMB3jTyxqPoGP7iMfJDgLVBNmIoIbBEYj0ExbLiJOGiNnLBMqTBwvZC2fNzsiSicjYzwnPCgLLBNqIoIaIywDLBNqTzNvSBhn0ywnRlwrLDMvSB3bLCI1Hz2vUDc0XmJm0nty3odKWmtiZiIWGiNn1yMPLy3qIoIaItMvLzcbHC3nPC3rHBMnLihDPDgGGy29KzsbYzxzPzxCIlcaIBwvZC2fNzsi6icjdB3vSzcb5B3uGCMv2Awv3ihrOzsbHDxrOzw50AwnHDgLVBIbTB2r1BguGssbQDxn0igLTCgXLBwvUDgvKpYiSicjWCMLVCML0Esi6icjUB3jTywWIlcaICMvXDwLYzxmTCMvWBhKIoIb0CNvLFv19cGPjtvbpuLrbtLq6iefSD2f5CYb1C2uGDgHLigz1BgWGywDLBNqGsuqGkgXPA2uGiMfNzw50lwz1BgXZDgfJAY1KzxzLBg9WzxiTywDLBNqTmtiZndu2nZG5mdeYmYiPigfZihrOzsbYzwnPCgLLBNqSig5VDcbQDxn0ihrOzsbUyw1LlIbhzxqGDgHLigv4ywn0ieLeigzYB20Gz2v0lwf2ywLSywjSzs1Hz2vUDhmGzMLYC3qUcGOZlIbtzw5KihDPDgGGyxr0ywnOBwvUDhmGkfHntcbMB3jTyxqPoGPBDg9VBf0kpgfJDgLVBJ5Zzw5Klw1LC3nHz2u8l2fJDgLVBJ4kphjLy2LWAwvUDd5Hz2vUDc1Pzc00nty8l3jLy2LWAwvUDd4kphn1yMPLy3q+qw5HBhLZAxmGCMvZDwX0CZWVC3vIAMvJDd4kpg1LC3nHz2u+sgvYzsbHCMuGDgHLihrLC3qGCMvZDwX0CYb5B3uGCMvXDwvZDgvKpc9TzxnZywDLpGO8yxr0ywnOBwvUDhm+w3SICgf0Aci6iciVCMvWB3j0CY90zxn0lxjLC3vSDhmUCgrMiIWGiNr5CguIoIaICgrMiN1Dpc9HDhrHy2HTzw50CZ4kwY90B29SxqOknc4GuMvWBhKGDg8GysbTzxnZywDLoGPBDg9VBf0kpgfJDgLVBJ5YzxbSEs10BY1TzxnZywDLpc9Hy3rPB24+cJXTzxnZywDLlwLKpM1ZzY03odK8l21LC3nHz2uTAwq+cJXTzxnZywDLpLrOyw5RCYbMB3iGDgHLihjLDMLLDY4GssD2zsbHzgrYzxnZzwqGywXSihLVDxiGy29TBwvUDhmUpc9TzxnZywDLpGO8y2mTCMvJAxbPzw50CZ5BiMfNzw50lwLKlteXmsjDpc9JyY1YzwnPCgLLBNrZpGPBl3rVB2XDcGO1lIbhzxqGDw5YzxbSAwvKig1LC3nHz2vZoGPBDg9VBf0kpgfJDgLVBJ5NzxqTDw5YzxbSAwvKlw1LC3nHz2vZpc9Hy3rPB24+cJXPBMnSDwrLlwXVDY1WCMLVCML0Et5MywXZztWVAw5JBhvKzs1SB3CTChjPB3jPDhK+cLSVDg9VBf0kcJyUievUzcbHignVBNzLCNnHDgLVBJOkw3rVB2XDcJXHy3rPB24+BwfYAY1JB252zxjZyxrPB24Tzw5Kzwq8l2fJDgLVBJ4kpgnVBNzLCNnHDgLVBI1Pzd5JB252lxH5EJWVy29UDMvYC2f0Aw9UlwLKpGO8CMvHC29UpLrHC2SGy29TCgXLDgvKihn1y2nLC3nMDwXSEtWVCMvHC29UpGPBl3rVB2XDcGPtywzLDhKGr3vPzgvSAw5LCZOklsbnyxHPBxvTia','y29UzMLN','BwvZC2fNzxm','mtyYota3we95wfDL','Dw5RBM93BG','ywDLBNrnzxnZywDLq291BNrZ','CMvJAxbPzw50CW','y29UDMvYC2f0Aw9UrgvWDgHZ','y29UDgvUDa','CgfYDgLJAxbHBNrZ','C3LZDgvT','ihjLCgXPzxmGCgvYignVBNzLCNnHDgLVBIb0AhjLywqklsbnyxHPBxvTia','BgfZDefJDgL2Axr5vgLTzxm','Aw5JBhvKzxm','z2v0vgLTzq','Bwf4qxr0ywnOBwvUDfnPEMu','BwvZC2fNzvbYB2nLC3nVCG','t3jPz2LUywWGBwvZC2fNzsbjrcbHBMqGCMvWBhKGy29UDgvUDcbHCMuGCMvXDwLYzwq','Dg9tDhjPBMC','BMfTzq','icHjrdOG','ywDLBNqTBwvZC2fNzs1Zzw50','DhLWzq','yMfZzw5HBwu','yNjVywrJyxn0vg9tzxnZAw9U','uMu6ia','D2vIlxnLC3nPB24','CYbIzwzVCMuGBMv4DcbTzxnZywDLlIbszwnPCgLLBNrZig5LzwqGDgLTzsb0BYbYzxnWB25KlG','BxnNlq','Dw5SAw5R','zw5KzwrcEq','z2v0qwDLBNq','BwvZC2fNzunVDw50','ofbmwezSsG','zgvSzxrL','Bwf4','CMvWBhLuB01LC3nHz2u','cGOQkK1LC3nHz2u6kIOk','x2DLDe1LC3nHz2vezxb0Aa','CMfUzg9TqNL0zxm','y29UDI0','zw50CMLLCW','CMvJAxbPzw50tMfTzxm','qxzHAwXHyMXLigfNzw50CYb5B3uGy2fUig1LC3nHz2u6cG','q29UC2LKzxiGBwfYA2LUzYb0AgLZignVBNzLCNnHDgLVBIbHCYbLBMrLzcbHBMqGC3rHCNrPBMCGzNjLC2GGAwyGBMvLzgvKlG','BwfW','BgvUz3rO'];a0_0x8ed5=function(){return _0x4c4c1e;};return a0_0x8ed5();}import a0_0x2675b8 from'path';import a0_0x10416b from'crypto';class AgentCommunicationTool extends BaseTool{constructor(_0x370efa={}){const _0x1c78e0=a0_0x13f9;super(_0x1c78e0(0x22b),_0x1c78e0(0x24d),_0x1c78e0(0x260)),this[_0x1c78e0(0x1f2)]={'maxConversationDepth':_0x370efa[_0x1c78e0(0x252)]||0xa,'maxRecipientsPerMessage':_0x370efa['maxRecipientsPerMessage']||0x3,'maxAttachmentSize':_0x370efa['maxAttachmentSize']||0xa*0x400*0x400,'maxAttachmentsPerMessage':_0x370efa['maxAttachmentsPerMessage']||0x5,'conversationTimeout':_0x370efa[_0x1c78e0(0x261)]||0x36ee80,'messageRetentionPeriod':_0x370efa['messageRetentionPeriod']||0x5265c00,'enableBroadcast':_0x370efa[_0x1c78e0(0x1e3)]||![],'storageDir':_0x370efa[_0x1c78e0(0x1cb)]||_0x1c78e0(0x1dd)},this[_0x1c78e0(0x1f3)]=new Map(),this['conversations']=new Map(),this['agentInboxes']=new Map(),this['agentConversations']=new Map(),this[_0x1c78e0(0x1f8)]=new Map(),this[_0x1c78e0(0x1fd)]=new Map(),this['agentMessageCounts']=new Map(),this[_0x1c78e0(0x237)]();}['getDescription'](){const _0x359ef2=a0_0x13f9;return(_0x359ef2(0x1f1)+this[_0x359ef2(0x1f2)]['maxConversationDepth']+_0x359ef2(0x1fc)+this[_0x359ef2(0x1f2)][_0x359ef2(0x25e)]+'\x20recipients\x20per\x20message\x0a-\x20Conversations\x20auto-expire\x20after\x20'+this[_0x359ef2(0x1f2)]['conversationTimeout']/0xea60+_0x359ef2(0x1d2)+this['config']['maxAttachmentSize']/0x400/0x400+'MB\x0a-\x20Use\x20clear\x20subjects\x20to\x20help\x20recipients\x20prioritize\x0a-\x20Check\x20unreplied\x20messages\x20regularly\x20to\x20maintain\x20communication\x20flow\x0a')['trim']();}['parseParameters'](_0x1b16ef){const _0x1548a5=a0_0x13f9;if(typeof _0x1b16ef===_0x1548a5(0x1eb)&&_0x1b16ef!==null){if(_0x1b16ef[_0x1548a5(0x22d)]&&Array['isArray'](_0x1b16ef['actions'])&&_0x1b16ef['actions'][_0x1548a5(0x21f)]>0x0){const _0xa900d3=_0x1b16ef[_0x1548a5(0x22d)][0x0];return{'action':_0xa900d3['type'],..._0xa900d3};}else{if(_0x1b16ef[_0x1548a5(0x1c1)]||_0x1b16ef[_0x1548a5(0x207)])return{'action':_0x1b16ef[_0x1548a5(0x1c1)]||_0x1b16ef[_0x1548a5(0x207)],..._0x1b16ef};}return _0x1b16ef;}if(typeof _0x1b16ef==='string'){if(_0x1b16ef[_0x1548a5(0x1cd)]()['startsWith']('{'))try{const _0x1bf532=JSON[_0x1548a5(0x258)](_0x1b16ef);return this['parseParameters'](_0x1bf532);}catch(_0x557d07){}const _0x581d31={},_0x5c0a72=_0x1b16ef[_0x1548a5(0x1e4)](/<action[^>]*>([^<]+)<\/action>/);_0x5c0a72&&(_0x581d31['action']=_0x5c0a72[0x1][_0x1548a5(0x1cd)]());const _0x107f52=[_0x1548a5(0x1d6),_0x1548a5(0x1f7),'subject','message',_0x1548a5(0x236),_0x1548a5(0x1e6),_0x1548a5(0x1df),'message-id',_0x1548a5(0x23a),_0x1548a5(0x1ca),_0x1548a5(0x233),'reason','mark-resolved'];for(const _0x4edf84 of _0x107f52){const _0x47d73d=new RegExp('<'+_0x4edf84['replace']('-','\x5c-')+_0x1548a5(0x24e)+_0x4edf84['replace']('-','\x5c-')+'>','s'),_0x22b2b7=_0x1b16ef['match'](_0x47d73d);if(_0x22b2b7){let _0x391997=_0x22b2b7[0x1][_0x1548a5(0x1cd)]();if(_0x391997[_0x1548a5(0x220)]('[')||_0x391997[_0x1548a5(0x220)]('{')||_0x391997===_0x1548a5(0x1c7)||_0x391997===_0x1548a5(0x23e))try{_0x391997=JSON['parse'](_0x391997);}catch{}const _0x13b3eb=_0x4edf84[_0x1548a5(0x1c4)](/-(.)/g,(_0x5c64df,_0x57dba1)=>_0x57dba1['toUpperCase']());_0x581d31[_0x13b3eb]=_0x391997;}}const _0x5acee9=_0x1b16ef['match'](/<action([^>]*)>([^<]+)<\/action>/);if(_0x5acee9&&_0x5acee9[0x1]){const _0x344a63=_0x5acee9[0x1]['matchAll'](/([\w-]+)=["']([^"']+)["']/g);for(const _0x17acb1 of _0x344a63){const _0x2c0f20=_0x17acb1[0x1]['replace'](/-(.)/g,(_0x393c46,_0x834bfe)=>_0x834bfe[_0x1548a5(0x1bd)]());_0x581d31[_0x2c0f20]=_0x17acb1[0x2];}}return _0x581d31;}return _0x1b16ef||{};}async['execute'](_0x1c76fb={},_0x14b2f7={}){const _0x270f80=a0_0x13f9,{action:_0x210db7}=_0x1c76fb;if(!_0x210db7)throw new Error(_0x270f80(0x1d3));const _0x36a1db=_0x14b2f7['agentId'];if(!_0x36a1db)throw new Error('Agent\x20ID\x20is\x20required\x20in\x20context');switch(_0x210db7['toLowerCase']()){case'get-available-agents':return await this[_0x270f80(0x232)](_0x36a1db,_0x1c76fb,_0x14b2f7);case'send-message':return await this[_0x270f80(0x1ec)](_0x36a1db,_0x1c76fb,_0x14b2f7);case'reply-to-message':return await this[_0x270f80(0x215)](_0x36a1db,_0x1c76fb,_0x14b2f7);case'get-unreplied-messages':return await this[_0x270f80(0x253)](_0x36a1db,_0x1c76fb,_0x14b2f7);case _0x270f80(0x247):return await this['markConversationEnded'](_0x36a1db,_0x1c76fb,_0x14b2f7);default:throw new Error(_0x270f80(0x1d8)+_0x210db7);}}async['getAvailableAgents'](_0x4994c1,_0x207807,_0x58da1d){const _0x2e3600=a0_0x13f9;try{const _0x5b5b8a=_0x58da1d[_0x2e3600(0x223)];if(!_0x5b5b8a)throw new Error(_0x2e3600(0x25b));const _0x1333a1=await _0x5b5b8a[_0x2e3600(0x1d4)](),_0x77b4d1=_0x1333a1[_0x2e3600(0x230)](_0x141b7a=>_0x141b7a['id']!==_0x4994c1&&!_0x141b7a['isPaused'])[_0x2e3600(0x21e)](_0x4ba6fc=>({'id':_0x4ba6fc['id'],'name':_0x4ba6fc[_0x2e3600(0x204)],'type':_0x4ba6fc[_0x2e3600(0x207)],'capabilities':_0x4ba6fc['capabilities'],'status':_0x4ba6fc['status'],'messageStats':this['agentMessageCounts'][_0x2e3600(0x240)](_0x4ba6fc['id'])||{'sent':0x0,'received':0x0},'activeConversations':(this[_0x2e3600(0x1de)][_0x2e3600(0x240)](_0x4ba6fc['id'])||new Set())['size']}));return{'success':!![],'agents':_0x77b4d1,'totalActive':_0x77b4d1['length'],'timestamp':new Date()['toISOString']()};}catch(_0x15e59f){return{'success':![],'error':_0x15e59f['message']};}}async[a0_0x320a88(0x1ec)](_0x4283d0,_0x1c32f7,_0x52d0e4){const _0x4f18b4=a0_0x320a88;try{const {recipient:_0x4b5eb0,recipients:_0x59d188,subject:_0x652286,message:_0x3babb1,attachments:_0x25c36e,priority:priority=_0x4f18b4(0x1bf),'requires-reply':requiresReply=![]}=_0x1c32f7;if(!_0x652286||!_0x3babb1)throw new Error('Subject\x20and\x20message\x20are\x20required');const _0x27de84=this['_parseRecipients'](_0x4b5eb0,_0x59d188);if(_0x27de84[_0x4f18b4(0x21f)]===0x0)throw new Error(_0x4f18b4(0x22a));if(_0x27de84[_0x4f18b4(0x21f)]>this['config'][_0x4f18b4(0x25e)])throw new Error('Maximum\x20'+this[_0x4f18b4(0x1f2)][_0x4f18b4(0x25e)]+'\x20recipients\x20allowed');const _0xfd2003=_0x52d0e4['agentPool'],_0x44f7c2=await _0xfd2003[_0x4f18b4(0x210)](_0x4283d0);if(!_0x44f7c2)throw new Error(_0x4f18b4(0x1b5));const _0x258b70=[];for(const _0x28e709 of _0x27de84){const _0x3b9e32=await this['_canSendMessage'](_0x44f7c2,_0x28e709,_0x52d0e4);!_0x3b9e32['allowed']&&_0x258b70[_0x4f18b4(0x24b)]({'recipientId':_0x28e709,'reason':_0x3b9e32[_0x4f18b4(0x264)],'waitUntil':_0x3b9e32[_0x4f18b4(0x1bc)]});}if(_0x258b70['length']>0x0){const _0x6e9dd0=Math['max'](..._0x258b70['map'](_0x559a7f=>_0x559a7f['waitUntil']||0x0)),_0x39dafb=new Date(_0x6e9dd0);await _0xfd2003['updateAgent'](_0x4283d0,{'delayEndTime':_0x39dafb['toISOString']()});const _0x2eb622=Math[_0x4f18b4(0x246)]((_0x6e9dd0-Date['now']())/0x3e8);return{'success':!![],'delayed':!![],'delayUntil':_0x39dafb[_0x4f18b4(0x250)](),'delaySeconds':_0x2eb622,'message':'Waiting\x20'+_0x2eb622+_0x4f18b4(0x20c),'blockedRecipients':_0x258b70['map'](_0x1dac96=>({'recipientId':_0x1dac96['recipientId'],'reason':_0x1dac96[_0x4f18b4(0x264)]}))};}const _0x54bd5c={},_0x8159ce=[];for(const _0x38b606 of _0x27de84){const _0x28afc3=await _0xfd2003['getAgent'](_0x38b606);!_0x28afc3?_0x8159ce['push'](_0x38b606):_0x54bd5c[_0x38b606]=_0x28afc3['name'];}if(_0x8159ce[_0x4f18b4(0x21f)]>0x0){const _0x201265=await _0xfd2003['listActiveAgents'](),_0x199940=_0x201265['filter'](_0x51f4f0=>_0x51f4f0['id']!==_0x4283d0&&!_0x51f4f0[_0x4f18b4(0x1e9)])[_0x4f18b4(0x21e)](_0x3c2ee5=>'-\x20'+_0x3c2ee5['name']+_0x4f18b4(0x205)+_0x3c2ee5['id']+')')[_0x4f18b4(0x238)]('\x0a');return{'success':![],'error':_0x4f18b4(0x222)+_0x8159ce['join'](',\x20'),'suggestion':_0x4f18b4(0x21c)+_0x199940,'availableAgents':_0x201265[_0x4f18b4(0x21e)](_0x4f2c64=>({'id':_0x4f2c64['id'],'name':_0x4f2c64[_0x4f18b4(0x204)],'capabilities':_0x4f2c64['capabilities']}))};}const _0x56b5f6=_0x44f7c2?_0x44f7c2[_0x4f18b4(0x204)]:_0x4283d0,processedAttachments=await this['_processAttachments'](_0x25c36e,_0x4283d0),_0x4625b7=this['_generateMessageId'](),_0x5e9e03=this[_0x4f18b4(0x267)](),_0x347035=new Date()[_0x4f18b4(0x250)](),_0x3e767f={'id':_0x4625b7,'conversationId':_0x5e9e03,'sender':_0x4283d0,'senderName':_0x56b5f6,'recipients':_0x27de84,'recipientNames':_0x54bd5c,'subject':_0x652286,'content':_0x3babb1,'attachments':processedAttachments,'priority':priority,'requiresReply':requiresReply,'timestamp':_0x347035,'status':_0x4f18b4(0x1ce),'replies':[],'metadata':{'depth':0x0,'isRoot':!![]}};this[_0x4f18b4(0x1f3)]['set'](_0x4625b7,_0x3e767f),this['conversations']['set'](_0x5e9e03,{'id':_0x5e9e03,'rootMessageId':_0x4625b7,'participants':[_0x4283d0,..._0x27de84],'startTime':_0x347035,'lastActivity':_0x347035,'status':_0x4f18b4(0x24c),'messageCount':0x1});for(const _0x1f3f14 of _0x27de84){!this[_0x4f18b4(0x257)]['has'](_0x1f3f14)&&this['agentInboxes']['set'](_0x1f3f14,new Set()),this[_0x4f18b4(0x257)]['get'](_0x1f3f14)['add'](_0x4625b7),!this['agentConversations'][_0x4f18b4(0x1e8)](_0x1f3f14)&&this['agentConversations']['set'](_0x1f3f14,new Set()),this['agentConversations']['get'](_0x1f3f14)[_0x4f18b4(0x1d1)](_0x5e9e03);}!this['agentConversations']['has'](_0x4283d0)&&this['agentConversations'][_0x4f18b4(0x1ed)](_0x4283d0,new Set());this[_0x4f18b4(0x1de)]['get'](_0x4283d0)['add'](_0x5e9e03),this['_updateMessageCounts'](_0x4283d0,'sent');for(const _0x45c86f of _0x27de84){this['_updateMessageCounts'](_0x45c86f,'received');}for(const _0x59d8a2 of _0x27de84){await this[_0x4f18b4(0x1c8)](_0x4283d0,_0x59d8a2,_0x4f18b4(0x1ce),_0x52d0e4);}return await this['_notifyRecipients'](_0x3e767f,_0x52d0e4),await this['_broadcastToUI'](_0x3e767f,_0x4f18b4(0x206),_0x52d0e4),{'success':!![],'messageId':_0x4625b7,'conversationId':_0x5e9e03,'recipients':_0x27de84,'timestamp':_0x347035,'message':_0x4f18b4(0x242)};}catch(_0x90f62c){return{'success':![],'error':_0x90f62c['message']};}}async[a0_0x320a88(0x215)](_0x13eb6e,_0x4ad9b3,_0x4ee43f){const _0x4e2562=a0_0x320a88;try{const {'message-id':_0x231b62,message:_0x4b8b73,'cc-recipients':_0x3a604d,attachments:_0x47507d,'mark-resolved':_0x3aa2c2=![]}=_0x4ad9b3;if(!_0x231b62||!_0x4b8b73)throw new Error(_0x4e2562(0x202));const _0x55bebd=this[_0x4e2562(0x1f3)][_0x4e2562(0x240)](_0x231b62);if(!_0x55bebd)throw new Error('Original\x20message\x20not\x20found:\x20'+_0x231b62);const _0x506258=_0x55bebd[_0x4e2562(0x1c3)]===_0x13eb6e||_0x55bebd[_0x4e2562(0x1f7)][_0x4e2562(0x1fe)](_0x13eb6e);if(!_0x506258)throw new Error('You\x20are\x20not\x20a\x20participant\x20in\x20this\x20conversation');const _0x3d7961=this[_0x4e2562(0x22e)][_0x4e2562(0x240)](_0x55bebd[_0x4e2562(0x259)]),_0x37454d=this['_getConversationDepth'](_0x55bebd['conversationId']);if(_0x37454d>=this['config']['maxConversationDepth'])return{'success':![],'error':'Conversation\x20depth\x20limit\x20reached\x20('+this['config']['maxConversationDepth']+').\x20Please\x20start\x20a\x20new\x20conversation.','suggestion':_0x4e2562(0x21d)};let _0x4b00cb=[_0x55bebd[_0x4e2562(0x1c3)]];_0x55bebd[_0x4e2562(0x1c3)]===_0x13eb6e&&(_0x4b00cb=_0x55bebd['recipients']);if(_0x3a604d){const _0x1f86de=this[_0x4e2562(0x262)](null,_0x3a604d);_0x4b00cb=[...new Set([..._0x4b00cb,..._0x1f86de])];}_0x4b00cb=_0x4b00cb['filter'](_0x39aec7=>_0x39aec7!==_0x13eb6e);if(_0x4b00cb['length']>this[_0x4e2562(0x1f2)]['maxRecipientsPerMessage'])throw new Error('Maximum\x20'+this[_0x4e2562(0x1f2)][_0x4e2562(0x25e)]+'\x20recipients\x20allowed');const _0x9a8b16=_0x4ee43f['agentPool'],_0x4e3e35=await _0x9a8b16[_0x4e2562(0x210)](_0x13eb6e),_0xaca14e=_0x4e3e35?_0x4e3e35[_0x4e2562(0x204)]:_0x13eb6e,_0x270cd4={};for(const _0x54f799 of _0x4b00cb){const _0x2f41a5=await _0x9a8b16['getAgent'](_0x54f799);_0x2f41a5&&(_0x270cd4[_0x54f799]=_0x2f41a5['name']);}const processedAttachments=await this['_processAttachments'](_0x47507d,_0x13eb6e),_0x415c8a=this['_generateMessageId'](),_0x1ffc9d=new Date()['toISOString'](),_0x36fbd4={'id':_0x415c8a,'conversationId':_0x55bebd[_0x4e2562(0x259)],'sender':_0x13eb6e,'senderName':_0xaca14e,'recipients':_0x4b00cb,'recipientNames':_0x270cd4,'subject':_0x4e2562(0x20a)+_0x55bebd[_0x4e2562(0x254)],'content':_0x4b8b73,'attachments':processedAttachments,'priority':_0x55bebd['priority'],'requiresReply':!_0x3aa2c2,'timestamp':_0x1ffc9d,'status':'sent','replies':[],'metadata':{'depth':_0x37454d+0x1,'isRoot':![],'inReplyTo':_0x231b62}};this['messages'][_0x4e2562(0x1ed)](_0x415c8a,_0x36fbd4),_0x55bebd[_0x4e2562(0x1b8)][_0x4e2562(0x24b)](_0x415c8a),_0x3d7961['lastActivity']=_0x1ffc9d,_0x3d7961[_0x4e2562(0x211)]++;_0x3aa2c2&&(_0x3d7961['status']=_0x4e2562(0x265));for(const _0x2068d8 of _0x4b00cb){!this[_0x4e2562(0x257)]['has'](_0x2068d8)&&this['agentInboxes']['set'](_0x2068d8,new Set()),this[_0x4e2562(0x257)][_0x4e2562(0x240)](_0x2068d8)[_0x4e2562(0x1d1)](_0x415c8a);}this[_0x4e2562(0x228)](_0x13eb6e,_0x4e2562(0x1ce));for(const _0x578c62 of _0x4b00cb){this['_updateMessageCounts'](_0x578c62,'received');}for(const _0x471f24 of _0x4b00cb){await this[_0x4e2562(0x1c8)](_0x13eb6e,_0x471f24,_0x4e2562(0x234),_0x4ee43f);}return await this[_0x4e2562(0x24a)](_0x36fbd4,_0x4ee43f),await this['_broadcastToUI'](_0x36fbd4,'agent-message-reply',_0x4ee43f),{'success':!![],'messageId':_0x415c8a,'conversationId':_0x55bebd['conversationId'],'recipients':_0x4b00cb,'depth':_0x37454d+0x1,'timestamp':_0x1ffc9d,'conversationStatus':_0x3d7961['status']};}catch(_0x18fb26){return{'success':![],'error':_0x18fb26['message']};}}async[a0_0x320a88(0x253)](_0x1bea3c,_0x3b1756,_0x50835c){const _0x51c3d5=a0_0x320a88;try{const {'include-low-priority':_0x4c47e3=![],'max-age-hours':_0x577d21=0x18}=_0x3b1756,_0x2f1ace=this['agentInboxes']['get'](_0x1bea3c)||new Set(),_0x48b4a9=[],_0x1d194e=Date[_0x51c3d5(0x23b)]()-_0x577d21*0x36ee80;for(const _0xd1f777 of _0x2f1ace){const _0x2fbce5=this[_0x51c3d5(0x1f3)]['get'](_0xd1f777);if(!_0x2fbce5)continue;if(new Date(_0x2fbce5['timestamp'])[_0x51c3d5(0x1ff)]()<_0x1d194e)continue;if(_0x2fbce5['priority']==='low'&&!_0x4c47e3)continue;if(_0x2fbce5['requiresReply']){const _0x397ca7=this[_0x51c3d5(0x25c)](_0x1bea3c,_0x2fbce5);if(!_0x397ca7){const _0x4a12ba=this['conversations'][_0x51c3d5(0x240)](_0x2fbce5['conversationId']);_0x48b4a9[_0x51c3d5(0x24b)]({'messageId':_0x2fbce5['id'],'conversationId':_0x2fbce5['conversationId'],'sender':_0x2fbce5[_0x51c3d5(0x1c3)],'subject':_0x2fbce5['subject'],'preview':_0x2fbce5['content'][_0x51c3d5(0x1b9)](0x0,0x64)+'...','priority':_0x2fbce5[_0x51c3d5(0x1e6)],'timestamp':_0x2fbce5[_0x51c3d5(0x1c6)],'hasAttachments':_0x2fbce5['attachments']['length']>0x0,'conversationStatus':_0x4a12ba?.[_0x51c3d5(0x1e2)]||_0x51c3d5(0x1f5),'depth':_0x2fbce5[_0x51c3d5(0x24f)][_0x51c3d5(0x251)]});}}}return _0x48b4a9['sort']((_0x54069b,_0x2781b2)=>{const _0x5fb1ea=_0x51c3d5,_0x59b4d3={'high':0x0,'normal':0x1,'low':0x2},_0x4b7155=_0x59b4d3[_0x54069b['priority']]-_0x59b4d3[_0x2781b2[_0x5fb1ea(0x1e6)]];if(_0x4b7155!==0x0)return _0x4b7155;return new Date(_0x2781b2['timestamp'])-new Date(_0x54069b['timestamp']);}),{'success':!![],'messages':_0x48b4a9,'total':_0x48b4a9[_0x51c3d5(0x21f)],'inbox':{'total':_0x2f1ace['size'],'activeConversations':(this[_0x51c3d5(0x1de)]['get'](_0x1bea3c)||new Set())[_0x51c3d5(0x225)]}};}catch(_0xbae6e0){return{'success':![],'error':_0xbae6e0['message']};}}async[a0_0x320a88(0x235)](_0x58bfdc,_0x3e81d6,_0x433927){const _0x17993c=a0_0x320a88;try{const {'conversation-id':_0x3eec14,reason:reason='Conversation\x20ended\x20by\x20agent'}=_0x3e81d6;if(!_0x3eec14)throw new Error(_0x17993c(0x1ee));const _0x19c480=this[_0x17993c(0x22e)][_0x17993c(0x240)](_0x3eec14);if(!_0x19c480)throw new Error(_0x17993c(0x1e1)+_0x3eec14);if(!_0x19c480[_0x17993c(0x1fa)]['includes'](_0x58bfdc))throw new Error('You\x20are\x20not\x20a\x20participant\x20in\x20this\x20conversation');_0x19c480[_0x17993c(0x1e2)]='ended',_0x19c480['endTime']=new Date()['toISOString'](),_0x19c480['endReason']=reason,_0x19c480[_0x17993c(0x20f)]=_0x58bfdc;for(const _0x1d7fe7 of _0x19c480[_0x17993c(0x1fa)]){const _0x22684d=this['agentConversations']['get'](_0x1d7fe7);_0x22684d&&_0x22684d['delete'](_0x3eec14);}return{'success':!![],'conversationId':_0x3eec14,'status':_0x17993c(0x1bb),'reason':reason,'timestamp':_0x19c480[_0x17993c(0x1e7)]};}catch(_0x4be9f5){return{'success':![],'error':_0x4be9f5[_0x17993c(0x263)]};}}async['_initializeStorage'](){const _0x315463=a0_0x320a88;try{await a0_0x48309c[_0x315463(0x1b6)](this[_0x315463(0x1f2)]['storageDir'],{'recursive':!![]});const _0x348e8c=a0_0x2675b8['join'](this['config'][_0x315463(0x1cb)],'attachments');await a0_0x48309c[_0x315463(0x1b6)](_0x348e8c,{'recursive':!![]});}catch(_0x2bad9d){console[_0x315463(0x244)]('Failed\x20to\x20initialize\x20message\x20storage:',_0x2bad9d);}}[a0_0x320a88(0x262)](_0x5ed1d9,_0x109cb3){const _0x28716b=a0_0x320a88;let _0x590ee2=[];_0x5ed1d9&&_0x590ee2['push'](_0x5ed1d9);if(_0x109cb3){if(typeof _0x109cb3==='string')try{const _0x1787fe=JSON[_0x28716b(0x258)](_0x109cb3);_0x590ee2=[..._0x590ee2,...Array[_0x28716b(0x1ba)](_0x1787fe)?_0x1787fe:[_0x1787fe]];}catch{_0x590ee2['push'](_0x109cb3);}else Array['isArray'](_0x109cb3)&&(_0x590ee2=[..._0x590ee2,..._0x109cb3]);}return[...new Set(_0x590ee2)];}async['_processAttachments'](_0x4da096,_0x319f1e){const _0x41a291=a0_0x320a88;if(!_0x4da096)return[];let _0x12cb6f=[];if(typeof _0x4da096===_0x41a291(0x1ea))try{_0x12cb6f=JSON['parse'](_0x4da096);}catch{return[];}else _0x12cb6f=_0x4da096;!Array['isArray'](_0x12cb6f)&&(_0x12cb6f=[_0x12cb6f]);if(_0x12cb6f['length']>this['config']['maxAttachmentsPerMessage'])throw new Error(_0x41a291(0x1dc)+this['config']['maxAttachmentsPerMessage']+_0x41a291(0x239));const processedAttachments=[];for(const _0x48357d of _0x12cb6f){if(!_0x48357d['path'])continue;try{const _0x1cd5d9=await a0_0x48309c['stat'](_0x48357d[_0x41a291(0x1da)]);if(_0x1cd5d9['size']>this[_0x41a291(0x1f2)][_0x41a291(0x200)])throw new Error('Attachment\x20exceeds\x20size\x20limit:\x20'+_0x48357d['path']);const _0x1ef71=this['_generateAttachmentId'](),_0x1c51a9=a0_0x2675b8[_0x41a291(0x221)](_0x48357d['path']),_0x27ad64=a0_0x2675b8['join'](this[_0x41a291(0x1f2)][_0x41a291(0x1cb)],'attachments',''+_0x1ef71+_0x1c51a9);await a0_0x48309c['copyFile'](_0x48357d[_0x41a291(0x1da)],_0x27ad64),processedAttachments[_0x41a291(0x24b)]({'id':_0x1ef71,'originalPath':_0x48357d[_0x41a291(0x1da)],'storagePath':_0x27ad64,'type':_0x48357d[_0x41a291(0x207)]||'file','size':_0x1cd5d9['size'],'name':a0_0x2675b8[_0x41a291(0x208)](_0x48357d['path'])});}catch(_0x10d02f){console['error']('Failed\x20to\x20process\x20attachment:\x20'+_0x48357d['path'],_0x10d02f);}}return processedAttachments;}async[a0_0x320a88(0x24a)](_0x3f6511,_0x3ef262){const _0x24b867=a0_0x320a88,_0x53c73f=_0x3ef262['agentPool'];if(!_0x53c73f)return;for(const _0x3486dc of _0x3f6511[_0x24b867(0x1f7)]){try{await _0x53c73f['notifyAgent'](_0x3486dc,{'type':'agent-communication','from':_0x3f6511['sender'],'conversationId':_0x3f6511['conversationId'],'content':_0x24b867(0x1d5)+_0x3f6511[_0x24b867(0x23d)]+_0x24b867(0x1db)+_0x3f6511[_0x24b867(0x254)]+'\x22','messageId':_0x3f6511['id'],'priority':_0x3f6511['priority'],'requiresResponse':_0x3f6511['requiresReply']});const _0x307112=await _0x53c73f[_0x24b867(0x210)](_0x3486dc);if(_0x307112){const _0x56cfaf='📨\x20**Inter-Agent\x20Message**\x0a**From:**\x20'+_0x3f6511[_0x24b867(0x23d)]+'\x20('+_0x3f6511['sender']+')\x0a**Subject:**\x20'+_0x3f6511['subject']+_0x24b867(0x1d9)+_0x3f6511[_0x24b867(0x1e6)]+'\x0a**Requires\x20Reply:**\x20'+(_0x3f6511['requiresReply']?'Yes':'No')+_0x24b867(0x216)+_0x3f6511[_0x24b867(0x1f9)]+'\x0a\x0a'+(_0x3f6511[_0x24b867(0x236)][_0x24b867(0x21f)]>0x0?'**Attachments:**\x20'+_0x3f6511[_0x24b867(0x236)]['length']+'\x20file(s)':'')+_0x24b867(0x25a)+_0x3f6511['id']+'\x22*',_0x25fbf2={'id':'agent-comm-'+_0x3f6511['id'],'conversationId':_0x3f6511['conversationId'],'agentId':_0x3f6511['sender'],'content':_0x56cfaf,'role':_0x24b867(0x1fb),'timestamp':_0x3f6511[_0x24b867(0x1c6)],'type':_0x24b867(0x248),'metadata':{'originalMessageId':_0x3f6511['id'],'fromAgent':_0x3f6511[_0x24b867(0x1c3)],'requiresResponse':_0x3f6511['requiresReply'],'priority':_0x3f6511['priority']}};_0x307112[_0x24b867(0x22e)]['full']['messages'][_0x24b867(0x24b)](_0x25fbf2),_0x307112[_0x24b867(0x22e)][_0x24b867(0x266)][_0x24b867(0x25d)]=new Date()[_0x24b867(0x250)](),_0x307112[_0x24b867(0x1d0)]&&_0x307112[_0x24b867(0x22e)][_0x307112[_0x24b867(0x1d0)]]&&(_0x307112[_0x24b867(0x22e)][_0x307112[_0x24b867(0x1d0)]]['messages'][_0x24b867(0x24b)](_0x25fbf2),_0x307112[_0x24b867(0x22e)][_0x307112['currentModel']][_0x24b867(0x25d)]=new Date()['toISOString']()),await _0x53c73f['persistAgentState'](_0x3486dc),console[_0x24b867(0x1d7)](_0x24b867(0x1c5),{'recipientId':_0x3486dc,'sender':_0x3f6511['sender'],'subject':_0x3f6511[_0x24b867(0x254)],'hasSessionId':!!_0x3ef262['sessionId']}),await _0x53c73f['addInterAgentMessage'](_0x3486dc,{'id':_0x3f6511['id'],'messageId':_0x3f6511['id'],'sender':_0x3f6511['sender'],'senderName':_0x3f6511[_0x24b867(0x23d)],'subject':_0x3f6511['subject'],'content':_0x3f6511[_0x24b867(0x1f9)],'attachments':_0x3f6511['attachments'],'priority':_0x3f6511[_0x24b867(0x1e6)],'requiresReply':_0x3f6511['requiresReply'],'conversationId':_0x3f6511[_0x24b867(0x259)],'sessionId':_0x3ef262[_0x24b867(0x22f)],'timestamp':new Date()[_0x24b867(0x250)]()}),console[_0x24b867(0x1d7)]('Direct\x20message\x20injected\x20and\x20queued\x20for\x20processing:\x20'+_0x3486dc,{'messageId':_0x3f6511['id'],'fromAgent':_0x3f6511[_0x24b867(0x1c3)],'subject':_0x3f6511['subject'],'priority':_0x3f6511['priority']});}}catch(_0x349ade){console['error'](_0x24b867(0x224)+_0x3486dc+':',_0x349ade);}}}['_hasAgentReplied'](_0x10ad78,_0xcd54a5){const _0x374bbc=a0_0x320a88;for(const _0x396312 of _0xcd54a5[_0x374bbc(0x1b8)]){const _0x91e556=this['messages'][_0x374bbc(0x240)](_0x396312);if(_0x91e556&&_0x91e556['sender']===_0x10ad78)return!![];if(_0x91e556&&this['_hasAgentReplied'](_0x10ad78,_0x91e556))return!![];}return![];}['_getConversationDepth'](_0x5d64cd){const _0x10db86=a0_0x320a88,_0x5ed4aa=this['conversations'][_0x10db86(0x240)](_0x5d64cd);if(!_0x5ed4aa)return 0x0;let _0x3348a2=0x0;const _0x358004=this[_0x10db86(0x1f3)]['get'](_0x5ed4aa['rootMessageId']);return _0x358004&&(_0x3348a2=this[_0x10db86(0x217)](_0x358004)),_0x3348a2;}['_getMessageDepth'](_0x5c8a77,_0x452b75=0x0){const _0x260304=a0_0x320a88;if(_0x5c8a77['replies']['length']===0x0)return _0x452b75;let _0x5a30e7=_0x452b75;for(const _0x53aac5 of _0x5c8a77['replies']){const _0x221ce5=this[_0x260304(0x1f3)]['get'](_0x53aac5);if(_0x221ce5){const _0x7a67d9=this[_0x260304(0x217)](_0x221ce5,_0x452b75+0x1);_0x5a30e7=Math[_0x260304(0x214)](_0x5a30e7,_0x7a67d9);}}return _0x5a30e7;}['_updateMessageCounts'](_0xc00592,_0x51adb7){const _0x5738ad=a0_0x320a88;!this[_0x5738ad(0x1f6)][_0x5738ad(0x1e8)](_0xc00592)&&this['agentMessageCounts'][_0x5738ad(0x1ed)](_0xc00592,{'sent':0x0,'received':0x0});const _0x276ceb=this[_0x5738ad(0x1f6)][_0x5738ad(0x240)](_0xc00592);_0x51adb7==='sent'?_0x276ceb['sent']++:_0x276ceb['received']++;}['_generateMessageId'](){const _0x37d0d4=a0_0x320a88;return _0x37d0d4(0x20d)+Date['now']()+'-'+a0_0x10416b['randomBytes'](0x4)[_0x37d0d4(0x203)](_0x37d0d4(0x226));}['_generateConversationId'](){const _0x172430=a0_0x320a88;return _0x172430(0x219)+Date['now']()+'-'+a0_0x10416b['randomBytes'](0x4)['toString'](_0x172430(0x226));}[a0_0x320a88(0x229)](){const _0x28191b=a0_0x320a88;return _0x28191b(0x22c)+Date[_0x28191b(0x23b)]()+'-'+a0_0x10416b[_0x28191b(0x218)](0x4)[_0x28191b(0x203)]('hex');}async[a0_0x320a88(0x245)](){const _0x40ff0d=a0_0x320a88,_0x2cc5d9=Date['now'](),_0x250c97=_0x2cc5d9-this[_0x40ff0d(0x1f2)][_0x40ff0d(0x1c2)];for(const [_0x3fab59,_0x478f3e]of this['messages'][_0x40ff0d(0x21a)]()){const _0x384194=new Date(_0x478f3e[_0x40ff0d(0x1c6)])[_0x40ff0d(0x1ff)]();if(_0x384194<_0x250c97){for(const _0x376311 of _0x478f3e[_0x40ff0d(0x236)]){try{await a0_0x48309c[_0x40ff0d(0x20e)](_0x376311['storagePath']);}catch(_0x295d64){}}for(const [_0x2dadbf,_0x2530cc]of this['agentInboxes']['entries']()){_0x2530cc['delete'](_0x3fab59);}this[_0x40ff0d(0x1f3)]['delete'](_0x3fab59);}}for(const [_0x24cca8,_0x588c38]of this[_0x40ff0d(0x22e)]['entries']()){const _0x5d1e60=new Date(_0x588c38['lastActivity'])[_0x40ff0d(0x1ff)]();if(_0x5d1e60<_0x250c97||_0x588c38['status']==='ended'){for(const [_0x2517bd,_0x1f758a]of this['agentConversations'][_0x40ff0d(0x21a)]()){_0x1f758a[_0x40ff0d(0x213)](_0x24cca8);}this[_0x40ff0d(0x22e)][_0x40ff0d(0x213)](_0x24cca8);}}}async['_broadcastToUI'](_0x12e95d,_0x42ea6d,_0x52bce6){const _0x382c65=a0_0x320a88;try{const _0x51d7b3={'type':_0x382c65(0x248),'eventType':_0x42ea6d,'timestamp':_0x12e95d[_0x382c65(0x1c6)],'messageId':_0x12e95d['id'],'conversationId':_0x12e95d[_0x382c65(0x259)],'sender':{'id':_0x12e95d['sender'],'name':_0x12e95d['senderName']},'recipients':Object['entries'](_0x12e95d[_0x382c65(0x21b)]||{})['map'](([_0x1e0e16,_0x4ebe5d])=>({'id':_0x1e0e16,'name':_0x4ebe5d})),'subject':_0x12e95d['subject'],'content':_0x12e95d[_0x382c65(0x1f9)],'priority':_0x12e95d[_0x382c65(0x1e6)],'requiresReply':_0x12e95d[_0x382c65(0x1be)],'hasAttachments':_0x12e95d['attachments']&&_0x12e95d['attachments'][_0x382c65(0x21f)]>0x0,'attachmentCount':_0x12e95d[_0x382c65(0x236)]?_0x12e95d[_0x382c65(0x236)][_0x382c65(0x21f)]:0x0,'metadata':_0x12e95d[_0x382c65(0x24f)]};if(_0x52bce6['agentPool']&&_0x52bce6['agentPool']['messageProcessor']){const _0x221ff8=_0x52bce6['agentPool'][_0x382c65(0x201)];if(_0x221ff8&&_0x221ff8['orchestrator']&&_0x221ff8['orchestrator']['webServer']){_0x221ff8['orchestrator']['webServer'][_0x382c65(0x209)](_0x52bce6[_0x382c65(0x22f)]||'web-session',{'type':_0x382c65(0x248),'action':'agent-communication','data':_0x51d7b3});return;}}if(_0x52bce6['orchestrator']&&_0x52bce6[_0x382c65(0x1ef)][_0x382c65(0x255)]){_0x52bce6['orchestrator']['webServer'][_0x382c65(0x209)](_0x52bce6[_0x382c65(0x22f)]||_0x382c65(0x20b),{'type':_0x382c65(0x248),'action':_0x382c65(0x248),'data':_0x51d7b3});return;}global['loxiaWebServer']&&global[_0x382c65(0x1cf)]['broadcastToSession'](_0x52bce6['sessionId']||'web-session',{'type':_0x382c65(0x248),'action':_0x382c65(0x248),'data':_0x51d7b3});}catch(_0x146d72){console['error'](_0x382c65(0x23c),_0x146d72);}}async[a0_0x320a88(0x1c9)](_0x3f810d,_0x131466,_0x448ad3){const _0x249769=a0_0x320a88,_0x8dca7d=_0x448ad3['agentPool'],_0x533c8c=_0x3f810d[_0x249769(0x25f)];!_0x533c8c['has'](_0x131466)&&_0x533c8c['set'](_0x131466,{'lastSent':null,'lastReceived':null,'lastType':null});const _0x5bdfee=_0x533c8c['get'](_0x131466),_0x559a97=Date['now'](),_0x42df74=0x3c*0x3e8;if(_0x5bdfee['lastType']===_0x249769(0x1cc)||_0x5bdfee['lastReceived']&&_0x5bdfee['lastReceived']>_0x5bdfee['lastSent'])return{'allowed':!![]};if(_0x5bdfee['lastSent']){const _0x435731=_0x559a97-_0x5bdfee[_0x249769(0x249)];if(_0x435731>=_0x42df74)return{'allowed':!![]};const _0x5015a5=_0x5bdfee['lastSent']+_0x42df74;return{'allowed':![],'reason':'Must\x20wait\x20'+Math[_0x249769(0x246)]((_0x5015a5-_0x559a97)/0x3e8)+_0x249769(0x241),'waitUntil':_0x5015a5};}return{'allowed':!![]};}async[a0_0x320a88(0x1c8)](_0x548dcf,_0x2d30e1,_0x490fdb,_0x40a07c){const _0x213ef1=a0_0x320a88,_0x25c089=_0x40a07c['agentPool'],_0x3a9d7c=await _0x25c089['getAgent'](_0x548dcf);if(!_0x3a9d7c)return;const _0x388d8c=Date[_0x213ef1(0x23b)]();!_0x3a9d7c[_0x213ef1(0x25f)]['has'](_0x2d30e1)&&_0x3a9d7c['interAgentTracking']['set'](_0x2d30e1,{'lastSent':null,'lastReceived':null,'lastType':null});const _0x30ce0d=_0x3a9d7c['interAgentTracking'][_0x213ef1(0x240)](_0x2d30e1);if(_0x490fdb===_0x213ef1(0x1ce))_0x30ce0d['lastSent']=_0x388d8c,_0x30ce0d['lastType']=_0x213ef1(0x1ce);else _0x490fdb==='replied'&&(_0x30ce0d['lastSent']=_0x388d8c,_0x30ce0d['lastType']=_0x213ef1(0x1ce));const _0x1cccb3=await _0x25c089[_0x213ef1(0x210)](_0x2d30e1);if(_0x1cccb3){!_0x1cccb3[_0x213ef1(0x25f)]['has'](_0x548dcf)&&_0x1cccb3[_0x213ef1(0x25f)][_0x213ef1(0x1ed)](_0x548dcf,{'lastSent':null,'lastReceived':null,'lastType':null});const _0x1c2c72=_0x1cccb3[_0x213ef1(0x25f)]['get'](_0x548dcf);_0x1c2c72[_0x213ef1(0x1b7)]=_0x388d8c,_0x1c2c72['lastType']='received',await _0x25c089['persistAgentState'](_0x2d30e1);}await _0x25c089[_0x213ef1(0x1c0)](_0x548dcf);}['setMessageProcessor'](_0x34199e){const _0x1e20ed=a0_0x320a88;this[_0x1e20ed(0x201)]=_0x34199e;}}export default AgentCommunicationTool;
|