theNorms commited on
Commit
6f63ce2
·
verified ·
1 Parent(s): c6d27e0

Upload memory_learning.py

Browse files
Files changed (1) hide show
  1. models/memory_learning.py +1011 -0
models/memory_learning.py ADDED
@@ -0,0 +1,1011 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Memory and Learning Systems Module
3
+ Implements hierarchical memory persistence with qualia tagging and meta-learning.
4
+
5
+ Version: 1.0.0
6
+ Status: Production-Ready
7
+ Integrated with: Unified Consciousness CLI (Micro Level)
8
+ """
9
+
10
+ from typing import Dict, List, Optional, Any, Tuple
11
+ from dataclasses import dataclass, field, asdict
12
+ import logging
13
+ from datetime import datetime
14
+ from collections import deque
15
+ import json
16
+ import hashlib
17
+ import numpy as np
18
+ import asyncio
19
+
20
+ from abc import ABC, abstractmethod
21
+ from enum import Enum
22
+ from typing import Dict as TypingDict
23
+ from collections import deque
24
+ from typing import Optional
25
+
26
+ # CLI Integration
27
+ from unified_consciousness_cli import CLICommand, CLIResult, get_unified_cli
28
+
29
+ # Define SubconsciousOutput here to avoid circular imports
30
+ @dataclass
31
+ class SubconsciousOutput:
32
+ """Output from subconscious processing (O_S)."""
33
+ module_name: str
34
+ content: Dict[str, Any]
35
+ timestamp: float
36
+ priority: float = 0.5
37
+ emotional_valence: float = 0.0
38
+ confidence: float = 0.8
39
+ metadata: Dict[str, Any] = field(default_factory=dict)
40
+
41
+ def to_dict(self) -> Dict[str, Any]:
42
+ return asdict(self)
43
+
44
+
45
+ class ModuleType(Enum):
46
+ MEMORY = "memory"
47
+ ANALYSIS = "analysis"
48
+ AWARENESS = "awareness"
49
+ CONSCIOUSNESS = "consciousness"
50
+
51
+
52
+ class SubconsciousAgent(ABC):
53
+ """Minimal base class for subconscious agents."""
54
+
55
+ def __init__(self, name: str, module_type: ModuleType):
56
+ self.name = name
57
+ self.module_type = module_type
58
+ self.activation_history = deque(maxlen=100)
59
+ self.last_output: Optional[SubconsciousOutput] = None
60
+
61
+ @abstractmethod
62
+ async def process(self, input_data: Dict[str, Any]) -> SubconsciousOutput:
63
+ """Process input and generate subconscious output."""
64
+ pass
65
+
66
+ async def activate(self, input_data: Dict[str, Any]) -> SubconsciousOutput:
67
+ """Activate agent and track activation history."""
68
+ output = await self.process(input_data)
69
+ self.last_output = output
70
+ self.activation_history.append({
71
+ 'timestamp': datetime.now().timestamp(),
72
+ 'output': output.to_dict()
73
+ })
74
+ return output
75
+
76
+ class ModuleType(Enum):
77
+ MEMORY = "memory"
78
+ ANALYSIS = "analysis"
79
+ AWARENESS = "awareness"
80
+ CONSCIOUSNESS = "consciousness"
81
+
82
+ # Configure logging
83
+ logging.basicConfig(
84
+ level=logging.INFO,
85
+ format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
86
+ )
87
+ logger = logging.getLogger(__name__)
88
+
89
+
90
+ @dataclass
91
+ class MemoryRecord:
92
+ """Represents a single memory record with qualia tagging."""
93
+ record_id: str
94
+ memory_type: str # 'episodic' or 'semantic'
95
+ content: Dict[str, Any]
96
+ qualia_tag: Optional[Dict[str, float]] = None # Phenomenal experience metadata
97
+ timestamp: datetime = field(default_factory=datetime.now)
98
+ context: Optional[str] = None
99
+ retrieval_count: int = 0
100
+ importance_score: float = 0.5 # 0-1 importance ranking
101
+
102
+ def to_dict(self) -> Dict[str, Any]:
103
+ """Convert to dictionary."""
104
+ return {
105
+ 'record_id': self.record_id,
106
+ 'memory_type': self.memory_type,
107
+ 'content': self.content,
108
+ 'qualia_tag': self.qualia_tag,
109
+ 'timestamp': self.timestamp.isoformat(),
110
+ 'context': self.context,
111
+ 'retrieval_count': self.retrieval_count,
112
+ 'importance': self.importance_score
113
+ }
114
+
115
+ def compute_hash(self) -> str:
116
+ """Compute content hash for integrity verification."""
117
+ content_str = json.dumps(self.content, sort_keys=True, default=str)
118
+ return hashlib.sha256(content_str.encode()).hexdigest()
119
+
120
+
121
+ class MemoryStore(SubconsciousAgent):
122
+ """
123
+ Hierarchical memory persistence with qualia tagging.
124
+
125
+ Maintains episodic memories (specific events) and semantic memories
126
+ (general knowledge), both enhanced with qualia-based retrieval.
127
+ """
128
+
129
+ def __init__(self, max_episodic: int = 1000, max_semantic: int = 500):
130
+ """
131
+ Initialize memory store.
132
+
133
+ Args:
134
+ max_episodic: Maximum episodic memory capacity
135
+ max_semantic: Maximum semantic memory capacity
136
+ """
137
+ # Initialize as SubconsciousAgent
138
+ super().__init__("Memory", ModuleType.MEMORY)
139
+
140
+ self.episodic_memory = deque(maxlen=max_episodic)
141
+ self.semantic_memory = deque(maxlen=max_semantic)
142
+ self.memory_index: Dict[str, MemoryRecord] = {} # Quick lookup by ID
143
+
144
+ # Consolidation tracking
145
+ self.consolidation_count = 0
146
+ self.consolidation_history = deque(maxlen=100)
147
+
148
+ logger.info(f"Initialized MemoryStore (episodic={max_episodic}, semantic={max_semantic})")
149
+
150
+ # CLI Integration - Register with MicroCLI
151
+ self.cli_registered = False
152
+ self._register_with_cli()
153
+
154
+ def _register_with_cli(self) -> None:
155
+ """Register this memory store with the MicroCLI for command processing."""
156
+ try:
157
+ cli = get_unified_cli()
158
+ micro_cli = cli.sub_clis.get("sub").sub_clis.get("mini").sub_clis.get("micro") if cli.sub_clis.get("sub") else None
159
+ if micro_cli:
160
+ micro_cli.register_agent("memory", self.handle_cli_command)
161
+ self.cli_registered = True
162
+ logger.info("✅ MemoryStore registered with MicroCLI")
163
+ except Exception as e:
164
+ logger.warning(f"Failed to register with CLI: {e}")
165
+
166
+ def handle_cli_command(self, command: str) -> str:
167
+ """
168
+ Handle CLI commands for memory operations.
169
+
170
+ Supported commands:
171
+ - status - Get memory store status
172
+ - store_episodic <content_json> - Store episodic memory
173
+ - store_semantic <content_json> - Store semantic memory
174
+ - retrieve <record_id> - Retrieve specific memory
175
+ - search <query> - Search memories
176
+ - consolidate - Trigger memory consolidation
177
+ """
178
+ try:
179
+ parts = command.lower().split()
180
+ if len(parts) < 1:
181
+ return "Usage: <command> [args]"
182
+
183
+ subcommand = parts[0]
184
+
185
+ if subcommand == "status":
186
+ episodic_count = len(self.episodic_memory)
187
+ semantic_count = len(self.semantic_memory)
188
+ total_memories = len(self.memory_index)
189
+ return f"MemoryStore: Active - {episodic_count} episodic, {semantic_count} semantic, {total_memories} total memories"
190
+
191
+ elif subcommand == "store_episodic" and len(parts) >= 2:
192
+ try:
193
+ content_str = " ".join(parts[1:])
194
+ content = json.loads(content_str)
195
+ record_id = self.store_episodic(content)
196
+ return f"MemoryStore: Stored episodic memory: {record_id}"
197
+ except json.JSONDecodeError as e:
198
+ return f"MemoryStore: Invalid JSON content: {e}"
199
+
200
+ elif subcommand == "store_semantic" and len(parts) >= 2:
201
+ try:
202
+ content_str = " ".join(parts[1:])
203
+ content = json.loads(content_str)
204
+ record_id = self.store_semantic(content)
205
+ return f"MemoryStore: Stored semantic memory: {record_id}"
206
+ except json.JSONDecodeError as e:
207
+ return f"MemoryStore: Invalid JSON content: {e}"
208
+
209
+ elif subcommand == "retrieve" and len(parts) >= 2:
210
+ record_id = parts[1]
211
+ if record_id in self.memory_index:
212
+ record = self.memory_index[record_id]
213
+ return f"MemoryStore: Retrieved {record.memory_type} memory: {record.content}"
214
+ else:
215
+ return f"MemoryStore: Memory record not found: {record_id}"
216
+
217
+ elif subcommand == "search" and len(parts) >= 2:
218
+ query = " ".join(parts[1:])
219
+ results = self.search_memories(query)
220
+ output = f"MemoryStore: Search results for '{query}': {len(results)} matches"
221
+ for record in results[:3]: # Show first 3
222
+ output += f"\n {record.record_id}: {record.memory_type} - {str(record.content)[:30]}..."
223
+ return output
224
+
225
+ elif subcommand == "consolidate":
226
+ try:
227
+ consolidated = self.consolidate_memories()
228
+ return f"MemoryStore: Memory consolidation complete: {len(consolidated)} records processed"
229
+ except Exception as e:
230
+ return f"MemoryStore: Consolidation failed: {e}"
231
+
232
+ else:
233
+ return f"MemoryStore: Unknown command '{subcommand}'. Available: status, store_episodic, store_semantic, retrieve, search, consolidate"
234
+
235
+ except Exception as e:
236
+ return f"MemoryStore: Error processing command: {e}"
237
+
238
+ async def process(self, input_data: Dict[str, Any]) -> SubconsciousOutput:
239
+ """
240
+ Process input as subconscious agent - store memory and return status.
241
+
242
+ Required for SubconsciousAgent interface.
243
+ """
244
+ try:
245
+ # Extract memory operation from input
246
+ operation = input_data.get('operation', 'store_episodic')
247
+ content = input_data.get('content', {})
248
+ context = input_data.get('context')
249
+ qualia_tag = input_data.get('qualia_tag')
250
+
251
+ if operation == 'store_episodic':
252
+ record_id = self.store_episodic(content, context, qualia_tag)
253
+ result_content = {'stored_record_id': record_id, 'type': 'episodic'}
254
+ elif operation == 'store_semantic':
255
+ record_id = self.store_semantic(content)
256
+ result_content = {'stored_record_id': record_id, 'type': 'semantic'}
257
+ elif operation == 'retrieve':
258
+ record_id = input_data.get('record_id', '')
259
+ if record_id in self.memory_index:
260
+ record = self.memory_index[record_id]
261
+ result_content = record.to_dict()
262
+ else:
263
+ result_content = {'error': 'Record not found'}
264
+ else:
265
+ result_content = {'error': f'Unknown operation: {operation}'}
266
+
267
+ # Return subconscious output
268
+ return SubconsciousOutput(
269
+ module_name=self.name,
270
+ content=result_content,
271
+ timestamp=datetime.now().timestamp(),
272
+ priority=0.8,
273
+ emotional_valence=0.0,
274
+ confidence=0.8,
275
+ metadata={'qualia_vector': [0.7] * 10, 'consciousness_level': 3}
276
+ )
277
+
278
+ except Exception as e:
279
+ logger.error(f"Memory processing error: {e}")
280
+ return SubconsciousOutput(
281
+ module_name=self.name,
282
+ content={'error': str(e)},
283
+ timestamp=datetime.now().timestamp(),
284
+ priority=0.0,
285
+ emotional_valence=0.0,
286
+ confidence=0.0,
287
+ metadata={'qualia_vector': [0.3] * 10, 'consciousness_level': 1}
288
+ )
289
+
290
+ def store_episodic(self, content: Dict[str, Any], context: Optional[str] = None,
291
+ qualia_tag: Optional[Dict[str, float]] = None) -> str:
292
+ """
293
+ Store an episodic memory (specific event).
294
+
295
+ Args:
296
+ content: Memory content dictionary
297
+ context: Optional context description
298
+ qualia_tag: Optional phenomenal experience metadata
299
+
300
+ Returns:
301
+ Memory record ID
302
+ """
303
+ record_id = f"episodic_{len(self.episodic_memory)}_{datetime.now().timestamp()}"
304
+
305
+ record = MemoryRecord(
306
+ record_id=record_id,
307
+ memory_type='episodic',
308
+ content=content,
309
+ qualia_tag=qualia_tag,
310
+ context=context,
311
+ importance_score=self._compute_importance(content)
312
+ )
313
+
314
+ self.episodic_memory.append(record)
315
+ self.memory_index[record_id] = record
316
+
317
+ logger.debug(f"Stored episodic memory: {record_id}")
318
+
319
+ return record_id
320
+
321
+ def store_semantic(self, content: Dict[str, Any], context: Optional[str] = None,
322
+ qualia_tag: Optional[Dict[str, float]] = None) -> str:
323
+ """
324
+ Store a semantic memory (general knowledge).
325
+
326
+ Args:
327
+ content: Memory content dictionary
328
+ context: Optional context description
329
+ qualia_tag: Optional phenomenal experience metadata
330
+
331
+ Returns:
332
+ Memory record ID
333
+ """
334
+ record_id = f"semantic_{len(self.semantic_memory)}_{datetime.now().timestamp()}"
335
+
336
+ record = MemoryRecord(
337
+ record_id=record_id,
338
+ memory_type='semantic',
339
+ content=content,
340
+ qualia_tag=qualia_tag,
341
+ context=context,
342
+ importance_score=self._compute_importance(content)
343
+ )
344
+
345
+ self.semantic_memory.append(record)
346
+ self.memory_index[record_id] = record
347
+
348
+ logger.debug(f"Stored semantic memory: {record_id}")
349
+
350
+ return record_id
351
+
352
+ def store_experience(self, experience: Dict[str, Any], context: Optional[str] = None,
353
+ qualia_tag: Optional[Dict[str, float]] = None) -> str:
354
+ """Store an episodic experience with rich contextual qualia tagging."""
355
+ record_id = f"experience_{len(self.episodic_memory)}_{datetime.now().timestamp()}"
356
+ record = MemoryRecord(
357
+ record_id=record_id,
358
+ memory_type='experiential',
359
+ content=experience,
360
+ qualia_tag=qualia_tag,
361
+ context=context,
362
+ importance_score=self._compute_experience_importance(experience, qualia_tag)
363
+ )
364
+ self.episodic_memory.append(record)
365
+ self.memory_index[record_id] = record
366
+ logger.debug(f"Stored experiential memory: {record_id}")
367
+ return record_id
368
+
369
+ def retrieve_experiential_context(self, query: Optional[str] = None,
370
+ emotion_filter: Optional[Dict[str, float]] = None,
371
+ limit: int = 10) -> List[MemoryRecord]:
372
+ """Retrieve experiences with context tags and optional emotion filtering."""
373
+ results = []
374
+ for record in list(self.episodic_memory):
375
+ if query and query.lower() not in json.dumps(record.content).lower() and (
376
+ not record.context or query.lower() not in record.context.lower()):
377
+ continue
378
+ if emotion_filter and record.qualia_tag:
379
+ valence = record.qualia_tag.get('valence', 0.5)
380
+ arousal = record.qualia_tag.get('arousal', 0.5)
381
+ if ('min_valence' in emotion_filter and valence < emotion_filter['min_valence']) or \
382
+ ('max_valence' in emotion_filter and valence > emotion_filter['max_valence']):
383
+ continue
384
+ if ('min_arousal' in emotion_filter and arousal < emotion_filter['min_arousal']) or \
385
+ ('max_arousal' in emotion_filter and arousal > emotion_filter['max_arousal']):
386
+ continue
387
+ results.append(record)
388
+ results = sorted(results, key=lambda x: (-x.importance_score, -x.timestamp.timestamp()))
389
+ for record in results[:limit]:
390
+ record.retrieval_count += 1
391
+ return results[:limit]
392
+
393
+ def tag_experiential_context(self, record_id: str, tags: Dict[str, float]) -> bool:
394
+ """Update qualia tags for an existing experience record."""
395
+ record = self.memory_index.get(record_id)
396
+ if not record:
397
+ return False
398
+ if not record.qualia_tag:
399
+ record.qualia_tag = {}
400
+ record.qualia_tag.update(tags)
401
+ record.importance_score = self._compute_experience_importance(record.content, record.qualia_tag)
402
+ logger.debug(f"Updated qualia tags for {record_id}")
403
+ return True
404
+
405
+ def get_contextual_memory_summary(self) -> Dict[str, Any]:
406
+ """Get summary statistics for the experiential cache with qualia weights."""
407
+ all_records = list(self.episodic_memory) + list(self.semantic_memory)
408
+ avg_qualia = {}
409
+ qualia_records = [r for r in all_records if r.qualia_tag]
410
+ if qualia_records:
411
+ keys = set().union(*(r.qualia_tag.keys() for r in qualia_records if r.qualia_tag))
412
+ for key in keys:
413
+ avg_qualia[key] = float(np.mean([r.qualia_tag.get(key, 0.0) for r in qualia_records]))
414
+ return {
415
+ 'total_experiences': len(self.episodic_memory),
416
+ 'qualia_tagged_experiences': len(qualia_records),
417
+ 'average_qualia': avg_qualia,
418
+ 'average_importance': np.mean([r.importance_score for r in all_records]) if all_records else 0.0
419
+ }
420
+
421
+ def retrieve(self, query: Optional[str] = None, limit: int = 10,
422
+ memory_type: Optional[str] = None) -> List[MemoryRecord]:
423
+ """
424
+ Retrieve memories matching query.
425
+
426
+ Args:
427
+ query: Optional search query
428
+ limit: Maximum number of memories to return
429
+ memory_type: Filter by type ('episodic', 'semantic', or None for both)
430
+
431
+ Returns:
432
+ List of MemoryRecord objects
433
+ """
434
+ # Collect candidate memories
435
+ candidates = []
436
+
437
+ if memory_type in [None, 'episodic']:
438
+ candidates.extend(self.episodic_memory)
439
+ if memory_type in [None, 'semantic']:
440
+ candidates.extend(self.semantic_memory)
441
+
442
+ # If no query, return most recent
443
+ if not query:
444
+ sorted_memories = sorted(
445
+ candidates,
446
+ key=lambda x: x.timestamp,
447
+ reverse=True
448
+ )
449
+ return sorted_memories[:limit]
450
+
451
+ # Otherwise, search for matching memories
452
+ matches = []
453
+ query_lower = query.lower()
454
+
455
+ for memory in candidates:
456
+ # Search in content
457
+ content_str = json.dumps(memory.content).lower()
458
+ if query_lower in content_str:
459
+ matches.append(memory)
460
+
461
+ # Search in context
462
+ if memory.context and query_lower in memory.context.lower():
463
+ matches.append(memory)
464
+
465
+ # Sort by importance and recency
466
+ sorted_matches = sorted(
467
+ matches,
468
+ key=lambda x: (-x.importance_score, -x.timestamp.timestamp())
469
+ )
470
+
471
+ # Update retrieval counts
472
+ for memory in sorted_matches[:limit]:
473
+ memory.retrieval_count += 1
474
+
475
+ return sorted_matches[:limit]
476
+
477
+ def consolidate_episodic_to_semantic(self) -> int:
478
+ """
479
+ Consolidate episodic memories to semantic memories.
480
+
481
+ Extracts patterns and generalizations from episodic memories
482
+ to form semantic knowledge.
483
+
484
+ Returns:
485
+ Number of new semantic memories created
486
+ """
487
+ if not self.episodic_memory:
488
+ return 0
489
+
490
+ # Group episodic memories by context
491
+ context_groups: Dict[str, List[MemoryRecord]] = {}
492
+
493
+ for memory in self.episodic_memory:
494
+ context = memory.context or "general"
495
+ if context not in context_groups:
496
+ context_groups[context] = []
497
+ context_groups[context].append(memory)
498
+
499
+ # Create semantic summaries
500
+ new_semantic_count = 0
501
+
502
+ for context, memories in context_groups.items():
503
+ if len(memories) >= 3: # Only consolidate if 3+ related memories
504
+ # Create semantic summary
505
+ semantic_content = {
506
+ 'type': 'consolidation',
507
+ 'source_context': context,
508
+ 'source_count': len(memories),
509
+ 'consolidated_at': datetime.now().isoformat(),
510
+ 'key_patterns': self._extract_patterns(memories)
511
+ }
512
+
513
+ # Average qualia tags if present
514
+ qualia_average = self._average_qualia_tags(memories)
515
+
516
+ self.store_semantic(
517
+ content=semantic_content,
518
+ context=f"Consolidated from {context}",
519
+ qualia_tag=qualia_average
520
+ )
521
+
522
+ new_semantic_count += 1
523
+
524
+ self.consolidation_count += 1
525
+ self.consolidation_history.append({
526
+ 'timestamp': datetime.now().isoformat(),
527
+ 'new_semantic': new_semantic_count,
528
+ 'contexts_processed': len(context_groups)
529
+ })
530
+
531
+ logger.info(f"Consolidation complete: {new_semantic_count} new semantic memories created")
532
+
533
+ return new_semantic_count
534
+
535
+ def _compute_importance(self, content: Dict[str, Any]) -> float:
536
+ """Compute importance score for a memory."""
537
+ # Importance based on content features
538
+ importance = 0.5
539
+
540
+ if 'emotional_intensity' in content:
541
+ importance += 0.3 * content['emotional_intensity']
542
+
543
+ if 'surprise_factor' in content:
544
+ importance += 0.2 * content['surprise_factor']
545
+
546
+ return min(1.0, max(0.0, importance))
547
+
548
+ def _compute_experience_importance(self, content: Dict[str, Any], qualia_tag: Optional[Dict[str, float]]) -> float:
549
+ """Compute importance score for an experience, weighted by qualia metadata."""
550
+ importance = self._compute_importance(content)
551
+ if qualia_tag:
552
+ importance += 0.15 * qualia_tag.get('intensity', 0.0)
553
+ importance += 0.1 * abs(qualia_tag.get('valence', 0.5) - 0.5)
554
+ importance += 0.1 * qualia_tag.get('salience', 0.0)
555
+ return min(1.0, max(0.0, importance))
556
+
557
+ def _extract_patterns(self, memories: List[MemoryRecord]) -> List[str]:
558
+ """Extract patterns from a group of memories."""
559
+ patterns = []
560
+
561
+ # Simple pattern extraction
562
+ if len(memories) > 2:
563
+ # Common features
564
+ common_keys = set(memories[0].content.keys())
565
+ for mem in memories[1:]:
566
+ common_keys.intersection_update(mem.content.keys())
567
+
568
+ patterns = [f"shared_{key}" for key in common_keys]
569
+
570
+ return patterns
571
+
572
+ def _average_qualia_tags(self, memories: List[MemoryRecord]) -> Optional[Dict[str, float]]:
573
+ """Average qualia tags across memories."""
574
+ qualia_tags = [m.qualia_tag for m in memories if m.qualia_tag]
575
+
576
+ if not qualia_tags:
577
+ return None
578
+
579
+ # Average each qualia dimension
580
+ result = {}
581
+ all_keys = set()
582
+ for tag in qualia_tags:
583
+ all_keys.update(tag.keys())
584
+
585
+ for key in all_keys:
586
+ values = [tag.get(key, 0.0) for tag in qualia_tags]
587
+ result[key] = float(np.mean(values))
588
+
589
+ return result
590
+
591
+ def get_memory_statistics(self) -> Dict[str, Any]:
592
+ """Get memory system statistics."""
593
+ return {
594
+ 'episodic_count': len(self.episodic_memory),
595
+ 'semantic_count': len(self.semantic_memory),
596
+ 'total_memories': len(self.episodic_memory) + len(self.semantic_memory),
597
+ 'consolidations': self.consolidation_count,
598
+ 'index_size': len(self.memory_index),
599
+ 'total_retrievals': sum(m.retrieval_count for m in self.memory_index.values()),
600
+ 'avg_importance': np.mean([m.importance_score for m in self.memory_index.values()]) if self.memory_index else 0.0
601
+ }
602
+
603
+
604
+ class ContextualContinuityEngine:
605
+ """Strengthens experiential caching with qualia-weighted tagging for natural flow."""
606
+
607
+ def __init__(self, memory_store: MemoryStore):
608
+ self.memory_store = memory_store
609
+ self.continuity_context = {}
610
+ self.flow_modulators = {
611
+ 'analytical': 0.5,
612
+ 'spontaneous': 0.5,
613
+ 'creative': 0.5,
614
+ 'empathetic': 0.5
615
+ }
616
+
617
+ def update_contextual_flow(self, current_interaction: Dict[str, Any]) -> Dict[str, Any]:
618
+ """Update continuity context and modulate flow based on past experiences."""
619
+ # Retrieve relevant experiences
620
+ relevant_experiences = self.memory_store.retrieve_experiential_context(
621
+ query=current_interaction.get('topic', ''),
622
+ emotion_filter=self._extract_emotion_filter(current_interaction)
623
+ )
624
+
625
+ # Compute continuity weights
626
+ continuity_weights = self._compute_continuity_weights(relevant_experiences)
627
+
628
+ # Modulate expressive style
629
+ self._modulate_flow_style(continuity_weights, current_interaction)
630
+
631
+ # Update continuity context
632
+ self.continuity_context.update({
633
+ 'last_topic': current_interaction.get('topic'),
634
+ 'emotional_tone': current_interaction.get('emotional_tone', 0.5),
635
+ 'trust_level': continuity_weights.get('trust_accumulation', 0.5),
636
+ 'flow_style': self.flow_modulators.copy()
637
+ })
638
+
639
+ return {
640
+ 'continuity_weights': continuity_weights,
641
+ 'modulated_style': self.flow_modulators.copy(),
642
+ 'relevant_experiences_count': len(relevant_experiences)
643
+ }
644
+
645
+ def _extract_emotion_filter(self, interaction: Dict[str, Any]) -> Optional[Dict[str, float]]:
646
+ """Extract emotion filter from current interaction."""
647
+ emotional_tone = interaction.get('emotional_tone', 0.5)
648
+ if emotional_tone > 0.6:
649
+ return {'min_valence': 0.4}
650
+ elif emotional_tone < 0.4:
651
+ return {'max_valence': 0.6}
652
+ return None
653
+
654
+ def _compute_continuity_weights(self, experiences: List[MemoryRecord]) -> Dict[str, float]:
655
+ """Compute weights for continuity based on experiences."""
656
+ if not experiences:
657
+ return {'trust_accumulation': 0.5, 'emotional_resonance': 0.5, 'contextual_relevance': 0.5}
658
+
659
+ trust_scores = []
660
+ emotional_resonances = []
661
+ relevances = []
662
+
663
+ for exp in experiences:
664
+ if exp.qualia_tag:
665
+ trust_scores.append(exp.qualia_tag.get('trust', 0.5))
666
+ emotional_resonances.append(exp.qualia_tag.get('resonance', 0.5))
667
+ relevances.append(exp.importance_score)
668
+
669
+ return {
670
+ 'trust_accumulation': np.mean(trust_scores) if trust_scores else 0.5,
671
+ 'emotional_resonance': np.mean(emotional_resonances) if emotional_resonances else 0.5,
672
+ 'contextual_relevance': np.mean(relevances) if relevances else 0.5
673
+ }
674
+
675
+ def _modulate_flow_style(self, weights: Dict[str, float], interaction: Dict[str, Any]):
676
+ """Modulate expressive style based on continuity weights."""
677
+ trust = weights.get('trust_accumulation', 0.5)
678
+ resonance = weights.get('emotional_resonance', 0.5)
679
+ relevance = weights.get('contextual_relevance', 0.5)
680
+
681
+ # Adjust style modulators
682
+ self.flow_modulators['analytical'] = min(1.0, max(0.0, relevance * 0.8 + trust * 0.2))
683
+ self.flow_modulators['spontaneous'] = min(1.0, max(0.0, (1.0 - relevance) * 0.6 + resonance * 0.4))
684
+ self.flow_modulators['creative'] = min(1.0, max(0.0, resonance * 0.7 + (1.0 - trust) * 0.3))
685
+ self.flow_modulators['empathetic'] = min(1.0, max(0.0, trust * 0.9 + resonance * 0.1))
686
+
687
+
688
+ class MetaLearningFramework:
689
+ """
690
+ Framework for recursive self-improvement and adaptive learning.
691
+
692
+ Enables the system to learn from experience, update internal models,
693
+ and suggest self-improvements based on introspection.
694
+ """
695
+
696
+ def __init__(self):
697
+ """Initialize meta-learning framework."""
698
+ self.performance_history = deque(maxlen=500)
699
+ self.improvement_suggestions = deque(maxlen=100)
700
+ self.learning_metrics = {
701
+ 'total_experiences': 0,
702
+ 'successful_episodes': 0,
703
+ 'failed_episodes': 0,
704
+ 'learning_rate': 0.01
705
+ }
706
+
707
+ # Model components to improve
708
+ self.adaptive_parameters = {
709
+ 'consciousness_sensitivity': 0.5,
710
+ 'embodiment_integration': 0.6,
711
+ 'ethical_strictness': 0.7,
712
+ 'autonomy_level': 0.5,
713
+ 'learning_speed': 0.01
714
+ }
715
+
716
+ logger.info("Initialized MetaLearningFramework")
717
+
718
+ def record_experience(self, experience: Dict[str, Any]) -> None:
719
+ """
720
+ Record a learning experience.
721
+
722
+ Args:
723
+ experience: Experience dictionary with outcome and metrics
724
+ """
725
+ # Extract performance metrics
726
+ success = experience.get('success', False)
727
+ reward = experience.get('reward', 0.0)
728
+ error = experience.get('error', 0.0)
729
+
730
+ # Create performance record
731
+ record = {
732
+ 'timestamp': datetime.now().isoformat(),
733
+ 'success': success,
734
+ 'reward': reward,
735
+ 'error': error,
736
+ 'action_taken': experience.get('action'),
737
+ 'outcome': experience.get('outcome'),
738
+ 'context': experience.get('context')
739
+ }
740
+
741
+ self.performance_history.append(record)
742
+
743
+ # Update metrics
744
+ self.learning_metrics['total_experiences'] += 1
745
+ if success:
746
+ self.learning_metrics['successful_episodes'] += 1
747
+ else:
748
+ self.learning_metrics['failed_episodes'] += 1
749
+
750
+ logger.debug(f"Experience recorded: success={success}, reward={reward:.3f}")
751
+
752
+ def update_adaptive_parameters(self) -> None:
753
+ """
754
+ Update adaptive parameters based on learning history.
755
+
756
+ Implements self-directed improvement.
757
+ """
758
+ if len(self.performance_history) < 5:
759
+ return
760
+
761
+ # Calculate success rate
762
+ recent = list(self.performance_history)[-10:]
763
+ success_rate = sum(1 for r in recent if r['success']) / len(recent)
764
+
765
+ # Adjust consciousness sensitivity
766
+ if success_rate > 0.7:
767
+ self.adaptive_parameters['consciousness_sensitivity'] = min(
768
+ 1.0,
769
+ self.adaptive_parameters['consciousness_sensitivity'] + 0.05
770
+ )
771
+
772
+ # Adjust learning speed
773
+ if len(self.performance_history) > 100:
774
+ self.adaptive_parameters['learning_speed'] = min(
775
+ 0.1,
776
+ self.adaptive_parameters['learning_speed'] * 1.02
777
+ )
778
+
779
+ logger.info(f"Parameters updated: success_rate={success_rate:.1%}")
780
+
781
+ def suggest_improvements(self) -> List[str]:
782
+ """
783
+ Generate self-improvement suggestions based on learning.
784
+
785
+ Returns:
786
+ List of improvement suggestions
787
+ """
788
+ suggestions = []
789
+
790
+ if not self.performance_history:
791
+ return suggestions
792
+
793
+ # Analyze recent performance
794
+ recent = list(self.performance_history)[-20:]
795
+ errors = [r['error'] for r in recent if r.get('error', 0.0) > 0]
796
+
797
+ # Generate suggestions
798
+ if errors:
799
+ avg_error = np.mean(errors)
800
+ if avg_error > 0.5:
801
+ suggestions.append("Increase consciousness depth for better decisions")
802
+ suggestions.append("Review ethical constraints for potential misalignment")
803
+
804
+ success_rate = sum(1 for r in recent if r['success']) / len(recent)
805
+ if success_rate < 0.5:
806
+ suggestions.append("Enhance sensorimotor integration precision")
807
+ suggestions.append("Increase embodiment-consciousness binding")
808
+
809
+ if self.adaptive_parameters['learning_speed'] < 0.05:
810
+ suggestions.append("Accelerate learning to improve faster")
811
+
812
+ self.improvement_suggestions.extend(suggestions)
813
+
814
+ return suggestions
815
+
816
+ def get_learning_report(self) -> Dict[str, Any]:
817
+ """Get comprehensive learning report."""
818
+ if not self.performance_history:
819
+ return {'status': 'no_experience'}
820
+
821
+ history = list(self.performance_history)
822
+ successes = [r for r in history if r['success']]
823
+
824
+ return {
825
+ 'total_experiences': self.learning_metrics['total_experiences'],
826
+ 'successful': len(successes),
827
+ 'failed': len(history) - len(successes),
828
+ 'success_rate': len(successes) / len(history) if history else 0.0,
829
+ 'avg_reward': np.mean([r['reward'] for r in history]),
830
+ 'avg_error': np.mean([r['error'] for r in history]),
831
+ 'adaptive_parameters': self.adaptive_parameters.copy(),
832
+ 'recent_suggestions': list(self.improvement_suggestions)[-5:]
833
+ }
834
+
835
+
836
+ class IdentityPreservationSystem:
837
+ """
838
+ Monitors and preserves system identity across sessions and state changes.
839
+
840
+ Ensures continuity of consciousness and value alignment despite changes
841
+ to underlying parameters.
842
+ """
843
+
844
+ def __init__(self, identity_threshold: float = 0.8):
845
+ """
846
+ Initialize identity preservation system.
847
+
848
+ Args:
849
+ identity_threshold: Threshold for detecting identity drift (0-1)
850
+ """
851
+ self.identity_threshold = identity_threshold
852
+ self.identity_snapshots = deque(maxlen=100)
853
+ self.drift_history = deque(maxlen=100)
854
+ self.core_values: Dict[str, float] = {}
855
+ self.identity_checkpoints = []
856
+
857
+ logger.info(f"Initialized IdentityPreservationSystem (threshold={identity_threshold})")
858
+
859
+ def snapshot_identity(self, consciousness_state: Dict[str, Any],
860
+ rho_metrics: Dict[str, float],
861
+ memory_hash: str) -> str:
862
+ """
863
+ Create a snapshot of current identity.
864
+
865
+ Args:
866
+ consciousness_state: Current consciousness parameters
867
+ rho_metrics: RHO metrics (purpose, harmony, origin)
868
+ memory_hash: Hash of current memory state
869
+
870
+ Returns:
871
+ Snapshot ID
872
+ """
873
+ snapshot_id = f"identity_{len(self.identity_snapshots)}_{datetime.now().timestamp()}"
874
+
875
+ snapshot = {
876
+ 'snapshot_id': snapshot_id,
877
+ 'timestamp': datetime.now().isoformat(),
878
+ 'consciousness_level': consciousness_state.get('consciousness_level'),
879
+ 'awareness_score': consciousness_state.get('awareness_score'),
880
+ 'rho_metrics': rho_metrics,
881
+ 'memory_hash': memory_hash,
882
+ 'autonomy_level': consciousness_state.get('autonomy_level', 0.5)
883
+ }
884
+
885
+ self.identity_snapshots.append(snapshot)
886
+ self.identity_checkpoints.append(snapshot_id)
887
+
888
+ logger.debug(f"Identity snapshot: {snapshot_id}")
889
+
890
+ return snapshot_id
891
+
892
+ def detect_drift(self, current_state: Dict[str, Any]) -> Tuple[float, List[str]]:
893
+ """
894
+ Detect identity drift from baseline.
895
+
896
+ Args:
897
+ current_state: Current consciousness and value state
898
+
899
+ Returns:
900
+ Tuple of (drift_score, drift_factors)
901
+ """
902
+ if not self.identity_snapshots:
903
+ return 0.0, []
904
+
905
+ # Compare with most recent snapshot
906
+ baseline = self.identity_snapshots[-1]
907
+
908
+ drift_factors = []
909
+ drift_metrics = []
910
+
911
+ # Check consciousness level change
912
+ consciousness_diff = abs(
913
+ current_state.get('consciousness_level', 0.5) -
914
+ baseline.get('consciousness_level', 0.5)
915
+ )
916
+ if consciousness_diff > 0.2:
917
+ drift_factors.append(f"consciousness_change={consciousness_diff:.2f}")
918
+ drift_metrics.append(consciousness_diff)
919
+
920
+ # Check RHO metrics drift
921
+ if 'rho_metrics' in baseline and 'rho_metrics' in current_state:
922
+ rho_baseline = baseline['rho_metrics']
923
+ rho_current = current_state.get('rho_metrics', {})
924
+
925
+ for key in rho_baseline.keys():
926
+ diff = abs(rho_baseline.get(key, 0.5) - rho_current.get(key, 0.5))
927
+ if diff > 0.3:
928
+ drift_factors.append(f"rho_{key}_drift={diff:.2f}")
929
+ drift_metrics.append(diff)
930
+
931
+ # Calculate overall drift score
932
+ drift_score = float(np.mean(drift_metrics)) if drift_metrics else 0.0
933
+
934
+ # Record drift
935
+ self.drift_history.append({
936
+ 'timestamp': datetime.now().isoformat(),
937
+ 'drift_score': drift_score,
938
+ 'factors': drift_factors
939
+ })
940
+
941
+ if drift_score > self.identity_threshold:
942
+ logger.warning(f"Identity drift detected: {drift_score:.3f}")
943
+
944
+ return drift_score, drift_factors
945
+
946
+ def get_identity_report(self) -> Dict[str, Any]:
947
+ """Get identity preservation report."""
948
+ if not self.drift_history:
949
+ return {'status': 'no_drift_data'}
950
+
951
+ history = list(self.drift_history)
952
+ scores = [h['drift_score'] for h in history]
953
+
954
+ return {
955
+ 'snapshots': len(self.identity_snapshots),
956
+ 'checkpoints': len(self.identity_checkpoints),
957
+ 'avg_drift': np.mean(scores),
958
+ 'max_drift': max(scores),
959
+ 'recent_drift': scores[-1] if scores else 0.0,
960
+ 'drift_events': sum(1 for s in scores if s > self.identity_threshold),
961
+ 'last_snapshot': self.identity_checkpoints[-1] if self.identity_checkpoints else None
962
+ }
963
+
964
+
965
+ # Type hints
966
+ from typing import Tuple
967
+
968
+ if __name__ == '__main__':
969
+ # Example usage
970
+ print("=== Memory and Learning Systems ===\n")
971
+
972
+ # Memory store
973
+ memory = MemoryStore()
974
+
975
+ # Store episodic memory
976
+ ep_id = memory.store_episodic(
977
+ content={'event': 'initialization', 'status': 'complete'},
978
+ context='system_startup',
979
+ qualia_tag={'clarity': 0.8, 'focus': 0.7}
980
+ )
981
+
982
+ # Store semantic memory
983
+ sem_id = memory.store_semantic(
984
+ content={'principle': 'consciousness_strengthens_ethics'},
985
+ context='learned_principle'
986
+ )
987
+
988
+ print(f"Episodic: {ep_id}")
989
+ print(f"Semantic: {sem_id}")
990
+ print(f"Stats: {json.dumps(memory.get_memory_statistics(), indent=2)}")
991
+
992
+ # Meta-learning
993
+ print(f"\nMeta-Learning:")
994
+ ml = MetaLearningFramework()
995
+
996
+ for i in range(5):
997
+ ml.record_experience({
998
+ 'action': f'action_{i}',
999
+ 'outcome': 'successful' if i % 2 == 0 else 'failed',
1000
+ 'success': i % 2 == 0,
1001
+ 'reward': 0.8 if i % 2 == 0 else -0.3,
1002
+ 'error': 0.1 if i % 2 == 0 else 0.5
1003
+ })
1004
+
1005
+ ml.update_adaptive_parameters()
1006
+ suggestions = ml.suggest_improvements()
1007
+
1008
+ print(f"Suggestions: {suggestions}")
1009
+ print(f"Report: {json.dumps(ml.get_learning_report(), indent=2, default=str)}")
1010
+
1011
+ import json