claude-flow-novice 1.6.3 → 1.6.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/.claude/settings.json +12 -2
- package/.claude/settings.local.json +3 -2
- package/.claude-flow-novice/dist/src/coordination/index.js +3 -0
- package/.claude-flow-novice/dist/src/coordination/index.js.map +1 -1
- package/.claude-flow-novice/dist/src/coordination/v1-transparency/interfaces/v1-transparency-system.js +12 -0
- package/.claude-flow-novice/dist/src/coordination/v1-transparency/interfaces/v1-transparency-system.js.map +1 -0
- package/.claude-flow-novice/dist/src/coordination/v1-transparency/v1-to-v2-bridge.js +433 -0
- package/.claude-flow-novice/dist/src/coordination/v1-transparency/v1-to-v2-bridge.js.map +1 -0
- package/.claude-flow-novice/dist/src/coordination/v1-transparency/v1-transparency-adapter.js +1468 -0
- package/.claude-flow-novice/dist/src/coordination/v1-transparency/v1-transparency-adapter.js.map +1 -0
- package/.claude-flow-novice/dist/src/monitoring/apm/apm-integration.js +5 -0
- package/.claude-flow-novice/dist/src/monitoring/apm/apm-integration.js.map +1 -1
- package/.claude-flow-novice/dist/src/providers/provider-manager.js +5 -3
- package/.claude-flow-novice/dist/src/providers/provider-manager.js.map +1 -1
- package/.claude-flow-novice/dist/src/providers/tiered-router.js +9 -17
- package/.claude-flow-novice/dist/src/providers/tiered-router.js.map +1 -1
- package/.claude-flow-novice/metrics.db +0 -0
- package/CLAUDE.md +72 -0
- package/config/hooks/post-edit-pipeline.js +68 -118
- package/config/hooks/pre-tool-memory-safety.js +209 -0
- package/package.json +6 -3
- package/scripts/cleanup-idle-sessions.sh +59 -0
- package/scripts/test-provider-routing.cjs +7 -9
- package/wiki/Provider-Routing.md +57 -69
- package/.claude-flow-novice/metrics.db-shm +0 -0
- package/.claude-flow-novice/metrics.db-wal +0 -0
- package/MEMORY_LEAK_ROOT_CAUSE.md +0 -149
|
@@ -0,0 +1,1468 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* V1 Transparency System Adapter
|
|
3
|
+
*
|
|
4
|
+
* Adapts existing V1 coordinators (QueenAgent, MeshCoordinator) to provide
|
|
5
|
+
* transparency features without modifying the original coordinator implementations.
|
|
6
|
+
*
|
|
7
|
+
* @module coordination/v1-transparency/v1-transparency-adapter
|
|
8
|
+
*/ import { EventEmitter } from 'events';
|
|
9
|
+
import { v4 as uuidv4 } from 'uuid';
|
|
10
|
+
/**
|
|
11
|
+
* V1 Transparency System Implementation
|
|
12
|
+
*
|
|
13
|
+
* Wraps existing V1 coordinators to provide transparency features
|
|
14
|
+
* by listening to their events and collecting metrics.
|
|
15
|
+
*/ export class V1TransparencySystem extends EventEmitter {
|
|
16
|
+
logger;
|
|
17
|
+
config;
|
|
18
|
+
isInitialized = false;
|
|
19
|
+
isMonitoring = false;
|
|
20
|
+
// V1 Coordinator tracking
|
|
21
|
+
coordinatorAdapters = new Map();
|
|
22
|
+
coordinatorInfo = new Map();
|
|
23
|
+
agentInfo = new Map();
|
|
24
|
+
taskInfo = new Map();
|
|
25
|
+
transparencyEvents = [];
|
|
26
|
+
eventListeners = new Set();
|
|
27
|
+
// Monitoring intervals
|
|
28
|
+
metricsCollectionInterval;
|
|
29
|
+
healthCheckInterval;
|
|
30
|
+
// Performance tracking
|
|
31
|
+
lastMetricsUpdate = new Date();
|
|
32
|
+
eventsPerSecond = 0;
|
|
33
|
+
recentEventTimestamps = [];
|
|
34
|
+
// Rate limiting for security
|
|
35
|
+
eventCountsBySource = new Map();
|
|
36
|
+
RATE_LIMIT_WINDOW_MS = 60000;
|
|
37
|
+
RATE_LIMIT_MAX_EVENTS = 1000;
|
|
38
|
+
constructor(logger){
|
|
39
|
+
super();
|
|
40
|
+
this.logger = logger;
|
|
41
|
+
this.config = this.getDefaultConfig();
|
|
42
|
+
}
|
|
43
|
+
// ===========================
|
|
44
|
+
// System Lifecycle
|
|
45
|
+
// ===========================
|
|
46
|
+
async initialize(config = {}) {
|
|
47
|
+
if (this.isInitialized) {
|
|
48
|
+
this.logger.warn('V1TransparencySystem already initialized');
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
this.config = {
|
|
52
|
+
...this.getDefaultConfig(),
|
|
53
|
+
...config
|
|
54
|
+
};
|
|
55
|
+
this.logger.info('Initializing V1TransparencySystem', this.config);
|
|
56
|
+
// Initialize data structures
|
|
57
|
+
this.transparencyEvents = [];
|
|
58
|
+
this.agentInfo.clear();
|
|
59
|
+
this.taskInfo.clear();
|
|
60
|
+
this.coordinatorAdapters.clear();
|
|
61
|
+
this.eventListeners.clear();
|
|
62
|
+
this.isInitialized = true;
|
|
63
|
+
this.emit('initialized');
|
|
64
|
+
this.logger.info('V1TransparencySystem initialized successfully');
|
|
65
|
+
}
|
|
66
|
+
async startMonitoring() {
|
|
67
|
+
if (!this.isInitialized) {
|
|
68
|
+
throw new Error('V1TransparencySystem not initialized');
|
|
69
|
+
}
|
|
70
|
+
if (this.isMonitoring) {
|
|
71
|
+
this.logger.warn('V1TransparencySystem monitoring already started');
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
this.logger.info('Starting V1 transparency monitoring');
|
|
75
|
+
// Start metrics collection
|
|
76
|
+
if (this.config.enableRealTimeMonitoring) {
|
|
77
|
+
this.metricsCollectionInterval = setInterval(()=>this.collectMetrics(), this.config.metricsCollectionIntervalMs);
|
|
78
|
+
}
|
|
79
|
+
// Start health checks
|
|
80
|
+
if (this.config.enableHealthMonitoring) {
|
|
81
|
+
this.healthCheckInterval = setInterval(()=>this.performHealthChecks(), 30000 // 30 seconds
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
// Start all coordinator monitoring
|
|
85
|
+
for (const adapter of this.coordinatorAdapters.values()){
|
|
86
|
+
if (adapter.isActive) {
|
|
87
|
+
this.startCoordinatorMonitoring(adapter);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
this.isMonitoring = true;
|
|
91
|
+
this.emit('monitoringStarted');
|
|
92
|
+
this.logger.info('V1 transparency monitoring started');
|
|
93
|
+
}
|
|
94
|
+
async stopMonitoring() {
|
|
95
|
+
if (!this.isMonitoring) {
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
this.logger.info('Stopping V1 transparency monitoring');
|
|
99
|
+
// Clear intervals
|
|
100
|
+
if (this.metricsCollectionInterval) {
|
|
101
|
+
clearInterval(this.metricsCollectionInterval);
|
|
102
|
+
this.metricsCollectionInterval = undefined;
|
|
103
|
+
}
|
|
104
|
+
if (this.healthCheckInterval) {
|
|
105
|
+
clearInterval(this.healthCheckInterval);
|
|
106
|
+
this.healthCheckInterval = undefined;
|
|
107
|
+
}
|
|
108
|
+
this.isMonitoring = false;
|
|
109
|
+
this.emit('monitoringStopped');
|
|
110
|
+
this.logger.info('V1 transparency monitoring stopped');
|
|
111
|
+
}
|
|
112
|
+
async cleanup() {
|
|
113
|
+
this.logger.info('Cleaning up V1TransparencySystem');
|
|
114
|
+
await this.stopMonitoring();
|
|
115
|
+
// Cleanup all data
|
|
116
|
+
this.transparencyEvents = [];
|
|
117
|
+
this.agentInfo.clear();
|
|
118
|
+
this.taskInfo.clear();
|
|
119
|
+
this.coordinatorAdapters.clear();
|
|
120
|
+
this.eventListeners.clear();
|
|
121
|
+
this.removeAllListeners();
|
|
122
|
+
this.isInitialized = false;
|
|
123
|
+
this.logger.info('V1TransparencySystem cleanup complete');
|
|
124
|
+
}
|
|
125
|
+
// ===========================
|
|
126
|
+
// V1 Coordinator Registration
|
|
127
|
+
// ===========================
|
|
128
|
+
/**
|
|
129
|
+
* Register a QueenAgent for transparency monitoring
|
|
130
|
+
*/ registerQueenAgent(coordinatorId, queenAgent) {
|
|
131
|
+
const adapter = {
|
|
132
|
+
id: coordinatorId,
|
|
133
|
+
type: 'queen-agent',
|
|
134
|
+
instance: queenAgent,
|
|
135
|
+
eventEmitter: queenAgent,
|
|
136
|
+
isActive: true,
|
|
137
|
+
registeredAt: new Date()
|
|
138
|
+
};
|
|
139
|
+
this.coordinatorAdapters.set(coordinatorId, adapter);
|
|
140
|
+
this.setupCoordinatorEventListeners(adapter);
|
|
141
|
+
this.recordEvent({
|
|
142
|
+
eventId: uuidv4(),
|
|
143
|
+
timestamp: new Date(),
|
|
144
|
+
eventType: 'coordinator_initialized',
|
|
145
|
+
eventData: {
|
|
146
|
+
coordinatorId,
|
|
147
|
+
coordinatorType: 'queen-agent'
|
|
148
|
+
},
|
|
149
|
+
source: {
|
|
150
|
+
component: 'V1TransparencySystem',
|
|
151
|
+
instance: this.constructor.name
|
|
152
|
+
},
|
|
153
|
+
severity: 'info',
|
|
154
|
+
category: 'lifecycle'
|
|
155
|
+
});
|
|
156
|
+
this.logger.info(`QueenAgent registered for transparency: ${coordinatorId}`);
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Register a MeshCoordinator for transparency monitoring
|
|
160
|
+
*/ registerMeshCoordinator(coordinatorId, meshCoordinator) {
|
|
161
|
+
const adapter = {
|
|
162
|
+
id: coordinatorId,
|
|
163
|
+
type: 'mesh-coordinator',
|
|
164
|
+
instance: meshCoordinator,
|
|
165
|
+
eventEmitter: meshCoordinator,
|
|
166
|
+
isActive: true,
|
|
167
|
+
registeredAt: new Date()
|
|
168
|
+
};
|
|
169
|
+
this.coordinatorAdapters.set(coordinatorId, adapter);
|
|
170
|
+
this.setupCoordinatorEventListeners(adapter);
|
|
171
|
+
this.recordEvent({
|
|
172
|
+
eventId: uuidv4(),
|
|
173
|
+
timestamp: new Date(),
|
|
174
|
+
eventType: 'coordinator_initialized',
|
|
175
|
+
eventData: {
|
|
176
|
+
coordinatorId,
|
|
177
|
+
coordinatorType: 'mesh-coordinator'
|
|
178
|
+
},
|
|
179
|
+
source: {
|
|
180
|
+
component: 'V1TransparencySystem',
|
|
181
|
+
instance: this.constructor.name
|
|
182
|
+
},
|
|
183
|
+
severity: 'info',
|
|
184
|
+
category: 'lifecycle'
|
|
185
|
+
});
|
|
186
|
+
this.logger.info(`MeshCoordinator registered for transparency: ${coordinatorId}`);
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Register metrics collector for a coordinator
|
|
190
|
+
*/ registerMetricsCollector(coordinatorId, metricsCollector) {
|
|
191
|
+
const adapter = this.coordinatorAdapters.get(coordinatorId);
|
|
192
|
+
if (adapter) {
|
|
193
|
+
adapter.metrics = metricsCollector;
|
|
194
|
+
this.logger.debug(`Metrics collector registered for coordinator: ${coordinatorId}`);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
// ===========================
|
|
198
|
+
// Agent Monitoring
|
|
199
|
+
// ===========================
|
|
200
|
+
async getAllAgents() {
|
|
201
|
+
return Array.from(this.agentInfo.values());
|
|
202
|
+
}
|
|
203
|
+
async getAgentsByCoordinator(coordinatorId) {
|
|
204
|
+
return Array.from(this.agentInfo.values()).filter((agent)=>agent.coordinatorId === coordinatorId);
|
|
205
|
+
}
|
|
206
|
+
async getAgentsByType(agentType) {
|
|
207
|
+
return Array.from(this.agentInfo.values()).filter((agent)=>agent.agentType === agentType);
|
|
208
|
+
}
|
|
209
|
+
async getAgentInfo(agentId) {
|
|
210
|
+
const agent = this.agentInfo.get(agentId);
|
|
211
|
+
if (!agent) {
|
|
212
|
+
throw new Error(`Agent ${agentId} not found`);
|
|
213
|
+
}
|
|
214
|
+
return agent;
|
|
215
|
+
}
|
|
216
|
+
// ===========================
|
|
217
|
+
// Task Monitoring
|
|
218
|
+
// ===========================
|
|
219
|
+
async getAllTasks() {
|
|
220
|
+
return Array.from(this.taskInfo.values());
|
|
221
|
+
}
|
|
222
|
+
async getTasksByAgent(agentId) {
|
|
223
|
+
return Array.from(this.taskInfo.values()).filter((task)=>task.assignedAgents.includes(agentId));
|
|
224
|
+
}
|
|
225
|
+
async getTasksByStatus(status) {
|
|
226
|
+
return Array.from(this.taskInfo.values()).filter((task)=>task.status === status);
|
|
227
|
+
}
|
|
228
|
+
async getTaskInfo(taskId) {
|
|
229
|
+
const task = this.taskInfo.get(taskId);
|
|
230
|
+
if (!task) {
|
|
231
|
+
throw new Error(`Task ${taskId} not found`);
|
|
232
|
+
}
|
|
233
|
+
return task;
|
|
234
|
+
}
|
|
235
|
+
// ===========================
|
|
236
|
+
// Coordinator Monitoring
|
|
237
|
+
// ===========================
|
|
238
|
+
async getAllCoordinators() {
|
|
239
|
+
const coordinators = [];
|
|
240
|
+
for (const [id, adapter] of this.coordinatorAdapters.entries()){
|
|
241
|
+
const coordinatorInfo = {
|
|
242
|
+
coordinatorId: id,
|
|
243
|
+
coordinatorType: adapter.type,
|
|
244
|
+
topology: adapter.type === 'queen-agent' ? 'hierarchical' : 'mesh',
|
|
245
|
+
config: {
|
|
246
|
+
maxAgents: this.getMaxAgentsForCoordinator(adapter),
|
|
247
|
+
currentAgents: this.getAgentCountForCoordinator(id),
|
|
248
|
+
strategy: 'balanced',
|
|
249
|
+
enableConsensus: false
|
|
250
|
+
},
|
|
251
|
+
status: adapter.isActive ? 'active' : 'offline',
|
|
252
|
+
agents: (await this.getAgentsByCoordinator(id)).map((a)=>a.agentId),
|
|
253
|
+
tasks: (await this.getTasksByCoordinator(id)).map((t)=>t.taskId),
|
|
254
|
+
performance: await this.getCoordinatorPerformance(adapter),
|
|
255
|
+
timestamps: {
|
|
256
|
+
startedAt: adapter.registeredAt,
|
|
257
|
+
lastActivity: new Date(),
|
|
258
|
+
lastHealthCheck: new Date()
|
|
259
|
+
}
|
|
260
|
+
};
|
|
261
|
+
coordinators.push(coordinatorInfo);
|
|
262
|
+
}
|
|
263
|
+
return coordinators;
|
|
264
|
+
}
|
|
265
|
+
async getCoordinatorInfo(coordinatorId) {
|
|
266
|
+
const coordinators = await this.getAllCoordinators();
|
|
267
|
+
const coordinator = coordinators.find((c)=>c.coordinatorId === coordinatorId);
|
|
268
|
+
if (!coordinator) {
|
|
269
|
+
throw new Error(`Coordinator ${coordinatorId} not found`);
|
|
270
|
+
}
|
|
271
|
+
return coordinator;
|
|
272
|
+
}
|
|
273
|
+
async getTasksByCoordinator(coordinatorId) {
|
|
274
|
+
return Array.from(this.taskInfo.values()).filter((task)=>task.assignedAgents.some((agentId)=>{
|
|
275
|
+
const agent = this.agentInfo.get(agentId);
|
|
276
|
+
return agent?.coordinatorId === coordinatorId;
|
|
277
|
+
}));
|
|
278
|
+
}
|
|
279
|
+
async getTopologyInfo(coordinatorId) {
|
|
280
|
+
const adapter = this.coordinatorAdapters.get(coordinatorId);
|
|
281
|
+
if (!adapter) {
|
|
282
|
+
throw new Error(`Coordinator ${coordinatorId} not found`);
|
|
283
|
+
}
|
|
284
|
+
// Return topology-specific information
|
|
285
|
+
if (adapter.type === 'queen-agent') {
|
|
286
|
+
return {
|
|
287
|
+
type: 'hierarchical',
|
|
288
|
+
coordinatorId,
|
|
289
|
+
workers: await this.getAgentsByCoordinator(coordinatorId),
|
|
290
|
+
hierarchy: this.buildHierarchyFromQueenAgent(adapter.instance)
|
|
291
|
+
};
|
|
292
|
+
} else {
|
|
293
|
+
return {
|
|
294
|
+
type: 'mesh',
|
|
295
|
+
coordinatorId,
|
|
296
|
+
agents: await this.getAgentsByCoordinator(coordinatorId),
|
|
297
|
+
connections: this.getMeshConnections(adapter.instance)
|
|
298
|
+
};
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
// ===========================
|
|
302
|
+
// Event Streaming
|
|
303
|
+
// ===========================
|
|
304
|
+
async getRecentEvents(limit = 100, eventType) {
|
|
305
|
+
let events = [
|
|
306
|
+
...this.transparencyEvents
|
|
307
|
+
].reverse();
|
|
308
|
+
if (eventType) {
|
|
309
|
+
events = events.filter((event)=>event.eventType === eventType);
|
|
310
|
+
}
|
|
311
|
+
return events.slice(0, limit);
|
|
312
|
+
}
|
|
313
|
+
async getAgentEvents(agentId, limit = 50) {
|
|
314
|
+
const events = this.transparencyEvents.filter((event)=>event.eventData.agentId === agentId).reverse();
|
|
315
|
+
return events.slice(0, limit);
|
|
316
|
+
}
|
|
317
|
+
async getCoordinatorEvents(coordinatorId, limit = 50) {
|
|
318
|
+
const events = this.transparencyEvents.filter((event)=>event.eventData.coordinatorId === coordinatorId).reverse();
|
|
319
|
+
return events.slice(0, limit);
|
|
320
|
+
}
|
|
321
|
+
async getEventsInTimeRange(startTime, endTime, limit = 100) {
|
|
322
|
+
const events = this.transparencyEvents.filter((event)=>event.timestamp >= startTime && event.timestamp <= endTime).reverse();
|
|
323
|
+
return events.slice(0, limit);
|
|
324
|
+
}
|
|
325
|
+
// ===========================
|
|
326
|
+
// Metrics and Analytics
|
|
327
|
+
// ===========================
|
|
328
|
+
async getTransparencyMetrics() {
|
|
329
|
+
const agents = Array.from(this.agentInfo.values());
|
|
330
|
+
const tasks = Array.from(this.taskInfo.values());
|
|
331
|
+
const coordinators = Array.from(this.coordinatorAdapters.values());
|
|
332
|
+
// Calculate events per second
|
|
333
|
+
this.calculateEventsPerSecond();
|
|
334
|
+
return {
|
|
335
|
+
timestamp: new Date(),
|
|
336
|
+
coordinators: {
|
|
337
|
+
total: coordinators.length,
|
|
338
|
+
active: coordinators.filter((c)=>c.isActive).length,
|
|
339
|
+
byType: {
|
|
340
|
+
'queen-agent': coordinators.filter((c)=>c.type === 'queen-agent').length,
|
|
341
|
+
'mesh-coordinator': coordinators.filter((c)=>c.type === 'mesh-coordinator').length
|
|
342
|
+
},
|
|
343
|
+
byTopology: {
|
|
344
|
+
hierarchical: coordinators.filter((c)=>c.type === 'queen-agent').length,
|
|
345
|
+
mesh: coordinators.filter((c)=>c.type === 'mesh-coordinator').length
|
|
346
|
+
}
|
|
347
|
+
},
|
|
348
|
+
agents: {
|
|
349
|
+
total: agents.length,
|
|
350
|
+
active: agents.filter((a)=>a.status === 'busy' || a.status === 'ready' || a.status === 'working').length,
|
|
351
|
+
idle: agents.filter((a)=>a.status === 'idle').length,
|
|
352
|
+
busy: agents.filter((a)=>a.status === 'busy' || a.status === 'working').length,
|
|
353
|
+
degraded: agents.filter((a)=>a.status === 'degraded').length,
|
|
354
|
+
offline: agents.filter((a)=>a.status === 'offline').length,
|
|
355
|
+
byType: this.groupAgentsByType(agents),
|
|
356
|
+
byCoordinator: this.groupAgentsByCoordinator(agents),
|
|
357
|
+
averageHealth: this.calculateAverageHealth(agents),
|
|
358
|
+
utilizationRate: this.calculateAgentUtilization(agents)
|
|
359
|
+
},
|
|
360
|
+
tasks: {
|
|
361
|
+
total: tasks.length,
|
|
362
|
+
active: tasks.filter((t)=>t.status === 'active').length,
|
|
363
|
+
completed: tasks.filter((t)=>t.status === 'completed').length,
|
|
364
|
+
failed: tasks.filter((t)=>t.status === 'failed').length,
|
|
365
|
+
cancelled: tasks.filter((t)=>t.status === 'cancelled').length,
|
|
366
|
+
byType: this.groupTasksByType(tasks),
|
|
367
|
+
byPriority: this.groupTasksByPriority(tasks),
|
|
368
|
+
averageDuration: this.calculateAverageTaskDuration(tasks),
|
|
369
|
+
successRate: this.calculateTaskSuccessRate(tasks)
|
|
370
|
+
},
|
|
371
|
+
performance: {
|
|
372
|
+
taskThroughput: this.calculateTaskThroughput(tasks),
|
|
373
|
+
averageResponseTime: this.calculateAverageResponseTime(agents),
|
|
374
|
+
memoryUsage: this.calculateTotalMemoryUsage(agents),
|
|
375
|
+
cpuUsage: this.calculateTotalCpuUsage(agents),
|
|
376
|
+
networkIO: this.calculateTotalNetworkIO(agents),
|
|
377
|
+
errorRate: this.calculateErrorRate(tasks)
|
|
378
|
+
},
|
|
379
|
+
resources: {
|
|
380
|
+
totalResources: agents.reduce((sum, a)=>sum + a.topology.maxConnections, 0),
|
|
381
|
+
allocatedResources: agents.reduce((sum, a)=>sum + a.topology.connections, 0),
|
|
382
|
+
freeResources: agents.reduce((sum, a)=>sum + (a.topology.maxConnections - a.topology.connections), 0),
|
|
383
|
+
resourceUtilization: this.calculateResourceUtilization(agents),
|
|
384
|
+
lockContention: 0
|
|
385
|
+
},
|
|
386
|
+
events: {
|
|
387
|
+
totalEvents: this.transparencyEvents.length,
|
|
388
|
+
eventsByType: this.groupEventsByType(),
|
|
389
|
+
eventsBySeverity: this.groupEventsBySeverity(),
|
|
390
|
+
eventsByCategory: this.groupEventsByCategory(),
|
|
391
|
+
eventsPerSecond: this.eventsPerSecond
|
|
392
|
+
}
|
|
393
|
+
};
|
|
394
|
+
}
|
|
395
|
+
async getPerformanceAnalytics() {
|
|
396
|
+
const agents = Array.from(this.agentInfo.values());
|
|
397
|
+
const tasks = Array.from(this.taskInfo.values());
|
|
398
|
+
return {
|
|
399
|
+
agentPerformance: {
|
|
400
|
+
healthDistribution: this.getHealthDistribution(agents),
|
|
401
|
+
utilizationTrends: this.getUtilizationTrends(agents),
|
|
402
|
+
performanceByType: this.getPerformanceByAgentType(agents)
|
|
403
|
+
},
|
|
404
|
+
taskPerformance: {
|
|
405
|
+
completionRates: this.getTaskCompletionRates(tasks),
|
|
406
|
+
averageDurations: this.getTaskDurationsByType(tasks),
|
|
407
|
+
failurePatterns: this.getFailurePatterns(tasks)
|
|
408
|
+
},
|
|
409
|
+
systemPerformance: {
|
|
410
|
+
scalabilityMetrics: this.getScalabilityMetrics(),
|
|
411
|
+
bottleneckAnalysis: this.getBottleneckAnalysis(),
|
|
412
|
+
efficiencyMetrics: this.getEfficiencyMetrics()
|
|
413
|
+
}
|
|
414
|
+
};
|
|
415
|
+
}
|
|
416
|
+
async getTopologyAnalytics() {
|
|
417
|
+
const queenAgents = Array.from(this.coordinatorAdapters.values()).filter((adapter)=>adapter.type === 'queen-agent');
|
|
418
|
+
const meshCoordinators = Array.from(this.coordinatorAdapters.values()).filter((adapter)=>adapter.type === 'mesh-coordinator');
|
|
419
|
+
return {
|
|
420
|
+
hierarchicalTopology: {
|
|
421
|
+
count: queenAgents.length,
|
|
422
|
+
averageWorkersPerQueen: this.getAverageWorkersPerQueen(queenAgents),
|
|
423
|
+
hierarchyDepth: this.getHierarchyDepth(queenAgents),
|
|
424
|
+
efficiency: this.getHierarchicalEfficiency(queenAgents)
|
|
425
|
+
},
|
|
426
|
+
meshTopology: {
|
|
427
|
+
count: meshCoordinators.length,
|
|
428
|
+
averageConnectionsPerAgent: this.getAverageConnectionsPerAgent(meshCoordinators),
|
|
429
|
+
networkDiameter: this.getNetworkDiameter(meshCoordinators),
|
|
430
|
+
clustering: this.getMeshClusteringMetrics(meshCoordinators)
|
|
431
|
+
},
|
|
432
|
+
overallMetrics: {
|
|
433
|
+
totalCoordinators: this.coordinatorAdapters.size,
|
|
434
|
+
topologyEfficiency: this.getOverallTopologyEfficiency(),
|
|
435
|
+
scalingCharacteristics: this.getScalingCharacteristics()
|
|
436
|
+
}
|
|
437
|
+
};
|
|
438
|
+
}
|
|
439
|
+
// ===========================
|
|
440
|
+
// Event Listeners
|
|
441
|
+
// ===========================
|
|
442
|
+
async registerEventListener(listener) {
|
|
443
|
+
this.eventListeners.add(listener);
|
|
444
|
+
this.logger.debug('V1 transparency event listener registered');
|
|
445
|
+
}
|
|
446
|
+
async unregisterEventListener(listener) {
|
|
447
|
+
this.eventListeners.delete(listener);
|
|
448
|
+
this.logger.debug('V1 transparency event listener unregistered');
|
|
449
|
+
}
|
|
450
|
+
// ===========================
|
|
451
|
+
// Private Helper Methods
|
|
452
|
+
// ===========================
|
|
453
|
+
getDefaultConfig() {
|
|
454
|
+
return {
|
|
455
|
+
enableRealTimeMonitoring: true,
|
|
456
|
+
enableEventStreaming: true,
|
|
457
|
+
eventRetentionHours: 24,
|
|
458
|
+
metricsCollectionIntervalMs: 5000,
|
|
459
|
+
enablePerformanceMonitoring: true,
|
|
460
|
+
enableDependencyTracking: true,
|
|
461
|
+
maxEventsInMemory: 10000,
|
|
462
|
+
enableCoordinatorMonitoring: true,
|
|
463
|
+
enableHealthMonitoring: true,
|
|
464
|
+
enableTaskTracking: true
|
|
465
|
+
};
|
|
466
|
+
}
|
|
467
|
+
setupCoordinatorEventListeners(adapter) {
|
|
468
|
+
const { eventEmitter, id: coordinatorId } = adapter;
|
|
469
|
+
// Listen to all coordinator events
|
|
470
|
+
eventEmitter.on('workerSpawned', (data)=>this.handleWorkerSpawned(coordinatorId, data));
|
|
471
|
+
eventEmitter.on('workerStatusChanged', (data)=>this.handleWorkerStatusChanged(coordinatorId, data));
|
|
472
|
+
eventEmitter.on('taskDelegated', (data)=>this.handleTaskDelegated(coordinatorId, data));
|
|
473
|
+
eventEmitter.on('taskCompleted', (data)=>this.handleTaskCompleted(coordinatorId, data));
|
|
474
|
+
eventEmitter.on('taskFailed', (data)=>this.handleTaskFailed(coordinatorId, data));
|
|
475
|
+
eventEmitter.on('error', (error)=>this.handleCoordinatorError(coordinatorId, error));
|
|
476
|
+
// Start monitoring if already started
|
|
477
|
+
if (this.isMonitoring) {
|
|
478
|
+
this.startCoordinatorMonitoring(adapter);
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
startCoordinatorMonitoring(adapter) {
|
|
482
|
+
// Initial data collection
|
|
483
|
+
this.collectCoordinatorData(adapter);
|
|
484
|
+
}
|
|
485
|
+
collectCoordinatorData(adapter) {
|
|
486
|
+
// This would collect initial data from the coordinator
|
|
487
|
+
// Implementation depends on the specific coordinator type
|
|
488
|
+
}
|
|
489
|
+
collectMetrics() {
|
|
490
|
+
if (!this.isMonitoring) return;
|
|
491
|
+
// Collect metrics from all registered coordinators
|
|
492
|
+
for (const adapter of this.coordinatorAdapters.values()){
|
|
493
|
+
if (adapter.metrics) {
|
|
494
|
+
const metrics = adapter.metrics.getCurrentMetrics();
|
|
495
|
+
// Process metrics...
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
this.notifyMetricsUpdate();
|
|
499
|
+
}
|
|
500
|
+
performHealthChecks() {
|
|
501
|
+
// Perform health checks on all agents and coordinators
|
|
502
|
+
for (const [agentId, agent] of this.agentInfo.entries()){
|
|
503
|
+
const now = new Date();
|
|
504
|
+
const timeSinceLastActivity = now.getTime() - agent.timestamps.lastActivity.getTime();
|
|
505
|
+
if (timeSinceLastActivity > 300000) {
|
|
506
|
+
agent.status = 'degraded';
|
|
507
|
+
this.recordEvent({
|
|
508
|
+
eventId: uuidv4(),
|
|
509
|
+
timestamp: now,
|
|
510
|
+
eventType: 'agent_health_updated',
|
|
511
|
+
eventData: {
|
|
512
|
+
agentId,
|
|
513
|
+
previousState: agent.status,
|
|
514
|
+
newState: 'degraded',
|
|
515
|
+
reason: 'No recent activity'
|
|
516
|
+
},
|
|
517
|
+
source: {
|
|
518
|
+
component: 'V1TransparencySystem',
|
|
519
|
+
instance: 'health-check'
|
|
520
|
+
},
|
|
521
|
+
severity: 'warning',
|
|
522
|
+
category: 'coordination'
|
|
523
|
+
});
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
recordEvent(event) {
|
|
528
|
+
// Rate limiting check to prevent event flooding attacks
|
|
529
|
+
const sourceId = event.source?.instance || 'unknown';
|
|
530
|
+
if (!this.checkRateLimit(sourceId)) {
|
|
531
|
+
this.logger.warn(`Event rate limit exceeded for source: ${sourceId}`);
|
|
532
|
+
return; // Drop the event if rate limit exceeded
|
|
533
|
+
}
|
|
534
|
+
// Input sanitization for security
|
|
535
|
+
const sanitizedEvent = this.sanitizeEvent(event);
|
|
536
|
+
this.transparencyEvents.push(sanitizedEvent);
|
|
537
|
+
// Enforce event retention limit
|
|
538
|
+
if (this.transparencyEvents.length > this.config.maxEventsInMemory) {
|
|
539
|
+
const excess = this.transparencyEvents.length - this.config.maxEventsInMemory;
|
|
540
|
+
this.transparencyEvents.splice(0, excess);
|
|
541
|
+
}
|
|
542
|
+
// Update events per second calculation
|
|
543
|
+
this.recentEventTimestamps.push(sanitizedEvent.timestamp);
|
|
544
|
+
this.cleanupOldEventTimestamps();
|
|
545
|
+
// Notify listeners
|
|
546
|
+
this.eventListeners.forEach((listener)=>{
|
|
547
|
+
if (listener.onTransparencyEvent) {
|
|
548
|
+
try {
|
|
549
|
+
listener.onTransparencyEvent(sanitizedEvent);
|
|
550
|
+
} catch (error) {
|
|
551
|
+
this.logger.error('Error in transparency event listener', error);
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
});
|
|
555
|
+
this.emit('transparencyEvent', sanitizedEvent);
|
|
556
|
+
}
|
|
557
|
+
/**
|
|
558
|
+
* Check rate limiting for event sources to prevent DoS attacks
|
|
559
|
+
*
|
|
560
|
+
* Note: This is a basic implementation. In production, consider:
|
|
561
|
+
* - Distributed rate limiting for multi-instance deployments
|
|
562
|
+
* - Adaptive rate limits based on system load
|
|
563
|
+
* - Different limits for different event types/severities
|
|
564
|
+
* - Configurable rate limits per coordinator type
|
|
565
|
+
*/ checkRateLimit(sourceId) {
|
|
566
|
+
const now = new Date();
|
|
567
|
+
const sourceData = this.eventCountsBySource.get(sourceId);
|
|
568
|
+
if (!sourceData) {
|
|
569
|
+
// First event from this source
|
|
570
|
+
this.eventCountsBySource.set(sourceId, {
|
|
571
|
+
count: 1,
|
|
572
|
+
lastReset: now
|
|
573
|
+
});
|
|
574
|
+
return true;
|
|
575
|
+
}
|
|
576
|
+
// Check if we need to reset the counter (time window passed)
|
|
577
|
+
const timeSinceReset = now.getTime() - sourceData.lastReset.getTime();
|
|
578
|
+
if (timeSinceReset > this.RATE_LIMIT_WINDOW_MS) {
|
|
579
|
+
// Reset counter for new time window
|
|
580
|
+
this.eventCountsBySource.set(sourceId, {
|
|
581
|
+
count: 1,
|
|
582
|
+
lastReset: now
|
|
583
|
+
});
|
|
584
|
+
return true;
|
|
585
|
+
}
|
|
586
|
+
// Check if source has exceeded rate limit
|
|
587
|
+
if (sourceData.count >= this.RATE_LIMIT_MAX_EVENTS) {
|
|
588
|
+
return false; // Rate limit exceeded
|
|
589
|
+
}
|
|
590
|
+
// Increment counter
|
|
591
|
+
sourceData.count++;
|
|
592
|
+
return true;
|
|
593
|
+
}
|
|
594
|
+
/**
|
|
595
|
+
* Sanitize event data to prevent security issues
|
|
596
|
+
*
|
|
597
|
+
* Security considerations:
|
|
598
|
+
* - Remove potentially malicious HTML/JS from event data
|
|
599
|
+
* - Limit string lengths to prevent DoS attacks
|
|
600
|
+
* - Validate event structure before processing
|
|
601
|
+
* - Rate limiting concept for event streams (implementation note)
|
|
602
|
+
*/ sanitizeEvent(event) {
|
|
603
|
+
const sanitized = {
|
|
604
|
+
...event
|
|
605
|
+
};
|
|
606
|
+
// Sanitize event data fields
|
|
607
|
+
if (sanitized.eventData) {
|
|
608
|
+
sanitized.eventData = this.sanitizeEventData(sanitized.eventData);
|
|
609
|
+
}
|
|
610
|
+
// Limit string lengths to prevent memory issues
|
|
611
|
+
if (sanitized.eventType && sanitized.eventType.length > 100) {
|
|
612
|
+
sanitized.eventType = sanitized.eventType.substring(0, 100);
|
|
613
|
+
}
|
|
614
|
+
if (sanitized.category && sanitized.category.length > 50) {
|
|
615
|
+
sanitized.category = sanitized.category.substring(0, 50);
|
|
616
|
+
}
|
|
617
|
+
// Ensure severity is valid
|
|
618
|
+
const validSeverities = [
|
|
619
|
+
'info',
|
|
620
|
+
'warning',
|
|
621
|
+
'error',
|
|
622
|
+
'critical'
|
|
623
|
+
];
|
|
624
|
+
if (!validSeverities.includes(sanitized.severity)) {
|
|
625
|
+
sanitized.severity = 'info';
|
|
626
|
+
}
|
|
627
|
+
return sanitized;
|
|
628
|
+
}
|
|
629
|
+
/**
|
|
630
|
+
* Sanitize event data object to prevent injection attacks
|
|
631
|
+
*/ sanitizeEventData(eventData) {
|
|
632
|
+
if (!eventData || typeof eventData !== 'object') {
|
|
633
|
+
return {};
|
|
634
|
+
}
|
|
635
|
+
const sanitized = {};
|
|
636
|
+
Object.keys(eventData).forEach((key)=>{
|
|
637
|
+
const value = eventData[key];
|
|
638
|
+
// Limit key length
|
|
639
|
+
const sanitizedKey = key.length > 100 ? key.substring(0, 100) : key;
|
|
640
|
+
// Sanitize different value types
|
|
641
|
+
if (typeof value === 'string') {
|
|
642
|
+
// Remove potential XSS patterns and limit length
|
|
643
|
+
const cleanValue = value.replace(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi, '[SCRIPT_REMOVED]').replace(/javascript:/gi, '[JS_REMOVED]').replace(/on\w+\s*=/gi, '[EVENT_HANDLER_REMOVED]').substring(0, 1000); // Limit string length
|
|
644
|
+
sanitized[sanitizedKey] = cleanValue;
|
|
645
|
+
} else if (typeof value === 'object' && value !== null) {
|
|
646
|
+
// Recursively sanitize nested objects
|
|
647
|
+
sanitized[sanitizedKey] = this.sanitizeEventData(value);
|
|
648
|
+
} else {
|
|
649
|
+
// Keep primitive types as-is
|
|
650
|
+
sanitized[sanitizedKey] = value;
|
|
651
|
+
}
|
|
652
|
+
});
|
|
653
|
+
return sanitized;
|
|
654
|
+
}
|
|
655
|
+
notifyMetricsUpdate() {
|
|
656
|
+
this.getTransparencyMetrics().then((metrics)=>{
|
|
657
|
+
this.eventListeners.forEach((listener)=>{
|
|
658
|
+
if (listener.onMetricsUpdate) {
|
|
659
|
+
try {
|
|
660
|
+
listener.onMetricsUpdate(metrics);
|
|
661
|
+
} catch (error) {
|
|
662
|
+
this.logger.error('Error in metrics update listener', error);
|
|
663
|
+
}
|
|
664
|
+
}
|
|
665
|
+
});
|
|
666
|
+
this.emit('metricsUpdate', metrics);
|
|
667
|
+
}).catch((error)=>{
|
|
668
|
+
this.logger.error('Error getting transparency metrics', error);
|
|
669
|
+
});
|
|
670
|
+
}
|
|
671
|
+
// Event handlers
|
|
672
|
+
handleWorkerSpawned(coordinatorId, data) {
|
|
673
|
+
const agent = {
|
|
674
|
+
agentId: data.workerId,
|
|
675
|
+
agentType: data.workerType,
|
|
676
|
+
capabilities: data.capabilities,
|
|
677
|
+
status: 'idle',
|
|
678
|
+
level: 2,
|
|
679
|
+
coordinatorId,
|
|
680
|
+
peerAgentIds: [],
|
|
681
|
+
childAgentIds: [],
|
|
682
|
+
currentTasks: [],
|
|
683
|
+
taskStats: {
|
|
684
|
+
completed: 0,
|
|
685
|
+
failed: 0,
|
|
686
|
+
total: 0,
|
|
687
|
+
successRate: 100
|
|
688
|
+
},
|
|
689
|
+
health: {
|
|
690
|
+
successRate: 100,
|
|
691
|
+
averageResponseTime: 0,
|
|
692
|
+
errorCount: 0,
|
|
693
|
+
consecutiveFailures: 0,
|
|
694
|
+
lastHealthCheck: new Date()
|
|
695
|
+
},
|
|
696
|
+
resources: {
|
|
697
|
+
memoryUsage: 0,
|
|
698
|
+
cpuUsage: 0,
|
|
699
|
+
networkIO: 0
|
|
700
|
+
},
|
|
701
|
+
timestamps: {
|
|
702
|
+
spawnedAt: new Date(),
|
|
703
|
+
lastActivity: new Date(),
|
|
704
|
+
lastStateChange: new Date()
|
|
705
|
+
},
|
|
706
|
+
topology: {
|
|
707
|
+
connections: 0,
|
|
708
|
+
maxConnections: data.capabilities?.maxConcurrentTasks || 5,
|
|
709
|
+
workload: 0
|
|
710
|
+
},
|
|
711
|
+
dependencies: {
|
|
712
|
+
dependsOn: [],
|
|
713
|
+
blocksCompletion: [],
|
|
714
|
+
waitingFor: []
|
|
715
|
+
}
|
|
716
|
+
};
|
|
717
|
+
this.agentInfo.set(data.workerId, agent);
|
|
718
|
+
this.recordEvent({
|
|
719
|
+
eventId: uuidv4(),
|
|
720
|
+
timestamp: new Date(),
|
|
721
|
+
eventType: 'agent_spawned',
|
|
722
|
+
eventData: {
|
|
723
|
+
agentId: data.workerId,
|
|
724
|
+
coordinatorId,
|
|
725
|
+
agentType: data.workerType
|
|
726
|
+
},
|
|
727
|
+
source: {
|
|
728
|
+
component: 'V1TransparencySystem',
|
|
729
|
+
instance: coordinatorId
|
|
730
|
+
},
|
|
731
|
+
severity: 'info',
|
|
732
|
+
category: 'lifecycle'
|
|
733
|
+
});
|
|
734
|
+
}
|
|
735
|
+
handleWorkerStatusChanged(coordinatorId, data) {
|
|
736
|
+
const agent = this.agentInfo.get(data.workerId);
|
|
737
|
+
if (agent) {
|
|
738
|
+
const previousStatus = agent.status;
|
|
739
|
+
agent.status = data.newStatus;
|
|
740
|
+
agent.timestamps.lastStateChange = new Date();
|
|
741
|
+
this.recordEvent({
|
|
742
|
+
eventId: uuidv4(),
|
|
743
|
+
timestamp: new Date(),
|
|
744
|
+
eventType: 'agent_status_changed',
|
|
745
|
+
eventData: {
|
|
746
|
+
agentId: data.workerId,
|
|
747
|
+
coordinatorId,
|
|
748
|
+
previousState: previousStatus,
|
|
749
|
+
newState: data.newStatus,
|
|
750
|
+
reason: data.reason
|
|
751
|
+
},
|
|
752
|
+
source: {
|
|
753
|
+
component: 'V1TransparencySystem',
|
|
754
|
+
instance: coordinatorId
|
|
755
|
+
},
|
|
756
|
+
severity: 'info',
|
|
757
|
+
category: 'lifecycle'
|
|
758
|
+
});
|
|
759
|
+
}
|
|
760
|
+
}
|
|
761
|
+
handleTaskDelegated(coordinatorId, data) {
|
|
762
|
+
const task = {
|
|
763
|
+
taskId: data.taskId,
|
|
764
|
+
taskType: data.taskType,
|
|
765
|
+
description: data.description,
|
|
766
|
+
status: 'active',
|
|
767
|
+
priority: data.priority || 5,
|
|
768
|
+
assignedAgents: [
|
|
769
|
+
data.workerId
|
|
770
|
+
],
|
|
771
|
+
dependencies: data.dependencies || [],
|
|
772
|
+
progress: {
|
|
773
|
+
percentage: 0
|
|
774
|
+
},
|
|
775
|
+
timing: {
|
|
776
|
+
createdAt: new Date(),
|
|
777
|
+
startedAt: new Date()
|
|
778
|
+
},
|
|
779
|
+
resources: {
|
|
780
|
+
required: data.resources || {},
|
|
781
|
+
used: {}
|
|
782
|
+
},
|
|
783
|
+
quality: {
|
|
784
|
+
confidence: 0
|
|
785
|
+
}
|
|
786
|
+
};
|
|
787
|
+
this.taskInfo.set(data.taskId, task);
|
|
788
|
+
// Update agent's current tasks
|
|
789
|
+
const agent = this.agentInfo.get(data.workerId);
|
|
790
|
+
if (agent) {
|
|
791
|
+
agent.currentTasks.push(data.taskId);
|
|
792
|
+
agent.status = 'busy';
|
|
793
|
+
}
|
|
794
|
+
this.recordEvent({
|
|
795
|
+
eventId: uuidv4(),
|
|
796
|
+
timestamp: new Date(),
|
|
797
|
+
eventType: 'task_assigned',
|
|
798
|
+
eventData: {
|
|
799
|
+
taskId: data.taskId,
|
|
800
|
+
agentId: data.workerId,
|
|
801
|
+
coordinatorId
|
|
802
|
+
},
|
|
803
|
+
source: {
|
|
804
|
+
component: 'V1TransparencySystem',
|
|
805
|
+
instance: coordinatorId
|
|
806
|
+
},
|
|
807
|
+
severity: 'info',
|
|
808
|
+
category: 'coordination'
|
|
809
|
+
});
|
|
810
|
+
}
|
|
811
|
+
handleTaskCompleted(coordinatorId, data) {
|
|
812
|
+
const task = this.taskInfo.get(data.taskId);
|
|
813
|
+
if (task) {
|
|
814
|
+
task.status = 'completed';
|
|
815
|
+
task.timing.completedAt = new Date();
|
|
816
|
+
task.result = data.result;
|
|
817
|
+
task.quality.confidence = data.confidence || 0.8;
|
|
818
|
+
// Update agent's task stats
|
|
819
|
+
for (const agentId of task.assignedAgents){
|
|
820
|
+
const agent = this.agentInfo.get(agentId);
|
|
821
|
+
if (agent) {
|
|
822
|
+
agent.taskStats.completed++;
|
|
823
|
+
agent.taskStats.total++;
|
|
824
|
+
agent.taskStats.successRate = agent.taskStats.completed / agent.taskStats.total * 100;
|
|
825
|
+
// Remove from current tasks
|
|
826
|
+
agent.currentTasks = agent.currentTasks.filter((id)=>id !== data.taskId);
|
|
827
|
+
if (agent.currentTasks.length === 0) {
|
|
828
|
+
agent.status = 'idle';
|
|
829
|
+
}
|
|
830
|
+
}
|
|
831
|
+
}
|
|
832
|
+
this.recordEvent({
|
|
833
|
+
eventId: uuidv4(),
|
|
834
|
+
timestamp: new Date(),
|
|
835
|
+
eventType: 'task_completed',
|
|
836
|
+
eventData: {
|
|
837
|
+
taskId: data.taskId,
|
|
838
|
+
agentIds: task.assignedAgents,
|
|
839
|
+
coordinatorId,
|
|
840
|
+
confidence: task.quality.confidence
|
|
841
|
+
},
|
|
842
|
+
source: {
|
|
843
|
+
component: 'V1TransparencySystem',
|
|
844
|
+
instance: coordinatorId
|
|
845
|
+
},
|
|
846
|
+
severity: 'info',
|
|
847
|
+
category: 'coordination'
|
|
848
|
+
});
|
|
849
|
+
}
|
|
850
|
+
}
|
|
851
|
+
handleTaskFailed(coordinatorId, data) {
|
|
852
|
+
const task = this.taskInfo.get(data.taskId);
|
|
853
|
+
if (task) {
|
|
854
|
+
task.status = 'failed';
|
|
855
|
+
task.timing.completedAt = new Date();
|
|
856
|
+
task.error = data.error;
|
|
857
|
+
// Update agent's task stats
|
|
858
|
+
for (const agentId of task.assignedAgents){
|
|
859
|
+
const agent = this.agentInfo.get(agentId);
|
|
860
|
+
if (agent) {
|
|
861
|
+
agent.taskStats.failed++;
|
|
862
|
+
agent.taskStats.total++;
|
|
863
|
+
agent.taskStats.successRate = agent.taskStats.completed / agent.taskStats.total * 100;
|
|
864
|
+
agent.health.errorCount++;
|
|
865
|
+
agent.health.consecutiveFailures++;
|
|
866
|
+
// Remove from current tasks
|
|
867
|
+
agent.currentTasks = agent.currentTasks.filter((id)=>id !== data.taskId);
|
|
868
|
+
if (agent.currentTasks.length === 0) {
|
|
869
|
+
agent.status = 'idle';
|
|
870
|
+
}
|
|
871
|
+
}
|
|
872
|
+
}
|
|
873
|
+
this.recordEvent({
|
|
874
|
+
eventId: uuidv4(),
|
|
875
|
+
timestamp: new Date(),
|
|
876
|
+
eventType: 'task_failed',
|
|
877
|
+
eventData: {
|
|
878
|
+
taskId: data.taskId,
|
|
879
|
+
agentIds: task.assignedAgents,
|
|
880
|
+
coordinatorId,
|
|
881
|
+
error: data.error
|
|
882
|
+
},
|
|
883
|
+
source: {
|
|
884
|
+
component: 'V1TransparencySystem',
|
|
885
|
+
instance: coordinatorId
|
|
886
|
+
},
|
|
887
|
+
severity: 'error',
|
|
888
|
+
category: 'error'
|
|
889
|
+
});
|
|
890
|
+
}
|
|
891
|
+
}
|
|
892
|
+
handleCoordinatorError(coordinatorId, error) {
|
|
893
|
+
this.recordEvent({
|
|
894
|
+
eventId: uuidv4(),
|
|
895
|
+
timestamp: new Date(),
|
|
896
|
+
eventType: 'error_occurred',
|
|
897
|
+
eventData: {
|
|
898
|
+
coordinatorId,
|
|
899
|
+
error: error.message,
|
|
900
|
+
stack: error.stack
|
|
901
|
+
},
|
|
902
|
+
source: {
|
|
903
|
+
component: 'V1TransparencySystem',
|
|
904
|
+
instance: coordinatorId
|
|
905
|
+
},
|
|
906
|
+
severity: 'error',
|
|
907
|
+
category: 'error'
|
|
908
|
+
});
|
|
909
|
+
}
|
|
910
|
+
// Helper methods for metrics calculation
|
|
911
|
+
calculateEventsPerSecond() {
|
|
912
|
+
const now = new Date();
|
|
913
|
+
const oneSecondAgo = new Date(now.getTime() - 1000);
|
|
914
|
+
const recentEvents = this.recentEventTimestamps.filter((timestamp)=>timestamp >= oneSecondAgo);
|
|
915
|
+
this.eventsPerSecond = recentEvents.length;
|
|
916
|
+
}
|
|
917
|
+
cleanupOldEventTimestamps() {
|
|
918
|
+
const fiveMinutesAgo = new Date(Date.now() - 300000);
|
|
919
|
+
this.recentEventTimestamps = this.recentEventTimestamps.filter((timestamp)=>timestamp >= fiveMinutesAgo);
|
|
920
|
+
}
|
|
921
|
+
groupAgentsByType(agents) {
|
|
922
|
+
const groups = {};
|
|
923
|
+
agents.forEach((agent)=>{
|
|
924
|
+
groups[agent.agentType] = (groups[agent.agentType] || 0) + 1;
|
|
925
|
+
});
|
|
926
|
+
return groups;
|
|
927
|
+
}
|
|
928
|
+
groupAgentsByCoordinator(agents) {
|
|
929
|
+
const groups = {};
|
|
930
|
+
agents.forEach((agent)=>{
|
|
931
|
+
groups[agent.coordinatorId] = (groups[agent.coordinatorId] || 0) + 1;
|
|
932
|
+
});
|
|
933
|
+
return groups;
|
|
934
|
+
}
|
|
935
|
+
calculateAverageHealth(agents) {
|
|
936
|
+
if (agents.length === 0) return 100;
|
|
937
|
+
const totalHealth = agents.reduce((sum, agent)=>sum + agent.health.successRate, 0);
|
|
938
|
+
return totalHealth / agents.length;
|
|
939
|
+
}
|
|
940
|
+
calculateAgentUtilization(agents) {
|
|
941
|
+
if (agents.length === 0) return 0;
|
|
942
|
+
const busyAgents = agents.filter((agent)=>agent.status === 'busy' || agent.status === 'working').length;
|
|
943
|
+
return busyAgents / agents.length * 100;
|
|
944
|
+
}
|
|
945
|
+
groupTasksByType(tasks) {
|
|
946
|
+
const groups = {};
|
|
947
|
+
tasks.forEach((task)=>{
|
|
948
|
+
groups[task.taskType] = (groups[task.taskType] || 0) + 1;
|
|
949
|
+
});
|
|
950
|
+
return groups;
|
|
951
|
+
}
|
|
952
|
+
groupTasksByPriority(tasks) {
|
|
953
|
+
const groups = {};
|
|
954
|
+
tasks.forEach((task)=>{
|
|
955
|
+
const priorityKey = `priority_${task.priority}`;
|
|
956
|
+
groups[priorityKey] = (groups[priorityKey] || 0) + 1;
|
|
957
|
+
});
|
|
958
|
+
return groups;
|
|
959
|
+
}
|
|
960
|
+
calculateAverageTaskDuration(tasks) {
|
|
961
|
+
const completedTasks = tasks.filter((task)=>task.timing.completedAt && task.timing.startedAt);
|
|
962
|
+
if (completedTasks.length === 0) return 0;
|
|
963
|
+
const totalDuration = completedTasks.reduce((sum, task)=>{
|
|
964
|
+
return sum + (task.timing.completedAt.getTime() - task.timing.startedAt.getTime());
|
|
965
|
+
}, 0);
|
|
966
|
+
return totalDuration / completedTasks.length;
|
|
967
|
+
}
|
|
968
|
+
calculateTaskSuccessRate(tasks) {
|
|
969
|
+
const completedTasks = tasks.filter((task)=>task.status === 'completed' || task.status === 'failed');
|
|
970
|
+
if (completedTasks.length === 0) return 100;
|
|
971
|
+
const successfulTasks = completedTasks.filter((task)=>task.status === 'completed').length;
|
|
972
|
+
return successfulTasks / completedTasks.length * 100;
|
|
973
|
+
}
|
|
974
|
+
calculateTaskThroughput(tasks) {
|
|
975
|
+
const now = new Date();
|
|
976
|
+
const oneHourAgo = new Date(now.getTime() - 3600000);
|
|
977
|
+
const recentTasks = tasks.filter((task)=>task.timing.completedAt && task.timing.completedAt >= oneHourAgo);
|
|
978
|
+
return recentTasks.length; // tasks per hour
|
|
979
|
+
}
|
|
980
|
+
calculateAverageResponseTime(agents) {
|
|
981
|
+
if (agents.length === 0) return 0;
|
|
982
|
+
const totalResponseTime = agents.reduce((sum, agent)=>sum + agent.health.averageResponseTime, 0);
|
|
983
|
+
return totalResponseTime / agents.length;
|
|
984
|
+
}
|
|
985
|
+
calculateTotalMemoryUsage(agents) {
|
|
986
|
+
return agents.reduce((sum, agent)=>sum + agent.resources.memoryUsage, 0);
|
|
987
|
+
}
|
|
988
|
+
calculateTotalCpuUsage(agents) {
|
|
989
|
+
if (agents.length === 0) return 0;
|
|
990
|
+
const totalCpu = agents.reduce((sum, agent)=>sum + agent.resources.cpuUsage, 0);
|
|
991
|
+
return totalCpu / agents.length;
|
|
992
|
+
}
|
|
993
|
+
calculateTotalNetworkIO(agents) {
|
|
994
|
+
return agents.reduce((sum, agent)=>sum + agent.resources.networkIO, 0);
|
|
995
|
+
}
|
|
996
|
+
calculateErrorRate(tasks) {
|
|
997
|
+
const totalTasks = tasks.length;
|
|
998
|
+
const failedTasks = tasks.filter((task)=>task.status === 'failed').length;
|
|
999
|
+
return totalTasks > 0 ? failedTasks / totalTasks * 100 : 0;
|
|
1000
|
+
}
|
|
1001
|
+
calculateResourceUtilization(agents) {
|
|
1002
|
+
if (agents.length === 0) return 0;
|
|
1003
|
+
const totalAllocated = agents.reduce((sum, agent)=>sum + agent.topology.connections, 0);
|
|
1004
|
+
const totalAvailable = agents.reduce((sum, agent)=>sum + agent.topology.maxConnections, 0);
|
|
1005
|
+
return totalAvailable > 0 ? totalAllocated / totalAvailable * 100 : 0;
|
|
1006
|
+
}
|
|
1007
|
+
groupEventsByType() {
|
|
1008
|
+
const groups = {};
|
|
1009
|
+
this.transparencyEvents.forEach((event)=>{
|
|
1010
|
+
groups[event.eventType] = (groups[event.eventType] || 0) + 1;
|
|
1011
|
+
});
|
|
1012
|
+
return groups;
|
|
1013
|
+
}
|
|
1014
|
+
groupEventsBySeverity() {
|
|
1015
|
+
const groups = {};
|
|
1016
|
+
this.transparencyEvents.forEach((event)=>{
|
|
1017
|
+
groups[event.severity] = (groups[event.severity] || 0) + 1;
|
|
1018
|
+
});
|
|
1019
|
+
return groups;
|
|
1020
|
+
}
|
|
1021
|
+
groupEventsByCategory() {
|
|
1022
|
+
const groups = {};
|
|
1023
|
+
this.transparencyEvents.forEach((event)=>{
|
|
1024
|
+
groups[event.category] = (groups[event.category] || 0) + 1;
|
|
1025
|
+
});
|
|
1026
|
+
return groups;
|
|
1027
|
+
}
|
|
1028
|
+
// Additional helper methods for analytics
|
|
1029
|
+
getHealthDistribution(agents) {
|
|
1030
|
+
const distribution = {
|
|
1031
|
+
excellent: 0,
|
|
1032
|
+
good: 0,
|
|
1033
|
+
fair: 0,
|
|
1034
|
+
poor: 0
|
|
1035
|
+
};
|
|
1036
|
+
agents.forEach((agent)=>{
|
|
1037
|
+
const health = agent.health.successRate;
|
|
1038
|
+
if (health >= 90) distribution.excellent++;
|
|
1039
|
+
else if (health >= 75) distribution.good++;
|
|
1040
|
+
else if (health >= 60) distribution.fair++;
|
|
1041
|
+
else distribution.poor++;
|
|
1042
|
+
});
|
|
1043
|
+
return distribution;
|
|
1044
|
+
}
|
|
1045
|
+
getUtilizationTrends(agents) {
|
|
1046
|
+
// Simple implementation - in real system, this would track trends over time
|
|
1047
|
+
const utilization = this.calculateAgentUtilization(agents);
|
|
1048
|
+
return {
|
|
1049
|
+
current: utilization,
|
|
1050
|
+
trend: 'stable',
|
|
1051
|
+
forecast: utilization
|
|
1052
|
+
};
|
|
1053
|
+
}
|
|
1054
|
+
getPerformanceByAgentType(agents) {
|
|
1055
|
+
const performanceByType = {};
|
|
1056
|
+
agents.forEach((agent)=>{
|
|
1057
|
+
if (!performanceByType[agent.agentType]) {
|
|
1058
|
+
performanceByType[agent.agentType] = {
|
|
1059
|
+
count: 0,
|
|
1060
|
+
averageHealth: 0,
|
|
1061
|
+
averageUtilization: 0,
|
|
1062
|
+
totalTasks: 0
|
|
1063
|
+
};
|
|
1064
|
+
}
|
|
1065
|
+
const typeData = performanceByType[agent.agentType];
|
|
1066
|
+
typeData.count++;
|
|
1067
|
+
typeData.averageHealth += agent.health.successRate;
|
|
1068
|
+
typeData.totalTasks += agent.taskStats.total;
|
|
1069
|
+
});
|
|
1070
|
+
// Calculate averages
|
|
1071
|
+
Object.values(performanceByType).forEach((data)=>{
|
|
1072
|
+
if (data.count > 0) {
|
|
1073
|
+
data.averageHealth /= data.count;
|
|
1074
|
+
data.averageUtilization = data.count > 0 ? 100 : 0; // Simplified
|
|
1075
|
+
}
|
|
1076
|
+
});
|
|
1077
|
+
return performanceByType;
|
|
1078
|
+
}
|
|
1079
|
+
// Additional methods would be implemented here for complete functionality...
|
|
1080
|
+
getMaxAgentsForCoordinator(adapter) {
|
|
1081
|
+
// Extract max agents from coordinator instance
|
|
1082
|
+
return 50; // Default value
|
|
1083
|
+
}
|
|
1084
|
+
getAgentCountForCoordinator(coordinatorId) {
|
|
1085
|
+
return this.agentInfo.size; // Simplified
|
|
1086
|
+
}
|
|
1087
|
+
async getCoordinatorPerformance(adapter) {
|
|
1088
|
+
return {
|
|
1089
|
+
taskThroughput: 10,
|
|
1090
|
+
agentUtilization: 75,
|
|
1091
|
+
averageResponseTime: 150,
|
|
1092
|
+
errorRate: 2
|
|
1093
|
+
};
|
|
1094
|
+
}
|
|
1095
|
+
buildHierarchyFromQueenAgent(queenAgent) {
|
|
1096
|
+
// Build hierarchy from QueenAgent instance
|
|
1097
|
+
return {
|
|
1098
|
+
level: 1,
|
|
1099
|
+
type: 'queen-agent',
|
|
1100
|
+
children: this.getAgentCountForCoordinator(queenAgent.toString())
|
|
1101
|
+
};
|
|
1102
|
+
}
|
|
1103
|
+
getAgentCountForCoordinator(coordinatorId) {
|
|
1104
|
+
return Array.from(this.agentInfo.values()).filter((agent)=>agent.coordinatorId === coordinatorId).length;
|
|
1105
|
+
}
|
|
1106
|
+
getMeshConnections(meshCoordinator) {
|
|
1107
|
+
// Get connection information from MeshCoordinator
|
|
1108
|
+
return {
|
|
1109
|
+
totalConnections: 0,
|
|
1110
|
+
averageConnectionsPerAgent: 0
|
|
1111
|
+
};
|
|
1112
|
+
}
|
|
1113
|
+
// Analytics implementations
|
|
1114
|
+
/**
|
|
1115
|
+
* Calculate task completion rates by task type and status
|
|
1116
|
+
*/ getTaskCompletionRates(tasks) {
|
|
1117
|
+
const totalTasks = tasks.length;
|
|
1118
|
+
if (totalTasks === 0) return {
|
|
1119
|
+
overall: 0,
|
|
1120
|
+
byType: {}
|
|
1121
|
+
};
|
|
1122
|
+
const completedTasks = tasks.filter((task)=>task.status === 'completed').length;
|
|
1123
|
+
const rates = {
|
|
1124
|
+
overall: completedTasks / totalTasks * 100,
|
|
1125
|
+
byType: {}
|
|
1126
|
+
};
|
|
1127
|
+
// Calculate completion rates by task type
|
|
1128
|
+
const tasksByType = {};
|
|
1129
|
+
tasks.forEach((task)=>{
|
|
1130
|
+
if (!tasksByType[task.taskType]) {
|
|
1131
|
+
tasksByType[task.taskType] = [];
|
|
1132
|
+
}
|
|
1133
|
+
tasksByType[task.taskType].push(task);
|
|
1134
|
+
});
|
|
1135
|
+
Object.entries(tasksByType).forEach(([type, typeTasks])=>{
|
|
1136
|
+
const completed = typeTasks.filter((task)=>task.status === 'completed').length;
|
|
1137
|
+
rates.byType[type] = typeTasks.length > 0 ? completed / typeTasks.length * 100 : 0;
|
|
1138
|
+
});
|
|
1139
|
+
return rates;
|
|
1140
|
+
}
|
|
1141
|
+
/**
|
|
1142
|
+
* Analyze task durations by type for performance insights
|
|
1143
|
+
*/ getTaskDurationsByType(tasks) {
|
|
1144
|
+
const durationsByType = {};
|
|
1145
|
+
tasks.forEach((task)=>{
|
|
1146
|
+
if (!durationsByType[task.taskType]) {
|
|
1147
|
+
durationsByType[task.taskType] = {
|
|
1148
|
+
durations: [],
|
|
1149
|
+
count: 0
|
|
1150
|
+
};
|
|
1151
|
+
}
|
|
1152
|
+
if (task.timing.completedAt && task.timing.startedAt) {
|
|
1153
|
+
const duration = task.timing.completedAt.getTime() - task.timing.startedAt.getTime();
|
|
1154
|
+
durationsByType[task.taskType].durations.push(duration);
|
|
1155
|
+
durationsByType[task.taskType].count++;
|
|
1156
|
+
}
|
|
1157
|
+
});
|
|
1158
|
+
const stats = {};
|
|
1159
|
+
Object.entries(durationsByType).forEach(([type, data])=>{
|
|
1160
|
+
if (data.durations.length > 0) {
|
|
1161
|
+
data.durations.sort((a, b)=>a - b);
|
|
1162
|
+
const sum = data.durations.reduce((acc, val)=>acc + val, 0);
|
|
1163
|
+
stats[type] = {
|
|
1164
|
+
average: sum / data.durations.length,
|
|
1165
|
+
median: data.durations[Math.floor(data.durations.length / 2)],
|
|
1166
|
+
min: Math.min(...data.durations),
|
|
1167
|
+
max: Math.max(...data.durations),
|
|
1168
|
+
count: data.count
|
|
1169
|
+
};
|
|
1170
|
+
}
|
|
1171
|
+
});
|
|
1172
|
+
return stats;
|
|
1173
|
+
}
|
|
1174
|
+
/**
|
|
1175
|
+
* Identify failure patterns in tasks for debugging and optimization
|
|
1176
|
+
*/ getFailurePatterns(tasks) {
|
|
1177
|
+
const failedTasks = tasks.filter((task)=>task.status === 'failed');
|
|
1178
|
+
if (failedTasks.length === 0) {
|
|
1179
|
+
return {
|
|
1180
|
+
totalFailures: 0,
|
|
1181
|
+
patterns: []
|
|
1182
|
+
};
|
|
1183
|
+
}
|
|
1184
|
+
const patterns = {
|
|
1185
|
+
byType: {},
|
|
1186
|
+
byAgent: {},
|
|
1187
|
+
byErrorType: {},
|
|
1188
|
+
commonErrors: []
|
|
1189
|
+
};
|
|
1190
|
+
failedTasks.forEach((task)=>{
|
|
1191
|
+
// Group by task type
|
|
1192
|
+
patterns.byType[task.taskType] = (patterns.byType[task.taskType] || 0) + 1;
|
|
1193
|
+
// Group by assigned agents
|
|
1194
|
+
task.assignedAgents.forEach((agentId)=>{
|
|
1195
|
+
patterns.byAgent[agentId] = (patterns.byAgent[agentId] || 0) + 1;
|
|
1196
|
+
});
|
|
1197
|
+
// Extract error patterns from task metadata or results
|
|
1198
|
+
if (task.error && typeof task.error === 'object' && task.error.type) {
|
|
1199
|
+
patterns.byErrorType[task.error.type] = (patterns.byErrorType[task.error.type] || 0) + 1;
|
|
1200
|
+
}
|
|
1201
|
+
});
|
|
1202
|
+
// Identify most common failures
|
|
1203
|
+
patterns.commonErrors = Object.entries(patterns.byType).sort(([, a], [, b])=>b - a).slice(0, 5).map(([type, count])=>`${type}: ${count} failures`);
|
|
1204
|
+
return {
|
|
1205
|
+
totalFailures: failedTasks.length,
|
|
1206
|
+
failureRate: failedTasks.length / tasks.length * 100,
|
|
1207
|
+
patterns
|
|
1208
|
+
};
|
|
1209
|
+
}
|
|
1210
|
+
/**
|
|
1211
|
+
* Calculate scalability metrics for system capacity planning
|
|
1212
|
+
*/ getScalabilityMetrics() {
|
|
1213
|
+
const activeAgents = this.agentInfo.size;
|
|
1214
|
+
const totalTasks = this.taskInfo.size;
|
|
1215
|
+
const activeCoordinators = this.coordinatorAdapters.size;
|
|
1216
|
+
return {
|
|
1217
|
+
currentCapacity: {
|
|
1218
|
+
agents: activeAgents,
|
|
1219
|
+
tasks: totalTasks,
|
|
1220
|
+
coordinators: activeCoordinators
|
|
1221
|
+
},
|
|
1222
|
+
utilization: {
|
|
1223
|
+
agentUtilization: this.calculateAgentUtilization(Array.from(this.agentInfo.values())),
|
|
1224
|
+
taskThroughput: totalTasks > 0 ? this.taskInfo.size / activeAgents : 0,
|
|
1225
|
+
coordinatorLoad: activeCoordinators > 0 ? activeAgents / activeCoordinators : 0
|
|
1226
|
+
},
|
|
1227
|
+
scalingLimits: {
|
|
1228
|
+
maxAgents: this.config.maxAgents || 100,
|
|
1229
|
+
maxTasksPerAgent: 10,
|
|
1230
|
+
maxCoordinators: 20
|
|
1231
|
+
}
|
|
1232
|
+
};
|
|
1233
|
+
}
|
|
1234
|
+
/**
|
|
1235
|
+
* Analyze system bottlenecks for performance optimization
|
|
1236
|
+
*/ getBottleneckAnalysis() {
|
|
1237
|
+
const bottlenecks = [];
|
|
1238
|
+
const agents = Array.from(this.agentInfo.values());
|
|
1239
|
+
// Check for overloaded agents
|
|
1240
|
+
const overloadedAgents = agents.filter((agent)=>agent.currentTasks.length > agent.capabilities.maxConcurrentTasks);
|
|
1241
|
+
if (overloadedAgents.length > 0) {
|
|
1242
|
+
bottlenecks.push({
|
|
1243
|
+
type: 'agent_overload',
|
|
1244
|
+
severity: 'high',
|
|
1245
|
+
description: `${overloadedAgents.length} agents exceeding task capacity`,
|
|
1246
|
+
affectedAgents: overloadedAgents.map((a)=>a.agentId)
|
|
1247
|
+
});
|
|
1248
|
+
}
|
|
1249
|
+
// Check for idle agents
|
|
1250
|
+
const idleAgents = agents.filter((agent)=>agent.status === 'idle' && agent.currentTasks.length === 0);
|
|
1251
|
+
if (idleAgents.length > agents.length * 0.5) {
|
|
1252
|
+
bottlenecks.push({
|
|
1253
|
+
type: 'agent_underutilization',
|
|
1254
|
+
severity: 'medium',
|
|
1255
|
+
description: `${idleAgents.length} agents idle while tasks may be pending`,
|
|
1256
|
+
affectedAgents: idleAgents.map((a)=>a.agentId)
|
|
1257
|
+
});
|
|
1258
|
+
}
|
|
1259
|
+
// Check for coordinator bottlenecks
|
|
1260
|
+
const coordinatorLoads = {};
|
|
1261
|
+
agents.forEach((agent)=>{
|
|
1262
|
+
if (agent.coordinatorId) {
|
|
1263
|
+
coordinatorLoads[agent.coordinatorId] = (coordinatorLoads[agent.coordinatorId] || 0) + 1;
|
|
1264
|
+
}
|
|
1265
|
+
});
|
|
1266
|
+
Object.entries(coordinatorLoads).forEach(([coordinatorId, load])=>{
|
|
1267
|
+
if (load > 20) {
|
|
1268
|
+
bottlenecks.push({
|
|
1269
|
+
type: 'coordinator_overload',
|
|
1270
|
+
severity: 'medium',
|
|
1271
|
+
description: `Coordinator ${coordinatorId} managing ${load} agents`,
|
|
1272
|
+
coordinatorId,
|
|
1273
|
+
load
|
|
1274
|
+
});
|
|
1275
|
+
}
|
|
1276
|
+
});
|
|
1277
|
+
return {
|
|
1278
|
+
bottlenecks,
|
|
1279
|
+
bottleneckCount: bottlenecks.length,
|
|
1280
|
+
recommendations: this.generateBottleneckRecommendations(bottlenecks)
|
|
1281
|
+
};
|
|
1282
|
+
}
|
|
1283
|
+
/**
|
|
1284
|
+
* Generate optimization recommendations based on bottlenecks
|
|
1285
|
+
*/ generateBottleneckRecommendations(bottlenecks) {
|
|
1286
|
+
const recommendations = [];
|
|
1287
|
+
bottlenecks.forEach((bottleneck)=>{
|
|
1288
|
+
switch(bottleneck.type){
|
|
1289
|
+
case 'agent_overload':
|
|
1290
|
+
recommendations.push('Reduce task assignment to overloaded agents or spawn additional agents');
|
|
1291
|
+
break;
|
|
1292
|
+
case 'agent_underutilization':
|
|
1293
|
+
recommendations.push('Optimize task distribution to utilize idle agents more effectively');
|
|
1294
|
+
break;
|
|
1295
|
+
case 'coordinator_overload':
|
|
1296
|
+
recommendations.push('Consider adding additional coordinators or rebalancing agent distribution');
|
|
1297
|
+
break;
|
|
1298
|
+
}
|
|
1299
|
+
});
|
|
1300
|
+
return recommendations;
|
|
1301
|
+
}
|
|
1302
|
+
/**
|
|
1303
|
+
* Calculate system efficiency metrics
|
|
1304
|
+
*/ getEfficiencyMetrics() {
|
|
1305
|
+
const agents = Array.from(this.agentInfo.values());
|
|
1306
|
+
const tasks = Array.from(this.taskInfo.values());
|
|
1307
|
+
const completedTasks = tasks.filter((task)=>task.status === 'completed');
|
|
1308
|
+
const failedTasks = tasks.filter((task)=>task.status === 'failed');
|
|
1309
|
+
return {
|
|
1310
|
+
taskEfficiency: tasks.length > 0 ? completedTasks.length / tasks.length * 100 : 0,
|
|
1311
|
+
agentEfficiency: this.calculateAgentUtilization(agents),
|
|
1312
|
+
successRate: tasks.length > 0 ? completedTasks.length / tasks.length * 100 : 0,
|
|
1313
|
+
errorRate: tasks.length > 0 ? failedTasks.length / tasks.length * 100 : 0,
|
|
1314
|
+
averageTaskCompletionTime: this.calculateAverageCompletionTime(completedTasks)
|
|
1315
|
+
};
|
|
1316
|
+
}
|
|
1317
|
+
/**
|
|
1318
|
+
* Calculate average task completion time
|
|
1319
|
+
*/ calculateAverageCompletionTime(completedTasks) {
|
|
1320
|
+
if (completedTasks.length === 0) return 0;
|
|
1321
|
+
const totalDuration = completedTasks.reduce((sum, task)=>{
|
|
1322
|
+
if (task.timing.completedAt && task.timing.startedAt) {
|
|
1323
|
+
return sum + (task.timing.completedAt.getTime() - task.timing.startedAt.getTime());
|
|
1324
|
+
}
|
|
1325
|
+
return sum;
|
|
1326
|
+
}, 0);
|
|
1327
|
+
return totalDuration / completedTasks.length;
|
|
1328
|
+
}
|
|
1329
|
+
// Hierarchical topology metrics
|
|
1330
|
+
getAverageWorkersPerQueen(queenAgents) {
|
|
1331
|
+
if (queenAgents.length === 0) return 0;
|
|
1332
|
+
const totalWorkers = queenAgents.reduce((sum, queen)=>{
|
|
1333
|
+
const workers = Array.from(this.agentInfo.values()).filter((agent)=>agent.coordinatorId === queen.id);
|
|
1334
|
+
return sum + workers.length;
|
|
1335
|
+
}, 0);
|
|
1336
|
+
return totalWorkers / queenAgents.length;
|
|
1337
|
+
}
|
|
1338
|
+
getHierarchyDepth(queenAgents) {
|
|
1339
|
+
// Simple implementation - count coordinator levels
|
|
1340
|
+
if (queenAgents.length === 0) return 0;
|
|
1341
|
+
let maxDepth = 1;
|
|
1342
|
+
const visited = new Set();
|
|
1343
|
+
const calculateDepth = (coordinatorId, currentDepth)=>{
|
|
1344
|
+
if (visited.has(coordinatorId)) return currentDepth;
|
|
1345
|
+
visited.add(coordinatorId);
|
|
1346
|
+
const children = Array.from(this.agentInfo.values()).filter((agent)=>agent.coordinatorId === coordinatorId);
|
|
1347
|
+
if (children.length === 0) return currentDepth;
|
|
1348
|
+
return Math.max(...children.map((child)=>calculateDepth(child.agentId, currentDepth + 1)));
|
|
1349
|
+
};
|
|
1350
|
+
queenAgents.forEach((queen)=>{
|
|
1351
|
+
maxDepth = Math.max(maxDepth, calculateDepth(queen.id, 1));
|
|
1352
|
+
});
|
|
1353
|
+
return maxDepth;
|
|
1354
|
+
}
|
|
1355
|
+
getHierarchicalEfficiency(queenAgents) {
|
|
1356
|
+
if (queenAgents.length === 0) return 0;
|
|
1357
|
+
const totalAgents = this.agentInfo.size;
|
|
1358
|
+
const queenAgentsCount = queenAgents.length;
|
|
1359
|
+
// Efficiency based on optimal span of control (5-10 agents per queen)
|
|
1360
|
+
const optimalSpan = 7;
|
|
1361
|
+
const actualSpan = totalAgents / queenAgentsCount;
|
|
1362
|
+
const spanEfficiency = Math.max(0, 100 - Math.abs(actualSpan - optimalSpan) * 5);
|
|
1363
|
+
return Math.round(spanEfficiency);
|
|
1364
|
+
}
|
|
1365
|
+
// Mesh topology metrics
|
|
1366
|
+
getAverageConnectionsPerAgent(meshCoordinators) {
|
|
1367
|
+
const agents = Array.from(this.agentInfo.values());
|
|
1368
|
+
if (agents.length === 0) return 0;
|
|
1369
|
+
// Calculate average connections based on agent collaboration
|
|
1370
|
+
let totalConnections = 0;
|
|
1371
|
+
agents.forEach((agent)=>{
|
|
1372
|
+
// Estimate connections based on shared tasks and coordinator relationships
|
|
1373
|
+
const sharedTasks = Array.from(this.taskInfo.values()).filter((task)=>task.assignedAgents.includes(agent.agentId) && task.assignedAgents.length > 1);
|
|
1374
|
+
totalConnections += sharedTasks.length;
|
|
1375
|
+
});
|
|
1376
|
+
return totalConnections / agents.length;
|
|
1377
|
+
}
|
|
1378
|
+
getNetworkDiameter(meshCoordinators) {
|
|
1379
|
+
// Simplified network diameter calculation
|
|
1380
|
+
// In a real implementation, this would use graph algorithms
|
|
1381
|
+
const agentCount = this.agentInfo.size;
|
|
1382
|
+
const coordinatorCount = meshCoordinators.length;
|
|
1383
|
+
if (agentCount === 0) return 0;
|
|
1384
|
+
// Estimate diameter based on network size and topology
|
|
1385
|
+
return Math.ceil(Math.log2(agentCount + coordinatorCount));
|
|
1386
|
+
}
|
|
1387
|
+
getMeshClusteringMetrics(meshCoordinators) {
|
|
1388
|
+
const agents = Array.from(this.agentInfo.values());
|
|
1389
|
+
const tasks = Array.from(this.taskInfo.values());
|
|
1390
|
+
// Calculate clustering coefficient based on task collaboration
|
|
1391
|
+
let totalTriangles = 0;
|
|
1392
|
+
let possibleTriangles = 0;
|
|
1393
|
+
agents.forEach((agent)=>{
|
|
1394
|
+
const collaborators = new Set();
|
|
1395
|
+
tasks.forEach((task)=>{
|
|
1396
|
+
if (task.assignedAgents.includes(agent.agentId)) {
|
|
1397
|
+
task.assignedAgents.forEach((otherAgent)=>{
|
|
1398
|
+
if (otherAgent !== agent.agentId) {
|
|
1399
|
+
collaborators.add(otherAgent);
|
|
1400
|
+
}
|
|
1401
|
+
});
|
|
1402
|
+
}
|
|
1403
|
+
});
|
|
1404
|
+
const collaboratorList = Array.from(collaborators);
|
|
1405
|
+
if (collaboratorList.length >= 2) {
|
|
1406
|
+
possibleTriangles += collaboratorList.length * (collaboratorList.length - 1) / 2;
|
|
1407
|
+
// Count actual triangles (simplified)
|
|
1408
|
+
for(let i = 0; i < collaboratorList.length; i++){
|
|
1409
|
+
for(let j = i + 1; j < collaboratorList.length; j++){
|
|
1410
|
+
// Check if these collaborators also work together
|
|
1411
|
+
const sharedTasks = tasks.filter((task)=>task.assignedAgents.includes(collaboratorList[i]) && task.assignedAgents.includes(collaboratorList[j]));
|
|
1412
|
+
if (sharedTasks.length > 0) {
|
|
1413
|
+
totalTriangles++;
|
|
1414
|
+
}
|
|
1415
|
+
}
|
|
1416
|
+
}
|
|
1417
|
+
}
|
|
1418
|
+
});
|
|
1419
|
+
const clusteringCoefficient = possibleTriangles > 0 ? totalTriangles / possibleTriangles : 0;
|
|
1420
|
+
return {
|
|
1421
|
+
clusteringCoefficient,
|
|
1422
|
+
totalClusters: Math.round(agents.length * clusteringCoefficient),
|
|
1423
|
+
averageClusterSize: clusteringCoefficient > 0 ? Math.round(agents.length / (agents.length * clusteringCoefficient)) : 0
|
|
1424
|
+
};
|
|
1425
|
+
}
|
|
1426
|
+
getOverallTopologyEfficiency() {
|
|
1427
|
+
const agents = Array.from(this.agentInfo.values());
|
|
1428
|
+
const tasks = Array.from(this.taskInfo.values());
|
|
1429
|
+
if (agents.length === 0 || tasks.length === 0) return 0;
|
|
1430
|
+
// Calculate efficiency based on multiple factors
|
|
1431
|
+
const utilizationEfficiency = this.calculateAgentUtilization(agents);
|
|
1432
|
+
const taskSuccessRate = this.getTaskCompletionRates(tasks).overall;
|
|
1433
|
+
const collaborationEfficiency = Math.min(this.getAverageConnectionsPerAgent([]) * 10, 100); // Scale to 0-100
|
|
1434
|
+
return Math.round((utilizationEfficiency + taskSuccessRate + collaborationEfficiency) / 3);
|
|
1435
|
+
}
|
|
1436
|
+
getScalingCharacteristics() {
|
|
1437
|
+
const currentLoad = this.agentInfo.size;
|
|
1438
|
+
const taskLoad = this.taskInfo.size;
|
|
1439
|
+
return {
|
|
1440
|
+
currentScale: {
|
|
1441
|
+
agents: currentLoad,
|
|
1442
|
+
tasks: taskLoad,
|
|
1443
|
+
coordinators: this.coordinatorAdapters.size
|
|
1444
|
+
},
|
|
1445
|
+
scalingLimits: {
|
|
1446
|
+
maxAgents: this.config.maxAgents || 100,
|
|
1447
|
+
maxTasks: this.config.maxEventsInMemory || 1000,
|
|
1448
|
+
maxCoordinators: 20
|
|
1449
|
+
},
|
|
1450
|
+
scalingRecommendations: this.generateScalingRecommendations(currentLoad, taskLoad)
|
|
1451
|
+
};
|
|
1452
|
+
}
|
|
1453
|
+
generateScalingRecommendations(currentAgents, currentTasks) {
|
|
1454
|
+
const recommendations = [];
|
|
1455
|
+
if (currentAgents > (this.config.maxAgents || 100) * 0.8) {
|
|
1456
|
+
recommendations.push('Approaching agent limit - consider scaling coordinator infrastructure');
|
|
1457
|
+
}
|
|
1458
|
+
if (currentTasks > currentAgents * 8) {
|
|
1459
|
+
recommendations.push('High task-to-agent ratio - consider spawning additional agents');
|
|
1460
|
+
}
|
|
1461
|
+
if (currentAgents < (this.config.maxAgents || 100) * 0.3 && currentTasks > 0) {
|
|
1462
|
+
recommendations.push('Low agent utilization - optimize task distribution or reduce agent count');
|
|
1463
|
+
}
|
|
1464
|
+
return recommendations;
|
|
1465
|
+
}
|
|
1466
|
+
}
|
|
1467
|
+
|
|
1468
|
+
//# sourceMappingURL=v1-transparency-adapter.js.map
|