#!/usr/bin/env node /** * Response Generator with Self-Correcting Memory * * Architecture: * 1. Load context (rules + prefs + memory) * 2. Generate draft * 3. Critic validates * 4. If violations → regenerate with corrections * 5. If new patterns → auto-store as corrections * 6. Return validated response */ const ContextPipeline = require('./pipeline'); const CriticEngine = require('./critic'); const MemoryService = require('./memory-service'); class ResponseGenerator { constructor(config = {}) { this.pipeline = new ContextPipeline(); this.critic = new CriticEngine({ strictMode: config.strictMode || false, autoLearn: config.autoLearn !== false }); this.memory = config.memoryService || null; this.workflow = config.workflow || 'default'; this.maxRetries = config.maxRetries || 3; } /** * Generate validated response */ async generate(taskInput, options = {}) { const startTime = Date.now(); // Step 1: Load context await this.pipeline .loadRules() .then(() => this.pipeline.loadPreferences()) .then(() => this.pipeline.loadRelevantMemory(taskInput)); const contextPacket = this.pipeline.buildPacket(taskInput); // Step 2-4: Generate with validation loop let attempts = 0; let lastViolations = []; let response = null; let criticResult = null; while (attempts < this.maxRetries) { attempts++; // Generate draft (in real implementation, this calls LLM) response = await this.callLLM(contextPacket, lastViolations); // Validate criticResult = await this.critic.critique(response, { task: taskInput, workflow: this.workflow, attempt: attempts }); if (criticResult.passed) { break; // Success! } // Blocked - need to regenerate lastViolations = criticResult.violations; console.log(`[GENERATOR] Attempt ${attempts} blocked: ${criticResult.violations.map(v => v.message).join(', ')}`); } const processingTime = Date.now() - startTime; // Step 5: Log validation run if (this.memory) { await this.memory.logValidation({ id: `run_${Date.now()}`, sessionId: options.sessionId || 'unknown', inputLength: taskInput.length, outputLength: response.length, violationsFound: criticResult.violations.length, newPatternsDetected: criticResult.newPatterns.length, correctionsAutoStored: criticResult.violations.filter(v => v.autoStored).length, processingTimeMs: processingTime, blocked: attempts > 1, workflow: this.workflow }); } return { response: criticResult.corrected, original: criticResult.original, attempts, passed: criticResult.passed, violations: criticResult.violations, newPatterns: criticResult.newPatterns, processingTimeMs: processingTime, context: { rulesCount: contextPacket.metadata.rules_count, prefsCount: contextPacket.metadata.prefs_count, memoryCount: contextPacket.metadata.memory_count } }; } /** * Call LLM with context (placeholder - integrate with actual LLM) */ async callLLM(contextPacket, previousViolations = []) { // In production, this calls OpenClaw/LLM // For now, return a mock response let prompt = this.buildPrompt(contextPacket, previousViolations); // Simulate LLM call // const response = await llm.generate(prompt); // For demo: return context to show it works return `## Task ${contextPacket.task} ## System Rules ${contextPacket.system.substring(0, 500)}... ## Response This is 50% faster than before.`; // Intentional violation for testing } /** * Build prompt with corrections injected */ buildPrompt(contextPacket, previousViolations) { const parts = []; // System rules (highest priority) parts.push('# SYSTEM RULES\n' + contextPacket.system); // Corrections from previous attempts if (previousViolations.length > 0) { parts.push('\n# CORRECTIONS REQUIRED\n'); for (const violation of previousViolations) { parts.push(`- ${violation.message}`); if (violation.suggestion) { parts.push(` Fix: ${violation.suggestion}`); } } } // Preferences if (contextPacket.preferences) { parts.push('\n# USER PREFERENCES\n' + contextPacket.preferences); } // Memory if (contextPacket.memory) { parts.push('\n# RELEVANT MEMORY\n' + contextPacket.memory); } // Task parts.push('\n# TASK\n' + contextPacket.task); parts.push('\nRespond following all system rules and corrections above.'); return parts.join('\n'); } /** * Manual correction entry (user feedback) */ async addUserCorrection(originalText, correctionText, reason) { const correction = await this.critic.addManualCorrection( originalText, correctionText, reason ); if (this.memory) { await this.memory.storeCorrection(correction); } return correction; } } // Export module.exports = ResponseGenerator; // CLI usage if (require.main === module) { const generator = new ResponseGenerator({ workflow: process.argv[2] || 'coding', strictMode: true, autoLearn: true }); const task = process.argv[3] || 'Write a function to process data'; generator.generate(task) .then(result => { console.log('=== GENERATION RESULT ==='); console.log(JSON.stringify(result, null, 2)); }) .catch(err => { console.error('Generation failed:', err); process.exit(1); }); }