"""True AGI Framework - Based on Common Model of Cognition & Best AGI Research.

Architecture inspired by:
- Common Model of Cognition (Laird, ACT-R, Soar, Sigma)
- Cognitive Design Patterns (Observe-Decide-Act, Hierarchical Decomposition)
- AGI Cognitive Architecture (World Models, Planning, Self-Improvement)
- CoALA Framework (Cognitive Architectures for Language Agents)

Core Components (Common Model of Cognition):
1. PERCEPTION - Input processing and sensory encoding
2. WORKING MEMORY - Current context and active processing
3. PROCEDURAL MEMORY - Rules, operators, action selection (SOAR-style productions)
4. DECLARATIVE MEMORY - Semantic + Episodic knowledge storage
5. MOTOR/ACTION - Output execution and tool use
6. METACOGNITION - Self-monitoring, reflection, improvement

Advanced Features:
- World Model construction
- Hierarchical Task Networks (HTN)
- Multi-method reasoning
- Theory of Mind
- Causal inference
- Self-improvement loops
"""

from __future__ import annotations

import asyncio
import hashlib
import json
import re
import time
import uuid
from collections import defaultdict, deque
from dataclasses import dataclass, field
from enum import Enum
from typing import Any, Callable, Dict, List, Optional, Set, Tuple, Type

import sys
sys.path.insert(0, "/Users/himand/open-agent/src")


# ============================================================================
# CORE ENUMS & TYPES
# ============================================================================

class CognitiveModule(str, Enum):
    """Modules in the Common Model of Cognition."""
    PERCEPTION = "perception"
    WORKING_MEMORY = "working_memory"
    PROCEDURAL_MEMORY = "procedural_memory"
    DECLARATIVE_MEMORY = "declarative_memory"
    SEMANTIC_MEMORY = "semantic_memory"
    EPISODIC_MEMORY = "episodic_memory"
    MOTOR = "motor"
    METACOGNITION = "metacognition"
    EMOTION = "emotion"
    ATTENTION = "attention"
    WORLD_MODEL = "world_model"
    GOAL = "goal"


class CognitiveState(str, Enum):
    """States of cognitive processing."""
    IDLE = "idle"
    PERCEIVING = "perceiving"
    REASONING = "reasoning"
    PLANNING = "planning"
    ACTING = "acting"
    LEARNING = "learning"
    REFLECTING = "reflecting"


class MemoryType(str, Enum):
    """Types of memory."""
    WORKING = "working"
    SEMANTIC = "semantic"
    EPISODIC = "episodic"
    PROCEDURAL = "procedural"


class ReasoningMethod(str, Enum):
    """Reasoning methods."""
    DEDUCTIVE = "deductive"
    INDUCTIVE = "inductive"
    ABDUCTIVE = "abductive"
    CAUSAL = "causal"
    ANALOGICAL = "analogical"
    COUNTERFACTUAL = "counterfactual"
    TEMPORAL = "temporal"


# ============================================================================
# MEMORY SYSTEMS (Common Model of Cognition)
# ============================================================================

@dataclass
class MemoryItem:
    """Base class for memory items."""
    id: str
    content: Any
    memory_type: MemoryType
    activation: float = 0.5
    created_at: float = field(default_factory=time.time)
    last_accessed: float = field(default_factory=time.time)
    access_count: int = 0
    metadata: Dict[str, Any] = field(default_factory=dict)
    
    def access(self) -> None:
        """Record memory access."""
        self.last_accessed = time.time()
        self.access_count += 1
        self.activation = min(1.0, self.activation + 0.1)
    
    def decay(self, amount: float = 0.01) -> None:
        """Decay activation over time."""
        self.activation = max(0.0, self.activation - amount)


@dataclass
class Chunk(MemoryItem):
    """Declarative memory chunk (ACT-R style)."""
    slots: Dict[str, Any] = field(default_factory=dict)
    chunk_type: str = "concept"
    memory_type: MemoryType = field(default_factory=lambda: MemoryType.SEMANTIC)
    

@dataclass
class Production(MemoryItem):
    """Procedural memory production rule (SOAR style)."""
    conditions: List[str] = field(default_factory=list)
    actions: List[str] = field(default_factory=list)
    utility: float = 0.5
    priority: int = 0


@dataclass
class Episode(MemoryItem):
    """Episodic memory episode."""
    situation: str = ""
    actions: List[str] = field(default_factory=list)
    outcome: str = ""
    emotion: str = "neutral"
    memory_type: MemoryType = field(default_factory=lambda: MemoryType.EPISODIC)


# ============================================================================
# WORKING MEMORY (ACT-R Style Buffers)
# ============================================================================

class WorkingMemory:
    """Working memory with buffers (ACT-R style).
    
    Contains:
    - Goal buffer
    - Retrieval buffer
    - Perception buffer
    - Motor buffer
    - Internal buffers
    """
    
    def __init__(self):
        self.buffers: Dict[str, Optional[MemoryItem]] = {
            "goal": None,
            "retrieval": None,
            "perception": None,
            "motor": None,
            "internal": None,
            "context": None,
        }
        self.contents: Dict[str, Any] = {}
        self.attention_focus: Optional[str] = None
        
    def set_buffer(self, buffer_name: str, item: Optional[MemoryItem]) -> None:
        """Set a buffer value."""
        if buffer_name in self.buffers:
            self.buffers[buffer_name] = item
    
    def get_buffer(self, buffer_name: str) -> Optional[MemoryItem]:
        """Get a buffer value."""
        return self.buffers.get(buffer_name)
    
    def set(self, key: str, value: Any) -> None:
        """Set working memory content."""
        self.contents[key] = value
    
    def get(self, key: str, default: Any = None) -> Any:
        """Get working memory content."""
        return self.contents.get(key, default)
    
    def contains(self, key: str) -> bool:
        """Check if key exists."""
        return key in self.contents
    
    def clear(self) -> None:
        """Clear all buffers and contents."""
        for key in self.buffers:
            self.buffers[key] = None
        self.contents.clear()
        self.attention_focus = None


# ============================================================================
# PROCEDURAL MEMORY (SOAR Style Productions)
# ============================================================================

class ProceduralMemory:
    """Procedural memory with production rules (SOAR/ACT-R style).
    
    Production rules fire based on working memory matching.
    """
    
    def __init__(self):
        self.productions: List[Production] = []
        self._build_default_productions()
    
    def _build_default_productions(self) -> None:
        """Build default production rules."""
        self.productions = [
            Production(
                id="retrieve-knowledge",
                content="When goal requires knowledge and retrieval buffer is empty, retrieve",
                memory_type=MemoryType.PROCEDURAL,
                conditions=["goal requires knowledge", "retrieval buffer empty"],
                actions=["request retrieval"],
                utility=0.8,
                priority=10,
            ),
            Production(
                id="plan-action",
                content="When goal is set and no plan exists, create plan",
                memory_type=MemoryType.PROCEDURAL,
                conditions=["goal is set", "no plan exists"],
                actions=["create plan"],
                utility=0.9,
                priority=20,
            ),
            Production(
                id="execute-plan",
                content="When plan exists and ready, execute next action",
                memory_type=MemoryType.PROCEDURAL,
                conditions=["plan exists", "ready to act"],
                actions=["execute next action"],
                utility=0.7,
                priority=15,
            ),
            Production(
                id="learn-from-outcome",
                content="When outcome received, learn and update knowledge",
                memory_type=MemoryType.PROCEDURAL,
                conditions=["outcome received"],
                actions=["update knowledge", "store episode"],
                utility=0.6,
                priority=5,
            ),
            Production(
                id="reflect-on-failure",
                content="When action fails, reflect and replan",
                memory_type=MemoryType.PROCEDURAL,
                conditions=["action failed"],
                actions=["analyze failure", "replan"],
                utility=0.85,
                priority=25,
            ),
        ]
    
    def add_production(self, production: Production) -> None:
        """Add a production rule."""
        self.productions.append(production)
    
    def match_productions(self, working_memory: WorkingMemory) -> List[Production]:
        """Match productions against working memory."""
        matched = []
        
        for prod in self.productions:
            conditions_met = True
            
            for condition in prod.conditions:
                if "goal" in condition and not working_memory.contains("goal"):
                    conditions_met = False
                if "retrieval buffer empty" in condition and working_memory.get_buffer("retrieval"):
                    conditions_met = False
                if "plan exists" in condition and not working_memory.contains("plan"):
                    conditions_met = False
                if "action failed" in condition and working_memory.get("last_outcome") != "failure":
                    conditions_met = False
                if "outcome received" in condition and not working_memory.contains("outcome"):
                    conditions_met = False
            
            if conditions_met:
                matched.append(prod)
        
        # Sort by utility (highest first)
        matched.sort(key=lambda p: (p.utility, p.priority), reverse=True)
        return matched
    
    def fire_production(self, production: Production) -> List[str]:
        """Fire a production rule."""
        production.activation = min(1.0, production.activation + 0.05)
        return production.actions


# ============================================================================
# DECLARATIVE MEMORY (Semantic + Episodic)
# ============================================================================

class DeclarativeMemory:
    """Declarative memory with semantic and episodic stores (ACT-R style).
    
    Semantic memory: General knowledge, facts, concepts
    Episodic memory: Specific experiences, events, episodes
    """
    
    def __init__(self):
        self.semantic: Dict[str, Chunk] = {}
        self.episodic: List[Episode] = []
        self._build_base_knowledge()
    
    def _build_base_knowledge(self) -> None:
        """Build foundational semantic knowledge."""
        base_concepts = [
            ("causation", "When A causes B, A leads to B"),
            ("correlation", "When A and B occur together, they may be related"),
            ("time", "Events occur in sequence"),
            ("space", "Objects have location"),
            ("object", "Entities exist independently"),
            ("category", "Entities can be grouped"),
            ("action", "Changes can be made to the world"),
            ("goal", "Desired end states guide behavior"),
            ("belief", "Representations of the world"),
            ("plan", "Sequences of actions to achieve goals"),
        ]
        
        for name, content in base_concepts:
            chunk = Chunk(
                id=name,
                content=content,
                memory_type=MemoryType.SEMANTIC,
                chunk_type="foundation",
                activation=0.8,
            )
            chunk.slots["name"] = name
            self.semantic[name] = chunk
    
    def store_semantic(self, name: str, content: Any, chunk_type: str = "concept") -> Chunk:
        """Store semantic knowledge."""
        chunk = Chunk(
            id=name,
            content=content,
            memory_type=MemoryType.SEMANTIC,
            chunk_type=chunk_type,
        )
        if isinstance(content, dict):
            chunk.slots = content
        self.semantic[name] = chunk
        return chunk
    
    def retrieve_semantic(self, cue: str, limit: int = 5) -> List[Chunk]:
        """Retrieve semantic memories by cue."""
        results = []
        cue_lower = cue.lower()
        
        for chunk in self.semantic.values():
            content_match = (
                isinstance(chunk.content, str) and cue_lower in chunk.content.lower()
            ) or (
                isinstance(chunk.content, dict) and cue_lower in str(chunk.content).lower()
            )
            slots_match = cue_lower in str(chunk.slots).lower()
            
            if content_match or slots_match:
                chunk.access()
                results.append(chunk)
        
        results.sort(key=lambda c: c.activation, reverse=True)
        return results[:limit]
    
    def store_episode(
        self,
        situation: str,
        actions: List[str],
        outcome: str,
        emotion: str = "neutral"
    ) -> Episode:
        """Store an episodic memory."""
        episode = Episode(
            id=str(uuid.uuid4())[:8],
            content=f"{situation} -> {outcome}",
            memory_type=MemoryType.EPISODIC,
            situation=situation,
            actions=actions,
            outcome=outcome,
            emotion=emotion,
        )
        self.episodic.append(episode)
        
        # Keep only last 1000 episodes
        if len(self.episodic) > 1000:
            self.episodic = self.episodic[-1000:]
        
        return episode
    
    def retrieve_episodes(self, cue: str, limit: int = 5) -> List[Episode]:
        """Retrieve episodic memories by cue."""
        results = []
        
        for episode in reversed(self.episodic):
            if cue.lower() in episode.situation.lower() or cue.lower() in episode.outcome.lower():
                episode.access()
                results.append(episode)
        
        return results[:limit]
    
    def get_recent_episodes(self, count: int = 10) -> List[Episode]:
        """Get most recent episodes."""
        return self.episodic[-count:]


# ============================================================================
# WORLD MODEL (AGI Core Component)
# ============================================================================

class WorldModel:
    """World model for simulation, prediction, and planning.
    
    The world model is a core AGI component that:
    - Represents the environment
    - Enables simulation and counterfactuals
    - Supports planning
    - Enables transfer across tasks
    """
    
    def __init__(self):
        self.entities: Dict[str, Dict[str, Any]] = {}
        self.relations: List[Tuple[str, str, str]] = []  # (entity, relation, entity)
        self.rules: List[str] = []
        self.causal_graph: Dict[str, List[str]] = defaultdict(list)
        self.state_history: List[Dict[str, Any]] = []
    
    def add_entity(self, name: str, properties: Dict[str, Any]) -> None:
        """Add an entity to the world model."""
        self.entities[name] = {
            "properties": properties,
            "created_at": time.time(),
        }
    
    def add_relation(self, from_entity: str, relation: str, to_entity: str) -> None:
        """Add a relation between entities."""
        self.relations.append((from_entity, relation, to_entity))
        
        # Build causal graph
        if "causes" in relation.lower() or "enables" in relation.lower():
            self.causal_graph[from_entity].append(to_entity)
    
    def add_rule(self, rule: str) -> None:
        """Add an inference rule."""
        self.rules.append(rule)
    
    def predict(self, from_state: Dict[str, Any], action: str) -> Dict[str, Any]:
        """Predict next state given action."""
        # Simple rule-based prediction
        predicted = from_state.copy()
        
        # Apply known causal rules
        for entity, effects in self.causal_graph.items():
            if entity in from_state and from_state[entity].get("active"):
                for effect in effects:
                    predicted.setdefault(effect, {})["predicted_from"] = entity
        
        return predicted
    
    def simulate(self, actions: List[str], initial_state: Dict[str, Any]) -> List[Dict[str, Any]]:
        """Simulate a sequence of actions."""
        states = [initial_state]
        current = initial_state.copy()
        
        for action in actions:
            current = self.predict(current, action)
            states.append(current)
        
        return states
    
    def counterfactual(self, outcome: str,假设: str) -> str:
        """Generate counterfactual analysis."""
        return f"If {假设}, then {outcome} would likely differ"


# ============================================================================
# METACOGNITION (Self-Monitoring & Improvement)
# ============================================================================

class Metacognition:
    """Metacognition - thinking about thinking.
    
    Components:
    - Self-monitoring
    - Performance tracking
    - Strategy selection
    - Learning to learn
    """
    
    def __init__(self):
        self.reasoning_quality: float = 0.5
        self.strategy_effectiveness: Dict[str, float] = defaultdict(float)
        self.cognitive_load: float = 0.0
        self.self_knowledge: Dict[str, Any] = {}
        self.learning_history: List[Dict] = []
        
    def monitor(self, thought: str, result: Any) -> Dict[str, float]:
        """Monitor reasoning quality."""
        quality = self._assess_quality(thought, result)
        self.reasoning_quality = 0.9 * self.reasoning_quality + 0.1 * quality
        
        return {
            "quality": quality,
            "overall": self.reasoning_quality,
            "cognitive_load": self.cognitive_load,
        }
    
    def _assess_quality(self, thought: str, result: Any) -> float:
        """Assess quality of reasoning."""
        score = 0.5
        
        # Length heuristic
        if len(thought) > 100:
            score += 0.1
        
        # Contains reasoning words
        reasoning_words = ["because", "therefore", "thus", "since", "implies", "concludes"]
        if any(word in thought.lower() for word in reasoning_words):
            score += 0.2
        
        # Has conclusion
        if result:
            score += 0.2
        
        return min(1.0, score)
    
    def update_strategy_effectiveness(self, strategy: str, outcome: float) -> None:
        """Update strategy effectiveness score."""
        current = self.strategy_effectiveness[strategy]
        self.strategy_effectiveness[strategy] = 0.9 * current + 0.1 * outcome
    
    def select_strategy(self) -> str:
        """Select best performing strategy."""
        if not self.strategy_effectiveness:
            return "reason_deductively"
        
        best = max(self.strategy_effectiveness.items(), key=lambda x: x[1])
        return best[0]
    
    def reflect(self) -> str:
        """Generate self-reflection."""
        quality = "high" if self.reasoning_quality > 0.7 else "medium" if self.reasoning_quality > 0.4 else "low"
        
        suggestions = []
        if self.cognitive_load > 0.8:
            suggestions.append("reduce cognitive load")
        if self.reasoning_quality < 0.5:
            suggestions.append("use more evidence")
        
        return f"My reasoning quality is {quality}. {' '.join(suggestions) if suggestions else 'I am functioning well.'}"


# ============================================================================
# COGNITIVE AGENT (Common Model of Cognition Implementation)
# ============================================================================

class CognitiveAgent:
    """Cognitive Agent based on Common Model of Cognition.
    
    Implements:
    - Perception -> Working Memory -> Procedural Memory -> Action
    - Observe-Decide-Act pattern
    - Hierarchical task decomposition
    - Multi-method reasoning
    - Self-monitoring and improvement
    
    Inspired by: ACT-R, Soar, Sigma architectures
    """
    
    def __init__(
        self,
        name: str,
        role: str = "general",
        verbose: bool = True,
    ):
        self.name = name
        self.role = role
        
        # Common Model Components
        self.working_memory = WorkingMemory()
        self.procedural_memory = ProceduralMemory()
        self.declarative_memory = DeclarativeMemory()
        self.world_model = WorldModel()
        self.metacognition = Metacognition()
        
        # State
        self.state = CognitiveState.IDLE
        self.goal: Optional[str] = None
        self.plan: List[str] = []
        self.current_action: Optional[str] = None
        
        # Reasoning history
        self.reasoning_history: List[Dict] = []
        
        # Verbosity
        self.verbose = verbose
        
        # Initialize agent identity in world model
        self.world_model.add_entity(f"agent_{name}", {
            "type": "agent",
            "role": role,
        })
    
    # -------------------------------------------------------------------------
    # PERCEPTION (Input Processing)
    # -------------------------------------------------------------------------
    
    def perceive(self, input_data: Any) -> None:
        """Process perceptual input."""
        self.state = CognitiveState.PERCEIVING
        
        if self.verbose:
            print(f"[{self.name}] PERCEIVE: {str(input_data)[:50]}...")
        
        # Store in perception buffer
        self.working_memory.set_buffer("perception", MemoryItem(
            id="percept_" + str(uuid.uuid4())[:8],
            content=input_data,
            memory_type=MemoryType.WORKING,
        ))
        
        # Add to context
        self.working_memory.set("last_input", input_data)
        self.working_memory.set("perception_time", time.time())
        
        self.state = CognitiveState.IDLE
    
    # -------------------------------------------------------------------------
    # DECISION CYCLE (Observe-Decide-Act)
    # -------------------------------------------------------------------------
    
    def decision_cycle(self) -> Optional[str]:
        """Execute one decision cycle (Common Model of Cognition)."""
        # Match productions against working memory
        productions = self.procedural_memory.match_productions(self.working_memory)
        
        if not productions:
            return None
        
        # Fire highest utility production
        production = productions[0]
        actions = self.procedural_memory.fire_production(production)
        
        if self.verbose:
            print(f"[{self.name}] FIRE: {production.id} -> {actions}")
        
        return actions[0] if actions else None
    
    # -------------------------------------------------------------------------
    # REASONING (Multi-Method)
    # -------------------------------------------------------------------------
    
    def reason(
        self,
        query: str,
        method: Optional[ReasoningMethod] = None,
    ) -> Dict[str, Any]:
        """Reason about a query using specified method."""
        self.state = CognitiveState.REASONING
        
        if method is None:
            method = ReasoningMethod.DEDUCTIVE
        
        result = {
            "query": query,
            "method": method.value,
            "reasoning_steps": [],
            "conclusion": "",
            "confidence": 0.0,
        }
        
        if method == ReasoningMethod.DEDUCTIVE:
            result = self._deductive_reason(query, result)
        elif method == ReasoningMethod.INDUCTIVE:
            result = self._inductive_reason(query, result)
        elif method == ReasoningMethod.ABDUCTIVE:
            result = self._abductive_reason(query, result)
        elif method == ReasoningMethod.CAUSAL:
            result = self._causal_reason(query, result)
        elif method == ReasoningMethod.ANALOGICAL:
            result = self._analogical_reason(query, result)
        
        # Monitor reasoning quality
        quality = self.metacognition.monitor(str(result["reasoning_steps"]), result["conclusion"])
        result["quality"] = quality
        
        self.state = CognitiveState.IDLE
        self.reasoning_history.append(result)
        
        return result
    
    def _deductive_reason(self, query: str, result: Dict) -> Dict:
        """Deductive reasoning: Apply rules to derive conclusions."""
        result["reasoning_steps"].append(f"Analyze query: {query}")
        result["reasoning_steps"].append("Identify applicable rules")
        result["reasoning_steps"].append("Apply modus ponens")
        
        # Check declarative memory for rules
        rules = self.declarative_memory.retrieve_semantic("rule")
        if rules:
            result["reasoning_steps"].append(f"Found relevant rule: {rules[0].content}")
        
        result["conclusion"] = f"Deductively derived conclusion about: {query}"
        result["confidence"] = 0.8
        return result
    
    def _inductive_reason(self, query: str, result: Dict) -> Dict:
        """Inductive reasoning: Generalize from cases."""
        result["reasoning_steps"].append(f"Gather cases related to: {query}")
        
        # Retrieve episodic memories
        episodes = self.declarative_memory.retrieve_episodes(query, limit=5)
        result["reasoning_steps"].append(f"Found {len(episodes)} relevant episodes")
        
        if episodes:
            result["reasoning_steps"].append("Identify common patterns")
            result["reasoning_steps"].append("Form generalization")
            result["conclusion"] = f"Generalized pattern from {len(episodes)} cases"
            result["confidence"] = 0.6
        else:
            result["conclusion"] = "Insufficient evidence for induction"
            result["confidence"] = 0.3
        
        return result
    
    def _abductive_reason(self, query: str, result: Dict) -> Dict:
        """Abductive reasoning: Infer best explanation."""
        result["reasoning_steps"].append(f"Observe: {query}")
        result["reasoning_steps"].append("Generate possible explanations")
        result["reasoning_steps"].append("Select most likely explanation")
        
        result["conclusion"] = f"Best explanation for: {query}"
        result["confidence"] = 0.5
        return result
    
    def _causal_reason(self, query: str, result: Dict) -> Dict:
        """Causal reasoning: Understand cause-effect."""
        result["reasoning_steps"].append(f"Identify causes related to: {query}")
        
        # Query world model causal graph
        for entity, effects in self.world_model.causal_graph.items():
            if entity in query:
                result["reasoning_steps"].append(f"{entity} causes: {effects}")
        
        result["conclusion"] = f"Causal analysis of: {query}"
        result["confidence"] = 0.7
        return result
    
    def _analogical_reason(self, query: str, result: Dict) -> Dict:
        """Analogical reasoning: Transfer patterns."""
        result["reasoning_steps"].append(f"Find analogous case to: {query}")
        
        # Retrieve similar semantic memories
        similar = self.declarative_memory.retrieve_semantic(query, limit=3)
        if similar:
            result["reasoning_steps"].append(f"Using analogy from: {similar[0].content}")
        
        result["conclusion"] = f"Analogical conclusion for: {query}"
        result["confidence"] = 0.5
        return result
    
    # -------------------------------------------------------------------------
    # PLANNING (Hierarchical Task Network)
    # -------------------------------------------------------------------------
    
    def plan_action(self, goal: str) -> List[str]:
        """Create a plan to achieve goal (HTN-style)."""
        self.state = CognitiveState.PLANNING
        self.goal = goal
        self.working_memory.set("goal", goal)
        
        if self.verbose:
            print(f"[{self.name}] PLAN: Goal = {goal}")
        
        # Simple HTN-style decomposition
        plan = []
        
        # Phase 1: Understand goal
        plan.append("understand_goal")
        
        # Phase 2: Gather information
        plan.append("retrieve_knowledge")
        
        # Phase 3: Create subplan
        plan.append("decompose_subtasks")
        
        # Phase 4: Execute
        plan.append("execute_subtasks")
        
        # Phase 5: Verify
        plan.append("verify_outcome")
        
        self.plan = plan
        self.working_memory.set("plan", plan)
        
        if self.verbose:
            print(f"[{self.name}] PLAN: {len(plan)} steps created")
        
        self.state = CognitiveState.IDLE
        return plan
    
    # -------------------------------------------------------------------------
    # ACTION EXECUTION
    # -------------------------------------------------------------------------
    
    def act(self, action: str) -> Dict[str, Any]:
        """Execute an action."""
        self.state = CognitiveState.ACTING
        self.current_action = action
        
        if self.verbose:
            print(f"[{self.name}] ACT: {action}")
        
        result = {
            "action": action,
            "success": True,
            "outcome": f"Executed: {action}",
            "timestamp": time.time(),
        }
        
        self.working_memory.set("last_action", action)
        self.working_memory.set("last_outcome", "success")
        
        # Store episode
        episode = self.declarative_memory.store_episode(
            situation=f"Achieved goal: {self.goal}",
            actions=self.plan + [action],
            outcome="success",
        )
        
        self.state = CognitiveState.IDLE
        return result
    
    # -------------------------------------------------------------------------
    # LEARNING
    # -------------------------------------------------------------------------
    
    def learn(
        self,
        concept: str,
        content: Any,
        episodic_context: Optional[Dict] = None,
    ) -> None:
        """Learn new knowledge."""
        self.state = CognitiveState.LEARNING
        
        # Store in declarative memory
        self.declarative_memory.store_semantic(concept, content)
        
        # Add to world model
        if isinstance(content, dict):
            self.world_model.add_entity(concept, content)
        elif isinstance(content, str) and "->" in content:
            parts = content.split("->")
            if len(parts) == 2:
                self.world_model.add_relation(parts[0].strip(), "relates_to", parts[1].strip())
        
        # Store episode if context provided
        if episodic_context:
            self.declarative_memory.store_episode(
                situation=episodic_context.get("situation", f"Learned: {concept}"),
                actions=episodic_context.get("actions", []),
                outcome=episodic_context.get("outcome", "knowledge acquired"),
            )
        
        if self.verbose:
            print(f"[{self.name}] LEARN: {concept}")
        
        self.state = CognitiveState.IDLE
    
    # -------------------------------------------------------------------------
    # REFLECTION
    # -------------------------------------------------------------------------
    
    def reflect(self) -> str:
        """Reflect on recent experiences."""
        self.state = CognitiveState.REFLECTING
        
        reflection = self.metacognition.reflect()
        
        # Analyze recent episodes
        recent = self.declarative_memory.get_recent_episodes(5)
        if recent:
            successes = sum(1 for e in recent if e.outcome == "success")
            reflection += f" Recent success rate: {successes}/{len(recent)}"
        
        if self.verbose:
            print(f"[{self.name}] REFLECT: {reflection}")
        
        self.state = CognitiveState.IDLE
        return reflection
    
    # -------------------------------------------------------------------------
    # MAIN EXECUTION LOOP
    # -------------------------------------------------------------------------
    
    async def think(self, input_data: Any, goal: Optional[str] = None) -> Dict[str, Any]:
        """Main thinking loop - integrates all cognitive components."""
        results = {
            "input": input_data,
            "perception": None,
            "reasoning": None,
            "planning": None,
            "action": None,
            "learning": None,
            "reflection": None,
        }
        
        # 1. PERCEIVE
        self.perceive(input_data)
        results["perception"] = "processed"
        
        # 2. REASON (if query provided)
        if isinstance(input_data, str):
            reasoning_result = self.reason(input_data)
            results["reasoning"] = reasoning_result
        
        # 3. PLAN (if goal provided)
        if goal:
            plan = self.plan_action(goal)
            results["planning"] = {"goal": goal, "plan": plan}
        
        # 4. ACT (execute plan)
        if self.plan:
            for action in self.plan:
                action_result = self.act(action)
                results["action"] = action_result
        
        # 5. LEARN from outcome
        self.learn(
            concept=f"experience_{len(self.declarative_memory.episodic)}",
            content={"input": input_data, "goal": goal},
        )
        results["learning"] = "completed"
        
        # 6. REFLECT
        reflection = self.reflect()
        results["reflection"] = reflection
        
        return results
    
    def get_state(self) -> Dict[str, Any]:
        """Get current cognitive state."""
        return {
            "name": self.name,
            "role": self.role,
            "state": self.state.value,
            "goal": self.goal,
            "plan_length": len(self.plan),
            "semantic_memories": len(self.declarative_memory.semantic),
            "episodes": len(self.declarative_memory.episodic),
            "reasoning_quality": self.metacognition.reasoning_quality,
        }


# ============================================================================
# COGNITIVE MULTI-AGENT SYSTEM
# ============================================================================

class CognitiveCrew:
    """Multi-agent crew with shared cognition architecture."""
    
    def __init__(self, agents: List[CognitiveAgent], name: str = "crew"):
        self.agents = {a.name: a for a in agents}
        self.name = name
        self.shared_memory = DeclarativeMemory()
        self.world_model = WorldModel()
        
        # Connect agents to shared resources
        for agent in agents:
            # Share world model
            for entity, props in self.world_model.entities.items():
                agent.world_model.entities[entity] = props
        
    def add_agent(self, agent: CognitiveAgent) -> None:
        """Add an agent to the crew."""
        self.agents[agent.name] = agent
    
    async def solve_collaboratively(
        self,
        problem: str,
        roles: Optional[Dict[str, str]] = None,
    ) -> Dict[str, Any]:
        """Solve a problem collaboratively."""
        results = {}
        
        # Phase 1: Parallel analysis
        tasks = []
        for name, agent in self.agents.items():
            role_context = roles.get(name, "general") if roles else "general"
            task = agent.think(f"As a {role_context}: {problem}", goal=f"Solve: {problem}")
            tasks.append(task)
        
        phase_results = await asyncio.gather(*tasks)
        
        for (name, agent), result in zip(self.agents.items(), phase_results):
            results[name] = result
        
        # Phase 2: Synthesis
        synthesis = self._synthesize(results)
        results["synthesis"] = synthesis
        
        return results
    
    def _synthesize(self, results: Dict) -> str:
        """Synthesize results from multiple agents."""
        parts = [f"## Collaborative Solution from {self.name}\n"]
        
        for name, result in results.items():
            if name != "synthesis":
                reasoning = result.get("reasoning", {})
                if reasoning:
                    parts.append(f"\n### {name}:\n{reasoning.get('conclusion', '')}")
        
        parts.append("\n## Final Synthesis:\nMulti-agent analysis complete.")
        
        return "\n".join(parts)


# ============================================================================
# OPENSHELL INTEGRATION
# ============================================================================

class OpenShellIntegration:
    """Integration with OpenShell for sandboxed execution.
    
    Provides:
    - Secure code execution
    - Sandboxed tool use
    - Policy enforcement
    """
    
    def __init__(self, verbose: bool = True):
        self.verbose = verbose
        self.sessions: Dict[str, Any] = {}
        self._check_openshell()
    
    def _check_openshell(self) -> None:
        """Check if OpenShell CLI is available."""
        try:
            import subprocess
            result = subprocess.run(
                ["openshell", "--version"],
                capture_output=True,
                text=True,
                timeout=5,
            )
            if result.returncode == 0:
                if self.verbose:
                    print(f"[OpenShell] Available: {result.stdout.strip()}")
                self.available = True
            else:
                if self.verbose:
                    print("[OpenShell] CLI returned non-zero")
                self.available = False
        except FileNotFoundError:
            if self.verbose:
                print("[OpenShell] Not installed - will use fallback")
            self.available = False
        except Exception as e:
            if self.verbose:
                print(f"[OpenShell] Error: {e}")
            self.available = False
    
    def execute_sandboxed(
        self,
        code: str,
        language: str = "python",
    ) -> Dict[str, Any]:
        """Execute code in sandboxed environment."""
        if not self.available:
            return self._execute_fallback(code, language)
        
        # Use OpenShell for execution
        try:
            import subprocess
            result = subprocess.run(
                ["openshell", "exec", "-c", code],
                capture_output=True,
                text=True,
                timeout=30,
            )
            
            return {
                "success": result.returncode == 0,
                "output": result.stdout,
                "error": result.stderr,
            }
        except Exception as e:
            return {
                "success": False,
                "output": "",
                "error": str(e),
            }
    
    def _execute_fallback(self, code: str, language: str) -> Dict[str, Any]:
        """Fallback execution without OpenShell."""
        if language == "python":
            try:
                import io
                import contextlib
                
                output = io.StringIO()
                exec_globals = {"__name__": "__sandbox__"}
                
                with contextlib.redirect_stdout(output):
                    exec(code, exec_globals)
                
                return {
                    "success": True,
                    "output": output.getvalue(),
                    "error": "",
                    "mode": "fallback",
                }
            except Exception as e:
                return {
                    "success": False,
                    "output": "",
                    "error": str(e),
                    "mode": "fallback",
                }
        
        return {
            "success": False,
            "output": "",
            "error": f"Language {language} not supported in fallback mode",
            "mode": "fallback",
        }
    
    def create_sandbox_session(self, name: str = "default") -> Dict[str, Any]:
        """Create a sandbox session."""
        session_id = f"session_{uuid.uuid4().hex[:8]}"
        
        self.sessions[session_id] = {
            "created": time.time(),
            "name": name,
            "executions": 0,
        }
        
        return {"session_id": session_id, "available": self.available}


# ============================================================================
# TRUE AGI AGENT (Full Implementation)
# ============================================================================

class TrueAGIAgent:
    """True AGI Agent combining all components.
    
    Based on:
    - Common Model of Cognition (ACT-R, Soar, Sigma)
    - Cognitive Design Patterns
    - AGI Architecture Requirements
    - CoALA Framework
    
    Components:
    1. Perception - Input processing
    2. Working Memory - Current context
    3. Procedural Memory - Action rules
    4. Declarative Memory - Knowledge
    5. World Model - Environment representation
    6. Metacognition - Self-improvement
    7. OpenShell - Sandboxed execution
    """
    
    def __init__(
        self,
        name: str,
        role: str = "general",
        verbose: bool = True,
    ):
        # Core cognitive architecture
        self.cognitive = CognitiveAgent(name=name, role=role, verbose=verbose)
        
        # OpenShell integration
        self.shell = OpenShellIntegration(verbose=verbose)
        
        # Additional capabilities
        self.tools: Dict[str, Callable] = {}
        self.custom_rules: List[str] = []
        
        self.verbose = verbose
        
    def add_tool(self, name: str, func: Callable) -> None:
        """Add a tool for the agent to use."""
        self.tools[name] = func
        self.cognitive.procedural_memory.add_production(
            Production(
                id=f"use_tool_{name}",
                content=f"When tool {name} needed, execute it",
                memory_type=MemoryType.PROCEDURAL,
                conditions=[f"tool {name} needed"],
                actions=[f"execute tool {name}"],
                utility=0.8,
            )
        )
    
    async def think_and_act(
        self,
        input_data: Any,
        goal: Optional[str] = None,
        use_tools: bool = True,
    ) -> Dict[str, Any]:
        """Think and act - full cognitive cycle."""
        results = await self.cognitive.think(input_data, goal)
        
        # Execute any tools if needed
        if use_tools and self.tools:
            tool_results = {}
            for tool_name, tool_func in self.tools.items():
                try:
                    if asyncio.iscoroutinefunction(tool_func):
                        result = await tool_func(input_data)
                    else:
                        result = tool_func(input_data)
                    tool_results[tool_name] = result
                except Exception as e:
                    tool_results[tool_name] = f"Error: {e}"
            
            results["tools"] = tool_results
        
        return results
    
    def execute_code(self, code: str, language: str = "python") -> Dict[str, Any]:
        """Execute code using OpenShell."""
        return self.shell.execute_sandboxed(code, language)
    
    def learn_from_feedback(
        self,
        feedback: str,
        outcome: str,
    ) -> None:
        """Learn from feedback."""
        # Store in declarative memory
        self.cognitive.learn(
            concept=f"feedback_{len(self.cognitive.declarative_memory.episodic)}",
            content={"feedback": feedback, "outcome": outcome},
            episodic_context={
                "situation": "Received feedback",
                "actions": [feedback],
                "outcome": outcome,
            },
        )
        
        # Update metacognition
        success = outcome.lower() in ["success", "positive", "good"]
        self.cognitive.metacognition.update_strategy_effectiveness(
            "general",
            1.0 if success else 0.0,
        )
    
    def get_status(self) -> Dict[str, Any]:
        """Get agent status."""
        return {
            "cognitive": self.cognitive.get_state(),
            "tools": list(self.tools.keys()),
            "openshell_available": self.shell.available,
            "sessions": len(self.shell.sessions),
        }


# ============================================================================
# FACTORY FUNCTIONS
# ============================================================================

def create_cognitive_agent(
    name: str,
    role: str = "general",
    verbose: bool = True,
) -> CognitiveAgent:
    """Create a cognitive agent."""
    return CognitiveAgent(name=name, role=role, verbose=verbose)


def create_true_agi_agent(
    name: str,
    role: str = "general",
    verbose: bool = True,
) -> TrueAGIAgent:
    """Create a True AGI agent with full cognitive architecture."""
    return TrueAGIAgent(name=name, role=role, verbose=verbose)


def create_cognitive_crew(
    agents: List[CognitiveAgent],
    name: str = "crew",
) -> CognitiveCrew:
    """Create a cognitive multi-agent crew."""
    return CognitiveCrew(agents=agents, name=name)


__all__ = [
    # Enums
    "CognitiveModule",
    "CognitiveState",
    "MemoryType",
    "ReasoningMethod",
    # Memory
    "MemoryItem",
    "Chunk",
    "Production",
    "Episode",
    "WorkingMemory",
    "ProceduralMemory",
    "DeclarativeMemory",
    # Core
    "WorldModel",
    "Metacognition",
    "CognitiveAgent",
    "CognitiveCrew",
    "TrueAGIAgent",
    "OpenShellIntegration",
    # Factories
    "create_cognitive_agent",
    "create_true_agi_agent",
    "create_cognitive_crew",
]
