@cyqlelabs/mcp-dual-cycle-reasoner
Version:
MCP server implementing dual-cycle metacognitive reasoning framework for autonomous agents
202 lines (201 loc) ⢠8.79 kB
JavaScript
import { Sentinel } from './sentinel.js';
import { Adjudicator } from './adjudicator.js';
import { v4 as uuidv4 } from 'uuid';
import chalk from 'chalk';
/**
* The Dual-Cycle Engine implements the metacognitive framework described in the DUAL-CYCLE document.
* It consists of two interconnected cycles:
* - Cognitive Cycle (The "Doer"): Direct interaction with the environment
* - Metacognitive Cycle (The "Thinker"): Monitors and controls the cognitive cycle
*/
export class DualCycleEngine {
sentinel;
adjudicator;
currentTrace;
isMonitoring = false;
interventionCount = 0;
constructor(config) {
this.sentinel = new Sentinel(config);
this.adjudicator = new Adjudicator();
this.currentTrace = this.initializeTrace();
}
/**
* Initialize a new cognitive trace for monitoring
*/
initializeTrace() {
return {
recent_actions: [],
current_context: undefined,
goal: '',
step_count: 0
};
}
/**
* Start metacognitive monitoring of an agent's cognitive trace
*/
startMonitoring(initialGoal, initialBeliefs = []) {
this.isMonitoring = true;
this.currentTrace = this.initializeTrace();
this.currentTrace.goal = initialGoal;
this.interventionCount = 0;
console.log(chalk.blue('š§ Dual-Cycle Engine: Metacognitive monitoring started'));
console.log(chalk.gray(`Goal: ${initialGoal}`));
console.log(chalk.gray(`Initial beliefs: ${initialBeliefs.length}`));
}
/**
* Stop metacognitive monitoring
*/
stopMonitoring() {
this.isMonitoring = false;
console.log(chalk.blue('š§ Dual-Cycle Engine: Monitoring stopped'));
console.log(chalk.gray(`Total interventions: ${this.interventionCount}`));
}
/**
* Process a new cognitive trace update (called by the cognitive cycle)
*/
async processTraceUpdate(trace) {
if (!this.isMonitoring) {
return { intervention_required: false };
}
// Update current trace
this.currentTrace = { ...this.currentTrace, ...trace };
console.log(chalk.gray(`\nš Processing trace update: ${trace.recent_actions.length} actions, step ${trace.step_count}`));
// METACOGNITIVE CYCLE - Phase 1: MONITOR
const loopDetection = this.monitorForLoops(trace);
if (!loopDetection.detected) {
console.log(chalk.green('ā
No loops detected - cognitive cycle proceeding normally'));
return {
intervention_required: false,
loop_detected: loopDetection
};
}
console.log(chalk.yellow(`ā ļø Loop detected: ${loopDetection.type} (confidence: ${(loopDetection.confidence * 100).toFixed(1)}%)`));
console.log(chalk.yellow(` Details: ${loopDetection.details}`));
// METACOGNITIVE CYCLE - Phase 2: INTERPRET/DETECT
const diagnosis = await this.interpretFailure(loopDetection, trace);
console.log(chalk.red(`š Diagnosis: ${diagnosis.primary_hypothesis} (confidence: ${(diagnosis.confidence * 100).toFixed(1)}%)`));
console.log(chalk.red(` Evidence: ${diagnosis.evidence.join('; ')}`));
// METACOGNITIVE CYCLE - Phase 3: PLAN (Meta-Level)
const recoveryPlan = this.planRecovery(diagnosis, trace);
console.log(chalk.blue(`š ļø Recovery plan: ${recoveryPlan.pattern}`));
console.log(chalk.blue(` Rationale: ${recoveryPlan.rationale}`));
// METACOGNITIVE CYCLE - Phase 4: CONTROL (Meta-Level)
const beliefRevision = await this.controlCognition(loopDetection, diagnosis, trace);
console.log(chalk.magenta(`š§ Beliefs revised: ${beliefRevision.revised_beliefs.length} beliefs, ${beliefRevision.removed_beliefs.length} removed`));
// Store this experience for future learning
this.storeExperience(loopDetection, diagnosis, recoveryPlan, trace);
this.interventionCount++;
const explanation = this.generateInterventionExplanation(loopDetection, diagnosis, recoveryPlan, beliefRevision);
console.log(chalk.cyan(`\nš” Intervention #${this.interventionCount}: ${explanation}`));
return {
intervention_required: true,
loop_detected: loopDetection,
diagnosis,
recovery_plan: recoveryPlan,
revised_beliefs: beliefRevision,
explanation
};
}
/**
* METACOGNITIVE CYCLE - Phase 1: MONITOR
* Uses the Sentinel to detect problematic patterns
*/
monitorForLoops(trace) {
return this.sentinel.detectLoop(trace, 'hybrid');
}
/**
* METACOGNITIVE CYCLE - Phase 2: INTERPRET/DETECT
* Uses the Adjudicator to diagnose the failure
*/
async interpretFailure(loopResult, trace) {
return await this.adjudicator.diagnoseFailure(loopResult, trace);
}
/**
* METACOGNITIVE CYCLE - Phase 3: PLAN (Meta-Level)
* Uses the Adjudicator to generate a recovery plan
*/
planRecovery(diagnosis, trace) {
return this.adjudicator.generateRecoveryPlan(diagnosis, trace);
}
/**
* METACOGNITIVE CYCLE - Phase 4: CONTROL (Meta-Level)
* Revises beliefs and prepares cognitive control signals
*/
async controlCognition(loopResult, diagnosis, trace) {
const contradictingEvidence = `Loop detected: ${loopResult.type}. Diagnosis: ${diagnosis.primary_hypothesis}. Current strategy is ineffective.`;
// For simplified traces, we'll use empty beliefs array as default
const currentBeliefs = [];
return await this.adjudicator.reviseBeliefs(currentBeliefs, contradictingEvidence, trace);
}
/**
* Store the experience for case-based reasoning
*/
storeExperience(loopResult, diagnosis, recoveryPlan, trace) {
const experience = {
id: uuidv4(),
problem_description: `${loopResult.type} loop detected: ${diagnosis.primary_hypothesis} in context: ${this.extractContextSummary(trace)}`,
solution: `Apply ${recoveryPlan.pattern} strategy: ${recoveryPlan.rationale}`,
outcome: false, // Will be updated when outcome is known
timestamp: Date.now()
};
this.adjudicator.storeExperience(experience);
}
/**
* Generate a human-readable explanation of the intervention
*/
generateInterventionExplanation(loopResult, diagnosis, recoveryPlan, beliefRevision) {
const loopType = loopResult.type?.replace('_', ' ') || 'unknown';
const hypothesis = diagnosis.primary_hypothesis.replace('_', ' ');
const pattern = recoveryPlan.pattern.replace('_', ' ');
return `Detected ${loopType} loop (${(loopResult.confidence * 100).toFixed(0)}% confidence). ` +
`Diagnosed as ${hypothesis} issue. ` +
`Applying ${pattern} recovery strategy. ` +
`Revised ${beliefRevision.revised_beliefs.length} beliefs to maintain consistency.`;
}
/**
* Extract a summary of the current context for case storage
*/
extractContextSummary(trace) {
const recentActions = trace.recent_actions.slice(-3).join(' -> ');
const currentContext = trace.current_context || 'unknown';
return `Goal: ${trace.goal.substring(0, 50)}..., ` +
`Recent actions: ${recentActions}, ` +
`Context: ${currentContext}, ` +
`Step: ${trace.step_count}`;
}
/**
* Get current monitoring status and statistics
*/
getMonitoringStatus() {
return {
is_monitoring: this.isMonitoring,
intervention_count: this.interventionCount,
current_goal: this.currentTrace.goal,
trace_length: this.currentTrace.recent_actions.length
};
}
/**
* Update the outcome of a previously generated recovery plan
*/
updateRecoveryOutcome(successful, explanation) {
// In a full implementation, this would update the most recent case
// For now, we'll just log it
console.log(chalk.cyan(`š Recovery outcome updated: ${successful ? 'SUCCESS' : 'FAILURE'} - ${explanation}`));
}
/**
* Reset the engine state (useful for testing or new sessions)
*/
reset() {
this.sentinel.reset();
this.currentTrace = this.initializeTrace();
this.isMonitoring = false;
this.interventionCount = 0;
console.log(chalk.blue('š Dual-Cycle Engine reset'));
}
/**
* Get similar cases for analysis
*/
getSimilarCases(problemDescription, maxResults = 5) {
return this.adjudicator.retrieveSimilarCases(problemDescription, maxResults);
}
}