@sparkleideas/swarm 3.0.0-alpha.7
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/MIGRATION.md +472 -0
- package/README.md +634 -0
- package/__tests__/consensus.test.ts +577 -0
- package/__tests__/coordinator.test.ts +501 -0
- package/__tests__/queen-coordinator.test.ts +1335 -0
- package/__tests__/topology.test.ts +621 -0
- package/package.json +32 -0
- package/src/agent-pool.ts +476 -0
- package/src/application/commands/create-task.command.ts +124 -0
- package/src/application/commands/spawn-agent.command.ts +122 -0
- package/src/application/index.ts +30 -0
- package/src/application/services/swarm-application-service.ts +200 -0
- package/src/attention-coordinator.ts +1000 -0
- package/src/consensus/byzantine.ts +431 -0
- package/src/consensus/gossip.ts +513 -0
- package/src/consensus/index.ts +267 -0
- package/src/consensus/raft.ts +443 -0
- package/src/coordination/agent-registry.ts +544 -0
- package/src/coordination/index.ts +23 -0
- package/src/coordination/swarm-hub.ts +776 -0
- package/src/coordination/task-orchestrator.ts +605 -0
- package/src/domain/entities/agent.d.ts +151 -0
- package/src/domain/entities/agent.d.ts.map +1 -0
- package/src/domain/entities/agent.js +280 -0
- package/src/domain/entities/agent.js.map +1 -0
- package/src/domain/entities/agent.ts +370 -0
- package/src/domain/entities/task.d.ts +133 -0
- package/src/domain/entities/task.d.ts.map +1 -0
- package/src/domain/entities/task.js +261 -0
- package/src/domain/entities/task.js.map +1 -0
- package/src/domain/entities/task.ts +319 -0
- package/src/domain/index.ts +41 -0
- package/src/domain/repositories/agent-repository.interface.d.ts +57 -0
- package/src/domain/repositories/agent-repository.interface.d.ts.map +1 -0
- package/src/domain/repositories/agent-repository.interface.js +9 -0
- package/src/domain/repositories/agent-repository.interface.js.map +1 -0
- package/src/domain/repositories/agent-repository.interface.ts +69 -0
- package/src/domain/repositories/task-repository.interface.d.ts +61 -0
- package/src/domain/repositories/task-repository.interface.d.ts.map +1 -0
- package/src/domain/repositories/task-repository.interface.js +9 -0
- package/src/domain/repositories/task-repository.interface.js.map +1 -0
- package/src/domain/repositories/task-repository.interface.ts +75 -0
- package/src/domain/services/coordination-service.ts +320 -0
- package/src/federation-hub.d.ts +284 -0
- package/src/federation-hub.d.ts.map +1 -0
- package/src/federation-hub.js +692 -0
- package/src/federation-hub.js.map +1 -0
- package/src/federation-hub.ts +979 -0
- package/src/index.ts +348 -0
- package/src/message-bus.ts +607 -0
- package/src/queen-coordinator.ts +2025 -0
- package/src/shared/events.ts +285 -0
- package/src/shared/types.ts +389 -0
- package/src/topology-manager.ts +656 -0
- package/src/types.ts +545 -0
- package/src/unified-coordinator.ts +1844 -0
- package/src/workers/index.ts +65 -0
- package/src/workers/worker-dispatch.d.ts +234 -0
- package/src/workers/worker-dispatch.d.ts.map +1 -0
- package/src/workers/worker-dispatch.js +842 -0
- package/src/workers/worker-dispatch.js.map +1 -0
- package/src/workers/worker-dispatch.ts +1076 -0
- package/tmp.json +0 -0
- package/tsconfig.json +9 -0
- package/vitest.config.ts +20 -0
|
@@ -0,0 +1,2025 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Queen Coordinator - Central Orchestrator for 15-Agent Swarm
|
|
3
|
+
*
|
|
4
|
+
* The Queen Coordinator is the strategic decision-maker for the V3 hive-mind system.
|
|
5
|
+
* It analyzes tasks, delegates to appropriate agents, monitors swarm health,
|
|
6
|
+
* coordinates consensus, and learns from outcomes using ReasoningBank patterns.
|
|
7
|
+
*
|
|
8
|
+
* Features:
|
|
9
|
+
* - Strategic task analysis with ReasoningBank pattern matching
|
|
10
|
+
* - Agent delegation with capability scoring and load balancing
|
|
11
|
+
* - Swarm health monitoring with bottleneck detection
|
|
12
|
+
* - Consensus coordination (majority, weighted, unanimous)
|
|
13
|
+
* - Learning from outcomes for continuous improvement
|
|
14
|
+
*
|
|
15
|
+
* Performance Targets:
|
|
16
|
+
* - Task analysis: <50ms
|
|
17
|
+
* - Agent scoring: <20ms
|
|
18
|
+
* - Consensus coordination: <100ms
|
|
19
|
+
* - Health check: <30ms
|
|
20
|
+
*
|
|
21
|
+
* @module @sparkleideas/swarm/queen-coordinator
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
import { EventEmitter } from 'events';
|
|
25
|
+
import type {
|
|
26
|
+
AgentState,
|
|
27
|
+
AgentType,
|
|
28
|
+
AgentId,
|
|
29
|
+
TaskDefinition,
|
|
30
|
+
TaskType,
|
|
31
|
+
TaskPriority,
|
|
32
|
+
TaskStatus,
|
|
33
|
+
CoordinatorMetrics,
|
|
34
|
+
ConsensusResult,
|
|
35
|
+
SwarmEvent,
|
|
36
|
+
SwarmEventType,
|
|
37
|
+
} from './types.js';
|
|
38
|
+
import type { AgentDomain, DomainConfig, DomainStatus } from './unified-coordinator.js';
|
|
39
|
+
|
|
40
|
+
// =============================================================================
|
|
41
|
+
// Types
|
|
42
|
+
// =============================================================================
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Task analysis result from the Queen
|
|
46
|
+
*/
|
|
47
|
+
export interface TaskAnalysis {
|
|
48
|
+
/** Unique analysis ID */
|
|
49
|
+
analysisId: string;
|
|
50
|
+
/** Original task ID */
|
|
51
|
+
taskId: string;
|
|
52
|
+
/** Task complexity score (0-1) */
|
|
53
|
+
complexity: number;
|
|
54
|
+
/** Estimated duration in milliseconds */
|
|
55
|
+
estimatedDurationMs: number;
|
|
56
|
+
/** Required capabilities for this task */
|
|
57
|
+
requiredCapabilities: string[];
|
|
58
|
+
/** Recommended domain for execution */
|
|
59
|
+
recommendedDomain: AgentDomain;
|
|
60
|
+
/** Sub-tasks if decomposition is needed */
|
|
61
|
+
subtasks: SubTask[];
|
|
62
|
+
/** Patterns found from ReasoningBank */
|
|
63
|
+
matchedPatterns: MatchedPattern[];
|
|
64
|
+
/** Resource requirements */
|
|
65
|
+
resourceRequirements: ResourceRequirements;
|
|
66
|
+
/** Confidence in this analysis (0-1) */
|
|
67
|
+
confidence: number;
|
|
68
|
+
/** Analysis timestamp */
|
|
69
|
+
timestamp: Date;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Sub-task from task decomposition
|
|
74
|
+
*/
|
|
75
|
+
export interface SubTask {
|
|
76
|
+
id: string;
|
|
77
|
+
name: string;
|
|
78
|
+
description: string;
|
|
79
|
+
type: TaskType;
|
|
80
|
+
priority: TaskPriority;
|
|
81
|
+
dependencies: string[];
|
|
82
|
+
estimatedDurationMs: number;
|
|
83
|
+
requiredCapabilities: string[];
|
|
84
|
+
recommendedDomain: AgentDomain;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Pattern matched from ReasoningBank
|
|
89
|
+
*/
|
|
90
|
+
export interface MatchedPattern {
|
|
91
|
+
patternId: string;
|
|
92
|
+
strategy: string;
|
|
93
|
+
successRate: number;
|
|
94
|
+
relevanceScore: number;
|
|
95
|
+
keyLearnings: string[];
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Resource requirements for a task
|
|
100
|
+
*/
|
|
101
|
+
export interface ResourceRequirements {
|
|
102
|
+
minAgents: number;
|
|
103
|
+
maxAgents: number;
|
|
104
|
+
memoryMb: number;
|
|
105
|
+
cpuIntensive: boolean;
|
|
106
|
+
ioIntensive: boolean;
|
|
107
|
+
networkRequired: boolean;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Delegation plan for task execution
|
|
112
|
+
*/
|
|
113
|
+
export interface DelegationPlan {
|
|
114
|
+
/** Plan ID */
|
|
115
|
+
planId: string;
|
|
116
|
+
/** Task ID being delegated */
|
|
117
|
+
taskId: string;
|
|
118
|
+
/** Analysis that informed this plan */
|
|
119
|
+
analysisId: string;
|
|
120
|
+
/** Primary agent assignment */
|
|
121
|
+
primaryAgent: AgentAssignment;
|
|
122
|
+
/** Backup agents for failover */
|
|
123
|
+
backupAgents: AgentAssignment[];
|
|
124
|
+
/** Parallel sub-task assignments */
|
|
125
|
+
parallelAssignments: ParallelAssignment[];
|
|
126
|
+
/** Execution strategy */
|
|
127
|
+
strategy: ExecutionStrategy;
|
|
128
|
+
/** Estimated completion time */
|
|
129
|
+
estimatedCompletionMs: number;
|
|
130
|
+
/** Plan creation timestamp */
|
|
131
|
+
timestamp: Date;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Agent assignment in a delegation plan
|
|
136
|
+
*/
|
|
137
|
+
export interface AgentAssignment {
|
|
138
|
+
agentId: string;
|
|
139
|
+
domain: AgentDomain;
|
|
140
|
+
taskId: string;
|
|
141
|
+
score: number;
|
|
142
|
+
assignedAt: Date;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Parallel task assignment
|
|
147
|
+
*/
|
|
148
|
+
export interface ParallelAssignment {
|
|
149
|
+
subtaskId: string;
|
|
150
|
+
agentId: string;
|
|
151
|
+
domain: AgentDomain;
|
|
152
|
+
dependencies: string[];
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Execution strategy for delegation
|
|
157
|
+
*/
|
|
158
|
+
export type ExecutionStrategy =
|
|
159
|
+
| 'sequential'
|
|
160
|
+
| 'parallel'
|
|
161
|
+
| 'pipeline'
|
|
162
|
+
| 'fan-out-fan-in'
|
|
163
|
+
| 'hybrid';
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Agent score for task assignment
|
|
167
|
+
*/
|
|
168
|
+
export interface AgentScore {
|
|
169
|
+
agentId: string;
|
|
170
|
+
domain: AgentDomain;
|
|
171
|
+
totalScore: number;
|
|
172
|
+
capabilityScore: number;
|
|
173
|
+
loadScore: number;
|
|
174
|
+
performanceScore: number;
|
|
175
|
+
healthScore: number;
|
|
176
|
+
availabilityScore: number;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Health report for the swarm
|
|
181
|
+
*/
|
|
182
|
+
export interface HealthReport {
|
|
183
|
+
/** Report ID */
|
|
184
|
+
reportId: string;
|
|
185
|
+
/** Report timestamp */
|
|
186
|
+
timestamp: Date;
|
|
187
|
+
/** Overall swarm health (0-1) */
|
|
188
|
+
overallHealth: number;
|
|
189
|
+
/** Status of each domain */
|
|
190
|
+
domainHealth: Map<AgentDomain, DomainHealthStatus>;
|
|
191
|
+
/** Individual agent health */
|
|
192
|
+
agentHealth: AgentHealthEntry[];
|
|
193
|
+
/** Detected bottlenecks */
|
|
194
|
+
bottlenecks: Bottleneck[];
|
|
195
|
+
/** Active alerts */
|
|
196
|
+
alerts: HealthAlert[];
|
|
197
|
+
/** Performance metrics */
|
|
198
|
+
metrics: HealthMetrics;
|
|
199
|
+
/** Recommendations for improvement */
|
|
200
|
+
recommendations: string[];
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* Domain health status
|
|
205
|
+
*/
|
|
206
|
+
export interface DomainHealthStatus {
|
|
207
|
+
domain: AgentDomain;
|
|
208
|
+
health: number;
|
|
209
|
+
activeAgents: number;
|
|
210
|
+
totalAgents: number;
|
|
211
|
+
queuedTasks: number;
|
|
212
|
+
avgResponseTimeMs: number;
|
|
213
|
+
errorRate: number;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* Agent health entry
|
|
218
|
+
*/
|
|
219
|
+
export interface AgentHealthEntry {
|
|
220
|
+
agentId: string;
|
|
221
|
+
domain: AgentDomain;
|
|
222
|
+
health: number;
|
|
223
|
+
status: string;
|
|
224
|
+
lastHeartbeat: Date;
|
|
225
|
+
currentLoad: number;
|
|
226
|
+
recentErrors: number;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* Bottleneck detection result
|
|
231
|
+
*/
|
|
232
|
+
export interface Bottleneck {
|
|
233
|
+
type: 'agent' | 'domain' | 'task' | 'resource';
|
|
234
|
+
location: string;
|
|
235
|
+
severity: 'low' | 'medium' | 'high' | 'critical';
|
|
236
|
+
description: string;
|
|
237
|
+
impact: string;
|
|
238
|
+
suggestedAction: string;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* Health alert
|
|
243
|
+
*/
|
|
244
|
+
export interface HealthAlert {
|
|
245
|
+
alertId: string;
|
|
246
|
+
type: 'warning' | 'error' | 'critical';
|
|
247
|
+
source: string;
|
|
248
|
+
message: string;
|
|
249
|
+
timestamp: Date;
|
|
250
|
+
acknowledged: boolean;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/**
|
|
254
|
+
* Health metrics
|
|
255
|
+
*/
|
|
256
|
+
export interface HealthMetrics {
|
|
257
|
+
totalAgents: number;
|
|
258
|
+
activeAgents: number;
|
|
259
|
+
idleAgents: number;
|
|
260
|
+
errorAgents: number;
|
|
261
|
+
totalTasks: number;
|
|
262
|
+
completedTasks: number;
|
|
263
|
+
failedTasks: number;
|
|
264
|
+
avgTaskDurationMs: number;
|
|
265
|
+
taskThroughputPerMin: number;
|
|
266
|
+
consensusSuccessRate: number;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
/**
|
|
270
|
+
* Decision requiring consensus
|
|
271
|
+
*/
|
|
272
|
+
export interface Decision {
|
|
273
|
+
decisionId: string;
|
|
274
|
+
type: DecisionType;
|
|
275
|
+
proposal: unknown;
|
|
276
|
+
requiredConsensus: ConsensusType;
|
|
277
|
+
timeout: number;
|
|
278
|
+
initiator: string;
|
|
279
|
+
metadata: Record<string, unknown>;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
/**
|
|
283
|
+
* Decision types
|
|
284
|
+
*/
|
|
285
|
+
export type DecisionType =
|
|
286
|
+
| 'task-assignment'
|
|
287
|
+
| 'resource-allocation'
|
|
288
|
+
| 'topology-change'
|
|
289
|
+
| 'agent-termination'
|
|
290
|
+
| 'priority-override'
|
|
291
|
+
| 'emergency-action';
|
|
292
|
+
|
|
293
|
+
/**
|
|
294
|
+
* Consensus types
|
|
295
|
+
*/
|
|
296
|
+
export type ConsensusType =
|
|
297
|
+
| 'majority'
|
|
298
|
+
| 'supermajority'
|
|
299
|
+
| 'unanimous'
|
|
300
|
+
| 'weighted'
|
|
301
|
+
| 'queen-override';
|
|
302
|
+
|
|
303
|
+
/**
|
|
304
|
+
* Task result for learning
|
|
305
|
+
*/
|
|
306
|
+
export interface TaskResult {
|
|
307
|
+
taskId: string;
|
|
308
|
+
success: boolean;
|
|
309
|
+
output?: unknown;
|
|
310
|
+
error?: string;
|
|
311
|
+
durationMs: number;
|
|
312
|
+
agentId: string;
|
|
313
|
+
domain: AgentDomain;
|
|
314
|
+
metrics: TaskMetrics;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
/**
|
|
318
|
+
* Task execution metrics
|
|
319
|
+
*/
|
|
320
|
+
export interface TaskMetrics {
|
|
321
|
+
startTime: Date;
|
|
322
|
+
endTime: Date;
|
|
323
|
+
retries: number;
|
|
324
|
+
resourceUsage: {
|
|
325
|
+
memoryMb: number;
|
|
326
|
+
cpuPercent: number;
|
|
327
|
+
};
|
|
328
|
+
stepsCompleted: number;
|
|
329
|
+
qualityScore: number;
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
/**
|
|
333
|
+
* Queen Coordinator configuration
|
|
334
|
+
*/
|
|
335
|
+
export interface QueenCoordinatorConfig {
|
|
336
|
+
/** Enable ReasoningBank integration */
|
|
337
|
+
enableLearning: boolean;
|
|
338
|
+
/** Number of patterns to retrieve for analysis */
|
|
339
|
+
patternRetrievalK: number;
|
|
340
|
+
/** Minimum pattern relevance threshold */
|
|
341
|
+
patternThreshold: number;
|
|
342
|
+
/** Task complexity thresholds */
|
|
343
|
+
complexityThresholds: {
|
|
344
|
+
simple: number;
|
|
345
|
+
moderate: number;
|
|
346
|
+
complex: number;
|
|
347
|
+
};
|
|
348
|
+
/** Health check interval in ms */
|
|
349
|
+
healthCheckIntervalMs: number;
|
|
350
|
+
/** Bottleneck detection thresholds */
|
|
351
|
+
bottleneckThresholds: {
|
|
352
|
+
queueDepth: number;
|
|
353
|
+
errorRate: number;
|
|
354
|
+
responseTimeMs: number;
|
|
355
|
+
};
|
|
356
|
+
/** Consensus timeouts */
|
|
357
|
+
consensusTimeouts: {
|
|
358
|
+
majority: number;
|
|
359
|
+
supermajority: number;
|
|
360
|
+
unanimous: number;
|
|
361
|
+
};
|
|
362
|
+
/** Enable automatic failover */
|
|
363
|
+
enableFailover: boolean;
|
|
364
|
+
/** Maximum delegation attempts */
|
|
365
|
+
maxDelegationAttempts: number;
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
/**
|
|
369
|
+
* Default Queen Coordinator configuration
|
|
370
|
+
*/
|
|
371
|
+
const DEFAULT_CONFIG: QueenCoordinatorConfig = {
|
|
372
|
+
enableLearning: true,
|
|
373
|
+
patternRetrievalK: 5,
|
|
374
|
+
patternThreshold: 0.6,
|
|
375
|
+
complexityThresholds: {
|
|
376
|
+
simple: 0.3,
|
|
377
|
+
moderate: 0.6,
|
|
378
|
+
complex: 0.85,
|
|
379
|
+
},
|
|
380
|
+
healthCheckIntervalMs: 10000,
|
|
381
|
+
bottleneckThresholds: {
|
|
382
|
+
queueDepth: 10,
|
|
383
|
+
errorRate: 0.1,
|
|
384
|
+
responseTimeMs: 5000,
|
|
385
|
+
},
|
|
386
|
+
consensusTimeouts: {
|
|
387
|
+
majority: 5000,
|
|
388
|
+
supermajority: 10000,
|
|
389
|
+
unanimous: 30000,
|
|
390
|
+
},
|
|
391
|
+
enableFailover: true,
|
|
392
|
+
maxDelegationAttempts: 3,
|
|
393
|
+
};
|
|
394
|
+
|
|
395
|
+
// =============================================================================
|
|
396
|
+
// Interfaces for Dependencies
|
|
397
|
+
// =============================================================================
|
|
398
|
+
|
|
399
|
+
/**
|
|
400
|
+
* Interface for swarm coordinator interactions
|
|
401
|
+
*/
|
|
402
|
+
export interface ISwarmCoordinator {
|
|
403
|
+
getAgentsByDomain(domain: AgentDomain): AgentState[];
|
|
404
|
+
getAllAgents(): AgentState[];
|
|
405
|
+
getAvailableAgents(): AgentState[];
|
|
406
|
+
getMetrics(): CoordinatorMetrics;
|
|
407
|
+
getDomainConfigs(): Map<AgentDomain, DomainConfig>;
|
|
408
|
+
getStatus(): {
|
|
409
|
+
domains: DomainStatus[];
|
|
410
|
+
metrics: CoordinatorMetrics;
|
|
411
|
+
};
|
|
412
|
+
assignTaskToDomain(taskId: string, domain: AgentDomain): Promise<string | undefined>;
|
|
413
|
+
proposeConsensus(value: unknown): Promise<ConsensusResult>;
|
|
414
|
+
broadcastMessage(payload: unknown, priority?: 'urgent' | 'high' | 'normal' | 'low'): Promise<void>;
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
/**
|
|
418
|
+
* Interface for neural learning system interactions
|
|
419
|
+
*/
|
|
420
|
+
export interface INeuralLearningSystem {
|
|
421
|
+
initialize(): Promise<void>;
|
|
422
|
+
beginTask(context: string, domain?: string): string;
|
|
423
|
+
recordStep(trajectoryId: string, action: string, reward: number, stateEmbedding: Float32Array): void;
|
|
424
|
+
completeTask(trajectoryId: string, quality?: number): Promise<void>;
|
|
425
|
+
findPatterns(queryEmbedding: Float32Array, k?: number): Promise<PatternMatchResult[]>;
|
|
426
|
+
retrieveMemories(queryEmbedding: Float32Array, k?: number): Promise<MemoryRetrievalResult[]>;
|
|
427
|
+
triggerLearning(): Promise<void>;
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
/**
|
|
431
|
+
* Pattern match result from neural system
|
|
432
|
+
*/
|
|
433
|
+
export interface PatternMatchResult {
|
|
434
|
+
patternId: string;
|
|
435
|
+
strategy: string;
|
|
436
|
+
successRate: number;
|
|
437
|
+
relevanceScore: number;
|
|
438
|
+
keyLearnings?: string[];
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
/**
|
|
442
|
+
* Memory retrieval result from neural system
|
|
443
|
+
*/
|
|
444
|
+
export interface MemoryRetrievalResult {
|
|
445
|
+
memory: {
|
|
446
|
+
memoryId: string;
|
|
447
|
+
strategy: string;
|
|
448
|
+
quality: number;
|
|
449
|
+
keyLearnings: string[];
|
|
450
|
+
};
|
|
451
|
+
relevanceScore: number;
|
|
452
|
+
combinedScore: number;
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
/**
|
|
456
|
+
* Interface for memory service interactions
|
|
457
|
+
*/
|
|
458
|
+
export interface IMemoryService {
|
|
459
|
+
semanticSearch(query: string, k?: number): Promise<SearchResultEntry[]>;
|
|
460
|
+
store(entry: MemoryStoreEntry): Promise<void>;
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
/**
|
|
464
|
+
* Search result entry from memory service
|
|
465
|
+
*/
|
|
466
|
+
export interface SearchResultEntry {
|
|
467
|
+
entry: {
|
|
468
|
+
id: string;
|
|
469
|
+
content: string;
|
|
470
|
+
metadata: Record<string, unknown>;
|
|
471
|
+
};
|
|
472
|
+
score: number;
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
/**
|
|
476
|
+
* Memory store entry
|
|
477
|
+
*/
|
|
478
|
+
export interface MemoryStoreEntry {
|
|
479
|
+
key: string;
|
|
480
|
+
content: string;
|
|
481
|
+
namespace: string;
|
|
482
|
+
tags: string[];
|
|
483
|
+
metadata: Record<string, unknown>;
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
// =============================================================================
|
|
487
|
+
// Queen Coordinator Class
|
|
488
|
+
// =============================================================================
|
|
489
|
+
|
|
490
|
+
/**
|
|
491
|
+
* Queen Coordinator - Central orchestrator for the 15-agent hive-mind swarm
|
|
492
|
+
*
|
|
493
|
+
* The Queen is responsible for:
|
|
494
|
+
* 1. Strategic task analysis and decomposition
|
|
495
|
+
* 2. Agent delegation with load balancing
|
|
496
|
+
* 3. Swarm health monitoring
|
|
497
|
+
* 4. Consensus coordination
|
|
498
|
+
* 5. Learning from outcomes
|
|
499
|
+
*/
|
|
500
|
+
export class QueenCoordinator extends EventEmitter {
|
|
501
|
+
private config: QueenCoordinatorConfig;
|
|
502
|
+
private swarm: ISwarmCoordinator;
|
|
503
|
+
private neural?: INeuralLearningSystem;
|
|
504
|
+
private memory?: IMemoryService;
|
|
505
|
+
|
|
506
|
+
// Internal state
|
|
507
|
+
private analysisCache: Map<string, TaskAnalysis> = new Map();
|
|
508
|
+
private delegationPlans: Map<string, DelegationPlan> = new Map();
|
|
509
|
+
private activeDecisions: Map<string, Decision> = new Map();
|
|
510
|
+
private outcomeHistory: TaskResult[] = [];
|
|
511
|
+
private healthHistory: HealthReport[] = [];
|
|
512
|
+
|
|
513
|
+
// Counters for IDs
|
|
514
|
+
private analysisCounter = 0;
|
|
515
|
+
private planCounter = 0;
|
|
516
|
+
private reportCounter = 0;
|
|
517
|
+
private decisionCounter = 0;
|
|
518
|
+
|
|
519
|
+
// Health monitoring
|
|
520
|
+
private healthCheckInterval?: NodeJS.Timeout;
|
|
521
|
+
private lastHealthReport?: HealthReport;
|
|
522
|
+
|
|
523
|
+
// Performance tracking
|
|
524
|
+
private analysisLatencies: number[] = [];
|
|
525
|
+
private delegationLatencies: number[] = [];
|
|
526
|
+
private consensusLatencies: number[] = [];
|
|
527
|
+
|
|
528
|
+
constructor(
|
|
529
|
+
swarm: ISwarmCoordinator,
|
|
530
|
+
config: Partial<QueenCoordinatorConfig> = {},
|
|
531
|
+
neural?: INeuralLearningSystem,
|
|
532
|
+
memory?: IMemoryService
|
|
533
|
+
) {
|
|
534
|
+
super();
|
|
535
|
+
this.swarm = swarm;
|
|
536
|
+
this.config = { ...DEFAULT_CONFIG, ...config };
|
|
537
|
+
this.neural = neural;
|
|
538
|
+
this.memory = memory;
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
// ===========================================================================
|
|
542
|
+
// Lifecycle
|
|
543
|
+
// ===========================================================================
|
|
544
|
+
|
|
545
|
+
/**
|
|
546
|
+
* Initialize the Queen Coordinator
|
|
547
|
+
*/
|
|
548
|
+
async initialize(): Promise<void> {
|
|
549
|
+
// Initialize neural system if available
|
|
550
|
+
if (this.neural && this.config.enableLearning) {
|
|
551
|
+
await this.neural.initialize();
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
// Start health monitoring
|
|
555
|
+
this.startHealthMonitoring();
|
|
556
|
+
|
|
557
|
+
this.emitEvent('queen.initialized', {
|
|
558
|
+
config: this.config,
|
|
559
|
+
learningEnabled: this.config.enableLearning && !!this.neural,
|
|
560
|
+
});
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
/**
|
|
564
|
+
* Shutdown the Queen Coordinator
|
|
565
|
+
*/
|
|
566
|
+
async shutdown(): Promise<void> {
|
|
567
|
+
this.stopHealthMonitoring();
|
|
568
|
+
|
|
569
|
+
// Trigger final learning if enabled
|
|
570
|
+
if (this.neural && this.config.enableLearning) {
|
|
571
|
+
await this.neural.triggerLearning();
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
this.emitEvent('queen.shutdown', {
|
|
575
|
+
totalAnalyses: this.analysisCounter,
|
|
576
|
+
totalPlans: this.planCounter,
|
|
577
|
+
totalDecisions: this.decisionCounter,
|
|
578
|
+
});
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
// ===========================================================================
|
|
582
|
+
// Strategic Task Analysis
|
|
583
|
+
// ===========================================================================
|
|
584
|
+
|
|
585
|
+
/**
|
|
586
|
+
* Analyze a task for optimal execution
|
|
587
|
+
*
|
|
588
|
+
* @param task - Task to analyze
|
|
589
|
+
* @returns Task analysis with recommendations
|
|
590
|
+
*/
|
|
591
|
+
async analyzeTask(task: TaskDefinition): Promise<TaskAnalysis> {
|
|
592
|
+
const startTime = performance.now();
|
|
593
|
+
|
|
594
|
+
this.analysisCounter++;
|
|
595
|
+
const analysisId = `analysis_${Date.now()}_${this.analysisCounter}`;
|
|
596
|
+
|
|
597
|
+
// Decompose complex tasks
|
|
598
|
+
const subtasks = this.decomposeTask(task);
|
|
599
|
+
|
|
600
|
+
// Identify required capabilities
|
|
601
|
+
const requiredCapabilities = this.identifyRequiredCapabilities(task);
|
|
602
|
+
|
|
603
|
+
// Calculate complexity
|
|
604
|
+
const complexity = this.calculateComplexity(task, subtasks);
|
|
605
|
+
|
|
606
|
+
// Estimate duration
|
|
607
|
+
const estimatedDurationMs = this.estimateDuration(task, complexity, subtasks);
|
|
608
|
+
|
|
609
|
+
// Determine recommended domain
|
|
610
|
+
const recommendedDomain = this.determineOptimalDomain(task, requiredCapabilities);
|
|
611
|
+
|
|
612
|
+
// Find matching patterns from ReasoningBank
|
|
613
|
+
const matchedPatterns = await this.findMatchingPatterns(task);
|
|
614
|
+
|
|
615
|
+
// Estimate resource requirements
|
|
616
|
+
const resourceRequirements = this.estimateResources(task, complexity);
|
|
617
|
+
|
|
618
|
+
// Calculate confidence
|
|
619
|
+
const confidence = this.calculateAnalysisConfidence(
|
|
620
|
+
matchedPatterns,
|
|
621
|
+
complexity,
|
|
622
|
+
requiredCapabilities
|
|
623
|
+
);
|
|
624
|
+
|
|
625
|
+
const analysis: TaskAnalysis = {
|
|
626
|
+
analysisId,
|
|
627
|
+
taskId: task.id.id,
|
|
628
|
+
complexity,
|
|
629
|
+
estimatedDurationMs,
|
|
630
|
+
requiredCapabilities,
|
|
631
|
+
recommendedDomain,
|
|
632
|
+
subtasks,
|
|
633
|
+
matchedPatterns,
|
|
634
|
+
resourceRequirements,
|
|
635
|
+
confidence,
|
|
636
|
+
timestamp: new Date(),
|
|
637
|
+
};
|
|
638
|
+
|
|
639
|
+
// Cache the analysis
|
|
640
|
+
this.analysisCache.set(analysisId, analysis);
|
|
641
|
+
|
|
642
|
+
// Record latency
|
|
643
|
+
const latency = performance.now() - startTime;
|
|
644
|
+
this.analysisLatencies.push(latency);
|
|
645
|
+
if (this.analysisLatencies.length > 100) {
|
|
646
|
+
this.analysisLatencies.shift();
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
this.emitEvent('queen.task.analyzed', {
|
|
650
|
+
analysisId,
|
|
651
|
+
taskId: task.id.id,
|
|
652
|
+
complexity,
|
|
653
|
+
recommendedDomain,
|
|
654
|
+
patternsFound: matchedPatterns.length,
|
|
655
|
+
latencyMs: latency,
|
|
656
|
+
});
|
|
657
|
+
|
|
658
|
+
return analysis;
|
|
659
|
+
}
|
|
660
|
+
|
|
661
|
+
/**
|
|
662
|
+
* Decompose a complex task into subtasks
|
|
663
|
+
*/
|
|
664
|
+
private decomposeTask(task: TaskDefinition): SubTask[] {
|
|
665
|
+
const subtasks: SubTask[] = [];
|
|
666
|
+
|
|
667
|
+
// Simple tasks don't need decomposition
|
|
668
|
+
if (this.isSimpleTask(task)) {
|
|
669
|
+
return subtasks;
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
// Decompose based on task type
|
|
673
|
+
switch (task.type) {
|
|
674
|
+
case 'coding':
|
|
675
|
+
subtasks.push(...this.decomposeCodingTask(task));
|
|
676
|
+
break;
|
|
677
|
+
case 'testing':
|
|
678
|
+
subtasks.push(...this.decomposeTestingTask(task));
|
|
679
|
+
break;
|
|
680
|
+
case 'research':
|
|
681
|
+
subtasks.push(...this.decomposeResearchTask(task));
|
|
682
|
+
break;
|
|
683
|
+
case 'coordination':
|
|
684
|
+
subtasks.push(...this.decomposeCoordinationTask(task));
|
|
685
|
+
break;
|
|
686
|
+
default:
|
|
687
|
+
// Generic decomposition
|
|
688
|
+
subtasks.push(...this.decomposeGenericTask(task));
|
|
689
|
+
}
|
|
690
|
+
|
|
691
|
+
return subtasks;
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
private isSimpleTask(task: TaskDefinition): boolean {
|
|
695
|
+
// Estimate if task is simple based on description length and type
|
|
696
|
+
const descLength = task.description?.length || 0;
|
|
697
|
+
const isSimpleType = ['documentation', 'review'].includes(task.type);
|
|
698
|
+
return descLength < 200 || isSimpleType;
|
|
699
|
+
}
|
|
700
|
+
|
|
701
|
+
private decomposeCodingTask(task: TaskDefinition): SubTask[] {
|
|
702
|
+
return [
|
|
703
|
+
{
|
|
704
|
+
id: `${task.id.id}_design`,
|
|
705
|
+
name: 'Design & Planning',
|
|
706
|
+
description: 'Design the solution architecture',
|
|
707
|
+
type: 'analysis',
|
|
708
|
+
priority: task.priority,
|
|
709
|
+
dependencies: [],
|
|
710
|
+
estimatedDurationMs: 10000,
|
|
711
|
+
requiredCapabilities: ['design', 'architecture'],
|
|
712
|
+
recommendedDomain: 'core',
|
|
713
|
+
},
|
|
714
|
+
{
|
|
715
|
+
id: `${task.id.id}_implement`,
|
|
716
|
+
name: 'Implementation',
|
|
717
|
+
description: 'Implement the designed solution',
|
|
718
|
+
type: 'coding',
|
|
719
|
+
priority: task.priority,
|
|
720
|
+
dependencies: [`${task.id.id}_design`],
|
|
721
|
+
estimatedDurationMs: 30000,
|
|
722
|
+
requiredCapabilities: ['coding', 'implementation'],
|
|
723
|
+
recommendedDomain: 'integration',
|
|
724
|
+
},
|
|
725
|
+
{
|
|
726
|
+
id: `${task.id.id}_test`,
|
|
727
|
+
name: 'Testing',
|
|
728
|
+
description: 'Test the implementation',
|
|
729
|
+
type: 'testing',
|
|
730
|
+
priority: task.priority,
|
|
731
|
+
dependencies: [`${task.id.id}_implement`],
|
|
732
|
+
estimatedDurationMs: 15000,
|
|
733
|
+
requiredCapabilities: ['testing', 'validation'],
|
|
734
|
+
recommendedDomain: 'support',
|
|
735
|
+
},
|
|
736
|
+
];
|
|
737
|
+
}
|
|
738
|
+
|
|
739
|
+
private decomposeTestingTask(task: TaskDefinition): SubTask[] {
|
|
740
|
+
return [
|
|
741
|
+
{
|
|
742
|
+
id: `${task.id.id}_analyze`,
|
|
743
|
+
name: 'Test Analysis',
|
|
744
|
+
description: 'Analyze what needs to be tested',
|
|
745
|
+
type: 'analysis',
|
|
746
|
+
priority: task.priority,
|
|
747
|
+
dependencies: [],
|
|
748
|
+
estimatedDurationMs: 5000,
|
|
749
|
+
requiredCapabilities: ['analysis', 'testing'],
|
|
750
|
+
recommendedDomain: 'support',
|
|
751
|
+
},
|
|
752
|
+
{
|
|
753
|
+
id: `${task.id.id}_execute`,
|
|
754
|
+
name: 'Test Execution',
|
|
755
|
+
description: 'Execute the tests',
|
|
756
|
+
type: 'testing',
|
|
757
|
+
priority: task.priority,
|
|
758
|
+
dependencies: [`${task.id.id}_analyze`],
|
|
759
|
+
estimatedDurationMs: 20000,
|
|
760
|
+
requiredCapabilities: ['testing', 'execution'],
|
|
761
|
+
recommendedDomain: 'support',
|
|
762
|
+
},
|
|
763
|
+
];
|
|
764
|
+
}
|
|
765
|
+
|
|
766
|
+
private decomposeResearchTask(task: TaskDefinition): SubTask[] {
|
|
767
|
+
return [
|
|
768
|
+
{
|
|
769
|
+
id: `${task.id.id}_gather`,
|
|
770
|
+
name: 'Information Gathering',
|
|
771
|
+
description: 'Gather relevant information',
|
|
772
|
+
type: 'research',
|
|
773
|
+
priority: task.priority,
|
|
774
|
+
dependencies: [],
|
|
775
|
+
estimatedDurationMs: 15000,
|
|
776
|
+
requiredCapabilities: ['research', 'analysis'],
|
|
777
|
+
recommendedDomain: 'core',
|
|
778
|
+
},
|
|
779
|
+
{
|
|
780
|
+
id: `${task.id.id}_analyze`,
|
|
781
|
+
name: 'Analysis',
|
|
782
|
+
description: 'Analyze gathered information',
|
|
783
|
+
type: 'analysis',
|
|
784
|
+
priority: task.priority,
|
|
785
|
+
dependencies: [`${task.id.id}_gather`],
|
|
786
|
+
estimatedDurationMs: 10000,
|
|
787
|
+
requiredCapabilities: ['analysis', 'synthesis'],
|
|
788
|
+
recommendedDomain: 'core',
|
|
789
|
+
},
|
|
790
|
+
];
|
|
791
|
+
}
|
|
792
|
+
|
|
793
|
+
private decomposeCoordinationTask(task: TaskDefinition): SubTask[] {
|
|
794
|
+
return [
|
|
795
|
+
{
|
|
796
|
+
id: `${task.id.id}_plan`,
|
|
797
|
+
name: 'Planning',
|
|
798
|
+
description: 'Create coordination plan',
|
|
799
|
+
type: 'coordination',
|
|
800
|
+
priority: task.priority,
|
|
801
|
+
dependencies: [],
|
|
802
|
+
estimatedDurationMs: 5000,
|
|
803
|
+
requiredCapabilities: ['planning', 'coordination'],
|
|
804
|
+
recommendedDomain: 'queen',
|
|
805
|
+
},
|
|
806
|
+
{
|
|
807
|
+
id: `${task.id.id}_execute`,
|
|
808
|
+
name: 'Execution',
|
|
809
|
+
description: 'Execute coordination plan',
|
|
810
|
+
type: 'coordination',
|
|
811
|
+
priority: task.priority,
|
|
812
|
+
dependencies: [`${task.id.id}_plan`],
|
|
813
|
+
estimatedDurationMs: 10000,
|
|
814
|
+
requiredCapabilities: ['coordination', 'oversight'],
|
|
815
|
+
recommendedDomain: 'queen',
|
|
816
|
+
},
|
|
817
|
+
];
|
|
818
|
+
}
|
|
819
|
+
|
|
820
|
+
private decomposeGenericTask(task: TaskDefinition): SubTask[] {
|
|
821
|
+
return [
|
|
822
|
+
{
|
|
823
|
+
id: `${task.id.id}_execute`,
|
|
824
|
+
name: 'Task Execution',
|
|
825
|
+
description: task.description,
|
|
826
|
+
type: task.type,
|
|
827
|
+
priority: task.priority,
|
|
828
|
+
dependencies: [],
|
|
829
|
+
estimatedDurationMs: 20000,
|
|
830
|
+
requiredCapabilities: this.identifyRequiredCapabilities(task),
|
|
831
|
+
recommendedDomain: this.inferDomainFromType(task.type),
|
|
832
|
+
},
|
|
833
|
+
];
|
|
834
|
+
}
|
|
835
|
+
|
|
836
|
+
/**
|
|
837
|
+
* Identify required capabilities for a task
|
|
838
|
+
*/
|
|
839
|
+
private identifyRequiredCapabilities(task: TaskDefinition): string[] {
|
|
840
|
+
const capabilities: Set<string> = new Set();
|
|
841
|
+
|
|
842
|
+
// Add type-based capabilities
|
|
843
|
+
const typeCapabilities: Record<TaskType, string[]> = {
|
|
844
|
+
research: ['research', 'analysis', 'synthesis'],
|
|
845
|
+
analysis: ['analysis', 'reasoning', 'synthesis'],
|
|
846
|
+
coding: ['coding', 'implementation', 'debugging'],
|
|
847
|
+
testing: ['testing', 'validation', 'quality'],
|
|
848
|
+
review: ['review', 'analysis', 'feedback'],
|
|
849
|
+
documentation: ['documentation', 'writing', 'clarity'],
|
|
850
|
+
coordination: ['coordination', 'planning', 'oversight'],
|
|
851
|
+
consensus: ['consensus', 'voting', 'agreement'],
|
|
852
|
+
custom: ['general', 'execution'],
|
|
853
|
+
};
|
|
854
|
+
|
|
855
|
+
for (const cap of typeCapabilities[task.type] || ['general']) {
|
|
856
|
+
capabilities.add(cap);
|
|
857
|
+
}
|
|
858
|
+
|
|
859
|
+
// Extract additional capabilities from description
|
|
860
|
+
const descLower = (task.description || '').toLowerCase();
|
|
861
|
+
if (descLower.includes('security')) capabilities.add('security');
|
|
862
|
+
if (descLower.includes('performance')) capabilities.add('performance');
|
|
863
|
+
if (descLower.includes('architecture')) capabilities.add('architecture');
|
|
864
|
+
if (descLower.includes('integration')) capabilities.add('integration');
|
|
865
|
+
if (descLower.includes('deploy')) capabilities.add('deployment');
|
|
866
|
+
|
|
867
|
+
return Array.from(capabilities);
|
|
868
|
+
}
|
|
869
|
+
|
|
870
|
+
/**
|
|
871
|
+
* Calculate task complexity score
|
|
872
|
+
*/
|
|
873
|
+
private calculateComplexity(task: TaskDefinition, subtasks: SubTask[]): number {
|
|
874
|
+
let complexity = 0.3; // Base complexity
|
|
875
|
+
|
|
876
|
+
// Add complexity for subtasks
|
|
877
|
+
complexity += subtasks.length * 0.1;
|
|
878
|
+
|
|
879
|
+
// Add complexity for dependencies
|
|
880
|
+
const totalDeps = subtasks.reduce((sum, st) => sum + st.dependencies.length, 0);
|
|
881
|
+
complexity += totalDeps * 0.05;
|
|
882
|
+
|
|
883
|
+
// Add complexity for priority
|
|
884
|
+
const priorityMultipliers: Record<TaskPriority, number> = {
|
|
885
|
+
critical: 1.3,
|
|
886
|
+
high: 1.15,
|
|
887
|
+
normal: 1.0,
|
|
888
|
+
low: 0.9,
|
|
889
|
+
background: 0.8,
|
|
890
|
+
};
|
|
891
|
+
complexity *= priorityMultipliers[task.priority];
|
|
892
|
+
|
|
893
|
+
// Add complexity for task type
|
|
894
|
+
const typeComplexity: Record<TaskType, number> = {
|
|
895
|
+
coordination: 0.2,
|
|
896
|
+
consensus: 0.25,
|
|
897
|
+
coding: 0.15,
|
|
898
|
+
testing: 0.1,
|
|
899
|
+
analysis: 0.1,
|
|
900
|
+
research: 0.1,
|
|
901
|
+
review: 0.05,
|
|
902
|
+
documentation: 0.05,
|
|
903
|
+
custom: 0.1,
|
|
904
|
+
};
|
|
905
|
+
complexity += typeComplexity[task.type] || 0.1;
|
|
906
|
+
|
|
907
|
+
// Add complexity for description length
|
|
908
|
+
const descLength = task.description?.length || 0;
|
|
909
|
+
complexity += Math.min(descLength / 2000, 0.2);
|
|
910
|
+
|
|
911
|
+
return Math.min(complexity, 1.0);
|
|
912
|
+
}
|
|
913
|
+
|
|
914
|
+
/**
|
|
915
|
+
* Estimate task duration
|
|
916
|
+
*/
|
|
917
|
+
private estimateDuration(
|
|
918
|
+
task: TaskDefinition,
|
|
919
|
+
complexity: number,
|
|
920
|
+
subtasks: SubTask[]
|
|
921
|
+
): number {
|
|
922
|
+
// Base duration by type (in ms)
|
|
923
|
+
const baseDurations: Record<TaskType, number> = {
|
|
924
|
+
research: 30000,
|
|
925
|
+
analysis: 20000,
|
|
926
|
+
coding: 60000,
|
|
927
|
+
testing: 30000,
|
|
928
|
+
review: 15000,
|
|
929
|
+
documentation: 20000,
|
|
930
|
+
coordination: 10000,
|
|
931
|
+
consensus: 15000,
|
|
932
|
+
custom: 30000,
|
|
933
|
+
};
|
|
934
|
+
|
|
935
|
+
const baseDuration = baseDurations[task.type] || 30000;
|
|
936
|
+
|
|
937
|
+
// Adjust for complexity
|
|
938
|
+
const complexityMultiplier = 0.5 + complexity * 1.5;
|
|
939
|
+
|
|
940
|
+
// Add subtask durations
|
|
941
|
+
const subtaskDuration = subtasks.reduce((sum, st) => sum + st.estimatedDurationMs, 0);
|
|
942
|
+
|
|
943
|
+
// Total estimate
|
|
944
|
+
return Math.round(baseDuration * complexityMultiplier + subtaskDuration * 0.5);
|
|
945
|
+
}
|
|
946
|
+
|
|
947
|
+
/**
|
|
948
|
+
* Determine optimal domain for task execution
|
|
949
|
+
*/
|
|
950
|
+
private determineOptimalDomain(
|
|
951
|
+
task: TaskDefinition,
|
|
952
|
+
capabilities: string[]
|
|
953
|
+
): AgentDomain {
|
|
954
|
+
// Check capabilities for domain hints
|
|
955
|
+
if (capabilities.includes('security')) return 'security';
|
|
956
|
+
if (capabilities.includes('coordination') || capabilities.includes('planning')) return 'queen';
|
|
957
|
+
if (capabilities.includes('testing') || capabilities.includes('performance')) return 'support';
|
|
958
|
+
if (capabilities.includes('integration')) return 'integration';
|
|
959
|
+
|
|
960
|
+
// Fall back to type-based inference
|
|
961
|
+
return this.inferDomainFromType(task.type);
|
|
962
|
+
}
|
|
963
|
+
|
|
964
|
+
private inferDomainFromType(type: TaskType): AgentDomain {
|
|
965
|
+
const typeDomains: Record<TaskType, AgentDomain> = {
|
|
966
|
+
coordination: 'queen',
|
|
967
|
+
consensus: 'queen',
|
|
968
|
+
coding: 'integration',
|
|
969
|
+
testing: 'support',
|
|
970
|
+
review: 'security',
|
|
971
|
+
analysis: 'core',
|
|
972
|
+
research: 'core',
|
|
973
|
+
documentation: 'support',
|
|
974
|
+
custom: 'core',
|
|
975
|
+
};
|
|
976
|
+
return typeDomains[type] || 'core';
|
|
977
|
+
}
|
|
978
|
+
|
|
979
|
+
/**
|
|
980
|
+
* Find matching patterns from ReasoningBank
|
|
981
|
+
*/
|
|
982
|
+
private async findMatchingPatterns(task: TaskDefinition): Promise<MatchedPattern[]> {
|
|
983
|
+
const patterns: MatchedPattern[] = [];
|
|
984
|
+
|
|
985
|
+
if (!this.neural || !this.config.enableLearning) {
|
|
986
|
+
return patterns;
|
|
987
|
+
}
|
|
988
|
+
|
|
989
|
+
try {
|
|
990
|
+
// Create a simple embedding from task description
|
|
991
|
+
const embedding = this.createSimpleEmbedding(task.description || task.name);
|
|
992
|
+
|
|
993
|
+
// Query ReasoningBank for similar patterns
|
|
994
|
+
const results = await this.neural.findPatterns(embedding, this.config.patternRetrievalK);
|
|
995
|
+
|
|
996
|
+
for (const result of results) {
|
|
997
|
+
if (result.relevanceScore >= this.config.patternThreshold) {
|
|
998
|
+
patterns.push({
|
|
999
|
+
patternId: result.patternId,
|
|
1000
|
+
strategy: result.strategy,
|
|
1001
|
+
successRate: result.successRate,
|
|
1002
|
+
relevanceScore: result.relevanceScore,
|
|
1003
|
+
keyLearnings: result.keyLearnings || [],
|
|
1004
|
+
});
|
|
1005
|
+
}
|
|
1006
|
+
}
|
|
1007
|
+
} catch (error) {
|
|
1008
|
+
// Log but don't fail - patterns are optional
|
|
1009
|
+
this.emitEvent('queen.pattern.error', { error: String(error) });
|
|
1010
|
+
}
|
|
1011
|
+
|
|
1012
|
+
return patterns;
|
|
1013
|
+
}
|
|
1014
|
+
|
|
1015
|
+
/**
|
|
1016
|
+
* Create a simple embedding from text using hash-based approach.
|
|
1017
|
+
* For higher quality embeddings, integrate @sparkleideas/agentic-flow's computeEmbedding.
|
|
1018
|
+
*/
|
|
1019
|
+
private createSimpleEmbedding(text: string): Float32Array {
|
|
1020
|
+
// Hash-based embedding - lightweight and fast for local similarity matching
|
|
1021
|
+
// For production ML embeddings, use: import('@sparkleideas/agentic-flow').computeEmbedding
|
|
1022
|
+
const embedding = new Float32Array(768);
|
|
1023
|
+
const words = text.toLowerCase().split(/\s+/);
|
|
1024
|
+
|
|
1025
|
+
for (let i = 0; i < words.length; i++) {
|
|
1026
|
+
const word = words[i];
|
|
1027
|
+
for (let j = 0; j < word.length; j++) {
|
|
1028
|
+
const idx = (word.charCodeAt(j) * (i + 1) * (j + 1)) % 768;
|
|
1029
|
+
embedding[idx] += 1 / words.length;
|
|
1030
|
+
}
|
|
1031
|
+
}
|
|
1032
|
+
|
|
1033
|
+
// Normalize
|
|
1034
|
+
let norm = 0;
|
|
1035
|
+
for (let i = 0; i < embedding.length; i++) {
|
|
1036
|
+
norm += embedding[i] * embedding[i];
|
|
1037
|
+
}
|
|
1038
|
+
norm = Math.sqrt(norm);
|
|
1039
|
+
if (norm > 0) {
|
|
1040
|
+
for (let i = 0; i < embedding.length; i++) {
|
|
1041
|
+
embedding[i] /= norm;
|
|
1042
|
+
}
|
|
1043
|
+
}
|
|
1044
|
+
|
|
1045
|
+
return embedding;
|
|
1046
|
+
}
|
|
1047
|
+
|
|
1048
|
+
/**
|
|
1049
|
+
* Estimate resource requirements
|
|
1050
|
+
*/
|
|
1051
|
+
private estimateResources(task: TaskDefinition, complexity: number): ResourceRequirements {
|
|
1052
|
+
const minAgents = complexity > 0.7 ? 2 : 1;
|
|
1053
|
+
const maxAgents = complexity > 0.8 ? 4 : complexity > 0.5 ? 3 : 2;
|
|
1054
|
+
|
|
1055
|
+
return {
|
|
1056
|
+
minAgents,
|
|
1057
|
+
maxAgents,
|
|
1058
|
+
memoryMb: Math.round(256 + complexity * 512),
|
|
1059
|
+
cpuIntensive: ['coding', 'analysis'].includes(task.type),
|
|
1060
|
+
ioIntensive: ['research', 'testing'].includes(task.type),
|
|
1061
|
+
networkRequired: task.type === 'research',
|
|
1062
|
+
};
|
|
1063
|
+
}
|
|
1064
|
+
|
|
1065
|
+
/**
|
|
1066
|
+
* Calculate confidence in analysis
|
|
1067
|
+
*/
|
|
1068
|
+
private calculateAnalysisConfidence(
|
|
1069
|
+
patterns: MatchedPattern[],
|
|
1070
|
+
complexity: number,
|
|
1071
|
+
capabilities: string[]
|
|
1072
|
+
): number {
|
|
1073
|
+
let confidence = 0.5; // Base confidence
|
|
1074
|
+
|
|
1075
|
+
// Higher confidence with more matching patterns
|
|
1076
|
+
confidence += patterns.length * 0.1;
|
|
1077
|
+
|
|
1078
|
+
// Higher confidence for simpler tasks
|
|
1079
|
+
confidence += (1 - complexity) * 0.2;
|
|
1080
|
+
|
|
1081
|
+
// Higher confidence with clear capabilities
|
|
1082
|
+
confidence += Math.min(capabilities.length * 0.05, 0.15);
|
|
1083
|
+
|
|
1084
|
+
// Boost from high-success patterns
|
|
1085
|
+
const avgPatternSuccess = patterns.length > 0
|
|
1086
|
+
? patterns.reduce((sum, p) => sum + p.successRate, 0) / patterns.length
|
|
1087
|
+
: 0;
|
|
1088
|
+
confidence += avgPatternSuccess * 0.1;
|
|
1089
|
+
|
|
1090
|
+
return Math.min(confidence, 0.95);
|
|
1091
|
+
}
|
|
1092
|
+
|
|
1093
|
+
// ===========================================================================
|
|
1094
|
+
// Agent Delegation
|
|
1095
|
+
// ===========================================================================
|
|
1096
|
+
|
|
1097
|
+
/**
|
|
1098
|
+
* Delegate a task to agents based on analysis
|
|
1099
|
+
*
|
|
1100
|
+
* @param task - Task to delegate
|
|
1101
|
+
* @param analysis - Previous task analysis
|
|
1102
|
+
* @returns Delegation plan
|
|
1103
|
+
*/
|
|
1104
|
+
async delegateToAgents(task: TaskDefinition, analysis: TaskAnalysis): Promise<DelegationPlan> {
|
|
1105
|
+
const startTime = performance.now();
|
|
1106
|
+
|
|
1107
|
+
this.planCounter++;
|
|
1108
|
+
const planId = `plan_${Date.now()}_${this.planCounter}`;
|
|
1109
|
+
|
|
1110
|
+
// Score all available agents for this task
|
|
1111
|
+
const agentScores = this.scoreAgents(task, analysis.matchedPatterns);
|
|
1112
|
+
|
|
1113
|
+
// Select primary agent
|
|
1114
|
+
const primaryAgent = this.selectPrimaryAgent(task, agentScores, analysis);
|
|
1115
|
+
|
|
1116
|
+
// Select backup agents
|
|
1117
|
+
const backupAgents = this.selectBackupAgents(task, agentScores, primaryAgent);
|
|
1118
|
+
|
|
1119
|
+
// Create parallel assignments for subtasks
|
|
1120
|
+
const parallelAssignments = this.createParallelAssignments(
|
|
1121
|
+
analysis.subtasks,
|
|
1122
|
+
agentScores
|
|
1123
|
+
);
|
|
1124
|
+
|
|
1125
|
+
// Determine execution strategy
|
|
1126
|
+
const strategy = this.determineExecutionStrategy(analysis);
|
|
1127
|
+
|
|
1128
|
+
const plan: DelegationPlan = {
|
|
1129
|
+
planId,
|
|
1130
|
+
taskId: task.id.id,
|
|
1131
|
+
analysisId: analysis.analysisId,
|
|
1132
|
+
primaryAgent,
|
|
1133
|
+
backupAgents,
|
|
1134
|
+
parallelAssignments,
|
|
1135
|
+
strategy,
|
|
1136
|
+
estimatedCompletionMs: analysis.estimatedDurationMs,
|
|
1137
|
+
timestamp: new Date(),
|
|
1138
|
+
};
|
|
1139
|
+
|
|
1140
|
+
// Store the plan
|
|
1141
|
+
this.delegationPlans.set(planId, plan);
|
|
1142
|
+
|
|
1143
|
+
// Execute the delegation
|
|
1144
|
+
await this.executeDelegation(plan);
|
|
1145
|
+
|
|
1146
|
+
// Record latency
|
|
1147
|
+
const latency = performance.now() - startTime;
|
|
1148
|
+
this.delegationLatencies.push(latency);
|
|
1149
|
+
if (this.delegationLatencies.length > 100) {
|
|
1150
|
+
this.delegationLatencies.shift();
|
|
1151
|
+
}
|
|
1152
|
+
|
|
1153
|
+
this.emitEvent('queen.task.delegated', {
|
|
1154
|
+
planId,
|
|
1155
|
+
taskId: task.id.id,
|
|
1156
|
+
primaryAgent: primaryAgent.agentId,
|
|
1157
|
+
strategy,
|
|
1158
|
+
latencyMs: latency,
|
|
1159
|
+
});
|
|
1160
|
+
|
|
1161
|
+
return plan;
|
|
1162
|
+
}
|
|
1163
|
+
|
|
1164
|
+
/**
|
|
1165
|
+
* Score agents for task assignment
|
|
1166
|
+
*/
|
|
1167
|
+
scoreAgents(task: TaskDefinition, patterns: MatchedPattern[]): AgentScore[] {
|
|
1168
|
+
const agents = this.swarm.getAllAgents();
|
|
1169
|
+
const scores: AgentScore[] = [];
|
|
1170
|
+
|
|
1171
|
+
for (const agent of agents) {
|
|
1172
|
+
const score = this.scoreAgent(agent, task, patterns);
|
|
1173
|
+
scores.push(score);
|
|
1174
|
+
}
|
|
1175
|
+
|
|
1176
|
+
// Sort by total score descending
|
|
1177
|
+
scores.sort((a, b) => b.totalScore - a.totalScore);
|
|
1178
|
+
|
|
1179
|
+
return scores;
|
|
1180
|
+
}
|
|
1181
|
+
|
|
1182
|
+
private scoreAgent(
|
|
1183
|
+
agent: AgentState,
|
|
1184
|
+
task: TaskDefinition,
|
|
1185
|
+
patterns: MatchedPattern[]
|
|
1186
|
+
): AgentScore {
|
|
1187
|
+
const domain = this.getAgentDomain(agent);
|
|
1188
|
+
|
|
1189
|
+
// Capability score - how well agent capabilities match task
|
|
1190
|
+
const capabilityScore = this.calculateCapabilityScore(agent, task);
|
|
1191
|
+
|
|
1192
|
+
// Load score - prefer less loaded agents
|
|
1193
|
+
const loadScore = 1 - agent.workload;
|
|
1194
|
+
|
|
1195
|
+
// Performance score - based on past performance
|
|
1196
|
+
const performanceScore = this.calculatePerformanceScore(agent, patterns);
|
|
1197
|
+
|
|
1198
|
+
// Health score - agent health
|
|
1199
|
+
const healthScore = agent.health;
|
|
1200
|
+
|
|
1201
|
+
// Availability score - is agent actually available
|
|
1202
|
+
const availabilityScore = agent.status === 'idle' ? 1.0 :
|
|
1203
|
+
agent.status === 'busy' ? 0.3 : 0.0;
|
|
1204
|
+
|
|
1205
|
+
// Weighted total
|
|
1206
|
+
const totalScore =
|
|
1207
|
+
capabilityScore * 0.30 +
|
|
1208
|
+
loadScore * 0.20 +
|
|
1209
|
+
performanceScore * 0.25 +
|
|
1210
|
+
healthScore * 0.15 +
|
|
1211
|
+
availabilityScore * 0.10;
|
|
1212
|
+
|
|
1213
|
+
return {
|
|
1214
|
+
agentId: agent.id.id,
|
|
1215
|
+
domain,
|
|
1216
|
+
totalScore,
|
|
1217
|
+
capabilityScore,
|
|
1218
|
+
loadScore,
|
|
1219
|
+
performanceScore,
|
|
1220
|
+
healthScore,
|
|
1221
|
+
availabilityScore,
|
|
1222
|
+
};
|
|
1223
|
+
}
|
|
1224
|
+
|
|
1225
|
+
private calculateCapabilityScore(agent: AgentState, task: TaskDefinition): number {
|
|
1226
|
+
let score = 0.5; // Base score
|
|
1227
|
+
|
|
1228
|
+
// Check type match
|
|
1229
|
+
const typeMatches: Record<TaskType, AgentType[]> = {
|
|
1230
|
+
research: ['researcher'],
|
|
1231
|
+
analysis: ['analyst', 'researcher'],
|
|
1232
|
+
coding: ['coder'],
|
|
1233
|
+
testing: ['tester'],
|
|
1234
|
+
review: ['reviewer'],
|
|
1235
|
+
documentation: ['documenter'],
|
|
1236
|
+
coordination: ['coordinator', 'queen'],
|
|
1237
|
+
consensus: ['coordinator', 'queen'],
|
|
1238
|
+
custom: ['worker'],
|
|
1239
|
+
};
|
|
1240
|
+
|
|
1241
|
+
const preferredTypes = typeMatches[task.type] || ['worker'];
|
|
1242
|
+
if (preferredTypes.includes(agent.type)) {
|
|
1243
|
+
score += 0.3;
|
|
1244
|
+
}
|
|
1245
|
+
|
|
1246
|
+
// Check specific capabilities
|
|
1247
|
+
const caps = agent.capabilities;
|
|
1248
|
+
if (task.type === 'coding' && caps.codeGeneration) score += 0.1;
|
|
1249
|
+
if (task.type === 'review' && caps.codeReview) score += 0.1;
|
|
1250
|
+
if (task.type === 'testing' && caps.testing) score += 0.1;
|
|
1251
|
+
if (task.type === 'coordination' && caps.coordination) score += 0.1;
|
|
1252
|
+
|
|
1253
|
+
return Math.min(score, 1.0);
|
|
1254
|
+
}
|
|
1255
|
+
|
|
1256
|
+
private calculatePerformanceScore(
|
|
1257
|
+
agent: AgentState,
|
|
1258
|
+
patterns: MatchedPattern[]
|
|
1259
|
+
): number {
|
|
1260
|
+
// Base on agent's success rate
|
|
1261
|
+
let score = agent.metrics.successRate;
|
|
1262
|
+
|
|
1263
|
+
// Boost if patterns suggest this agent type is successful
|
|
1264
|
+
const agentDomain = this.getAgentDomain(agent);
|
|
1265
|
+
for (const pattern of patterns) {
|
|
1266
|
+
if (pattern.strategy.toLowerCase().includes(agentDomain)) {
|
|
1267
|
+
score += pattern.successRate * 0.1;
|
|
1268
|
+
}
|
|
1269
|
+
}
|
|
1270
|
+
|
|
1271
|
+
return Math.min(score, 1.0);
|
|
1272
|
+
}
|
|
1273
|
+
|
|
1274
|
+
private getAgentDomain(agent: AgentState): AgentDomain {
|
|
1275
|
+
// Determine domain from agent type
|
|
1276
|
+
switch (agent.type) {
|
|
1277
|
+
case 'queen':
|
|
1278
|
+
return 'queen';
|
|
1279
|
+
case 'specialist':
|
|
1280
|
+
return 'security';
|
|
1281
|
+
case 'architect':
|
|
1282
|
+
return 'core';
|
|
1283
|
+
case 'coder':
|
|
1284
|
+
return 'integration';
|
|
1285
|
+
case 'tester':
|
|
1286
|
+
return 'support';
|
|
1287
|
+
default:
|
|
1288
|
+
return 'core';
|
|
1289
|
+
}
|
|
1290
|
+
}
|
|
1291
|
+
|
|
1292
|
+
private selectPrimaryAgent(
|
|
1293
|
+
task: TaskDefinition,
|
|
1294
|
+
scores: AgentScore[],
|
|
1295
|
+
analysis: TaskAnalysis
|
|
1296
|
+
): AgentAssignment {
|
|
1297
|
+
// Prefer agent from recommended domain
|
|
1298
|
+
const domainAgents = scores.filter(s => s.domain === analysis.recommendedDomain);
|
|
1299
|
+
|
|
1300
|
+
// Fall back to best overall if no domain match
|
|
1301
|
+
const bestScore = domainAgents.length > 0 ? domainAgents[0] : scores[0];
|
|
1302
|
+
|
|
1303
|
+
return {
|
|
1304
|
+
agentId: bestScore.agentId,
|
|
1305
|
+
domain: bestScore.domain,
|
|
1306
|
+
taskId: task.id.id,
|
|
1307
|
+
score: bestScore.totalScore,
|
|
1308
|
+
assignedAt: new Date(),
|
|
1309
|
+
};
|
|
1310
|
+
}
|
|
1311
|
+
|
|
1312
|
+
private selectBackupAgents(
|
|
1313
|
+
task: TaskDefinition,
|
|
1314
|
+
scores: AgentScore[],
|
|
1315
|
+
primary: AgentAssignment
|
|
1316
|
+
): AgentAssignment[] {
|
|
1317
|
+
const backups: AgentAssignment[] = [];
|
|
1318
|
+
|
|
1319
|
+
// Select up to 2 backup agents
|
|
1320
|
+
for (const score of scores) {
|
|
1321
|
+
if (score.agentId === primary.agentId) continue;
|
|
1322
|
+
if (score.totalScore < 0.3) continue;
|
|
1323
|
+
if (backups.length >= 2) break;
|
|
1324
|
+
|
|
1325
|
+
backups.push({
|
|
1326
|
+
agentId: score.agentId,
|
|
1327
|
+
domain: score.domain,
|
|
1328
|
+
taskId: task.id.id,
|
|
1329
|
+
score: score.totalScore,
|
|
1330
|
+
assignedAt: new Date(),
|
|
1331
|
+
});
|
|
1332
|
+
}
|
|
1333
|
+
|
|
1334
|
+
return backups;
|
|
1335
|
+
}
|
|
1336
|
+
|
|
1337
|
+
private createParallelAssignments(
|
|
1338
|
+
subtasks: SubTask[],
|
|
1339
|
+
scores: AgentScore[]
|
|
1340
|
+
): ParallelAssignment[] {
|
|
1341
|
+
const assignments: ParallelAssignment[] = [];
|
|
1342
|
+
|
|
1343
|
+
for (const subtask of subtasks) {
|
|
1344
|
+
// Find best agent for this subtask's domain
|
|
1345
|
+
const domainScores = scores.filter(s => s.domain === subtask.recommendedDomain);
|
|
1346
|
+
const bestScore = domainScores.length > 0 ? domainScores[0] : scores[0];
|
|
1347
|
+
|
|
1348
|
+
assignments.push({
|
|
1349
|
+
subtaskId: subtask.id,
|
|
1350
|
+
agentId: bestScore.agentId,
|
|
1351
|
+
domain: subtask.recommendedDomain,
|
|
1352
|
+
dependencies: subtask.dependencies,
|
|
1353
|
+
});
|
|
1354
|
+
}
|
|
1355
|
+
|
|
1356
|
+
return assignments;
|
|
1357
|
+
}
|
|
1358
|
+
|
|
1359
|
+
private determineExecutionStrategy(analysis: TaskAnalysis): ExecutionStrategy {
|
|
1360
|
+
const subtaskCount = analysis.subtasks.length;
|
|
1361
|
+
|
|
1362
|
+
if (subtaskCount === 0) {
|
|
1363
|
+
return 'sequential';
|
|
1364
|
+
}
|
|
1365
|
+
|
|
1366
|
+
// Check for dependencies
|
|
1367
|
+
const hasDependencies = analysis.subtasks.some(st => st.dependencies.length > 0);
|
|
1368
|
+
|
|
1369
|
+
if (!hasDependencies && subtaskCount > 2) {
|
|
1370
|
+
return 'parallel';
|
|
1371
|
+
}
|
|
1372
|
+
|
|
1373
|
+
if (hasDependencies && subtaskCount > 3) {
|
|
1374
|
+
return 'pipeline';
|
|
1375
|
+
}
|
|
1376
|
+
|
|
1377
|
+
if (analysis.complexity > 0.7) {
|
|
1378
|
+
return 'fan-out-fan-in';
|
|
1379
|
+
}
|
|
1380
|
+
|
|
1381
|
+
return 'hybrid';
|
|
1382
|
+
}
|
|
1383
|
+
|
|
1384
|
+
private async executeDelegation(plan: DelegationPlan): Promise<void> {
|
|
1385
|
+
// Delegate to the primary agent
|
|
1386
|
+
await this.swarm.assignTaskToDomain(plan.taskId, plan.primaryAgent.domain);
|
|
1387
|
+
|
|
1388
|
+
// Notify about the delegation
|
|
1389
|
+
await this.swarm.broadcastMessage(
|
|
1390
|
+
{
|
|
1391
|
+
type: 'delegation',
|
|
1392
|
+
planId: plan.planId,
|
|
1393
|
+
taskId: plan.taskId,
|
|
1394
|
+
primaryAgent: plan.primaryAgent.agentId,
|
|
1395
|
+
strategy: plan.strategy,
|
|
1396
|
+
},
|
|
1397
|
+
'normal'
|
|
1398
|
+
);
|
|
1399
|
+
}
|
|
1400
|
+
|
|
1401
|
+
// ===========================================================================
|
|
1402
|
+
// Swarm Health Monitoring
|
|
1403
|
+
// ===========================================================================
|
|
1404
|
+
|
|
1405
|
+
/**
|
|
1406
|
+
* Monitor swarm health and detect issues
|
|
1407
|
+
*
|
|
1408
|
+
* @returns Health report
|
|
1409
|
+
*/
|
|
1410
|
+
async monitorSwarmHealth(): Promise<HealthReport> {
|
|
1411
|
+
this.reportCounter++;
|
|
1412
|
+
const reportId = `health_${Date.now()}_${this.reportCounter}`;
|
|
1413
|
+
|
|
1414
|
+
const agents = this.swarm.getAllAgents();
|
|
1415
|
+
const status = this.swarm.getStatus();
|
|
1416
|
+
const metrics = this.swarm.getMetrics();
|
|
1417
|
+
|
|
1418
|
+
// Compute domain health
|
|
1419
|
+
const domainHealth = this.computeDomainHealth(status.domains);
|
|
1420
|
+
|
|
1421
|
+
// Compute agent health
|
|
1422
|
+
const agentHealth = this.computeAgentHealth(agents);
|
|
1423
|
+
|
|
1424
|
+
// Detect bottlenecks
|
|
1425
|
+
const bottlenecks = this.detectBottlenecks(status, agents, metrics);
|
|
1426
|
+
|
|
1427
|
+
// Generate alerts
|
|
1428
|
+
const alerts = this.generateAlerts(bottlenecks, agentHealth, metrics);
|
|
1429
|
+
|
|
1430
|
+
// Overall health score
|
|
1431
|
+
const overallHealth = this.calculateOverallHealth(domainHealth, agentHealth, bottlenecks);
|
|
1432
|
+
|
|
1433
|
+
// Generate recommendations
|
|
1434
|
+
const recommendations = this.generateRecommendations(bottlenecks, overallHealth);
|
|
1435
|
+
|
|
1436
|
+
// Compile health metrics
|
|
1437
|
+
const healthMetrics: HealthMetrics = {
|
|
1438
|
+
totalAgents: agents.length,
|
|
1439
|
+
activeAgents: agents.filter(a => a.status === 'idle' || a.status === 'busy').length,
|
|
1440
|
+
idleAgents: agents.filter(a => a.status === 'idle').length,
|
|
1441
|
+
errorAgents: agents.filter(a => a.status === 'error').length,
|
|
1442
|
+
totalTasks: metrics.totalTasks,
|
|
1443
|
+
completedTasks: metrics.completedTasks,
|
|
1444
|
+
failedTasks: metrics.failedTasks,
|
|
1445
|
+
avgTaskDurationMs: metrics.avgTaskDurationMs,
|
|
1446
|
+
taskThroughputPerMin: metrics.completedTasks / Math.max(metrics.uptime / 60, 1),
|
|
1447
|
+
consensusSuccessRate: metrics.consensusSuccessRate,
|
|
1448
|
+
};
|
|
1449
|
+
|
|
1450
|
+
const report: HealthReport = {
|
|
1451
|
+
reportId,
|
|
1452
|
+
timestamp: new Date(),
|
|
1453
|
+
overallHealth,
|
|
1454
|
+
domainHealth,
|
|
1455
|
+
agentHealth,
|
|
1456
|
+
bottlenecks,
|
|
1457
|
+
alerts,
|
|
1458
|
+
metrics: healthMetrics,
|
|
1459
|
+
recommendations,
|
|
1460
|
+
};
|
|
1461
|
+
|
|
1462
|
+
// Store in history
|
|
1463
|
+
this.healthHistory.push(report);
|
|
1464
|
+
if (this.healthHistory.length > 100) {
|
|
1465
|
+
this.healthHistory.shift();
|
|
1466
|
+
}
|
|
1467
|
+
this.lastHealthReport = report;
|
|
1468
|
+
|
|
1469
|
+
this.emitEvent('queen.health.report', {
|
|
1470
|
+
reportId,
|
|
1471
|
+
overallHealth,
|
|
1472
|
+
bottleneckCount: bottlenecks.length,
|
|
1473
|
+
alertCount: alerts.length,
|
|
1474
|
+
});
|
|
1475
|
+
|
|
1476
|
+
return report;
|
|
1477
|
+
}
|
|
1478
|
+
|
|
1479
|
+
private computeDomainHealth(domains: DomainStatus[]): Map<AgentDomain, DomainHealthStatus> {
|
|
1480
|
+
const health = new Map<AgentDomain, DomainHealthStatus>();
|
|
1481
|
+
|
|
1482
|
+
for (const domain of domains) {
|
|
1483
|
+
const utilization = domain.agentCount > 0
|
|
1484
|
+
? domain.busyAgents / domain.agentCount
|
|
1485
|
+
: 0;
|
|
1486
|
+
|
|
1487
|
+
const queuePressure = domain.tasksQueued > 5 ? 0.3 : domain.tasksQueued * 0.05;
|
|
1488
|
+
const domainHealth = Math.max(0, 1 - queuePressure - (1 - utilization) * 0.2);
|
|
1489
|
+
|
|
1490
|
+
health.set(domain.name, {
|
|
1491
|
+
domain: domain.name,
|
|
1492
|
+
health: domainHealth,
|
|
1493
|
+
activeAgents: domain.availableAgents + domain.busyAgents,
|
|
1494
|
+
totalAgents: domain.agentCount,
|
|
1495
|
+
queuedTasks: domain.tasksQueued,
|
|
1496
|
+
avgResponseTimeMs: 0, // Would need tracking
|
|
1497
|
+
errorRate: 0, // Would need tracking
|
|
1498
|
+
});
|
|
1499
|
+
}
|
|
1500
|
+
|
|
1501
|
+
return health;
|
|
1502
|
+
}
|
|
1503
|
+
|
|
1504
|
+
private computeAgentHealth(agents: AgentState[]): AgentHealthEntry[] {
|
|
1505
|
+
return agents.map(agent => ({
|
|
1506
|
+
agentId: agent.id.id,
|
|
1507
|
+
domain: this.getAgentDomain(agent),
|
|
1508
|
+
health: agent.health,
|
|
1509
|
+
status: agent.status,
|
|
1510
|
+
lastHeartbeat: agent.lastHeartbeat,
|
|
1511
|
+
currentLoad: agent.workload,
|
|
1512
|
+
recentErrors: agent.metrics.tasksFailed,
|
|
1513
|
+
}));
|
|
1514
|
+
}
|
|
1515
|
+
|
|
1516
|
+
private detectBottlenecks(
|
|
1517
|
+
status: { domains: DomainStatus[]; metrics: CoordinatorMetrics },
|
|
1518
|
+
agents: AgentState[],
|
|
1519
|
+
metrics: CoordinatorMetrics
|
|
1520
|
+
): Bottleneck[] {
|
|
1521
|
+
const bottlenecks: Bottleneck[] = [];
|
|
1522
|
+
|
|
1523
|
+
// Check domain queues
|
|
1524
|
+
for (const domain of status.domains) {
|
|
1525
|
+
if (domain.tasksQueued > this.config.bottleneckThresholds.queueDepth) {
|
|
1526
|
+
bottlenecks.push({
|
|
1527
|
+
type: 'domain',
|
|
1528
|
+
location: domain.name,
|
|
1529
|
+
severity: domain.tasksQueued > 20 ? 'critical' : 'high',
|
|
1530
|
+
description: `High task queue depth in ${domain.name} domain`,
|
|
1531
|
+
impact: `${domain.tasksQueued} tasks waiting for processing`,
|
|
1532
|
+
suggestedAction: `Consider scaling ${domain.name} domain agents`,
|
|
1533
|
+
});
|
|
1534
|
+
}
|
|
1535
|
+
}
|
|
1536
|
+
|
|
1537
|
+
// Check error agents
|
|
1538
|
+
const errorAgents = agents.filter(a => a.status === 'error');
|
|
1539
|
+
if (errorAgents.length > 0) {
|
|
1540
|
+
bottlenecks.push({
|
|
1541
|
+
type: 'agent',
|
|
1542
|
+
location: errorAgents.map(a => a.id.id).join(', '),
|
|
1543
|
+
severity: errorAgents.length > 3 ? 'critical' : 'medium',
|
|
1544
|
+
description: `${errorAgents.length} agents in error state`,
|
|
1545
|
+
impact: 'Reduced processing capacity',
|
|
1546
|
+
suggestedAction: 'Investigate and recover error agents',
|
|
1547
|
+
});
|
|
1548
|
+
}
|
|
1549
|
+
|
|
1550
|
+
// Check coordination latency
|
|
1551
|
+
if (metrics.coordinationLatencyMs > this.config.bottleneckThresholds.responseTimeMs) {
|
|
1552
|
+
bottlenecks.push({
|
|
1553
|
+
type: 'resource',
|
|
1554
|
+
location: 'coordination',
|
|
1555
|
+
severity: 'high',
|
|
1556
|
+
description: 'High coordination latency detected',
|
|
1557
|
+
impact: `Current latency: ${metrics.coordinationLatencyMs}ms`,
|
|
1558
|
+
suggestedAction: 'Optimize coordination or reduce concurrent tasks',
|
|
1559
|
+
});
|
|
1560
|
+
}
|
|
1561
|
+
|
|
1562
|
+
return bottlenecks;
|
|
1563
|
+
}
|
|
1564
|
+
|
|
1565
|
+
private generateAlerts(
|
|
1566
|
+
bottlenecks: Bottleneck[],
|
|
1567
|
+
agentHealth: AgentHealthEntry[],
|
|
1568
|
+
metrics: CoordinatorMetrics
|
|
1569
|
+
): HealthAlert[] {
|
|
1570
|
+
const alerts: HealthAlert[] = [];
|
|
1571
|
+
|
|
1572
|
+
// Generate alerts for critical bottlenecks
|
|
1573
|
+
for (const bottleneck of bottlenecks) {
|
|
1574
|
+
if (bottleneck.severity === 'critical' || bottleneck.severity === 'high') {
|
|
1575
|
+
alerts.push({
|
|
1576
|
+
alertId: `alert_${Date.now()}_${alerts.length}`,
|
|
1577
|
+
type: bottleneck.severity === 'critical' ? 'critical' : 'error',
|
|
1578
|
+
source: bottleneck.location,
|
|
1579
|
+
message: bottleneck.description,
|
|
1580
|
+
timestamp: new Date(),
|
|
1581
|
+
acknowledged: false,
|
|
1582
|
+
});
|
|
1583
|
+
}
|
|
1584
|
+
}
|
|
1585
|
+
|
|
1586
|
+
// Alert on low overall agent health
|
|
1587
|
+
const avgHealth = agentHealth.length > 0
|
|
1588
|
+
? agentHealth.reduce((sum, a) => sum + a.health, 0) / agentHealth.length
|
|
1589
|
+
: 1.0;
|
|
1590
|
+
|
|
1591
|
+
if (avgHealth < 0.5) {
|
|
1592
|
+
alerts.push({
|
|
1593
|
+
alertId: `alert_${Date.now()}_health`,
|
|
1594
|
+
type: avgHealth < 0.3 ? 'critical' : 'warning',
|
|
1595
|
+
source: 'swarm',
|
|
1596
|
+
message: `Low average agent health: ${(avgHealth * 100).toFixed(1)}%`,
|
|
1597
|
+
timestamp: new Date(),
|
|
1598
|
+
acknowledged: false,
|
|
1599
|
+
});
|
|
1600
|
+
}
|
|
1601
|
+
|
|
1602
|
+
// Alert on high failure rate
|
|
1603
|
+
const failureRate = metrics.totalTasks > 0
|
|
1604
|
+
? metrics.failedTasks / metrics.totalTasks
|
|
1605
|
+
: 0;
|
|
1606
|
+
|
|
1607
|
+
if (failureRate > this.config.bottleneckThresholds.errorRate) {
|
|
1608
|
+
alerts.push({
|
|
1609
|
+
alertId: `alert_${Date.now()}_failures`,
|
|
1610
|
+
type: failureRate > 0.2 ? 'critical' : 'warning',
|
|
1611
|
+
source: 'tasks',
|
|
1612
|
+
message: `High task failure rate: ${(failureRate * 100).toFixed(1)}%`,
|
|
1613
|
+
timestamp: new Date(),
|
|
1614
|
+
acknowledged: false,
|
|
1615
|
+
});
|
|
1616
|
+
}
|
|
1617
|
+
|
|
1618
|
+
return alerts;
|
|
1619
|
+
}
|
|
1620
|
+
|
|
1621
|
+
private calculateOverallHealth(
|
|
1622
|
+
domainHealth: Map<AgentDomain, DomainHealthStatus>,
|
|
1623
|
+
agentHealth: AgentHealthEntry[],
|
|
1624
|
+
bottlenecks: Bottleneck[]
|
|
1625
|
+
): number {
|
|
1626
|
+
// Average domain health
|
|
1627
|
+
const domainHealthAvg = domainHealth.size > 0
|
|
1628
|
+
? Array.from(domainHealth.values()).reduce((sum, d) => sum + d.health, 0) / domainHealth.size
|
|
1629
|
+
: 1.0;
|
|
1630
|
+
|
|
1631
|
+
// Average agent health
|
|
1632
|
+
const agentHealthAvg = agentHealth.length > 0
|
|
1633
|
+
? agentHealth.reduce((sum, a) => sum + a.health, 0) / agentHealth.length
|
|
1634
|
+
: 1.0;
|
|
1635
|
+
|
|
1636
|
+
// Bottleneck penalty
|
|
1637
|
+
const bottleneckPenalty = bottlenecks.reduce((penalty, b) => {
|
|
1638
|
+
switch (b.severity) {
|
|
1639
|
+
case 'critical': return penalty + 0.2;
|
|
1640
|
+
case 'high': return penalty + 0.1;
|
|
1641
|
+
case 'medium': return penalty + 0.05;
|
|
1642
|
+
case 'low': return penalty + 0.02;
|
|
1643
|
+
default: return penalty;
|
|
1644
|
+
}
|
|
1645
|
+
}, 0);
|
|
1646
|
+
|
|
1647
|
+
const overallHealth = (domainHealthAvg * 0.4 + agentHealthAvg * 0.4) - bottleneckPenalty;
|
|
1648
|
+
return Math.max(0, Math.min(1, overallHealth));
|
|
1649
|
+
}
|
|
1650
|
+
|
|
1651
|
+
private generateRecommendations(bottlenecks: Bottleneck[], overallHealth: number): string[] {
|
|
1652
|
+
const recommendations: string[] = [];
|
|
1653
|
+
|
|
1654
|
+
// Add bottleneck-specific recommendations
|
|
1655
|
+
for (const bottleneck of bottlenecks) {
|
|
1656
|
+
recommendations.push(bottleneck.suggestedAction);
|
|
1657
|
+
}
|
|
1658
|
+
|
|
1659
|
+
// General recommendations based on health
|
|
1660
|
+
if (overallHealth < 0.5) {
|
|
1661
|
+
recommendations.push('Consider reducing task load or adding more agents');
|
|
1662
|
+
}
|
|
1663
|
+
|
|
1664
|
+
if (overallHealth < 0.3) {
|
|
1665
|
+
recommendations.push('URGENT: Investigate system-wide issues immediately');
|
|
1666
|
+
}
|
|
1667
|
+
|
|
1668
|
+
return [...new Set(recommendations)]; // Deduplicate
|
|
1669
|
+
}
|
|
1670
|
+
|
|
1671
|
+
private startHealthMonitoring(): void {
|
|
1672
|
+
this.healthCheckInterval = setInterval(async () => {
|
|
1673
|
+
try {
|
|
1674
|
+
await this.monitorSwarmHealth();
|
|
1675
|
+
} catch (error) {
|
|
1676
|
+
this.emitEvent('queen.health.error', { error: String(error) });
|
|
1677
|
+
}
|
|
1678
|
+
}, this.config.healthCheckIntervalMs);
|
|
1679
|
+
}
|
|
1680
|
+
|
|
1681
|
+
private stopHealthMonitoring(): void {
|
|
1682
|
+
if (this.healthCheckInterval) {
|
|
1683
|
+
clearInterval(this.healthCheckInterval);
|
|
1684
|
+
this.healthCheckInterval = undefined;
|
|
1685
|
+
}
|
|
1686
|
+
}
|
|
1687
|
+
|
|
1688
|
+
// ===========================================================================
|
|
1689
|
+
// Consensus Coordination
|
|
1690
|
+
// ===========================================================================
|
|
1691
|
+
|
|
1692
|
+
/**
|
|
1693
|
+
* Coordinate consensus for a decision
|
|
1694
|
+
*
|
|
1695
|
+
* @param decision - Decision requiring consensus
|
|
1696
|
+
* @returns Consensus result
|
|
1697
|
+
*/
|
|
1698
|
+
async coordinateConsensus(decision: Decision): Promise<ConsensusResult> {
|
|
1699
|
+
const startTime = performance.now();
|
|
1700
|
+
|
|
1701
|
+
this.decisionCounter++;
|
|
1702
|
+
decision.decisionId = `decision_${Date.now()}_${this.decisionCounter}`;
|
|
1703
|
+
|
|
1704
|
+
// Store active decision
|
|
1705
|
+
this.activeDecisions.set(decision.decisionId, decision);
|
|
1706
|
+
|
|
1707
|
+
try {
|
|
1708
|
+
let result: ConsensusResult;
|
|
1709
|
+
|
|
1710
|
+
switch (decision.requiredConsensus) {
|
|
1711
|
+
case 'queen-override':
|
|
1712
|
+
// Queen can make unilateral decisions for certain types
|
|
1713
|
+
result = this.queenOverride(decision);
|
|
1714
|
+
break;
|
|
1715
|
+
|
|
1716
|
+
case 'unanimous':
|
|
1717
|
+
result = await this.unanimousConsensus(decision);
|
|
1718
|
+
break;
|
|
1719
|
+
|
|
1720
|
+
case 'supermajority':
|
|
1721
|
+
result = await this.supermajorityConsensus(decision);
|
|
1722
|
+
break;
|
|
1723
|
+
|
|
1724
|
+
case 'weighted':
|
|
1725
|
+
result = await this.weightedConsensus(decision);
|
|
1726
|
+
break;
|
|
1727
|
+
|
|
1728
|
+
case 'majority':
|
|
1729
|
+
default:
|
|
1730
|
+
result = await this.majorityConsensus(decision);
|
|
1731
|
+
}
|
|
1732
|
+
|
|
1733
|
+
// Record latency
|
|
1734
|
+
const latency = performance.now() - startTime;
|
|
1735
|
+
this.consensusLatencies.push(latency);
|
|
1736
|
+
if (this.consensusLatencies.length > 100) {
|
|
1737
|
+
this.consensusLatencies.shift();
|
|
1738
|
+
}
|
|
1739
|
+
|
|
1740
|
+
this.emitEvent('queen.consensus.completed', {
|
|
1741
|
+
decisionId: decision.decisionId,
|
|
1742
|
+
type: decision.requiredConsensus,
|
|
1743
|
+
approved: result.approved,
|
|
1744
|
+
approvalRate: result.approvalRate,
|
|
1745
|
+
latencyMs: latency,
|
|
1746
|
+
});
|
|
1747
|
+
|
|
1748
|
+
return result;
|
|
1749
|
+
} finally {
|
|
1750
|
+
this.activeDecisions.delete(decision.decisionId);
|
|
1751
|
+
}
|
|
1752
|
+
}
|
|
1753
|
+
|
|
1754
|
+
private queenOverride(decision: Decision): ConsensusResult {
|
|
1755
|
+
// Queen can make immediate decisions for:
|
|
1756
|
+
// - Emergency actions
|
|
1757
|
+
// - Agent termination
|
|
1758
|
+
// - Priority overrides
|
|
1759
|
+
const allowedTypes: DecisionType[] = ['emergency-action', 'agent-termination', 'priority-override'];
|
|
1760
|
+
|
|
1761
|
+
if (!allowedTypes.includes(decision.type)) {
|
|
1762
|
+
throw new Error(`Queen override not allowed for decision type: ${decision.type}`);
|
|
1763
|
+
}
|
|
1764
|
+
|
|
1765
|
+
return {
|
|
1766
|
+
proposalId: decision.decisionId,
|
|
1767
|
+
approved: true,
|
|
1768
|
+
approvalRate: 1.0,
|
|
1769
|
+
participationRate: 1.0,
|
|
1770
|
+
finalValue: decision.proposal,
|
|
1771
|
+
rounds: 1,
|
|
1772
|
+
durationMs: 0,
|
|
1773
|
+
};
|
|
1774
|
+
}
|
|
1775
|
+
|
|
1776
|
+
private async majorityConsensus(decision: Decision): Promise<ConsensusResult> {
|
|
1777
|
+
// Use swarm's consensus engine with majority threshold
|
|
1778
|
+
const result = await this.swarm.proposeConsensus({
|
|
1779
|
+
decision,
|
|
1780
|
+
threshold: 0.51,
|
|
1781
|
+
timeout: this.config.consensusTimeouts.majority,
|
|
1782
|
+
});
|
|
1783
|
+
|
|
1784
|
+
return result;
|
|
1785
|
+
}
|
|
1786
|
+
|
|
1787
|
+
private async supermajorityConsensus(decision: Decision): Promise<ConsensusResult> {
|
|
1788
|
+
// Use swarm's consensus engine with 2/3 threshold
|
|
1789
|
+
const result = await this.swarm.proposeConsensus({
|
|
1790
|
+
decision,
|
|
1791
|
+
threshold: 0.67,
|
|
1792
|
+
timeout: this.config.consensusTimeouts.supermajority,
|
|
1793
|
+
});
|
|
1794
|
+
|
|
1795
|
+
return result;
|
|
1796
|
+
}
|
|
1797
|
+
|
|
1798
|
+
private async unanimousConsensus(decision: Decision): Promise<ConsensusResult> {
|
|
1799
|
+
// Use swarm's consensus engine with unanimous requirement
|
|
1800
|
+
const result = await this.swarm.proposeConsensus({
|
|
1801
|
+
decision,
|
|
1802
|
+
threshold: 1.0,
|
|
1803
|
+
timeout: this.config.consensusTimeouts.unanimous,
|
|
1804
|
+
});
|
|
1805
|
+
|
|
1806
|
+
return result;
|
|
1807
|
+
}
|
|
1808
|
+
|
|
1809
|
+
private async weightedConsensus(decision: Decision): Promise<ConsensusResult> {
|
|
1810
|
+
// Weighted consensus based on agent performance
|
|
1811
|
+
// For now, delegate to the standard consensus with metadata
|
|
1812
|
+
const agents = this.swarm.getAllAgents();
|
|
1813
|
+
const weights = new Map<string, number>();
|
|
1814
|
+
|
|
1815
|
+
for (const agent of agents) {
|
|
1816
|
+
const weight = agent.metrics.successRate * agent.health;
|
|
1817
|
+
weights.set(agent.id.id, weight);
|
|
1818
|
+
}
|
|
1819
|
+
|
|
1820
|
+
const result = await this.swarm.proposeConsensus({
|
|
1821
|
+
decision,
|
|
1822
|
+
weights: Object.fromEntries(weights),
|
|
1823
|
+
threshold: 0.51,
|
|
1824
|
+
timeout: this.config.consensusTimeouts.majority,
|
|
1825
|
+
});
|
|
1826
|
+
|
|
1827
|
+
return result;
|
|
1828
|
+
}
|
|
1829
|
+
|
|
1830
|
+
// ===========================================================================
|
|
1831
|
+
// Learning from Outcomes
|
|
1832
|
+
// ===========================================================================
|
|
1833
|
+
|
|
1834
|
+
/**
|
|
1835
|
+
* Record task outcome for learning
|
|
1836
|
+
*
|
|
1837
|
+
* @param task - Completed task
|
|
1838
|
+
* @param result - Task result
|
|
1839
|
+
*/
|
|
1840
|
+
async recordOutcome(task: TaskDefinition, result: TaskResult): Promise<void> {
|
|
1841
|
+
// Store in outcome history
|
|
1842
|
+
this.outcomeHistory.push(result);
|
|
1843
|
+
if (this.outcomeHistory.length > 1000) {
|
|
1844
|
+
this.outcomeHistory.shift();
|
|
1845
|
+
}
|
|
1846
|
+
|
|
1847
|
+
// Learn from outcome if neural system available
|
|
1848
|
+
if (this.neural && this.config.enableLearning) {
|
|
1849
|
+
await this.learnFromOutcome(task, result);
|
|
1850
|
+
}
|
|
1851
|
+
|
|
1852
|
+
// Store in memory service if available
|
|
1853
|
+
if (this.memory) {
|
|
1854
|
+
await this.storeOutcomeMemory(task, result);
|
|
1855
|
+
}
|
|
1856
|
+
|
|
1857
|
+
this.emitEvent('queen.outcome.recorded', {
|
|
1858
|
+
taskId: task.id.id,
|
|
1859
|
+
success: result.success,
|
|
1860
|
+
durationMs: result.durationMs,
|
|
1861
|
+
qualityScore: result.metrics.qualityScore,
|
|
1862
|
+
});
|
|
1863
|
+
}
|
|
1864
|
+
|
|
1865
|
+
private async learnFromOutcome(task: TaskDefinition, result: TaskResult): Promise<void> {
|
|
1866
|
+
if (!this.neural) return;
|
|
1867
|
+
|
|
1868
|
+
// Create trajectory for this task
|
|
1869
|
+
const trajectoryId = this.neural.beginTask(
|
|
1870
|
+
task.description || task.name,
|
|
1871
|
+
result.domain
|
|
1872
|
+
);
|
|
1873
|
+
|
|
1874
|
+
// Record the execution step
|
|
1875
|
+
const embedding = this.createSimpleEmbedding(task.description || task.name);
|
|
1876
|
+
const reward = result.success
|
|
1877
|
+
? result.metrics.qualityScore * 0.8 + 0.2
|
|
1878
|
+
: result.metrics.qualityScore * 0.3;
|
|
1879
|
+
|
|
1880
|
+
this.neural.recordStep(
|
|
1881
|
+
trajectoryId,
|
|
1882
|
+
`executed_${task.type}_in_${result.domain}`,
|
|
1883
|
+
reward,
|
|
1884
|
+
embedding
|
|
1885
|
+
);
|
|
1886
|
+
|
|
1887
|
+
// Complete the task trajectory
|
|
1888
|
+
await this.neural.completeTask(trajectoryId, result.metrics.qualityScore);
|
|
1889
|
+
}
|
|
1890
|
+
|
|
1891
|
+
private async storeOutcomeMemory(task: TaskDefinition, result: TaskResult): Promise<void> {
|
|
1892
|
+
if (!this.memory) return;
|
|
1893
|
+
|
|
1894
|
+
try {
|
|
1895
|
+
await this.memory.store({
|
|
1896
|
+
key: `outcome_${task.id.id}`,
|
|
1897
|
+
content: this.formatOutcomeContent(task, result),
|
|
1898
|
+
namespace: 'queen-outcomes',
|
|
1899
|
+
tags: [
|
|
1900
|
+
task.type,
|
|
1901
|
+
result.domain,
|
|
1902
|
+
result.success ? 'success' : 'failure',
|
|
1903
|
+
],
|
|
1904
|
+
metadata: {
|
|
1905
|
+
taskId: task.id.id,
|
|
1906
|
+
success: result.success,
|
|
1907
|
+
durationMs: result.durationMs,
|
|
1908
|
+
qualityScore: result.metrics.qualityScore,
|
|
1909
|
+
agentId: result.agentId,
|
|
1910
|
+
},
|
|
1911
|
+
});
|
|
1912
|
+
} catch (error) {
|
|
1913
|
+
// Log but don't fail - memory storage is optional
|
|
1914
|
+
this.emitEvent('queen.memory.error', { error: String(error) });
|
|
1915
|
+
}
|
|
1916
|
+
}
|
|
1917
|
+
|
|
1918
|
+
private formatOutcomeContent(task: TaskDefinition, result: TaskResult): string {
|
|
1919
|
+
return [
|
|
1920
|
+
`Task: ${task.name}`,
|
|
1921
|
+
`Type: ${task.type}`,
|
|
1922
|
+
`Domain: ${result.domain}`,
|
|
1923
|
+
`Agent: ${result.agentId}`,
|
|
1924
|
+
`Success: ${result.success}`,
|
|
1925
|
+
`Duration: ${result.durationMs}ms`,
|
|
1926
|
+
`Quality: ${result.metrics.qualityScore}`,
|
|
1927
|
+
`Description: ${task.description || 'N/A'}`,
|
|
1928
|
+
].join('\n');
|
|
1929
|
+
}
|
|
1930
|
+
|
|
1931
|
+
// ===========================================================================
|
|
1932
|
+
// Utility Methods
|
|
1933
|
+
// ===========================================================================
|
|
1934
|
+
|
|
1935
|
+
/**
|
|
1936
|
+
* Get the last health report
|
|
1937
|
+
*/
|
|
1938
|
+
getLastHealthReport(): HealthReport | undefined {
|
|
1939
|
+
return this.lastHealthReport;
|
|
1940
|
+
}
|
|
1941
|
+
|
|
1942
|
+
/**
|
|
1943
|
+
* Get outcome history
|
|
1944
|
+
*/
|
|
1945
|
+
getOutcomeHistory(): TaskResult[] {
|
|
1946
|
+
return [...this.outcomeHistory];
|
|
1947
|
+
}
|
|
1948
|
+
|
|
1949
|
+
/**
|
|
1950
|
+
* Get analysis cache
|
|
1951
|
+
*/
|
|
1952
|
+
getAnalysisCache(): Map<string, TaskAnalysis> {
|
|
1953
|
+
return new Map(this.analysisCache);
|
|
1954
|
+
}
|
|
1955
|
+
|
|
1956
|
+
/**
|
|
1957
|
+
* Get delegation plans
|
|
1958
|
+
*/
|
|
1959
|
+
getDelegationPlans(): Map<string, DelegationPlan> {
|
|
1960
|
+
return new Map(this.delegationPlans);
|
|
1961
|
+
}
|
|
1962
|
+
|
|
1963
|
+
/**
|
|
1964
|
+
* Get performance statistics
|
|
1965
|
+
*/
|
|
1966
|
+
getPerformanceStats(): {
|
|
1967
|
+
avgAnalysisLatencyMs: number;
|
|
1968
|
+
avgDelegationLatencyMs: number;
|
|
1969
|
+
avgConsensusLatencyMs: number;
|
|
1970
|
+
totalAnalyses: number;
|
|
1971
|
+
totalDelegations: number;
|
|
1972
|
+
totalDecisions: number;
|
|
1973
|
+
} {
|
|
1974
|
+
const avg = (arr: number[]) => arr.length > 0
|
|
1975
|
+
? arr.reduce((a, b) => a + b, 0) / arr.length
|
|
1976
|
+
: 0;
|
|
1977
|
+
|
|
1978
|
+
return {
|
|
1979
|
+
avgAnalysisLatencyMs: avg(this.analysisLatencies),
|
|
1980
|
+
avgDelegationLatencyMs: avg(this.delegationLatencies),
|
|
1981
|
+
avgConsensusLatencyMs: avg(this.consensusLatencies),
|
|
1982
|
+
totalAnalyses: this.analysisCounter,
|
|
1983
|
+
totalDelegations: this.planCounter,
|
|
1984
|
+
totalDecisions: this.decisionCounter,
|
|
1985
|
+
};
|
|
1986
|
+
}
|
|
1987
|
+
|
|
1988
|
+
/**
|
|
1989
|
+
* Check if learning is enabled
|
|
1990
|
+
*/
|
|
1991
|
+
isLearningEnabled(): boolean {
|
|
1992
|
+
return this.config.enableLearning && !!this.neural;
|
|
1993
|
+
}
|
|
1994
|
+
|
|
1995
|
+
private emitEvent(type: string, data: Record<string, unknown>): void {
|
|
1996
|
+
const event = {
|
|
1997
|
+
id: `event_${Date.now()}_${Math.random().toString(36).substr(2, 6)}`,
|
|
1998
|
+
type,
|
|
1999
|
+
source: 'queen-coordinator',
|
|
2000
|
+
timestamp: new Date(),
|
|
2001
|
+
data,
|
|
2002
|
+
};
|
|
2003
|
+
|
|
2004
|
+
this.emit(type, event);
|
|
2005
|
+
this.emit('event', event);
|
|
2006
|
+
}
|
|
2007
|
+
}
|
|
2008
|
+
|
|
2009
|
+
// =============================================================================
|
|
2010
|
+
// Factory Function
|
|
2011
|
+
// =============================================================================
|
|
2012
|
+
|
|
2013
|
+
/**
|
|
2014
|
+
* Create a Queen Coordinator instance
|
|
2015
|
+
*/
|
|
2016
|
+
export function createQueenCoordinator(
|
|
2017
|
+
swarm: ISwarmCoordinator,
|
|
2018
|
+
config?: Partial<QueenCoordinatorConfig>,
|
|
2019
|
+
neural?: INeuralLearningSystem,
|
|
2020
|
+
memory?: IMemoryService
|
|
2021
|
+
): QueenCoordinator {
|
|
2022
|
+
return new QueenCoordinator(swarm, config, neural, memory);
|
|
2023
|
+
}
|
|
2024
|
+
|
|
2025
|
+
export default QueenCoordinator;
|