Skip to main content
Glama
DualProcessController.ts19 kB
/** * Dual Process Controller - Coordinates System 1 and System 2 thinking * Implements conflict resolution and mode switching between intuitive and deliberative processing */ import { ComponentStatus } from "../interfaces/cognitive.js"; import { CognitiveInput, DualProcessInfo, EmotionalState, ProcessingMode, ReasoningStep, ReasoningType, ThoughtMetadata, ThoughtResult, } from "../types/core.js"; import { DeliberativeProcessor } from "./DeliberativeProcessor.js"; import { IntuitiveProcessor } from "./IntuitiveProcessor.js"; interface ConflictResolution { selected_system: "system1" | "system2" | "hybrid"; confidence_difference: number; resolution_strategy: string; reasoning: string; } interface ProcessingDecision { use_system1: boolean; use_system2: boolean; conflict_expected: boolean; reasoning: string; selected_system: string; } interface DualProcessConfig { system1?: Record<string, unknown>; system2?: Record<string, unknown>; system2_activation_threshold?: number; conflict_threshold?: number; confidence_weight?: number; hybrid_blend_ratio?: number; processing_time_weight?: number; complexity_weight?: number; max_processing_time?: number; } export class DualProcessController { private initialized: boolean = false; private system1: IntuitiveProcessor; private system2: DeliberativeProcessor; private lastActivity: number = 0; private config: DualProcessConfig = {}; constructor() { this.system1 = new IntuitiveProcessor(); this.system2 = new DeliberativeProcessor(); } async initialize(config: DualProcessConfig): Promise<void> { this.config = { system2_activation_threshold: 0.6, conflict_threshold: 0.3, confidence_weight: 0.4, processing_time_weight: 0.2, complexity_weight: 0.4, max_processing_time: 30000, hybrid_blend_ratio: 0.6, // How much to weight System 2 in hybrid mode ...config, }; await this.system1.initialize( config.system1 ?? ({} as Record<string, unknown>) ); await this.system2.initialize( config.system2 ?? ({} as Record<string, unknown>) ); this.initialized = true; } async process(input: CognitiveInput): Promise<ThoughtResult> { const startTime = Date.now(); this.lastActivity = startTime; try { // Step 1: Decide which systems to activate const decision = this.makeProcessingDecision(input); // Step 2: Run System 1 (always runs first) const system1Result = await this.system1.processIntuitive(input); let system2Result: ThoughtResult | null = null; let finalResult: ThoughtResult; // Step 3: Run System 2 if needed if (decision.use_system2) { system2Result = await this.system2.processDeliberative(input); } // Step 4: Resolve conflicts and select final result if (system2Result) { const resolution = this.resolveConflict( system1Result, system2Result, input ); finalResult = this.applyResolution( system1Result, system2Result, resolution ); } else { finalResult = system1Result; } // Step 5: Add dual-process metadata const processingTime = Date.now() - startTime; finalResult.metadata = this.enhanceMetadata(finalResult.metadata, { dual_process_decision: { selected_system: decision.selected_system, reasoning: decision.reasoning, }, system1_confidence: system1Result.confidence, system2_confidence: system2Result?.confidence ?? null, conflict_resolution: system2Result ? this.getLastResolution() : null, total_processing_time: processingTime, conflict_detected: decision.conflict_expected, resolution_strategy: decision.reasoning, processing_time_system1: system1Result.metadata.processing_time_ms, processing_time_system2: system2Result?.metadata.processing_time_ms ?? 0, }); return finalResult; } catch (error) { throw new Error( `Dual process control failed: ${(error as Error).message}` ); } } private makeProcessingDecision(input: CognitiveInput): ProcessingDecision { let system2Score = 0; const reasons: string[] = []; // Factor 1: Explicit mode request if ( input.mode === ProcessingMode.DELIBERATIVE || input.mode === ProcessingMode.ANALYTICAL ) { system2Score += 1.0; reasons.push("Explicit deliberative mode requested"); } else if (input.mode === ProcessingMode.INTUITIVE) { system2Score -= 0.5; reasons.push("Explicit intuitive mode requested"); } // Factor 2: Input complexity const complexity = this.assessComplexity(input.input); if (complexity > 0.7) { system2Score += 0.4; reasons.push(`High complexity detected (${complexity.toFixed(2)})`); } // Factor 3: Uncertainty indicators const uncertaintyWords = [ "maybe", "perhaps", "might", "could", "uncertain", "unclear", "complex", "difficult", ]; const uncertaintyCount = uncertaintyWords.filter((word) => input.input.toLowerCase().includes(word) ).length; if (uncertaintyCount > 0) { system2Score += uncertaintyCount * 0.2; reasons.push(`Uncertainty indicators found (${uncertaintyCount})`); } // Factor 4: Question complexity if (this.isComplexQuestion(input.input)) { system2Score += 0.3; reasons.push("Complex question structure detected"); } // Factor 5: Context importance if (input.context.urgency !== undefined && input.context.urgency < 0.3) { system2Score += 0.2; reasons.push("Low urgency allows for deliberation"); } // Factor 6: Previous context suggests need for careful thinking if ( input.context.previous_thoughts && input.context.previous_thoughts.length > 0 ) { const hasComplexPrevious = input.context.previous_thoughts.some( (thought) => thought.length > 100 || thought.includes("analyze") || thought.includes("consider") ); if (hasComplexPrevious) { system2Score += 0.2; reasons.push( "Previous complex thoughts suggest continued deliberation" ); } } const useSystem2 = system2Score >= (this.config.system2_activation_threshold ?? 0.7); return { use_system1: true, // Always use System 1 use_system2: useSystem2, conflict_expected: useSystem2 && system2Score < 0.8, // Expect conflict if borderline decision reasoning: reasons.join("; "), selected_system: useSystem2 ? "system2" : "system1", }; } private assessComplexity(input: string): number { let complexity = 0; // Length factor complexity += Math.min(input.length / 500, 0.3); // Sentence structure complexity const sentences = input.split(/[.!?]+/).filter((s) => s.trim().length > 0); const avgSentenceLength = input.length / sentences.length; complexity += Math.min(avgSentenceLength / 50, 0.2); // Complex words and concepts const complexWords = [ "analyze", "synthesize", "evaluate", "compare", "contrast", "implications", "consequences", "relationships", "systematic", "comprehensive", ]; const complexWordCount = complexWords.filter((word) => input.toLowerCase().includes(word) ).length; complexity += complexWordCount * 0.1; // Multiple questions or topics const questionMarks = (input.match(/\?/g) ?? []).length; if (questionMarks > 1) { complexity += 0.2; } // Conditional statements const conditionalWords = [ "if", "when", "unless", "provided that", "assuming", ]; const conditionalCount = conditionalWords.filter((word) => input.toLowerCase().includes(word) ).length; complexity += conditionalCount * 0.1; return Math.min(complexity, 1.0); } private isComplexQuestion(input: string): boolean { // Multi-part questions if ((input.match(/\?/g) ?? []).length > 1) return true; // Questions with multiple clauses const complexQuestionPatterns = [ /what.*and.*how/i, /why.*but.*what/i, /how.*when.*where/i, /what.*if.*then/i, ]; return complexQuestionPatterns.some((pattern) => pattern.test(input)); } private resolveConflict( system1Result: ThoughtResult, system2Result: ThoughtResult, input: CognitiveInput ): ConflictResolution { const confidenceDiff = Math.abs( system1Result.confidence - system2Result.confidence ); // Determine if there's actually a conflict const contentSimilarity = this.assessContentSimilarity( system1Result.content, system2Result.content ); const hasConflict = confidenceDiff > (this.config.conflict_threshold ?? 0.3) || contentSimilarity < 0.5; if (!hasConflict) { // No significant conflict - blend the results return { selected_system: "hybrid", confidence_difference: confidenceDiff, resolution_strategy: "blend_compatible", reasoning: `Both systems agree (similarity: ${contentSimilarity.toFixed( 2 )}, confidence diff: ${confidenceDiff.toFixed(2)})`, }; } // Resolve conflict based on multiple factors let system1Score = 0; let system2Score = 0; const factors: string[] = []; // Factor 1: Confidence levels if (system1Result.confidence > system2Result.confidence) { system1Score += (system1Result.confidence - system2Result.confidence) * (this.config.confidence_weight ?? 0.5); factors.push( `System 1 more confident (+${( system1Result.confidence - system2Result.confidence ).toFixed(2)})` ); } else { system2Score += (system2Result.confidence - system1Result.confidence) * (this.config.confidence_weight ?? 0.5); factors.push( `System 2 more confident (+${( system2Result.confidence - system1Result.confidence ).toFixed(2)})` ); } // Factor 2: Processing time vs quality trade-off // Note: Processing times are available but not used in current logic if (input.context.urgency && input.context.urgency > 0.7) { // High urgency favors System 1 system1Score += 0.3; factors.push("High urgency favors quick response"); } else { // Low urgency allows for System 2's thoroughness system2Score += 0.2; factors.push("Low urgency allows thorough analysis"); } // Factor 3: Complexity of reasoning const system1ReasoningComplexity = system1Result.reasoning_path.length; const system2ReasoningComplexity = system2Result.reasoning_path.length; if (system2ReasoningComplexity > system1ReasoningComplexity * 1.5) { system2Score += 0.2; factors.push("System 2 provides more detailed reasoning"); } // Factor 4: Mode preference if (input.mode === ProcessingMode.INTUITIVE) { system1Score += 0.3; factors.push("Intuitive mode preference"); } else if ( input.mode === ProcessingMode.DELIBERATIVE || input.mode === ProcessingMode.ANALYTICAL ) { system2Score += 0.3; factors.push("Deliberative mode preference"); } // Factor 5: Emotional context appropriateness const emotionalIntensity = Math.abs(system1Result.emotional_context.valence) + system1Result.emotional_context.arousal; if (emotionalIntensity > 0.7) { system1Score += 0.1; factors.push("High emotional content favors intuitive processing"); } // Make final decision let selectedSystem: "system1" | "system2" | "hybrid"; let strategy: string; if (Math.abs(system1Score - system2Score) < 0.2) { selectedSystem = "hybrid"; strategy = "blend_weighted"; } else if (system1Score > system2Score) { selectedSystem = "system1"; strategy = "system1_override"; } else { selectedSystem = "system2"; strategy = "system2_override"; } return { selected_system: selectedSystem, confidence_difference: confidenceDiff, resolution_strategy: strategy, reasoning: `Factors: ${factors.join( "; " )}. Scores: S1=${system1Score.toFixed(2)}, S2=${system2Score.toFixed(2)}`, }; } private assessContentSimilarity(content1: string, content2: string): number { // Simple similarity assessment based on word overlap const words1 = new Set(content1.toLowerCase().split(/\s+/)); const words2 = new Set(content2.toLowerCase().split(/\s+/)); const intersection = new Set( [...words1].filter((word) => words2.has(word)) ); const union = new Set([...words1, ...words2]); return intersection.size / union.size; // Jaccard similarity } private applyResolution( system1Result: ThoughtResult, system2Result: ThoughtResult, resolution: ConflictResolution ): ThoughtResult { switch (resolution.selected_system) { case "system1": return { ...system1Result, reasoning_path: this.addResolutionStep( system1Result.reasoning_path, resolution, "system1" ), }; case "system2": return { ...system2Result, reasoning_path: this.addResolutionStep( system2Result.reasoning_path, resolution, "system2" ), }; case "hybrid": return this.blendResults(system1Result, system2Result, resolution); default: return system1Result; } } private blendResults( system1Result: ThoughtResult, system2Result: ThoughtResult, resolution: ConflictResolution ): ThoughtResult { const blendRatio = this.config.hybrid_blend_ratio ?? 0.5; // Blend confidence const blendedConfidence = system1Result.confidence * (1 - blendRatio) + system2Result.confidence * blendRatio; // Blend content let blendedContent: string; if (resolution.resolution_strategy === "blend_compatible") { blendedContent = `Initial impression: ${system1Result.content}\n\nUpon further analysis: ${system2Result.content}\n\nIntegrated perspective: Both approaches converge on a comprehensive understanding.`; } else { blendedContent = `Intuitive assessment: ${system1Result.content}\n\nDeliberative analysis: ${system2Result.content}\n\nBalanced conclusion: Considering both perspectives, the situation requires both quick insight and careful analysis.`; } // Combine reasoning paths const combinedReasoning = [ ...system1Result.reasoning_path.map((step) => ({ ...step, metadata: { ...step.metadata, source: "system1" }, })), ...system2Result.reasoning_path.map((step) => ({ ...step, metadata: { ...step.metadata, source: "system2" }, })), { type: ReasoningType.METACOGNITIVE, content: `Dual-process integration: ${resolution.reasoning}`, confidence: blendedConfidence, alternatives: [], }, ]; // Blend emotional context const blendedEmotional: EmotionalState = { valence: system1Result.emotional_context.valence * (1 - blendRatio) + system2Result.emotional_context.valence * blendRatio, arousal: system1Result.emotional_context.arousal * (1 - blendRatio) + system2Result.emotional_context.arousal * blendRatio, dominance: system1Result.emotional_context.dominance * (1 - blendRatio) + system2Result.emotional_context.dominance * blendRatio, specific_emotions: new Map([ ...system1Result.emotional_context.specific_emotions, ...system2Result.emotional_context.specific_emotions, ["integration", blendedConfidence], ]), }; return { content: blendedContent, confidence: blendedConfidence, reasoning_path: combinedReasoning, emotional_context: blendedEmotional, metadata: { processing_time_ms: system1Result.metadata.processing_time_ms + system2Result.metadata.processing_time_ms, components_used: [ "IntuitiveProcessor", "DeliberativeProcessor", "DualProcessController", ], memory_retrievals: system1Result.metadata.memory_retrievals + system2Result.metadata.memory_retrievals, system_mode: ProcessingMode.BALANCED, temperature: (system1Result.metadata.temperature + system2Result.metadata.temperature) / 2, }, }; } private addResolutionStep( reasoningPath: ReasoningStep[], resolution: ConflictResolution, selectedSystem: string ): ReasoningStep[] { const resolutionStep: ReasoningStep = { type: ReasoningType.METACOGNITIVE, content: `Dual-process resolution: Selected ${selectedSystem} (${resolution.resolution_strategy})`, confidence: 0.8, alternatives: [ { content: `Alternative: Use ${ selectedSystem === "system1" ? "system2" : "system1" }`, confidence: 0.6, reasoning: resolution.reasoning, }, ], }; return [...reasoningPath, resolutionStep]; } private enhanceMetadata( metadata: ThoughtMetadata, dualProcessInfo: DualProcessInfo ): ThoughtMetadata { return { ...metadata, dual_process_info: dualProcessInfo, }; } private lastResolution: ConflictResolution | null = null; private getLastResolution(): ConflictResolution | null { return this.lastResolution; } reset(): void { this.system1.reset(); this.system2.reset(); this.lastActivity = 0; this.lastResolution = null; } getStatus(): ComponentStatus { const system1Status = this.system1.getStatus(); const system2Status = this.system2.getStatus(); return { name: "DualProcessController", initialized: this.initialized && system1Status.initialized && system2Status.initialized, active: Date.now() - this.lastActivity < 30000, last_activity: this.lastActivity, error: system1Status.error ?? system2Status.error ?? "", }; } // Additional methods for external access getSystem1Status(): ComponentStatus { return this.system1.getStatus(); } getSystem2Status(): ComponentStatus { return this.system2.getStatus(); } async processSystem1Only(input: CognitiveInput): Promise<ThoughtResult> { return await this.system1.processIntuitive(input); } async processSystem2Only(input: CognitiveInput): Promise<ThoughtResult> { return await this.system2.processDeliberative(input); } }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/keyurgolani/ThoughtMcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server