@cyqlelabs/mcp-dual-cycle-reasoner
Version:
MCP server implementing dual-cycle metacognitive reasoning framework for autonomous agents
176 lines (175 loc) ⢠6.65 kB
JavaScript
import { Sentinel } from './sentinel.js';
import { Adjudicator } from './adjudicator.js';
import { semanticAnalyzer } from './semantic-analyzer.js';
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;
accumulatedActions = [];
constructor(config) {
this.sentinel = new Sentinel(config);
this.adjudicator = new Adjudicator();
this.currentTrace = this.initializeTrace();
// Configure semantic intents if provided
if (config?.semantic_intents) {
this.adjudicator.updateSemanticIntents(config.semantic_intents);
}
}
/**
* Initialize the semantic analyzer if not already done
*/
async ensureSemanticAnalyzerReady() {
if (!semanticAnalyzer.isReady()) {
await semanticAnalyzer.initialize();
}
}
/**
* Initialize a new cognitive trace for monitoring
*/
initializeTrace() {
return {
last_action: '',
current_context: undefined,
goal: '',
};
}
/**
* Start metacognitive monitoring of an agent's cognitive trace
*/
async startMonitoring(initialGoal, initialBeliefs = []) {
// Ensure semantic analyzer is ready before starting monitoring
await this.ensureSemanticAnalyzerReady();
this.isMonitoring = true;
this.currentTrace = this.initializeTrace();
this.currentTrace.goal = initialGoal;
this.interventionCount = 0;
this.accumulatedActions = [];
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 with a single action (called by the cognitive cycle)
*/
async processTraceUpdate(lastAction, currentContext, goal, windowSize) {
if (!this.isMonitoring) {
return { intervention_required: false };
}
// Add the new action to the accumulated actions
this.accumulatedActions.push(lastAction);
this.currentTrace.last_action = lastAction;
console.log(`š DEBUG: Added action "${lastAction}" to accumulated actions. Total: ${this.accumulatedActions.length}`);
// Update other trace properties if provided
if (currentContext) {
this.currentTrace.current_context = currentContext;
}
if (goal) {
this.currentTrace.goal = goal;
}
console.log(chalk.gray(`\nš Processing trace update: Added "${lastAction}" (${this.accumulatedActions.length} total actions)`));
// METACOGNITIVE CYCLE - Phase 1: MONITOR
const loopDetection = await this.monitorForLoops(this.currentTrace, windowSize ?? 10);
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}`));
this.interventionCount++;
const explanation = this.generateInterventionExplanation(loopDetection);
console.log(chalk.cyan(`\nš” Intervention #${this.interventionCount}: ${explanation}`));
return {
intervention_required: true,
loop_detected: loopDetection,
explanation,
};
}
/**
* Get current trace for standalone loop detection
*/
getCurrentTrace() {
return this.currentTrace;
}
/**
* Get enriched trace with accumulated actions for internal use
*/
getEnrichedTrace() {
return {
...this.currentTrace,
recent_actions: this.accumulatedActions || [],
};
}
/**
* Get enriched trace with accumulated actions (public method for standalone tools)
*/
getEnrichedCurrentTrace() {
return {
...this.currentTrace,
recent_actions: this.accumulatedActions || [],
};
}
/**
* METACOGNITIVE CYCLE - Phase 1: MONITOR
* Uses the Sentinel to detect problematic patterns
*/
async monitorForLoops(trace, windowSize = 10) {
const enrichedTrace = this.getEnrichedTrace();
return await this.sentinel.detectLoop(enrichedTrace, 'hybrid', windowSize);
}
/**
* Generate a human-readable explanation of the intervention
*/
generateInterventionExplanation(loopResult) {
const loopType = loopResult.type?.replace('_', ' ') || 'unknown';
return (`Detected ${loopType} loop (${(loopResult.confidence * 100).toFixed(0)}% confidence). ` +
`Intervention required to break the loop.`);
}
/**
* Get current monitoring status and statistics
*/
getMonitoringStatus() {
return {
is_monitoring: this.isMonitoring,
intervention_count: this.interventionCount,
current_goal: this.currentTrace.goal,
trace_length: this.accumulatedActions.length,
};
}
/**
* Reset the engine state (useful for testing or new sessions)
*/
reset() {
this.sentinel.reset();
this.currentTrace = this.initializeTrace();
this.isMonitoring = false;
this.interventionCount = 0;
this.accumulatedActions = [];
console.log(chalk.blue('š Dual-Cycle Engine reset'));
}
/**
* Get similar cases for analysis
*/
async getSimilarCases(problemDescription, maxResults = 5, filters = {}) {
return await this.adjudicator.retrieveSimilarCases(problemDescription, maxResults, filters);
}
}