claude-flow
Version:
Ruflo - Enterprise AI agent orchestration for Claude Code. Deploy 60+ specialized agents in coordinated swarms with self-learning, fault-tolerant consensus, vector memory, and MCP integration
326 lines • 11.9 kB
JavaScript
/**
* V3 Task Lifecycle Hooks
*
* Provides pre-task and post-task hooks for task execution lifecycle.
* Integrates with ReasoningBank for learning and pattern recognition.
*
* @module v3/shared/hooks/task-hooks
*/
import { HookEvent, HookPriority, } from './types.js';
/**
* Task Hooks Manager
*
* Manages pre-task and post-task hooks with ReasoningBank integration.
*/
export class TaskHooksManager {
registry;
activeTasks = new Map();
taskPatterns = new Map();
constructor(registry) {
this.registry = registry;
this.registerDefaultHooks();
}
/**
* Register default task hooks
*/
registerDefaultHooks() {
// Pre-task hook for agent suggestion
this.registry.register(HookEvent.PreTaskExecute, this.handlePreTask.bind(this), HookPriority.Normal, { name: 'task-hooks:pre-task' });
// Post-task hook for learning
this.registry.register(HookEvent.PostTaskExecute, this.handlePostTask.bind(this), HookPriority.Normal, { name: 'task-hooks:post-task' });
}
/**
* Handle pre-task execution
*/
async handlePreTask(context) {
const task = context.task;
if (!task) {
return { success: false, error: new Error('No task in context') };
}
// Store task for tracking
const taskStore = {
taskId: task.id,
description: task.description,
startTime: Date.now(),
metadata: task.metadata,
};
// Analyze task and suggest agents
const analysis = await this.analyzeTask(task);
taskStore.suggestedAgents = analysis.suggestedAgents;
this.activeTasks.set(task.id, taskStore);
// Store patterns for this task
if (analysis.patterns.length > 0) {
this.taskPatterns.set(task.id, analysis.patterns);
}
return {
success: true,
suggestedAgents: analysis.suggestedAgents,
complexity: analysis.complexity,
estimatedDuration: analysis.estimatedDuration,
patterns: analysis.patterns,
risks: analysis.risks,
recommendations: analysis.recommendations,
data: {
task: {
...task,
metadata: {
...task.metadata,
suggestedAgents: analysis.suggestedAgents.map(a => a.type),
complexity: analysis.complexity,
},
},
},
};
}
/**
* Handle post-task execution
*/
async handlePostTask(context) {
const task = context.task;
if (!task) {
return { success: false, error: new Error('No task in context') };
}
const taskStore = this.activeTasks.get(task.id);
const patterns = this.taskPatterns.get(task.id);
// Calculate duration
const duration = taskStore ? Date.now() - taskStore.startTime : 0;
// Extract outcome from context metadata
const success = context.metadata?.success !== false;
const quality = context.metadata?.quality;
const error = context.metadata?.error;
const agent = context.metadata?.agent;
const outcome = {
success,
duration,
quality,
error,
agent,
artifacts: context.metadata?.artifacts,
};
// Record learning trajectory
const learningUpdates = await this.recordLearning(task, outcome, patterns);
// Clean up
this.activeTasks.delete(task.id);
this.taskPatterns.delete(task.id);
return {
success: true,
outcome,
learningUpdates,
patternId: learningUpdates.newPatterns > 0 ? `pattern-${task.id}` : undefined,
trajectoryId: `trajectory-${task.id}-${Date.now()}`,
};
}
/**
* Analyze task for agent suggestions and patterns
*/
async analyzeTask(task) {
const description = task.description.toLowerCase();
// Pattern-based agent suggestion
const suggestedAgents = [];
const patterns = [];
const risks = [];
const recommendations = [];
// Analyze task keywords for agent routing
const agentPatterns = [
{
keywords: ['implement', 'code', 'create', 'build', 'develop', 'write'],
agent: 'coder',
capabilities: ['code-generation', 'implementation', 'debugging'],
},
{
keywords: ['test', 'spec', 'coverage', 'unit', 'integration'],
agent: 'tester',
capabilities: ['unit-testing', 'integration-testing', 'coverage-analysis'],
},
{
keywords: ['review', 'check', 'audit', 'analyze'],
agent: 'reviewer',
capabilities: ['code-review', 'quality-analysis', 'best-practices'],
},
{
keywords: ['research', 'investigate', 'explore', 'study'],
agent: 'researcher',
capabilities: ['research', 'analysis', 'documentation'],
},
{
keywords: ['security', 'vulnerability', 'cve', 'threat'],
agent: 'security-architect',
capabilities: ['security-analysis', 'vulnerability-detection', 'threat-modeling'],
},
{
keywords: ['performance', 'optimize', 'speed', 'memory'],
agent: 'performance-engineer',
capabilities: ['performance-optimization', 'profiling', 'benchmarking'],
},
{
keywords: ['architect', 'design', 'structure', 'pattern'],
agent: 'core-architect',
capabilities: ['architecture-design', 'pattern-application', 'system-design'],
},
{
keywords: ['memory', 'storage', 'database', 'cache'],
agent: 'memory-specialist',
capabilities: ['memory-management', 'data-persistence', 'caching'],
},
{
keywords: ['swarm', 'coordinate', 'orchestrate', 'agent'],
agent: 'swarm-specialist',
capabilities: ['swarm-coordination', 'agent-orchestration', 'distributed-systems'],
},
];
// Score each agent based on keyword matches
for (const pattern of agentPatterns) {
let matchCount = 0;
for (const keyword of pattern.keywords) {
if (description.includes(keyword)) {
matchCount++;
}
}
if (matchCount > 0) {
const confidence = Math.min(0.3 + matchCount * 0.2, 0.95);
suggestedAgents.push({
type: pattern.agent,
confidence,
reason: `Matched keywords: ${pattern.keywords.filter(k => description.includes(k)).join(', ')}`,
capabilities: pattern.capabilities,
});
}
}
// Sort by confidence
suggestedAgents.sort((a, b) => b.confidence - a.confidence);
// If no matches, default to coder
if (suggestedAgents.length === 0) {
suggestedAgents.push({
type: 'coder',
confidence: 0.5,
reason: 'Default agent for unclassified tasks',
capabilities: ['code-generation', 'implementation'],
});
}
// Estimate complexity based on description length and keywords
let complexity = 'medium';
const complexityKeywords = ['complex', 'large', 'multiple', 'refactor', 'redesign', 'critical'];
const simpleKeywords = ['simple', 'small', 'quick', 'fix', 'minor', 'typo'];
const hasComplexKeywords = complexityKeywords.some(k => description.includes(k));
const hasSimpleKeywords = simpleKeywords.some(k => description.includes(k));
if (hasComplexKeywords) {
complexity = 'high';
}
else if (hasSimpleKeywords) {
complexity = 'low';
}
else if (description.length > 200) {
complexity = 'high';
}
else if (description.length < 50) {
complexity = 'low';
}
// Estimate duration based on complexity
const durationMap = {
low: 5 * 60 * 1000, // 5 minutes
medium: 30 * 60 * 1000, // 30 minutes
high: 2 * 60 * 60 * 1000, // 2 hours
};
const estimatedDuration = durationMap[complexity];
// Detect risks
if (description.includes('production') || description.includes('live')) {
risks.push('Task involves production environment');
}
if (description.includes('delete') || description.includes('remove')) {
risks.push('Task involves destructive operations');
}
if (description.includes('security') || description.includes('auth')) {
risks.push('Task involves security-sensitive operations');
}
if (description.includes('database') || description.includes('migration')) {
risks.push('Task involves database changes');
}
// Add recommendations
if (complexity === 'high') {
recommendations.push('Consider breaking this task into smaller subtasks');
}
if (suggestedAgents.length > 1) {
recommendations.push('Consider using multiple agents for better coverage');
}
if (risks.length > 0) {
recommendations.push('Review risks before proceeding');
}
return {
suggestedAgents,
complexity,
estimatedDuration,
patterns,
risks,
recommendations,
};
}
/**
* Record learning trajectory
*/
async recordLearning(task, outcome, patterns) {
// In a real implementation, this would integrate with ReasoningBank
// For now, we track basic statistics
const learningUpdate = {
patternsUpdated: patterns?.length || 0,
newPatterns: outcome.success ? 1 : 0,
confidenceAdjusted: patterns?.length || 0,
trajectoriesRecorded: 1,
};
return learningUpdate;
}
/**
* Execute pre-task hook manually
*/
async executePreTask(taskId, description, metadata) {
const context = {
event: HookEvent.PreTaskExecute,
timestamp: new Date(),
task: {
id: taskId,
description,
metadata,
},
};
return this.handlePreTask(context);
}
/**
* Execute post-task hook manually
*/
async executePostTask(taskId, success, metadata) {
const taskStore = this.activeTasks.get(taskId);
const context = {
event: HookEvent.PostTaskExecute,
timestamp: new Date(),
task: {
id: taskId,
description: taskStore?.description || 'Unknown task',
metadata: taskStore?.metadata,
},
metadata: {
...metadata,
success,
},
};
return this.handlePostTask(context);
}
/**
* Get active tasks
*/
getActiveTasks() {
return new Map(this.activeTasks);
}
/**
* Clear all active tasks
*/
clearActiveTasks() {
this.activeTasks.clear();
this.taskPatterns.clear();
}
}
/**
* Create task hooks manager
*/
export function createTaskHooksManager(registry) {
return new TaskHooksManager(registry);
}
//# sourceMappingURL=task-hooks.js.map