agentic-qe 3.7.5 → 3.7.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (80) hide show
  1. package/.claude/skills/skills-manifest.json +1 -1
  2. package/CHANGELOG.md +18 -0
  3. package/dist/cli/bundle.js +5199 -1335
  4. package/dist/cli/commands/security.d.ts.map +1 -1
  5. package/dist/cli/commands/security.js +66 -1
  6. package/dist/cli/commands/security.js.map +1 -1
  7. package/dist/cli/commands/test.d.ts.map +1 -1
  8. package/dist/cli/commands/test.js +86 -3
  9. package/dist/cli/commands/test.js.map +1 -1
  10. package/dist/cli/index.js +119 -0
  11. package/dist/cli/index.js.map +1 -1
  12. package/dist/coordination/workflow-orchestrator.d.ts.map +1 -1
  13. package/dist/coordination/workflow-orchestrator.js +2 -6
  14. package/dist/coordination/workflow-orchestrator.js.map +1 -1
  15. package/dist/mcp/bundle.js +3977 -153
  16. package/dist/mcp/handlers/core-handlers.d.ts.map +1 -1
  17. package/dist/mcp/handlers/core-handlers.js +35 -0
  18. package/dist/mcp/handlers/core-handlers.js.map +1 -1
  19. package/dist/mcp/protocol-server.d.ts.map +1 -1
  20. package/dist/mcp/protocol-server.js +4 -1
  21. package/dist/mcp/protocol-server.js.map +1 -1
  22. package/dist/mcp/qe-tool-bridge.d.ts +27 -0
  23. package/dist/mcp/qe-tool-bridge.d.ts.map +1 -0
  24. package/dist/mcp/qe-tool-bridge.js +87 -0
  25. package/dist/mcp/qe-tool-bridge.js.map +1 -0
  26. package/dist/mcp/tools/registry.d.ts +4 -0
  27. package/dist/mcp/tools/registry.d.ts.map +1 -1
  28. package/dist/mcp/tools/registry.js +20 -0
  29. package/dist/mcp/tools/registry.js.map +1 -1
  30. package/dist/mcp/tools/security-compliance/visual-security.d.ts +45 -0
  31. package/dist/mcp/tools/security-compliance/visual-security.d.ts.map +1 -0
  32. package/dist/mcp/tools/security-compliance/visual-security.js +218 -0
  33. package/dist/mcp/tools/security-compliance/visual-security.js.map +1 -0
  34. package/dist/mcp/tools/test-execution/browser-workflow.d.ts +50 -0
  35. package/dist/mcp/tools/test-execution/browser-workflow.d.ts.map +1 -0
  36. package/dist/mcp/tools/test-execution/browser-workflow.js +145 -0
  37. package/dist/mcp/tools/test-execution/browser-workflow.js.map +1 -0
  38. package/dist/mcp/tools/test-execution/load-test.d.ts +37 -0
  39. package/dist/mcp/tools/test-execution/load-test.d.ts.map +1 -0
  40. package/dist/mcp/tools/test-execution/load-test.js +98 -0
  41. package/dist/mcp/tools/test-execution/load-test.js.map +1 -0
  42. package/dist/mcp/tools/test-execution/schedule.d.ts +44 -0
  43. package/dist/mcp/tools/test-execution/schedule.d.ts.map +1 -0
  44. package/dist/mcp/tools/test-execution/schedule.js +96 -0
  45. package/dist/mcp/tools/test-execution/schedule.js.map +1 -0
  46. package/dist/planning/goap-planner.d.ts.map +1 -1
  47. package/dist/planning/goap-planner.js +7 -28
  48. package/dist/planning/goap-planner.js.map +1 -1
  49. package/dist/planning/plan-executor.d.ts.map +1 -1
  50. package/dist/planning/plan-executor.js +7 -28
  51. package/dist/planning/plan-executor.js.map +1 -1
  52. package/package.json +3 -10
  53. package/dist/cli/commands/qe-tools.d.ts +0 -27
  54. package/dist/cli/commands/qe-tools.d.ts.map +0 -1
  55. package/dist/cli/commands/qe-tools.js +0 -771
  56. package/dist/cli/commands/qe-tools.js.map +0 -1
  57. package/dist/neural-optimizer/index.d.ts +0 -55
  58. package/dist/neural-optimizer/index.d.ts.map +0 -1
  59. package/dist/neural-optimizer/index.js +0 -57
  60. package/dist/neural-optimizer/index.js.map +0 -1
  61. package/dist/neural-optimizer/replay-buffer.d.ts +0 -126
  62. package/dist/neural-optimizer/replay-buffer.d.ts.map +0 -1
  63. package/dist/neural-optimizer/replay-buffer.js +0 -356
  64. package/dist/neural-optimizer/replay-buffer.js.map +0 -1
  65. package/dist/neural-optimizer/swarm-topology.d.ts +0 -157
  66. package/dist/neural-optimizer/swarm-topology.d.ts.map +0 -1
  67. package/dist/neural-optimizer/swarm-topology.js +0 -384
  68. package/dist/neural-optimizer/swarm-topology.js.map +0 -1
  69. package/dist/neural-optimizer/topology-optimizer.d.ts +0 -137
  70. package/dist/neural-optimizer/topology-optimizer.d.ts.map +0 -1
  71. package/dist/neural-optimizer/topology-optimizer.js +0 -657
  72. package/dist/neural-optimizer/topology-optimizer.js.map +0 -1
  73. package/dist/neural-optimizer/types.d.ts +0 -333
  74. package/dist/neural-optimizer/types.d.ts.map +0 -1
  75. package/dist/neural-optimizer/types.js +0 -57
  76. package/dist/neural-optimizer/types.js.map +0 -1
  77. package/dist/neural-optimizer/value-network.d.ts +0 -129
  78. package/dist/neural-optimizer/value-network.d.ts.map +0 -1
  79. package/dist/neural-optimizer/value-network.js +0 -279
  80. package/dist/neural-optimizer/value-network.js.map +0 -1
@@ -1,657 +0,0 @@
1
- /**
2
- * Agentic QE v3 - Neural Topology Optimizer
3
- * ADR-034: RL-based swarm topology optimization
4
- *
5
- * Implements reinforcement learning-based topology optimization:
6
- * - Q-learning with value network for state evaluation
7
- * - Experience replay for stable training
8
- * - Epsilon-greedy exploration
9
- * - Multi-objective reward (min-cut, efficiency, load balance)
10
- */
11
- import { DEFAULT_OPTIMIZER_CONFIG, actionToIndex, indexToActionType, ACTION_TYPES } from './types';
12
- import { ValueNetwork } from './value-network';
13
- import { PrioritizedReplayBuffer } from './replay-buffer';
14
- import { secureRandom, secureRandomInt } from '../shared/utils/crypto-random.js';
15
- // ============================================================================
16
- // Neural Topology Optimizer
17
- // ============================================================================
18
- /**
19
- * Neural Topology Optimizer using reinforcement learning
20
- *
21
- * Uses a value network to estimate state values and learns to select
22
- * topology modifications that improve overall swarm performance.
23
- */
24
- export class NeuralTopologyOptimizer {
25
- /** Primary value network */
26
- valueNetwork;
27
- /** Target network for stable learning */
28
- targetNetwork;
29
- /** Experience replay buffer */
30
- replayBuffer;
31
- /** Optimizer configuration */
32
- config;
33
- /** Reference to topology being optimized */
34
- topology;
35
- /** Previous state for learning */
36
- prevState = null;
37
- /** Previous min-cut estimate */
38
- prevMinCut = 0;
39
- /** Current exploration rate */
40
- epsilon;
41
- /** Simulation time */
42
- time = 0;
43
- /** Total optimization steps */
44
- totalSteps = 0;
45
- /** Episode count */
46
- episodes = 0;
47
- /** Cumulative reward */
48
- cumulativeReward = 0;
49
- /** Action counts */
50
- actionCounts;
51
- /** Min-cut history */
52
- minCutHistory = [];
53
- /** Reward history */
54
- rewardHistory = [];
55
- /** Last action taken (for feedback) */
56
- lastAction = null;
57
- constructor(topology, config = {}) {
58
- this.topology = topology;
59
- this.config = { ...DEFAULT_OPTIMIZER_CONFIG, ...config };
60
- this.epsilon = this.config.epsilon;
61
- // Initialize value networks
62
- this.valueNetwork = new ValueNetwork(this.config.inputSize, this.config.hiddenSize);
63
- this.targetNetwork = new ValueNetwork(this.config.inputSize, this.config.hiddenSize);
64
- this.targetNetwork.copyFrom(this.valueNetwork);
65
- // Initialize replay buffer
66
- this.replayBuffer = new PrioritizedReplayBuffer(this.config.replayBufferSize, { alpha: 0.6, beta: 0.4 });
67
- // Initialize action counts
68
- this.actionCounts = {};
69
- for (const actionType of ACTION_TYPES) {
70
- this.actionCounts[actionType] = 0;
71
- }
72
- // Initialize state
73
- this.prevState = this.extractFeatures();
74
- this.prevMinCut = this.estimateMinCut();
75
- }
76
- // ============================================================================
77
- // Public API
78
- // ============================================================================
79
- /**
80
- * Run one optimization step
81
- */
82
- optimizeStep() {
83
- // 1. Encode current state
84
- const state = this.extractFeatures();
85
- const valueBefore = this.valueNetwork.estimate(state);
86
- // 2. Select action using epsilon-greedy
87
- const action = this.selectAction(state);
88
- this.lastAction = action;
89
- // 3. Execute action
90
- const oldMinCut = this.estimateMinCut();
91
- this.applyAction(action);
92
- const newMinCut = this.estimateMinCut();
93
- // 4. Calculate multi-objective reward
94
- const reward = this.calculateReward(oldMinCut, newMinCut);
95
- // 5. Get new state
96
- const nextState = this.extractFeatures();
97
- const valueAfter = this.valueNetwork.estimate(nextState);
98
- // 6. Calculate TD error
99
- const targetValue = reward + this.config.gamma * this.targetNetwork.estimate(nextState);
100
- const tdError = targetValue - valueBefore;
101
- // 7. Update value network
102
- this.valueNetwork.update(state, tdError, this.config.learningRate);
103
- // 8. Store experience
104
- if (this.prevState !== null) {
105
- const experience = {
106
- state: this.prevState,
107
- actionIdx: actionToIndex(action),
108
- reward,
109
- nextState,
110
- done: false,
111
- tdError: Math.abs(tdError),
112
- timestamp: Date.now(),
113
- };
114
- this.replayBuffer.push(experience);
115
- }
116
- // 9. Train from replay buffer
117
- if (this.replayBuffer.length >= this.config.minExperiencesForTraining) {
118
- this.trainFromReplay();
119
- }
120
- // 10. Update target network periodically
121
- this.totalSteps++;
122
- if (this.totalSteps % this.config.targetUpdateFrequency === 0) {
123
- this.targetNetwork.softUpdate(this.valueNetwork, 0.01);
124
- }
125
- // 11. Decay exploration rate
126
- this.epsilon = Math.max(this.config.minEpsilon, this.epsilon * this.config.epsilonDecay);
127
- // 12. Update tracking
128
- this.prevState = nextState;
129
- this.prevMinCut = newMinCut;
130
- this.time += this.config.dt;
131
- this.actionCounts[action.type]++;
132
- this.cumulativeReward += reward;
133
- this.minCutHistory.push(newMinCut);
134
- this.rewardHistory.push(reward);
135
- // Limit history size
136
- if (this.minCutHistory.length > 1000) {
137
- this.minCutHistory.shift();
138
- this.rewardHistory.shift();
139
- }
140
- // Calculate metrics
141
- const loadStats = this.getLoadStats();
142
- return {
143
- action,
144
- reward,
145
- newMinCut,
146
- communicationEfficiency: this.measureCommunicationEfficiency(),
147
- loadBalance: 1 - loadStats.variance,
148
- tdError,
149
- epsilon: this.epsilon,
150
- valueBefore,
151
- valueAfter,
152
- };
153
- }
154
- /**
155
- * Run multiple optimization steps
156
- */
157
- optimize(steps) {
158
- const results = [];
159
- for (let i = 0; i < steps; i++) {
160
- results.push(this.optimizeStep());
161
- }
162
- this.episodes++;
163
- return results;
164
- }
165
- /**
166
- * Provide external feedback (e.g., from task completion)
167
- */
168
- provideFeedback(reward) {
169
- if (this.prevState === null || this.lastAction === null)
170
- return;
171
- const state = this.extractFeatures();
172
- const experience = {
173
- state: this.prevState,
174
- actionIdx: actionToIndex(this.lastAction),
175
- reward,
176
- nextState: state,
177
- done: false,
178
- tdError: Math.abs(reward),
179
- timestamp: Date.now(),
180
- };
181
- this.replayBuffer.push(experience);
182
- // Immediate learning from feedback
183
- const currentValue = this.valueNetwork.estimate(this.prevState);
184
- const nextValue = this.targetNetwork.estimate(state);
185
- const tdError = reward + this.config.gamma * nextValue - currentValue;
186
- this.valueNetwork.update(this.prevState, tdError, this.config.learningRate);
187
- }
188
- /**
189
- * Get skip regions (low activity areas)
190
- */
191
- getSkipRegions() {
192
- return this.topology.agents
193
- .filter((agent) => {
194
- const degree = this.topology.connections.filter((c) => c.from === agent.id || c.to === agent.id).length;
195
- return degree < 2;
196
- })
197
- .map((agent) => agent.id);
198
- }
199
- /**
200
- * Get optimization statistics
201
- */
202
- getStats() {
203
- const avgReward = this.totalSteps > 0 ? this.cumulativeReward / this.totalSteps : 0;
204
- const avgTdError = this.rewardHistory.length > 0
205
- ? this.rewardHistory.reduce((sum, r) => sum + Math.abs(r), 0) /
206
- this.rewardHistory.length
207
- : 0;
208
- return {
209
- totalSteps: this.totalSteps,
210
- episodes: this.episodes,
211
- cumulativeReward: this.cumulativeReward,
212
- avgReward,
213
- avgTdError,
214
- actionCounts: { ...this.actionCounts },
215
- minCutHistory: [...this.minCutHistory],
216
- rewardHistory: [...this.rewardHistory],
217
- currentEpsilon: this.epsilon,
218
- };
219
- }
220
- /**
221
- * Reset optimizer state
222
- */
223
- reset() {
224
- this.prevState = this.extractFeatures();
225
- this.prevMinCut = this.estimateMinCut();
226
- this.time = 0;
227
- this.epsilon = this.config.epsilon;
228
- this.lastAction = null;
229
- }
230
- /**
231
- * Hard reset (clear learning)
232
- */
233
- hardReset() {
234
- this.reset();
235
- this.replayBuffer.clear();
236
- this.totalSteps = 0;
237
- this.episodes = 0;
238
- this.cumulativeReward = 0;
239
- this.minCutHistory = [];
240
- this.rewardHistory = [];
241
- for (const actionType of ACTION_TYPES) {
242
- this.actionCounts[actionType] = 0;
243
- }
244
- // Reinitialize networks
245
- this.valueNetwork = new ValueNetwork(this.config.inputSize, this.config.hiddenSize);
246
- this.targetNetwork = new ValueNetwork(this.config.inputSize, this.config.hiddenSize);
247
- this.targetNetwork.copyFrom(this.valueNetwork);
248
- }
249
- /**
250
- * Export learned model
251
- */
252
- exportModel() {
253
- return {
254
- type: 'neural-topology-optimizer',
255
- version: '1.0.0',
256
- config: { ...this.config },
257
- valueNetwork: this.valueNetwork.export(),
258
- targetNetwork: this.targetNetwork.export(),
259
- stats: this.getStats(),
260
- exportedAt: new Date().toISOString(),
261
- };
262
- }
263
- /**
264
- * Import learned model
265
- */
266
- importModel(model) {
267
- if (model.type !== 'neural-topology-optimizer') {
268
- throw new Error(`Invalid model type: ${model.type}`);
269
- }
270
- // Import config
271
- this.config = { ...DEFAULT_OPTIMIZER_CONFIG, ...model.config };
272
- this.epsilon = model.stats.currentEpsilon;
273
- // Import networks
274
- this.valueNetwork = new ValueNetwork(this.config.inputSize, this.config.hiddenSize);
275
- this.valueNetwork.import(model.valueNetwork);
276
- if (model.targetNetwork) {
277
- this.targetNetwork = new ValueNetwork(this.config.inputSize, this.config.hiddenSize);
278
- this.targetNetwork.import(model.targetNetwork);
279
- }
280
- else {
281
- this.targetNetwork.copyFrom(this.valueNetwork);
282
- }
283
- // Import stats
284
- this.totalSteps = model.stats.totalSteps;
285
- this.episodes = model.stats.episodes;
286
- this.cumulativeReward = model.stats.cumulativeReward;
287
- this.actionCounts = { ...model.stats.actionCounts };
288
- this.minCutHistory = [...model.stats.minCutHistory];
289
- this.rewardHistory = [...model.stats.rewardHistory];
290
- }
291
- // ============================================================================
292
- // Private Methods
293
- // ============================================================================
294
- /**
295
- * Extract features from topology for state representation
296
- */
297
- extractFeatures() {
298
- const n = this.topology.agents.length;
299
- const m = this.topology.connections.length;
300
- const loadStats = this.getLoadStats();
301
- const state = {
302
- agentCount: n,
303
- connectionCount: m,
304
- density: this.getDensity(),
305
- avgDegree: this.getAverageDegree(),
306
- minDegree: this.getMinDegree(),
307
- avgWeight: this.getAverageWeight(),
308
- weightVariance: this.getWeightVariance(),
309
- avgLoad: loadStats.avg,
310
- loadVariance: loadStats.variance,
311
- avgLatency: this.getAverageLatency(),
312
- idleAgents: loadStats.idle,
313
- overloadedAgents: loadStats.overloaded,
314
- clusteringCoefficient: this.getClusteringCoefficient(),
315
- time: this.time,
316
- extra: [],
317
- };
318
- // Convert to feature vector (normalized)
319
- const features = new Array(this.config.inputSize).fill(0);
320
- if (this.config.inputSize > 0)
321
- features[0] = n / 100;
322
- if (this.config.inputSize > 1)
323
- features[1] = m / 500;
324
- if (this.config.inputSize > 2)
325
- features[2] = state.density;
326
- if (this.config.inputSize > 3)
327
- features[3] = state.avgDegree / 10;
328
- if (this.config.inputSize > 4)
329
- features[4] = state.minDegree / 10;
330
- if (this.config.inputSize > 5)
331
- features[5] = state.avgWeight / 5;
332
- if (this.config.inputSize > 6)
333
- features[6] = Math.min(1, state.weightVariance);
334
- if (this.config.inputSize > 7)
335
- features[7] = state.avgLoad;
336
- if (this.config.inputSize > 8)
337
- features[8] = Math.min(1, state.loadVariance);
338
- if (this.config.inputSize > 9)
339
- features[9] = state.avgLatency / 100;
340
- if (this.config.inputSize > 10)
341
- features[10] = state.idleAgents / Math.max(1, n);
342
- if (this.config.inputSize > 11)
343
- features[11] = state.overloadedAgents / Math.max(1, n);
344
- if (this.config.inputSize > 12)
345
- features[12] = state.clusteringCoefficient;
346
- if (this.config.inputSize > 13)
347
- features[13] = Math.sin(state.time * 0.1);
348
- if (this.config.inputSize > 14)
349
- features[14] = Math.cos(state.time * 0.1);
350
- if (this.config.inputSize > 15)
351
- features[15] = this.prevMinCut / Math.max(1, m);
352
- return features;
353
- }
354
- /**
355
- * Select action using epsilon-greedy policy
356
- */
357
- selectAction(state) {
358
- // Exploration: random action
359
- if (secureRandom() < this.epsilon) {
360
- return this.randomAction();
361
- }
362
- // Exploitation: select action with highest estimated value
363
- let bestAction = { type: 'no_op' };
364
- let bestValue = -Infinity;
365
- for (let i = 0; i < this.config.numActions; i++) {
366
- const action = this.indexToAction(i);
367
- const hypotheticalState = this.simulateAction(state, action);
368
- const value = this.valueNetwork.estimate(hypotheticalState);
369
- if (value > bestValue) {
370
- bestValue = value;
371
- bestAction = action;
372
- }
373
- }
374
- return bestAction;
375
- }
376
- /**
377
- * Convert index to action
378
- */
379
- indexToAction(idx) {
380
- const agents = this.topology.agents;
381
- if (agents.length < 2)
382
- return { type: 'no_op' };
383
- const actionType = indexToActionType(idx);
384
- const from = agents[idx % agents.length].id;
385
- const to = agents[(idx + 1) % agents.length].id;
386
- switch (actionType) {
387
- case 'add_connection':
388
- if (!this.hasConnection(from, to)) {
389
- return { type: 'add_connection', from, to, weight: 1.0 };
390
- }
391
- return { type: 'no_op' };
392
- case 'remove_connection':
393
- if (this.hasConnection(from, to)) {
394
- return { type: 'remove_connection', from, to };
395
- }
396
- return { type: 'no_op' };
397
- case 'strengthen_connection':
398
- return { type: 'strengthen_connection', from, to, delta: 0.1 };
399
- case 'weaken_connection':
400
- return { type: 'weaken_connection', from, to, delta: 0.1 };
401
- default:
402
- return { type: 'no_op' };
403
- }
404
- }
405
- /**
406
- * Generate random action
407
- */
408
- randomAction() {
409
- const agents = this.topology.agents;
410
- if (agents.length < 2)
411
- return { type: 'no_op' };
412
- const actionTypeIdx = secureRandomInt(0, ACTION_TYPES.length);
413
- const actionType = ACTION_TYPES[actionTypeIdx];
414
- const fromIdx = secureRandomInt(0, agents.length);
415
- let toIdx = secureRandomInt(0, agents.length);
416
- while (toIdx === fromIdx && agents.length > 1) {
417
- toIdx = secureRandomInt(0, agents.length);
418
- }
419
- const from = agents[fromIdx].id;
420
- const to = agents[toIdx].id;
421
- switch (actionType) {
422
- case 'add_connection':
423
- if (!this.hasConnection(from, to)) {
424
- return { type: 'add_connection', from, to, weight: 1.0 };
425
- }
426
- return { type: 'no_op' };
427
- case 'remove_connection':
428
- if (this.hasConnection(from, to)) {
429
- return { type: 'remove_connection', from, to };
430
- }
431
- return { type: 'no_op' };
432
- case 'strengthen_connection':
433
- return { type: 'strengthen_connection', from, to, delta: 0.1 };
434
- case 'weaken_connection':
435
- return { type: 'weaken_connection', from, to, delta: 0.1 };
436
- default:
437
- return { type: 'no_op' };
438
- }
439
- }
440
- /**
441
- * Simulate action effect on state (for lookahead)
442
- */
443
- simulateAction(state, action) {
444
- const newState = [...state];
445
- switch (action.type) {
446
- case 'add_connection':
447
- if (this.config.inputSize > 1)
448
- newState[1] += 0.002; // connection count
449
- if (this.config.inputSize > 2)
450
- newState[2] += 0.01; // density
451
- if (this.config.inputSize > 3)
452
- newState[3] += 0.1; // avg degree
453
- break;
454
- case 'remove_connection':
455
- if (this.config.inputSize > 1)
456
- newState[1] -= 0.002;
457
- if (this.config.inputSize > 2)
458
- newState[2] -= 0.01;
459
- if (this.config.inputSize > 3)
460
- newState[3] -= 0.1;
461
- break;
462
- case 'strengthen_connection':
463
- if (this.config.inputSize > 5)
464
- newState[5] += 0.02; // avg weight
465
- break;
466
- case 'weaken_connection':
467
- if (this.config.inputSize > 5)
468
- newState[5] -= 0.02;
469
- break;
470
- }
471
- return newState;
472
- }
473
- /**
474
- * Apply action to topology
475
- */
476
- applyAction(action) {
477
- switch (action.type) {
478
- case 'add_connection':
479
- this.topology.addConnection(action.from, action.to, action.weight || 1.0);
480
- break;
481
- case 'remove_connection':
482
- this.topology.removeConnection(action.from, action.to);
483
- break;
484
- case 'strengthen_connection':
485
- this.topology.updateConnectionWeight(action.from, action.to, action.delta);
486
- break;
487
- case 'weaken_connection':
488
- this.topology.updateConnectionWeight(action.from, action.to, -action.delta);
489
- break;
490
- case 'no_op':
491
- // Do nothing
492
- break;
493
- }
494
- }
495
- /**
496
- * Calculate multi-objective reward
497
- */
498
- calculateReward(oldMinCut, newMinCut) {
499
- // 1. Min-cut improvement (primary objective)
500
- const minCutReward = oldMinCut > 0 ? (newMinCut - oldMinCut) / oldMinCut : 0;
501
- // 2. Communication efficiency
502
- const efficiency = this.measureCommunicationEfficiency();
503
- // 3. Load balance
504
- const loadStats = this.getLoadStats();
505
- const loadBalance = 1 - loadStats.variance;
506
- // 4. Latency penalty
507
- const avgLatency = this.getAverageLatency();
508
- const latencyPenalty = avgLatency > 0 ? -avgLatency / 100 : 0;
509
- // Combine with weights
510
- const reward = minCutReward +
511
- this.config.efficiencyWeight * efficiency +
512
- this.config.loadBalanceWeight * loadBalance +
513
- this.config.latencyWeight * latencyPenalty;
514
- return Math.max(-1, Math.min(1, reward));
515
- }
516
- /**
517
- * Train from replay buffer
518
- */
519
- trainFromReplay() {
520
- const { experiences, weights, indices } = this.replayBuffer.sampleWithWeights(this.config.batchSize);
521
- const newPriorities = [];
522
- for (let i = 0; i < experiences.length; i++) {
523
- const exp = experiences[i];
524
- const weight = weights[i];
525
- // Calculate TD error
526
- const currentValue = this.valueNetwork.estimate(exp.state);
527
- const nextValue = exp.done
528
- ? 0
529
- : this.targetNetwork.estimate(exp.nextState);
530
- const targetValue = exp.reward + this.config.gamma * nextValue;
531
- const tdError = targetValue - currentValue;
532
- // Weighted update
533
- this.valueNetwork.update(exp.state, tdError * weight, this.config.learningRate);
534
- newPriorities.push(Math.abs(tdError));
535
- }
536
- // Update priorities
537
- this.replayBuffer.updatePriorities(indices, newPriorities);
538
- }
539
- // ============================================================================
540
- // Topology Metric Helpers
541
- // ============================================================================
542
- estimateMinCut() {
543
- if (this.topology.agents.length === 0)
544
- return 0;
545
- return this.getMinDegree();
546
- }
547
- hasConnection(from, to) {
548
- return this.topology.connections.some((c) => (c.from === from && c.to === to) || (c.from === to && c.to === from));
549
- }
550
- getDensity() {
551
- const n = this.topology.agents.length;
552
- if (n < 2)
553
- return 0;
554
- const maxConnections = (n * (n - 1)) / 2;
555
- return this.topology.connections.length / maxConnections;
556
- }
557
- getAverageDegree() {
558
- const n = this.topology.agents.length;
559
- if (n === 0)
560
- return 0;
561
- const totalDegree = this.topology.agents.reduce((sum, agent) => {
562
- return (sum +
563
- this.topology.connections.filter((c) => c.from === agent.id || c.to === agent.id).length);
564
- }, 0);
565
- return totalDegree / n;
566
- }
567
- getMinDegree() {
568
- if (this.topology.agents.length === 0)
569
- return 0;
570
- let minDegree = Infinity;
571
- for (const agent of this.topology.agents) {
572
- const degree = this.topology.connections.filter((c) => c.from === agent.id || c.to === agent.id).length;
573
- minDegree = Math.min(minDegree, degree);
574
- }
575
- return minDegree === Infinity ? 0 : minDegree;
576
- }
577
- getAverageWeight() {
578
- if (this.topology.connections.length === 0)
579
- return 0;
580
- const total = this.topology.connections.reduce((sum, c) => sum + c.weight, 0);
581
- return total / this.topology.connections.length;
582
- }
583
- getWeightVariance() {
584
- if (this.topology.connections.length === 0)
585
- return 0;
586
- const avg = this.getAverageWeight();
587
- const squaredDiffs = this.topology.connections.map((c) => (c.weight - avg) ** 2);
588
- return squaredDiffs.reduce((sum, d) => sum + d, 0) / this.topology.connections.length;
589
- }
590
- getAverageLatency() {
591
- const connectionsWithLatency = this.topology.connections.filter((c) => c.latencyMs !== undefined);
592
- if (connectionsWithLatency.length === 0)
593
- return 0;
594
- const total = connectionsWithLatency.reduce((sum, c) => sum + (c.latencyMs || 0), 0);
595
- return total / connectionsWithLatency.length;
596
- }
597
- measureCommunicationEfficiency() {
598
- const n = this.topology.agents.length;
599
- if (n < 2)
600
- return 0;
601
- const maxConnections = (n * (n - 1)) / 2;
602
- return this.topology.connections.length / maxConnections;
603
- }
604
- getClusteringCoefficient() {
605
- if (this.topology.agents.length < 3)
606
- return 0;
607
- let totalCoeff = 0;
608
- for (const agent of this.topology.agents) {
609
- const neighbors = this.getNeighbors(agent.id);
610
- const k = neighbors.length;
611
- if (k < 2)
612
- continue;
613
- let triangles = 0;
614
- for (let i = 0; i < neighbors.length; i++) {
615
- for (let j = i + 1; j < neighbors.length; j++) {
616
- if (this.hasConnection(neighbors[i], neighbors[j])) {
617
- triangles++;
618
- }
619
- }
620
- }
621
- const possibleTriangles = (k * (k - 1)) / 2;
622
- totalCoeff += triangles / possibleTriangles;
623
- }
624
- return totalCoeff / this.topology.agents.length;
625
- }
626
- getNeighbors(agentId) {
627
- const neighbors = [];
628
- for (const conn of this.topology.connections) {
629
- if (conn.from === agentId)
630
- neighbors.push(conn.to);
631
- else if (conn.to === agentId)
632
- neighbors.push(conn.from);
633
- }
634
- return neighbors;
635
- }
636
- getLoadStats() {
637
- if (this.topology.agents.length === 0) {
638
- return { avg: 0, variance: 0, idle: 0, overloaded: 0 };
639
- }
640
- const loads = this.topology.agents.map((a) => a.metrics?.currentLoad ?? 0);
641
- const avg = loads.reduce((sum, l) => sum + l, 0) / loads.length;
642
- const variance = loads.reduce((sum, l) => sum + (l - avg) ** 2, 0) / loads.length;
643
- const idle = this.topology.agents.filter((a) => a.status === 'idle').length;
644
- const overloaded = this.topology.agents.filter((a) => (a.metrics?.currentLoad ?? 0) > 0.8).length;
645
- return { avg, variance, idle, overloaded };
646
- }
647
- }
648
- // ============================================================================
649
- // Factory Function
650
- // ============================================================================
651
- /**
652
- * Create a neural topology optimizer
653
- */
654
- export function createNeuralTopologyOptimizer(topology, config) {
655
- return new NeuralTopologyOptimizer(topology, config);
656
- }
657
- //# sourceMappingURL=topology-optimizer.js.map