claude-flow
Version:
Enterprise-grade AI agent orchestration with ruv-swarm integration (Alpha Release)
796 lines (681 loc) • 28 kB
text/typescript
// Extended TaskType for auto strategy (extends base TaskType)
export type ExtendedTaskType =
| 'data-analysis' | 'performance-analysis' | 'statistical-analysis'
| 'visualization' | 'predictive-modeling' | 'anomaly-detection'
| 'trend-analysis' | 'business-intelligence' | 'quality-analysis'
| 'system-design' | 'architecture-review' | 'api-design'
| 'cloud-architecture' | 'microservices-design' | 'security-architecture'
| 'scalability-design' | 'database-architecture'
| 'code-generation' | 'code-review' | 'refactoring' | 'debugging'
| 'api-development' | 'database-design' | 'performance-optimization'
| 'task-orchestration' | 'progress-tracking' | 'resource-allocation'
| 'workflow-management' | 'team-coordination' | 'status-reporting'
| 'fact-check' | 'literature-review' | 'market-analysis'
| 'unit-testing' | 'integration-testing' | 'e2e-testing'
| 'performance-testing' | 'security-testing' | 'api-testing'
| 'test-automation' | 'test-analysis';
import { getErrorMessage } from '../../utils/error-handler.js';
/**
* Optimized AUTO Strategy Implementation
* Uses machine learning-inspired heuristics and intelligent task decomposition
*/
import { BaseStrategy } from './base.js';
import type { DecompositionResult, TaskBatch, AgentAllocation, TaskPattern } from './base.js';
import type { SwarmObjective, TaskDefinition, AgentState, TaskType, TaskPriority, TaskId, AgentType } from '../types.js';
import { generateId } from '../../utils/helpers.js';
interface MLHeuristics {
taskTypeWeights: Record<string, number>;
agentPerformanceHistory: Map<string, number>;
complexityFactors: Record<string, number>;
parallelismOpportunities: string[];
}
interface PredictiveSchedule {
timeline: ScheduleSlot[];
resourceUtilization: Record<string, number>;
bottlenecks: string[];
optimizationSuggestions: string[];
}
interface ScheduleSlot {
startTime: number;
endTime: number;
tasks: string[];
agents: string[];
dependencies: string[];
}
export class AutoStrategy extends BaseStrategy {
private mlHeuristics: MLHeuristics;
private decompositionCache: Map<string, DecompositionResult>;
private patternCache: Map<string, TaskPattern[]>;
private performanceHistory: Map<string, number[]>;
constructor(config: any) {
super(config);
this.mlHeuristics = this.initializeMLHeuristics();
this.decompositionCache = new Map();
this.patternCache = new Map();
this.performanceHistory = new Map();
}
/**
* Enhanced objective decomposition with async processing and intelligent batching
*/
override async decomposeObjective(objective: SwarmObjective): Promise<DecompositionResult> {
const startTime = Date.now();
const cacheKey = this.getCacheKey(objective);
// Check cache first
if (this.decompositionCache.has(cacheKey)) {
this.metrics.cacheHitRate = (this.metrics.cacheHitRate + 1) / 2;
return this.decompositionCache.get(cacheKey)!;
}
// Parallel pattern detection and task type analysis
const [detectedPatterns, taskTypes, complexity] = await Promise.all([
this.detectPatternsAsync(objective.description),
this.analyzeTaskTypesAsync(objective.description),
this.estimateComplexityAsync(objective.description)
]);
// Generate tasks based on detected patterns and strategy
const tasks = await this.generateTasksWithBatching(objective, detectedPatterns, taskTypes, complexity);
// Analyze dependencies and create batches
const dependencies = this.analyzeDependencies(tasks);
const batchGroups = this.createTaskBatches(tasks, dependencies);
// Estimate total duration with parallel processing consideration
const estimatedDuration = this.calculateOptimizedDuration(batchGroups);
const result: DecompositionResult = {
tasks,
dependencies,
estimatedDuration,
recommendedStrategy: this.selectOptimalStrategy(objective, complexity),
complexity,
batchGroups,
timestamp: new Date(),
ttl: 1800000, // 30 minutes
accessCount: 0,
lastAccessed: new Date(),
data: { objectiveId: objective.id, strategy: 'auto' }
};
// Cache the result
this.decompositionCache.set(cacheKey, result);
this.updateMetrics(result, Date.now() - startTime);
return result;
}
/**
* ML-inspired agent selection with performance history consideration
*/
override async selectAgentForTask(task: TaskDefinition, availableAgents: AgentState[]): Promise<string | null> {
if (availableAgents.length === 0) return null;
// Score agents using ML heuristics
const scoredAgents = await Promise.all(
availableAgents.map(async (agent) => ({
agent,
score: await this.calculateAgentScore(agent, task)
}))
);
// Sort by score and select best agent
scoredAgents.sort((a, b) => b.score - a.score);
// Update performance history
const selectedAgent = scoredAgents[0].agent;
this.updateAgentPerformanceHistory(selectedAgent.id.id, scoredAgents[0].score);
return selectedAgent.id.id;
}
/**
* Predictive task scheduling with dynamic agent allocation
*/
override async optimizeTaskSchedule(tasks: TaskDefinition[], agents: AgentState[]): Promise<AgentAllocation[]> {
const schedule = await this.createPredictiveSchedule(tasks, agents);
return this.allocateAgentsOptimally(tasks, agents, schedule);
}
// Private implementation methods
private initializeMLHeuristics(): MLHeuristics {
return {
taskTypeWeights: {
'development': 1.0,
'testing': 0.8,
'analysis': 0.9,
'documentation': 0.6,
'optimization': 1.1,
'research': 0.7
},
agentPerformanceHistory: new Map(),
complexityFactors: {
'integration': 1.5,
'system': 1.3,
'api': 1.2,
'database': 1.4,
'ui': 1.1,
'algorithm': 1.6
},
parallelismOpportunities: [
'independent modules',
'separate components',
'different layers',
'parallel testing',
'concurrent analysis'
]
};
}
private async detectPatternsAsync(description: string): Promise<TaskPattern[]> {
const cacheKey = `patterns-${description.slice(0, 50)}`;
if (this.patternCache.has(cacheKey)) {
return this.patternCache.get(cacheKey)!;
}
// Simulate async pattern detection with enhanced matching
return new Promise((resolve) => {
setTimeout(() => {
const patterns = this.taskPatterns.filter(pattern =>
pattern.pattern.test(description)
);
// Add dynamic patterns based on content analysis
const dynamicPatterns = this.generateDynamicPatterns(description);
const allPatterns = [...patterns, ...dynamicPatterns];
this.patternCache.set(cacheKey, allPatterns);
resolve(allPatterns);
}, 10); // Simulate async processing
});
}
private async analyzeTaskTypesAsync(description: string): Promise<string[]> {
return new Promise((resolve) => {
setTimeout(() => {
const types = [];
// Enhanced task type detection
if (/create|build|implement|develop|code/i.test(description)) {
types.push('development');
}
if (/test|verify|validate|check/i.test(description)) {
types.push('testing');
}
if (/analyze|research|investigate|study/i.test(description)) {
types.push('analysis');
}
if (/document|write|explain|describe/i.test(description)) {
types.push('documentation');
}
if (/optimize|improve|enhance|refactor/i.test(description)) {
types.push('optimization');
}
if (/deploy|install|configure|setup/i.test(description)) {
types.push('deployment');
}
resolve(types.length > 0 ? types : ['generic']);
}, 5);
});
}
private async estimateComplexityAsync(description: string): Promise<number> {
return new Promise((resolve) => {
setTimeout(() => {
let complexity = this.estimateComplexity(description);
// Apply ML heuristics for complexity adjustment
for (const [factor, weight] of Object.entries(this.mlHeuristics.complexityFactors)) {
if (description.toLowerCase().includes(factor)) {
complexity *= weight;
}
}
resolve(Math.min(Math.round(complexity), 5));
}, 5);
});
}
private generateDynamicPatterns(description: string): TaskPattern[] {
const patterns: TaskPattern[] = [];
// Generate patterns based on specific keywords and context
if (description.includes('API') || description.includes('endpoint')) {
patterns.push({
pattern: /api|endpoint|service/i,
type: 'api-development',
complexity: 3,
estimatedDuration: 20 * 60 * 1000,
requiredAgents: 2,
priority: 2
});
}
if (description.includes('database') || description.includes('data')) {
patterns.push({
pattern: /database|data|storage/i,
type: 'data-management',
complexity: 3,
estimatedDuration: 18 * 60 * 1000,
requiredAgents: 2,
priority: 2
});
}
return patterns;
}
private async generateTasksWithBatching(
objective: SwarmObjective,
patterns: TaskPattern[],
taskTypes: string[],
complexity: number
): Promise<TaskDefinition[]> {
const tasks: TaskDefinition[] = [];
// Determine strategy-specific task generation
if (objective.strategy === 'development') {
tasks.push(...await this.generateDevelopmentTasks(objective, complexity));
} else if (objective.strategy === 'analysis') {
tasks.push(...await this.generateAnalysisTasks(objective, complexity));
} else {
// Auto strategy - intelligent task generation based on patterns
tasks.push(...await this.generateAutoTasks(objective, patterns, taskTypes, complexity));
}
return tasks;
}
private async generateDevelopmentTasks(objective: SwarmObjective, complexity: number): Promise<TaskDefinition[]> {
const tasks: TaskDefinition[] = [];
const baseId = generateId('task');
// Analysis and Planning Phase
tasks.push(this.createTaskDefinition({
id: `${baseId}-analysis`,
type: 'analysis' as TaskType,
name: 'Requirements Analysis and Planning',
description: `Analyze requirements and create implementation plan for: ${objective.description}`,
priority: 'high' as TaskPriority,
estimatedDuration: Math.max(5 * 60 * 1000, complexity * 3 * 60 * 1000),
capabilities: ['analysis', 'documentation', 'research']
}));
// Implementation Phase (can be parallelized)
const implementationTasks = this.createParallelImplementationTasks(objective, complexity, baseId);
tasks.push(...implementationTasks);
// Testing Phase
tasks.push(this.createTaskDefinition({
id: `${baseId}-testing`,
type: 'testing' as TaskType,
name: 'Comprehensive Testing',
description: `Create and execute tests for the implementation`,
priority: 'high' as TaskPriority,
estimatedDuration: Math.max(8 * 60 * 1000, complexity * 4 * 60 * 1000),
capabilities: ['testing', 'code-generation'],
dependencies: implementationTasks.map(t => t.id.id)
}));
// Documentation Phase
tasks.push(this.createTaskDefinition({
id: `${baseId}-documentation`,
type: 'documentation' as TaskType,
name: 'Documentation Creation',
description: `Create comprehensive documentation`,
priority: 'medium' as TaskPriority,
estimatedDuration: Math.max(5 * 60 * 1000, complexity * 2 * 60 * 1000),
capabilities: ['documentation'],
dependencies: implementationTasks.map(t => t.id.id)
}));
return tasks;
}
private createParallelImplementationTasks(objective: SwarmObjective, complexity: number, baseId: string): TaskDefinition[] {
const tasks: TaskDefinition[] = [];
// Determine if we can split implementation into parallel tasks
const canParallelize = this.canParallelizeImplementation(objective.description);
if (canParallelize && complexity >= 3) {
// Create multiple parallel implementation tasks
const components = this.identifyComponents(objective.description);
components.forEach((component, index) => {
tasks.push(this.createTaskDefinition({
id: `${baseId}-impl-${index}`,
type: 'coding' as TaskType,
name: `Implement ${component}`,
description: `Implement ${component} component for: ${objective.description}`,
priority: 'high' as TaskPriority,
estimatedDuration: Math.max(10 * 60 * 1000, complexity * 5 * 60 * 1000),
capabilities: ['code-generation', 'file-system'],
dependencies: [`${baseId}-analysis`]
}));
});
} else {
// Single implementation task
tasks.push(this.createTaskDefinition({
id: `${baseId}-implementation`,
type: 'coding' as TaskType,
name: 'Core Implementation',
description: `Implement the solution for: ${objective.description}`,
priority: 'high' as TaskPriority,
estimatedDuration: Math.max(15 * 60 * 1000, complexity * 8 * 60 * 1000),
capabilities: ['code-generation', 'file-system'],
dependencies: [`${baseId}-analysis`]
}));
}
return tasks;
}
private async generateAnalysisTasks(objective: SwarmObjective, complexity: number): Promise<TaskDefinition[]> {
const tasks: TaskDefinition[] = [];
const baseId = generateId('task');
// Data Collection
tasks.push(this.createTaskDefinition({
id: `${baseId}-collection`,
type: 'research' as TaskType,
name: 'Data Collection and Research',
description: `Collect and research data for: ${objective.description}`,
priority: 'high' as TaskPriority,
estimatedDuration: Math.max(8 * 60 * 1000, complexity * 4 * 60 * 1000),
capabilities: ['research', 'analysis', 'web-search']
}));
// Analysis
tasks.push(this.createTaskDefinition({
id: `${baseId}-analysis`,
type: 'analysis' as TaskType,
name: 'Data Analysis',
description: `Analyze collected data and generate insights`,
priority: 'high' as TaskPriority,
estimatedDuration: Math.max(10 * 60 * 1000, complexity * 5 * 60 * 1000),
capabilities: ['analysis', 'documentation'],
dependencies: [`${baseId}-collection`]
}));
// Reporting
tasks.push(this.createTaskDefinition({
id: `${baseId}-reporting`,
type: 'documentation' as TaskType,
name: 'Analysis Report',
description: `Create comprehensive analysis report`,
priority: 'medium' as TaskPriority,
estimatedDuration: Math.max(6 * 60 * 1000, complexity * 3 * 60 * 1000),
capabilities: ['documentation', 'analysis'],
dependencies: [`${baseId}-analysis`]
}));
return tasks;
}
private async generateAutoTasks(
objective: SwarmObjective,
patterns: TaskPattern[],
taskTypes: string[],
complexity: number
): Promise<TaskDefinition[]> {
const tasks: TaskDefinition[] = [];
const baseId = generateId('task');
// Use ML heuristics to determine optimal task structure
const optimalStructure = this.determineOptimalTaskStructure(patterns, taskTypes, complexity);
if (optimalStructure.requiresAnalysis) {
tasks.push(this.createTaskDefinition({
id: `${baseId}-analysis`,
type: 'analysis' as TaskType,
name: 'Intelligent Analysis',
description: `Analyze and understand: ${objective.description}`,
priority: 'high' as TaskPriority,
estimatedDuration: optimalStructure.analysisDuration,
capabilities: ['analysis', 'research']
}));
}
if (optimalStructure.requiresImplementation) {
const implTasks = this.createOptimalImplementationTasks(objective, optimalStructure, baseId);
tasks.push(...implTasks);
}
if (optimalStructure.requiresTesting) {
tasks.push(this.createTaskDefinition({
id: `${baseId}-testing`,
type: 'testing' as TaskType,
name: 'Intelligent Testing',
description: `Test and validate the solution`,
priority: 'high' as TaskPriority,
estimatedDuration: optimalStructure.testingDuration,
capabilities: ['testing', 'validation'],
dependencies: tasks.filter(t => t.type === 'coding').map(t => t.id.id)
}));
}
return tasks;
}
private createTaskDefinition(params: {
id: string;
type: TaskType;
name: string;
description: string;
priority: TaskPriority;
estimatedDuration: number;
capabilities: string[];
dependencies?: string[];
}): TaskDefinition {
const taskId: TaskId = {
id: params.id,
swarmId: 'auto-strategy',
sequence: 1,
priority: 1
};
return {
id: taskId,
type: params.type,
name: params.name,
description: params.description,
instructions: params.description,
requirements: {
capabilities: params.capabilities,
tools: this.getRequiredTools(params.type),
permissions: ['read', 'write', 'execute']
},
constraints: {
dependencies: (params.dependencies || []).map(dep => ({ id: dep, swarmId: 'auto-strategy', sequence: 1, priority: 1 })),
dependents: [],
conflicts: [],
maxRetries: 3,
timeoutAfter: params.estimatedDuration
},
priority: params.priority,
input: { description: params.description },
context: {},
examples: [],
status: 'created',
createdAt: new Date(),
updatedAt: new Date(),
attempts: [],
statusHistory: [{
timestamp: new Date(),
from: 'created',
to: 'created',
reason: 'Task created by AutoStrategy',
triggeredBy: 'system'
}]
};
}
private getRequiredTools(type: TaskType): string[] {
const toolMap: Record<string, string[]> = {
'coding': ['file-system', 'terminal', 'editor'],
'testing': ['test-runner', 'file-system', 'terminal'],
'analysis': ['analyst', 'file-system', 'web-search'],
'documentation': ['editor', 'file-system'],
'research': ['web-search', 'analyst', 'file-system'],
'review': ['analyst', 'file-system'],
'deployment': ['terminal', 'file-system', 'deployment-tools'],
'monitoring': ['monitoring-tools', 'analyst'],
'coordination': ['communication-tools'],
'communication': ['communication-tools'],
'maintenance': ['file-system', 'terminal', 'monitoring-tools'],
'optimization': ['analyst', 'profiler', 'file-system'],
'validation': ['validator', 'test-runner'],
'integration': ['integration-tools', 'file-system', 'terminal'],
'custom': ['file-system']
};
return toolMap[type] || ['file-system'];
}
// Additional helper methods would continue here...
// (Truncated for brevity - the full implementation would include all helper methods)
private canParallelizeImplementation(description: string): boolean {
const parallelKeywords = ['components', 'modules', 'services', 'layers', 'parts'];
return parallelKeywords.some(keyword => description.toLowerCase().includes(keyword));
}
private identifyComponents(description: string): string[] {
// Simple component identification - in a real implementation this would be more sophisticated
const components = ['Core Logic', 'User Interface', 'Data Layer'];
if (description.toLowerCase().includes('api')) {
components.push('API Layer');
}
if (description.toLowerCase().includes('database')) {
components.push('Database Integration');
}
return components.slice(0, 3); // Limit to 3 parallel components
}
private determineOptimalTaskStructure(patterns: TaskPattern[], taskTypes: string[], complexity: number) {
return {
requiresAnalysis: complexity >= 2 || taskTypes.includes('analysis'),
requiresImplementation: taskTypes.includes('development') || taskTypes.includes('coding'),
requiresTesting: complexity >= 2 || taskTypes.includes('testing'),
analysisDuration: Math.max(5 * 60 * 1000, complexity * 3 * 60 * 1000),
testingDuration: Math.max(5 * 60 * 1000, complexity * 4 * 60 * 1000)
};
}
private createOptimalImplementationTasks(objective: SwarmObjective, structure: any, baseId: string): TaskDefinition[] {
return [this.createTaskDefinition({
id: `${baseId}-implementation`,
type: 'coding' as TaskType,
name: 'Optimal Implementation',
description: `Implement solution for: ${objective.description}`,
priority: 'high' as TaskPriority,
estimatedDuration: Math.max(15 * 60 * 1000, structure.complexity * 8 * 60 * 1000),
capabilities: ['code-generation', 'file-system'],
dependencies: structure.requiresAnalysis ? [`${baseId}-analysis`] : []
})];
}
private analyzeDependencies(tasks: TaskDefinition[]): Map<string, string[]> {
const dependencies = new Map<string, string[]>();
tasks.forEach(task => {
if (task.constraints.dependencies.length > 0) {
dependencies.set(task.id.id, task.constraints.dependencies.map(dep => dep.id));
}
});
return dependencies;
}
private createTaskBatches(tasks: TaskDefinition[], dependencies: Map<string, string[]>): TaskBatch[] {
const batches: TaskBatch[] = [];
const processed = new Set<string>();
let batchIndex = 0;
while (processed.size < tasks.length) {
const batchTasks = tasks.filter(task =>
!processed.has(task.id.id) &&
task.constraints.dependencies.every(dep => processed.has(dep.id))
);
if (batchTasks.length === 0) break; // Prevent infinite loop
const batch: TaskBatch = {
id: `batch-${batchIndex++}`,
tasks: batchTasks,
canRunInParallel: batchTasks.length > 1,
estimatedDuration: Math.max(...batchTasks.map(t => t.constraints.timeoutAfter || 0)),
requiredResources: this.calculateBatchResources(batchTasks)
};
batches.push(batch);
batchTasks.forEach(task => processed.add(task.id.id));
}
return batches;
}
private calculateBatchResources(tasks: TaskDefinition[]): Record<string, number> {
return {
agents: tasks.length,
memory: tasks.length * 512, // MB
cpu: tasks.length * 0.5 // CPU cores
};
}
private calculateOptimizedDuration(batches: TaskBatch[]): number {
return batches.reduce((total, batch) => total + batch.estimatedDuration, 0);
}
private selectOptimalStrategy(objective: SwarmObjective, complexity: number): string {
if (complexity >= 4) return 'development';
if (objective.description.toLowerCase().includes('analyze')) return 'analysis';
if (objective.description.toLowerCase().includes('test')) return 'testing';
return 'auto';
}
private async calculateAgentScore(agent: AgentState, task: TaskDefinition): Promise<number> {
let score = 0;
// Capability matching (40%)
const capabilityMatch = this.calculateCapabilityMatch(agent, task);
score += capabilityMatch * 0.4;
// Performance history (30%)
const performanceScore = this.getAgentPerformanceScore(agent.id.id);
score += performanceScore * 0.3;
// Current workload (20%)
const workloadScore = 1 - agent.workload;
score += workloadScore * 0.2;
// ML heuristics adjustment (10%)
const mlScore = this.applyMLHeuristics(agent, task);
score += mlScore * 0.1;
return score;
}
private calculateCapabilityMatch(agent: AgentState, task: TaskDefinition): number {
const requiredCaps = task.requirements.capabilities;
let matches = 0;
for (const cap of requiredCaps) {
if (this.agentHasCapability(agent, cap)) {
matches++;
}
}
return requiredCaps.length > 0 ? matches / requiredCaps.length : 1.0;
}
private agentHasCapability(agent: AgentState, capability: string): boolean {
const caps = agent.capabilities;
switch (capability) {
case 'code-generation': return caps.codeGeneration;
case 'code-review': return caps.codeReview;
case 'testing': return caps.testing;
case 'documentation': return caps.documentation;
case 'research': return caps.research;
case 'analysis': return caps.analysis;
case 'web-search': return caps.webSearch;
case 'api-integration': return caps.apiIntegration;
case 'file-system': return caps.fileSystem;
case 'terminal-access': return caps.terminalAccess;
default:
return caps.domains.includes(capability) ||
caps.languages.includes(capability) ||
caps.frameworks.includes(capability) ||
caps.tools.includes(capability);
}
}
private getAgentPerformanceScore(agentId: string): number {
const history = this.performanceHistory.get(agentId);
if (!history || history.length === 0) return 0.8; // Default score
const average = history.reduce((sum, score) => sum + score, 0) / history.length;
return Math.min(average, 1.0);
}
private applyMLHeuristics(agent: AgentState, task: TaskDefinition): number {
const taskType = this.detectTaskType(task.description);
const weight = this.mlHeuristics.taskTypeWeights[taskType] || 1.0;
// Apply agent type bonus
let bonus = 0;
if (agent.type === 'coder' && taskType === 'development') bonus = 0.2;
if (agent.type === 'tester' && taskType === 'testing') bonus = 0.2;
if (agent.type === 'analyst' && taskType === 'analysis') bonus = 0.2;
return Math.min(weight + bonus, 1.0);
}
private updateAgentPerformanceHistory(agentId: string, score: number): void {
if (!this.performanceHistory.has(agentId)) {
this.performanceHistory.set(agentId, []);
}
const history = this.performanceHistory.get(agentId)!;
history.push(score);
// Keep only last 10 scores
if (history.length > 10) {
history.shift();
}
}
private async createPredictiveSchedule(tasks: TaskDefinition[], agents: AgentState[]): Promise<PredictiveSchedule> {
// Simplified predictive scheduling implementation
const timeline: ScheduleSlot[] = [];
let currentTime = Date.now();
for (const task of tasks) {
const duration = task.constraints.timeoutAfter || 300000; // 5 min default
timeline.push({
startTime: currentTime,
endTime: currentTime + duration,
tasks: [task.id.id],
agents: [], // To be filled by allocation
dependencies: task.constraints.dependencies.map(dep => dep.id)
});
currentTime += duration;
}
return {
timeline,
resourceUtilization: { cpu: 0.7, memory: 0.6 },
bottlenecks: [],
optimizationSuggestions: ['Consider parallel execution for independent tasks']
};
}
private allocateAgentsOptimally(
tasks: TaskDefinition[],
agents: AgentState[],
schedule: PredictiveSchedule
): AgentAllocation[] {
const allocations: AgentAllocation[] = [];
agents.forEach(agent => {
const suitableTasks = tasks.filter(task =>
this.calculateCapabilityMatch(agent, task) > 0.5
);
if (suitableTasks.length > 0) {
allocations.push({
agentId: agent.id.id,
tasks: suitableTasks.slice(0, 3).map(t => t.id.id), // Limit to 3 tasks per agent
estimatedWorkload: suitableTasks.length * 0.3,
capabilities: Object.keys(agent.capabilities).filter(cap =>
(agent.capabilities as any)[cap] === true
)
});
}
});
return allocations;
}
}