claude-flow 1.0.0
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/LICENSE +21 -0
- package/README.md +612 -0
- package/bin/claude-flow +0 -0
- package/bin/claude-flow-simple +0 -0
- package/bin/claude-flow-typecheck +0 -0
- package/deno.json +84 -0
- package/package.json +45 -0
- package/scripts/check-links.ts +274 -0
- package/scripts/check-performance-regression.ts +168 -0
- package/scripts/claude-sparc.sh +562 -0
- package/scripts/coverage-report.ts +692 -0
- package/scripts/demo-task-system.ts +224 -0
- package/scripts/install.js +72 -0
- package/scripts/test-batch-tasks.ts +29 -0
- package/scripts/test-coordination-features.ts +238 -0
- package/scripts/test-mcp.ts +251 -0
- package/scripts/test-runner.ts +571 -0
- package/scripts/validate-examples.ts +288 -0
- package/src/cli/cli-core.ts +273 -0
- package/src/cli/commands/agent.ts +83 -0
- package/src/cli/commands/config.ts +442 -0
- package/src/cli/commands/help.ts +765 -0
- package/src/cli/commands/index.ts +963 -0
- package/src/cli/commands/mcp.ts +191 -0
- package/src/cli/commands/memory.ts +74 -0
- package/src/cli/commands/monitor.ts +403 -0
- package/src/cli/commands/session.ts +595 -0
- package/src/cli/commands/start.ts +156 -0
- package/src/cli/commands/status.ts +345 -0
- package/src/cli/commands/task.ts +79 -0
- package/src/cli/commands/workflow.ts +763 -0
- package/src/cli/completion.ts +553 -0
- package/src/cli/formatter.ts +310 -0
- package/src/cli/index.ts +211 -0
- package/src/cli/main.ts +23 -0
- package/src/cli/repl.ts +1050 -0
- package/src/cli/simple-cli.js +211 -0
- package/src/cli/simple-cli.ts +211 -0
- package/src/coordination/README.md +400 -0
- package/src/coordination/advanced-scheduler.ts +487 -0
- package/src/coordination/circuit-breaker.ts +366 -0
- package/src/coordination/conflict-resolution.ts +490 -0
- package/src/coordination/dependency-graph.ts +475 -0
- package/src/coordination/index.ts +63 -0
- package/src/coordination/manager.ts +460 -0
- package/src/coordination/messaging.ts +290 -0
- package/src/coordination/metrics.ts +585 -0
- package/src/coordination/resources.ts +322 -0
- package/src/coordination/scheduler.ts +390 -0
- package/src/coordination/work-stealing.ts +224 -0
- package/src/core/config.ts +627 -0
- package/src/core/event-bus.ts +186 -0
- package/src/core/json-persistence.ts +183 -0
- package/src/core/logger.ts +262 -0
- package/src/core/orchestrator-fixed.ts +312 -0
- package/src/core/orchestrator.ts +1234 -0
- package/src/core/persistence.ts +276 -0
- package/src/mcp/auth.ts +438 -0
- package/src/mcp/claude-flow-tools.ts +1280 -0
- package/src/mcp/load-balancer.ts +510 -0
- package/src/mcp/router.ts +240 -0
- package/src/mcp/server.ts +548 -0
- package/src/mcp/session-manager.ts +418 -0
- package/src/mcp/tools.ts +180 -0
- package/src/mcp/transports/base.ts +21 -0
- package/src/mcp/transports/http.ts +457 -0
- package/src/mcp/transports/stdio.ts +254 -0
- package/src/memory/backends/base.ts +22 -0
- package/src/memory/backends/markdown.ts +283 -0
- package/src/memory/backends/sqlite.ts +329 -0
- package/src/memory/cache.ts +238 -0
- package/src/memory/indexer.ts +238 -0
- package/src/memory/manager.ts +572 -0
- package/src/terminal/adapters/base.ts +29 -0
- package/src/terminal/adapters/native.ts +504 -0
- package/src/terminal/adapters/vscode.ts +340 -0
- package/src/terminal/manager.ts +308 -0
- package/src/terminal/pool.ts +271 -0
- package/src/terminal/session.ts +250 -0
- package/src/terminal/vscode-bridge.ts +242 -0
- package/src/utils/errors.ts +231 -0
- package/src/utils/helpers.ts +476 -0
- package/src/utils/types.ts +493 -0
|
@@ -0,0 +1,487 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Advanced task scheduler with intelligent agent selection and priority handling
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { Task, TaskStatus, CoordinationConfig, SystemEvents, AgentProfile } from '../utils/types.ts';
|
|
6
|
+
import { IEventBus } from '../core/event-bus.ts';
|
|
7
|
+
import { ILogger } from '../core/logger.ts';
|
|
8
|
+
import { TaskScheduler } from './scheduler.ts';
|
|
9
|
+
import { WorkStealingCoordinator } from './work-stealing.ts';
|
|
10
|
+
import { DependencyGraph } from './dependency-graph.ts';
|
|
11
|
+
import { CircuitBreakerManager, CircuitBreakerConfig } from './circuit-breaker.ts';
|
|
12
|
+
|
|
13
|
+
export interface SchedulingStrategy {
|
|
14
|
+
name: string;
|
|
15
|
+
selectAgent(task: Task, agents: AgentProfile[], context: SchedulingContext): string | null;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface SchedulingContext {
|
|
19
|
+
taskLoads: Map<string, number>;
|
|
20
|
+
agentCapabilities: Map<string, string[]>;
|
|
21
|
+
agentPriorities: Map<string, number>;
|
|
22
|
+
taskHistory: Map<string, TaskStats>;
|
|
23
|
+
currentTime: Date;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export interface TaskStats {
|
|
27
|
+
totalExecutions: number;
|
|
28
|
+
avgDuration: number;
|
|
29
|
+
successRate: number;
|
|
30
|
+
lastAgent?: string;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Capability-based scheduling strategy
|
|
35
|
+
*/
|
|
36
|
+
export class CapabilitySchedulingStrategy implements SchedulingStrategy {
|
|
37
|
+
name = 'capability';
|
|
38
|
+
|
|
39
|
+
selectAgent(task: Task, agents: AgentProfile[], context: SchedulingContext): string | null {
|
|
40
|
+
// Filter agents by capability match
|
|
41
|
+
const capableAgents = agents.filter(agent => {
|
|
42
|
+
const capabilities = context.agentCapabilities.get(agent.id) || agent.capabilities;
|
|
43
|
+
return task.type === 'any' ||
|
|
44
|
+
capabilities.includes(task.type) ||
|
|
45
|
+
capabilities.includes('*');
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
if (capableAgents.length === 0) {
|
|
49
|
+
return null;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Sort by load (ascending) and priority (descending)
|
|
53
|
+
capableAgents.sort((a, b) => {
|
|
54
|
+
const loadA = context.taskLoads.get(a.id) || 0;
|
|
55
|
+
const loadB = context.taskLoads.get(b.id) || 0;
|
|
56
|
+
|
|
57
|
+
if (loadA !== loadB) {
|
|
58
|
+
return loadA - loadB;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const priorityA = context.agentPriorities.get(a.id) || a.priority;
|
|
62
|
+
const priorityB = context.agentPriorities.get(b.id) || b.priority;
|
|
63
|
+
|
|
64
|
+
return priorityB - priorityA;
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
return capableAgents[0].id;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Round-robin scheduling strategy
|
|
73
|
+
*/
|
|
74
|
+
export class RoundRobinSchedulingStrategy implements SchedulingStrategy {
|
|
75
|
+
name = 'round-robin';
|
|
76
|
+
private lastIndex = 0;
|
|
77
|
+
|
|
78
|
+
selectAgent(task: Task, agents: AgentProfile[], context: SchedulingContext): string | null {
|
|
79
|
+
if (agents.length === 0) {
|
|
80
|
+
return null;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
this.lastIndex = (this.lastIndex + 1) % agents.length;
|
|
84
|
+
return agents[this.lastIndex].id;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Least-loaded scheduling strategy
|
|
90
|
+
*/
|
|
91
|
+
export class LeastLoadedSchedulingStrategy implements SchedulingStrategy {
|
|
92
|
+
name = 'least-loaded';
|
|
93
|
+
|
|
94
|
+
selectAgent(task: Task, agents: AgentProfile[], context: SchedulingContext): string | null {
|
|
95
|
+
if (agents.length === 0) {
|
|
96
|
+
return null;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
let minLoad = Infinity;
|
|
100
|
+
let selectedAgent: string | null = null;
|
|
101
|
+
|
|
102
|
+
for (const agent of agents) {
|
|
103
|
+
const load = context.taskLoads.get(agent.id) || 0;
|
|
104
|
+
if (load < minLoad) {
|
|
105
|
+
minLoad = load;
|
|
106
|
+
selectedAgent = agent.id;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
return selectedAgent;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Affinity-based scheduling strategy (prefers agents that previously executed similar tasks)
|
|
116
|
+
*/
|
|
117
|
+
export class AffinitySchedulingStrategy implements SchedulingStrategy {
|
|
118
|
+
name = 'affinity';
|
|
119
|
+
|
|
120
|
+
selectAgent(task: Task, agents: AgentProfile[], context: SchedulingContext): string | null {
|
|
121
|
+
const taskStats = context.taskHistory.get(task.type);
|
|
122
|
+
|
|
123
|
+
if (taskStats?.lastAgent) {
|
|
124
|
+
// Check if the last agent is available
|
|
125
|
+
const lastAgent = agents.find(a => a.id === taskStats.lastAgent);
|
|
126
|
+
if (lastAgent) {
|
|
127
|
+
const load = context.taskLoads.get(lastAgent.id) || 0;
|
|
128
|
+
// Use last agent if not overloaded
|
|
129
|
+
if (load < lastAgent.maxConcurrentTasks * 0.8) {
|
|
130
|
+
return lastAgent.id;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// Fall back to capability-based selection
|
|
136
|
+
return new CapabilitySchedulingStrategy().selectAgent(task, agents, context);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Advanced task scheduler with multiple strategies
|
|
142
|
+
*/
|
|
143
|
+
export class AdvancedTaskScheduler extends TaskScheduler {
|
|
144
|
+
private strategies = new Map<string, SchedulingStrategy>();
|
|
145
|
+
private activeAgents = new Map<string, AgentProfile>();
|
|
146
|
+
private taskStats = new Map<string, TaskStats>();
|
|
147
|
+
private workStealing: WorkStealingCoordinator;
|
|
148
|
+
private dependencyGraph: DependencyGraph;
|
|
149
|
+
private circuitBreakers: CircuitBreakerManager;
|
|
150
|
+
private defaultStrategy = 'capability';
|
|
151
|
+
|
|
152
|
+
constructor(
|
|
153
|
+
config: CoordinationConfig,
|
|
154
|
+
eventBus: IEventBus,
|
|
155
|
+
logger: ILogger,
|
|
156
|
+
) {
|
|
157
|
+
super(config, eventBus, logger);
|
|
158
|
+
|
|
159
|
+
// Initialize components
|
|
160
|
+
this.workStealing = new WorkStealingCoordinator(
|
|
161
|
+
{
|
|
162
|
+
enabled: true,
|
|
163
|
+
stealThreshold: 3,
|
|
164
|
+
maxStealBatch: 2,
|
|
165
|
+
stealInterval: 5000,
|
|
166
|
+
},
|
|
167
|
+
eventBus,
|
|
168
|
+
logger,
|
|
169
|
+
);
|
|
170
|
+
|
|
171
|
+
this.dependencyGraph = new DependencyGraph(logger);
|
|
172
|
+
|
|
173
|
+
const cbConfig: CircuitBreakerConfig = {
|
|
174
|
+
failureThreshold: 3,
|
|
175
|
+
successThreshold: 2,
|
|
176
|
+
timeout: 30000,
|
|
177
|
+
halfOpenLimit: 1,
|
|
178
|
+
};
|
|
179
|
+
this.circuitBreakers = new CircuitBreakerManager(cbConfig, logger, eventBus);
|
|
180
|
+
|
|
181
|
+
// Register default strategies
|
|
182
|
+
this.registerStrategy(new CapabilitySchedulingStrategy());
|
|
183
|
+
this.registerStrategy(new RoundRobinSchedulingStrategy());
|
|
184
|
+
this.registerStrategy(new LeastLoadedSchedulingStrategy());
|
|
185
|
+
this.registerStrategy(new AffinitySchedulingStrategy());
|
|
186
|
+
|
|
187
|
+
// Set up event handlers
|
|
188
|
+
this.setupAdvancedEventHandlers();
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
override async initialize(): Promise<void> {
|
|
192
|
+
await super.initialize();
|
|
193
|
+
await this.workStealing.initialize();
|
|
194
|
+
|
|
195
|
+
this.logger.info('Advanced task scheduler initialized');
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
override async shutdown(): Promise<void> {
|
|
199
|
+
await this.workStealing.shutdown();
|
|
200
|
+
await super.shutdown();
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* Register a scheduling strategy
|
|
205
|
+
*/
|
|
206
|
+
registerStrategy(strategy: SchedulingStrategy): void {
|
|
207
|
+
this.strategies.set(strategy.name, strategy);
|
|
208
|
+
this.logger.info('Registered scheduling strategy', { name: strategy.name });
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* Set the default scheduling strategy
|
|
213
|
+
*/
|
|
214
|
+
setDefaultStrategy(name: string): void {
|
|
215
|
+
if (!this.strategies.has(name)) {
|
|
216
|
+
throw new Error(`Strategy not found: ${name}`);
|
|
217
|
+
}
|
|
218
|
+
this.defaultStrategy = name;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/**
|
|
222
|
+
* Register an agent
|
|
223
|
+
*/
|
|
224
|
+
registerAgent(profile: AgentProfile): void {
|
|
225
|
+
this.activeAgents.set(profile.id, profile);
|
|
226
|
+
this.workStealing.updateAgentWorkload(profile.id, {
|
|
227
|
+
agentId: profile.id,
|
|
228
|
+
taskCount: 0,
|
|
229
|
+
avgTaskDuration: 0,
|
|
230
|
+
cpuUsage: 0,
|
|
231
|
+
memoryUsage: 0,
|
|
232
|
+
priority: profile.priority,
|
|
233
|
+
capabilities: profile.capabilities,
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
/**
|
|
238
|
+
* Unregister an agent
|
|
239
|
+
*/
|
|
240
|
+
unregisterAgent(agentId: string): void {
|
|
241
|
+
this.activeAgents.delete(agentId);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* Override assignTask to use advanced scheduling
|
|
246
|
+
*/
|
|
247
|
+
override async assignTask(task: Task, agentId?: string): Promise<void> {
|
|
248
|
+
// Add to dependency graph
|
|
249
|
+
this.dependencyGraph.addTask(task);
|
|
250
|
+
|
|
251
|
+
// If no agent specified, select one
|
|
252
|
+
if (!agentId) {
|
|
253
|
+
const selectedAgent = await this.selectAgentForTask(task);
|
|
254
|
+
if (!selectedAgent) {
|
|
255
|
+
throw new Error('No suitable agent found for task');
|
|
256
|
+
}
|
|
257
|
+
agentId = selectedAgent;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
// Use circuit breaker for assignment
|
|
261
|
+
await this.circuitBreakers.execute(`assign-${agentId}`, async () => {
|
|
262
|
+
await super.assignTask(task, agentId!);
|
|
263
|
+
});
|
|
264
|
+
|
|
265
|
+
// Update work stealing metrics
|
|
266
|
+
const taskCount = await this.getAgentTaskCount(agentId);
|
|
267
|
+
this.workStealing.updateAgentWorkload(agentId, { taskCount });
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
/**
|
|
271
|
+
* Select the best agent for a task
|
|
272
|
+
*/
|
|
273
|
+
private async selectAgentForTask(task: Task): Promise<string | null> {
|
|
274
|
+
const availableAgents = Array.from(this.activeAgents.values());
|
|
275
|
+
if (availableAgents.length === 0) {
|
|
276
|
+
return null;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
// Build scheduling context
|
|
280
|
+
const context: SchedulingContext = {
|
|
281
|
+
taskLoads: new Map(),
|
|
282
|
+
agentCapabilities: new Map(),
|
|
283
|
+
agentPriorities: new Map(),
|
|
284
|
+
taskHistory: this.taskStats,
|
|
285
|
+
currentTime: new Date(),
|
|
286
|
+
};
|
|
287
|
+
|
|
288
|
+
// Populate context
|
|
289
|
+
for (const agent of availableAgents) {
|
|
290
|
+
const taskCount = await this.getAgentTaskCount(agent.id);
|
|
291
|
+
context.taskLoads.set(agent.id, taskCount);
|
|
292
|
+
context.agentCapabilities.set(agent.id, agent.capabilities);
|
|
293
|
+
context.agentPriorities.set(agent.id, agent.priority);
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
// Try work stealing first
|
|
297
|
+
const workStealingAgent = this.workStealing.findBestAgent(task, availableAgents);
|
|
298
|
+
if (workStealingAgent) {
|
|
299
|
+
return workStealingAgent;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
// Use configured strategy
|
|
303
|
+
const strategy = this.strategies.get(this.defaultStrategy);
|
|
304
|
+
if (!strategy) {
|
|
305
|
+
throw new Error(`Strategy not found: ${this.defaultStrategy}`);
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
return strategy.selectAgent(task, availableAgents, context);
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
/**
|
|
312
|
+
* Override completeTask to update stats and dependency graph
|
|
313
|
+
*/
|
|
314
|
+
override async completeTask(taskId: string, result: unknown): Promise<void> {
|
|
315
|
+
const task = await this.getTask(taskId);
|
|
316
|
+
if (!task) {
|
|
317
|
+
throw new Error(`Task not found: ${taskId}`);
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
// Calculate duration
|
|
321
|
+
const duration = task.startedAt
|
|
322
|
+
? new Date().getTime() - task.startedAt.getTime()
|
|
323
|
+
: 0;
|
|
324
|
+
|
|
325
|
+
// Update task stats
|
|
326
|
+
this.updateTaskStats(task.type, true, duration);
|
|
327
|
+
|
|
328
|
+
// Update work stealing metrics
|
|
329
|
+
if (task.assignedAgent) {
|
|
330
|
+
this.workStealing.recordTaskDuration(task.assignedAgent, duration);
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
// Mark as completed in dependency graph
|
|
334
|
+
const readyTasks = this.dependencyGraph.markCompleted(taskId);
|
|
335
|
+
|
|
336
|
+
// Complete the task
|
|
337
|
+
await super.completeTask(taskId, result);
|
|
338
|
+
|
|
339
|
+
// Start ready tasks
|
|
340
|
+
for (const readyTaskId of readyTasks) {
|
|
341
|
+
const readyTask = await this.getTask(readyTaskId);
|
|
342
|
+
if (readyTask) {
|
|
343
|
+
this.eventBus.emit(SystemEvents.TASK_CREATED, { task: readyTask });
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
/**
|
|
349
|
+
* Override failTask to update stats and dependency graph
|
|
350
|
+
*/
|
|
351
|
+
override async failTask(taskId: string, error: Error): Promise<void> {
|
|
352
|
+
const task = await this.getTask(taskId);
|
|
353
|
+
if (!task) {
|
|
354
|
+
throw new Error(`Task not found: ${taskId}`);
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
// Update task stats
|
|
358
|
+
this.updateTaskStats(task.type, false, 0);
|
|
359
|
+
|
|
360
|
+
// Mark as failed in dependency graph
|
|
361
|
+
const toCancelIds = this.dependencyGraph.markFailed(taskId);
|
|
362
|
+
|
|
363
|
+
// Fail the task
|
|
364
|
+
await super.failTask(taskId, error);
|
|
365
|
+
|
|
366
|
+
// Cancel dependent tasks
|
|
367
|
+
for (const cancelId of toCancelIds) {
|
|
368
|
+
await this.cancelTask(cancelId, 'Parent task failed');
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
/**
|
|
373
|
+
* Get a task by ID (helper method)
|
|
374
|
+
*/
|
|
375
|
+
private async getTask(taskId: string): Promise<Task | null> {
|
|
376
|
+
// This would need to be implemented based on how tasks are stored
|
|
377
|
+
// For now, return null
|
|
378
|
+
return null;
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
/**
|
|
382
|
+
* Update task statistics
|
|
383
|
+
*/
|
|
384
|
+
private updateTaskStats(taskType: string, success: boolean, duration: number): void {
|
|
385
|
+
const stats = this.taskStats.get(taskType) || {
|
|
386
|
+
totalExecutions: 0,
|
|
387
|
+
avgDuration: 0,
|
|
388
|
+
successRate: 0,
|
|
389
|
+
};
|
|
390
|
+
|
|
391
|
+
stats.totalExecutions++;
|
|
392
|
+
|
|
393
|
+
if (success) {
|
|
394
|
+
const successCount = Math.round(stats.successRate * (stats.totalExecutions - 1));
|
|
395
|
+
stats.successRate = (successCount + 1) / stats.totalExecutions;
|
|
396
|
+
|
|
397
|
+
if (duration > 0) {
|
|
398
|
+
const totalDuration = stats.avgDuration * (stats.totalExecutions - 1);
|
|
399
|
+
stats.avgDuration = (totalDuration + duration) / stats.totalExecutions;
|
|
400
|
+
}
|
|
401
|
+
} else {
|
|
402
|
+
const successCount = Math.round(stats.successRate * (stats.totalExecutions - 1));
|
|
403
|
+
stats.successRate = successCount / stats.totalExecutions;
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
this.taskStats.set(taskType, stats);
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
/**
|
|
410
|
+
* Set up advanced event handlers
|
|
411
|
+
*/
|
|
412
|
+
private setupAdvancedEventHandlers(): void {
|
|
413
|
+
// Handle work stealing requests
|
|
414
|
+
this.eventBus.on('workstealing:request', async (data: any) => {
|
|
415
|
+
const { sourceAgent, targetAgent, taskCount } = data;
|
|
416
|
+
|
|
417
|
+
try {
|
|
418
|
+
const tasks = await this.getAgentTasks(sourceAgent);
|
|
419
|
+
const tasksToSteal = tasks
|
|
420
|
+
.filter(t => t.status === 'queued' || t.status === 'assigned')
|
|
421
|
+
.slice(0, taskCount);
|
|
422
|
+
|
|
423
|
+
for (const task of tasksToSteal) {
|
|
424
|
+
await this.reassignTask(task.id, targetAgent);
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
this.logger.info('Work stealing completed', {
|
|
428
|
+
from: sourceAgent,
|
|
429
|
+
to: targetAgent,
|
|
430
|
+
stolenCount: tasksToSteal.length,
|
|
431
|
+
});
|
|
432
|
+
} catch (error) {
|
|
433
|
+
this.logger.error('Work stealing failed', { error });
|
|
434
|
+
}
|
|
435
|
+
});
|
|
436
|
+
|
|
437
|
+
// Update workload on task events
|
|
438
|
+
this.eventBus.on(SystemEvents.TASK_ASSIGNED, async (data: any) => {
|
|
439
|
+
const { agentId } = data;
|
|
440
|
+
const taskCount = await this.getAgentTaskCount(agentId);
|
|
441
|
+
this.workStealing.updateAgentWorkload(agentId, { taskCount });
|
|
442
|
+
});
|
|
443
|
+
|
|
444
|
+
this.eventBus.on(SystemEvents.TASK_COMPLETED, async (data: any) => {
|
|
445
|
+
const { taskId } = data;
|
|
446
|
+
// Update workload after task completion
|
|
447
|
+
// This would need the agent ID from the task
|
|
448
|
+
});
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
/**
|
|
452
|
+
* Reassign a task to a different agent
|
|
453
|
+
*/
|
|
454
|
+
private async reassignTask(taskId: string, newAgentId: string): Promise<void> {
|
|
455
|
+
// Cancel the current assignment
|
|
456
|
+
await this.cancelTask(taskId, 'Reassigning to different agent');
|
|
457
|
+
|
|
458
|
+
// Get the task
|
|
459
|
+
const task = await this.getTask(taskId);
|
|
460
|
+
if (!task) {
|
|
461
|
+
throw new Error(`Task not found: ${taskId}`);
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
// Assign to new agent
|
|
465
|
+
await this.assignTask(task, newAgentId);
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
/**
|
|
469
|
+
* Get advanced scheduling metrics
|
|
470
|
+
*/
|
|
471
|
+
async getSchedulingMetrics(): Promise<Record<string, unknown>> {
|
|
472
|
+
const baseMetrics = await this.getHealthStatus();
|
|
473
|
+
const workloadStats = this.workStealing.getWorkloadStats();
|
|
474
|
+
const depGraphStats = this.dependencyGraph.getStats();
|
|
475
|
+
const cbMetrics = this.circuitBreakers.getAllMetrics();
|
|
476
|
+
|
|
477
|
+
return {
|
|
478
|
+
...baseMetrics.metrics,
|
|
479
|
+
workStealing: workloadStats,
|
|
480
|
+
dependencies: depGraphStats,
|
|
481
|
+
circuitBreakers: cbMetrics,
|
|
482
|
+
taskStats: Object.fromEntries(this.taskStats),
|
|
483
|
+
activeStrategies: Array.from(this.strategies.keys()),
|
|
484
|
+
defaultStrategy: this.defaultStrategy,
|
|
485
|
+
};
|
|
486
|
+
}
|
|
487
|
+
}
|