MnemoCore / src /mnemocore /core /router.py
Granis87's picture
Initial upload of MnemoCore
dbb04e4 verified
"""
Cognitive Router - Orchestrates System 1 (Fast) and System 2 (Slow) thinking.
"""
import time
from typing import Dict, Any, Tuple, Optional
from loguru import logger
from .engine import HAIMEngine
from .binary_hdv import majority_bundle, BinaryHDV
from .exceptions import MnemoCoreError
class CognitiveRouter:
"""
Orchestrates System 1 (Fast) and System 2 (Slow) thinking.
System 1: Intuitive, heuristic, fast memory retrieval.
System 2: Analytical, epistemic search, heavy reasoning.
"""
def __init__(self, engine: HAIMEngine):
self.engine = engine
self.complexity_threshold = 0.6 # Threshold for switching to Sys2
async def route(self, impulse: str, context: dict = None) -> Tuple[str, Dict[str, Any]]:
"""
Route the impulse to the appropriate system.
Returns: (response, debug_info)
"""
start_time = time.time()
complexity = await self._assess_complexity(impulse)
debug_info = {
"impulse": impulse,
"complexity_score": complexity,
"timestamp": start_time
}
if complexity < self.complexity_threshold:
# System 1: Fast Reflex
debug_info["system"] = "Sys1 (Fast)"
response = await self._system_1_reflex(impulse)
else:
# System 2: Heavy Reasoning
debug_info["system"] = "Sys2 (Slow)"
response = await self._system_2_reasoning(impulse, context)
debug_info["duration"] = time.time() - start_time
return response, debug_info
async def _assess_complexity(self, text: str) -> float:
"""
Heuristic to estimate cognitive load.
"""
score = 0.0
# Length heuristic
if len(text.split()) > 20:
score += 0.3
# Complexity markers
complex_markers = ["analyze", "compare", "why", "how", "plan", "design", "evaluate"]
if any(marker in text.lower() for marker in complex_markers):
score += 0.4
# Uncertainty markers
uncertainty = ["maybe", "unsure", "unknown", "complex"]
if any(u in text.lower() for u in uncertainty):
score += 0.2
# Epistemic check (query engine for familiarity)
# Low familiarity (high surprise) -> Higher complexity
try:
results = await self.engine.query(text, top_k=1, associative_jump=False)
if results and results[0][1] > 0.8:
# Strong memory match -> Familiar -> Lower complexity
score -= 0.3
elif not results or results[0][1] < 0.3:
# No clue -> Novelty -> Higher complexity
score += 0.4
except MnemoCoreError as e:
# Log domain errors but continue with heuristic-only assessment
logger.debug(f"Complexity assessment query failed: {e}")
except Exception as e:
# Log unexpected errors but continue
logger.warning(f"Unexpected error in complexity assessment: {e}")
return min(1.0, max(0.0, score))
async def _system_1_reflex(self, impulse: str) -> str:
"""
Fast retrieval and simple association.
"""
# 1. Quick memory lookup
results = await self.engine.query(impulse, top_k=3)
if not results:
return "I don't have an immediate reflex for that."
# 2. Synthesize simple answer from top memory (simulated)
# Use engine.get_memory() instead of direct dict access
top_mem_id, score = results[0]
node = await self.engine.get_memory(top_mem_id)
content = node.content if node else 'Unknown'
return f"[Reflex] Based on memory ({score:.2f}): {content}"
async def _system_2_reasoning(self, impulse: str, context: Optional[dict]) -> str:
"""Slow, deliberative process with Epistemic Drive."""
eig: Optional[float] = None
# 1. Epistemic Drive (Expected Information Gain)
if self.engine.epistemic_drive_active:
candidate_vec = self.engine.encode_content(impulse)
# Build context vector from working memory or sample from engine
ctx_vec: BinaryHDV
if context and isinstance(context.get("working_memory"), list) and context["working_memory"]:
vectors = []
for item in context["working_memory"]:
vectors.append(self.engine.encode_content(str(item)))
# Bundle all context vectors
if vectors:
ctx_vec = majority_bundle(vectors)
else:
ctx_vec = await self.engine._current_context_vector()
else:
ctx_vec = await self.engine._current_context_vector(sample_n=50)
eig = self.engine.calculate_eig(candidate_vec, ctx_vec)
# 2. Deep Search (Associative Jumps)
results = await self.engine.query(impulse, top_k=10, associative_jump=True)
# 3. Consolidation / Synthesis
memories = []
for mid, score in results:
node = await self.engine.get_memory(mid)
if node:
memories.append(f"- {node.content} (conf: {score:.2f})")
knowledge_block = "\n".join(memories)
eig_line = f"\nEpistemic Drive (EIG): {eig:.2f}" if eig is not None else ""
return f"[Reasoning] I have analyzed {len(memories)} data points.{eig_line}\nKey insights:\n{knowledge_block}"