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
514 lines (462 loc) • 14.1 kB
text/typescript
/**
* 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,
HookContext,
HookResult,
HookPriority,
TaskInfo,
} from './types.js';
import { HookRegistry } from './registry.js';
/**
* Pre-task hook result with agent suggestions
*/
export interface PreTaskHookResult extends HookResult {
/** Suggested agents for the task */
suggestedAgents?: AgentSuggestion[];
/** Task complexity estimation */
complexity?: 'low' | 'medium' | 'high';
/** Estimated duration in milliseconds */
estimatedDuration?: number;
/** Related patterns from ReasoningBank */
patterns?: TaskPattern[];
/** Potential risks */
risks?: string[];
/** Recommendations */
recommendations?: string[];
}
/**
* Post-task hook result with learning data
*/
export interface PostTaskHookResult extends HookResult {
/** Task outcome */
outcome?: TaskOutcome;
/** Learning updates applied */
learningUpdates?: LearningUpdate;
/** Pattern ID if a new pattern was created */
patternId?: string;
/** Trajectory ID for ReasoningBank */
trajectoryId?: string;
}
/**
* Agent suggestion for task routing
*/
export interface AgentSuggestion {
/** Agent type */
type: string;
/** Confidence score (0-1) */
confidence: number;
/** Reason for suggestion */
reason: string;
/** Capabilities relevant to this task */
capabilities?: string[];
}
/**
* Task pattern from ReasoningBank
*/
export interface TaskPattern {
/** Pattern identifier */
id: string;
/** Pattern description */
description: string;
/** Match score (0-1) */
matchScore: number;
/** Historical success rate */
successRate: number;
/** Average duration in ms */
avgDuration: number;
/** Recommended strategies */
strategies?: string[];
}
/**
* Task outcome for learning
*/
export interface TaskOutcome {
/** Whether the task succeeded */
success: boolean;
/** Duration in milliseconds */
duration: number;
/** Quality score (0-1) */
quality?: number;
/** Error details if failed */
error?: string;
/** Output artifacts */
artifacts?: string[];
/** Agent that executed the task */
agent?: string;
}
/**
* Learning update result
*/
export interface LearningUpdate {
/** Number of patterns updated */
patternsUpdated: number;
/** Number of new patterns created */
newPatterns: number;
/** Confidence adjustments made */
confidenceAdjusted: number;
/** Trajectories recorded */
trajectoriesRecorded: number;
}
/**
* Task store for tracking active tasks
*/
interface TaskStore {
taskId: string;
description: string;
startTime: number;
metadata?: Record<string, unknown>;
suggestedAgents?: AgentSuggestion[];
}
/**
* Task Hooks Manager
*
* Manages pre-task and post-task hooks with ReasoningBank integration.
*/
export class TaskHooksManager {
private registry: HookRegistry;
private activeTasks: Map<string, TaskStore> = new Map();
private taskPatterns: Map<string, TaskPattern[]> = new Map();
constructor(registry: HookRegistry) {
this.registry = registry;
this.registerDefaultHooks();
}
/**
* Register default task hooks
*/
private registerDefaultHooks(): void {
// 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: HookContext): Promise<PreTaskHookResult> {
const task = context.task;
if (!task) {
return { success: false, error: new Error('No task in context') };
}
// Store task for tracking
const taskStore: 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: HookContext): Promise<PostTaskHookResult> {
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 as number | undefined;
const error = context.metadata?.error as string | undefined;
const agent = context.metadata?.agent as string | undefined;
const outcome: TaskOutcome = {
success,
duration,
quality,
error,
agent,
artifacts: context.metadata?.artifacts as string[] | undefined,
};
// 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
*/
private async analyzeTask(task: TaskInfo): Promise<{
suggestedAgents: AgentSuggestion[];
complexity: 'low' | 'medium' | 'high';
estimatedDuration: number;
patterns: TaskPattern[];
risks: string[];
recommendations: string[];
}> {
const description = task.description.toLowerCase();
// Pattern-based agent suggestion
const suggestedAgents: AgentSuggestion[] = [];
const patterns: TaskPattern[] = [];
const risks: string[] = [];
const recommendations: string[] = [];
// Analyze task keywords for agent routing
const agentPatterns: Array<{
keywords: string[];
agent: string;
capabilities: string[];
}> = [
{
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: 'low' | 'medium' | 'high' = '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
*/
private async recordLearning(
task: TaskInfo,
outcome: TaskOutcome,
patterns?: TaskPattern[]
): Promise<LearningUpdate> {
// In a real implementation, this would integrate with ReasoningBank
// For now, we track basic statistics
const learningUpdate: 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: string,
description: string,
metadata?: Record<string, unknown>
): Promise<PreTaskHookResult> {
const context: HookContext = {
event: HookEvent.PreTaskExecute,
timestamp: new Date(),
task: {
id: taskId,
description,
metadata,
},
};
return this.handlePreTask(context);
}
/**
* Execute post-task hook manually
*/
async executePostTask(
taskId: string,
success: boolean,
metadata?: Record<string, unknown>
): Promise<PostTaskHookResult> {
const taskStore = this.activeTasks.get(taskId);
const context: HookContext = {
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(): Map<string, TaskStore> {
return new Map(this.activeTasks);
}
/**
* Clear all active tasks
*/
clearActiveTasks(): void {
this.activeTasks.clear();
this.taskPatterns.clear();
}
}
/**
* Create task hooks manager
*/
export function createTaskHooksManager(registry: HookRegistry): TaskHooksManager {
return new TaskHooksManager(registry);
}