UNPKG

claude-flow-novice

Version:

Claude Flow Novice - Advanced orchestration platform for multi-agent AI workflows with CFN Loop architecture Includes Local RuVector Accelerator and all CFN skills for complete functionality.

192 lines (190 loc) 7.53 kB
/** * Iteration History Management * * Loads and formats iteration history from Redis for CLI-spawned agents. * Enables agents to learn from previous attempts and feedback. * * Storage Pattern: * swarm:${TASK_ID}:${AGENT_ID}:result:iteration-${N} → Result text + confidence * swarm:${TASK_ID}:${AGENT_ID}:feedback:iteration-${N} → Validator feedback * * Sprint 3 - Phase 2 Implementation */ import { execSync } from 'child_process'; // Bug #6 Fix: Read Redis connection parameters from process.env // FIX: Default to 'localhost' for CLI mode (host execution), not 'cfn-redis' (Docker) const redisHost = process.env.CFN_REDIS_HOST || 'localhost'; const redisPort = process.env.CFN_REDIS_PORT || '6379'; /** * Load iteration history for an agent from Redis * * @param taskId - Task identifier * @param agentId - Agent identifier * @param currentIteration - Current iteration number (loads 1 to N-1) * @returns Array of iteration results */ export async function loadIterationHistory(taskId, agentId, currentIteration) { const history = []; // Load previous iterations (1 to currentIteration - 1) for(let i = 1; i < currentIteration; i++){ try { // Load result data const resultKey = `swarm:${taskId}:${agentId}:result:iteration-${i}`; const resultJson = execSync(`redis-cli -h ${redisHost} -p ${redisPort} get "${resultKey}"`, { encoding: 'utf8' }).trim(); if (resultJson === '(nil)' || !resultJson) { continue; } const resultData = JSON.parse(resultJson); // Load feedback data (may not exist for all iterations) const feedbackKey = `swarm:${taskId}:${agentId}:feedback:iteration-${i}`; let feedback; try { const feedbackJson = execSync(`redis-cli -h ${redisHost} -p ${redisPort} get "${feedbackKey}"`, { encoding: 'utf8' }).trim(); if (feedbackJson !== '(nil)' && feedbackJson) { const feedbackData = JSON.parse(feedbackJson); feedback = feedbackData.feedback || feedbackData.comments; } } catch (err) { // Feedback may not exist for this iteration feedback = undefined; } history.push({ iteration: i, result: resultData.result || resultData.output || '', confidence: resultData.confidence || 0, timestamp: resultData.timestamp || new Date().toISOString(), feedback }); } catch (err) { console.error(`[iteration-history] Failed to load iteration ${i}:`, err); // Continue loading other iterations } } return history; } /** * Store iteration result in Redis * * @param taskId - Task identifier * @param agentId - Agent identifier * @param iteration - Iteration number * @param result - Result text/output * @param confidence - Confidence score (0.0-1.0) */ export async function storeIterationResult(taskId, agentId, iteration, result, confidence) { const resultKey = `swarm:${taskId}:${agentId}:result:iteration-${iteration}`; const resultData = { result, confidence, timestamp: new Date().toISOString(), iteration }; const resultJson = JSON.stringify(resultData); try { // Store with 24 hour TTL execSync(`redis-cli -h ${redisHost} -p ${redisPort} setex "${resultKey}" 86400 '${resultJson.replace(/'/g, "'\\''")}'`, { encoding: 'utf8' }); console.log(`[iteration-history] Stored result for iteration ${iteration}`); } catch (err) { console.error(`[iteration-history] Failed to store result:`, err); throw err; } } /** * Format iteration history as markdown for system prompt * * @param history - Array of iteration results * @param currentIteration - Current iteration number * @returns Formatted markdown string */ export function formatIterationHistory(history, currentIteration) { if (history.length === 0) { return `## Current Iteration: ${currentIteration} This is your first attempt at this task. No previous iteration history available. `; } const sections = []; sections.push('## Iteration History'); sections.push(''); sections.push('Learn from your previous attempts and feedback:'); sections.push(''); // Format each iteration for (const iter of history){ sections.push(`### Iteration ${iter.iteration}`); sections.push(''); sections.push('**Result:**'); sections.push(iter.result.substring(0, 500)); // Truncate to 500 chars if (iter.result.length > 500) { sections.push('... (truncated)'); } sections.push(''); if (iter.feedback) { sections.push('**Feedback from Validators:**'); sections.push(iter.feedback); sections.push(''); } sections.push(`**Confidence:** ${iter.confidence.toFixed(2)}`); sections.push(`**Timestamp:** ${iter.timestamp}`); sections.push(''); sections.push('---'); sections.push(''); } // Add current iteration context sections.push(`## Current Iteration: ${currentIteration}`); sections.push(''); if (history.length > 0) { const lastIteration = history[history.length - 1]; if (lastIteration.feedback) { sections.push('**Your Task:** Address the feedback from the previous iteration:'); sections.push(''); sections.push(lastIteration.feedback); sections.push(''); } else { sections.push(`**Your Task:** Improve upon iteration ${lastIteration.iteration} (confidence: ${lastIteration.confidence.toFixed(2)})`); sections.push(''); } } return sections.join('\n'); } /** * Check if iteration history exists for an agent * * @param taskId - Task identifier * @param agentId - Agent identifier * @returns True if any iteration history exists */ export async function hasIterationHistory(taskId, agentId) { try { const pattern = `swarm:${taskId}:${agentId}:result:iteration-*`; const keys = execSync(`redis-cli -h ${redisHost} -p ${redisPort} --scan --pattern "${pattern}"`, { encoding: 'utf8' }).trim(); return keys.length > 0; } catch (err) { return false; } } /** * Get the latest iteration number for an agent * * @param taskId - Task identifier * @param agentId - Agent identifier * @returns Latest iteration number (0 if no history) */ export async function getLatestIteration(taskId, agentId) { try { const pattern = `swarm:${taskId}:${agentId}:result:iteration-*`; const keys = execSync(`redis-cli -h ${redisHost} -p ${redisPort} --scan --pattern "${pattern}"`, { encoding: 'utf8' }).trim().split('\n').filter((k)=>k.length > 0); if (keys.length === 0) return 0; // Extract iteration numbers and find max const iterations = keys.map((key)=>{ const match = key.match(/iteration-(\d+)$/); return match ? parseInt(match[1], 10) : 0; }); return Math.max(...iterations); } catch (err) { return 0; } } //# sourceMappingURL=iteration-history.js.map