Table of Contents
- Architecture: Memory and Sleep
- Overview
- 1. Three-Tier Memory Architecture
- Tier Summary
- Tier 1: Semantic Memory (Mem0)
- Tier 2: Entity Profiles (O-Mem Inspired)
- Tier 3: Working Memory
- 2. Sleep Mode Architecture
- 3. Sleep Tick Operations
- 4. Memory Consolidation
- 5. Context Compaction
- 6. Mode Transitions
- 7. Sleep Schedule
- 8. Reflection System
- Key Files
Architecture: Memory and Sleep
Layer 2 - Three-Tier Memory, Sleep Operations, and Consolidation
Overview
The memory and sleep system provides persistent knowledge storage and offline processing:
- rag_memory.py - Memory operations and sleep tick orchestration
- operating_mode.py - Mode transitions and wake conditions
- helpers/entity_profiles.py - Entity memory (O-Mem style)
- helpers/episodic_index.py - Journal scoring and search
- helpers/entity_context.py - Entity consolidation
1. Three-Tier Memory Architecture
Memory is organized in three tiers with different lifespans and purposes.
Tier Summary
| Tier | Storage | Lifespan | Purpose |
|---|---|---|---|
| Semantic (Mem0) | External vector DB | Permanent | Long-term world facts |
| Entity Profiles (db.*) | Django DB | Permanent | Per-entity knowledge (O-Mem) |
| Working Memory (ndb.*) | In-memory | Session | Active conversation state |
Tier 1: Semantic Memory (Mem0)
Long-term factual storage with vector similarity search.
# Retrieval with two-stage filtering
memories = yield retrieve_relevant_memories(
script, events, goals,
min_source_trust=0.5 # O-Mem style trust filtering
)
# Stage 1: Semantic relevance (score > 0.7)
# Stage 2: Source trust threshold (metadata.source_trust >= min)
Persona Protection Prompt (MIRIX-inspired):
ASSISTANT_FACT_EXTRACTION_PROMPT = """
Extract only objective facts about the world, users, and events.
Use third-person, factual language focused on WORLD STATE, not assistant behavior.
NEVER extract:
- Assistant actions ("The assistant helped", "I did X")
- Assistant personality or identity information
ALWAYS extract:
- World state facts ("The tavern is in the north wing")
- User/player information ("Player Alice prefers formal address")
"""
Tier 2: Entity Profiles (O-Mem Inspired)
Per-entity knowledge stored on character.db.entity_profiles:
profile = {
"entity_id": "#123",
"entity_type": "player",
"attributes": {}, # Pa - Consolidated facts (stable)
"observations": [], # Pf - Raw observations (recent)
"relationship": {
"state": "acquaintance", # stranger/acquaintance/friend/ally
"favorability": 0.45, # Dunbar-based thresholds
"interaction_count": 12,
},
}
Relationship States (Dunbar thresholds):
| State | Favorability | Meaning |
|---|---|---|
| stranger | < 0.25 | No relationship |
| acquaintance | 0.25 - 0.50 | Casual familiarity |
| friend | 0.50 - 0.75 | Positive relationship |
| ally | >= 0.75 | Strong trust |
Tier 3: Working Memory
Active conversation state in character.db.working_memory:
working_memory = {
"#123": {
"topic": "quest_help",
"started_at": "2025-12-06T10:00:00Z",
"messages": [...],
"pending_actions": [...],
},
}
2. Sleep Mode Architecture
Sleep mode enables offline memory processing with reduced tick rate.
Operating Modes
| Mode | Tick Rate | Tools | Purpose |
|---|---|---|---|
| awake | 5s (default) | All | Normal operation |
| sleep | 60s (default) | Limited | Memory consolidation |
Sleep Phases
+------------------+ consolidation +------------------+
| COMPACTING | ─────complete────────>| DREAMING |
| | | |
| Journal → Mem0 | | Link generation |
| Batch scoring | | Entity consolidation |
| Wake deferred | | Reflection |
+------------------+ | Episodic pruning |
| Context compaction |
+------------------+
Sleep Mode Tools
SLEEP_MODE_TOOLS = [
"noop",
"add_journal_entry",
"review_journal",
"recall_memories",
"store_memory",
]
3. Sleep Tick Operations
The run_sleep_tick() function orchestrates 8+ operations per dreaming tick.
Compacting Phase Operations
# Phase: compacting
# 1. Importance scoring - upgrade heuristic scores to LLM scores
scoring_result = yield score_pending_entries(script, character)
# 2. Memory consolidation - journal entries → Mem0
consolidation_result = yield run_sleep_consolidation(script, character)
# 3. Phase transition when complete
if consolidation_result.get("completed"):
script.db.sleep_phase = "dreaming"
Dreaming Phase Operations
# Phase: dreaming
# 1. A-MEM link generation - find semantic connections
dreaming_result = yield run_dreaming_tick(script, character)
# 2. Memory link cleanup - remove orphaned references
link_cleanup_result = yield prune_orphaned_memory_links(script)
# 3. Entity consolidation - observations → attributes (O-Mem)
# helpers/entity_context.py::run_entity_consolidation_batch()
entity_result = yield run_entity_consolidation_batch(script, character)
# 4. Generative reflection - triggered at importance threshold
if check_reflection_trigger(script): # cumulative >= 150
reflection_result = yield run_reflection(script, character)
# 5. Episodic pruning - remove old low-importance entries
# helpers/episodic_index.py::prune_low_importance_entries()
prune_result = prune_low_importance_entries(character)
# 6. Stale conversation cleanup - working memory maintenance
# helpers/working_memory.py::clear_stale_conversations()
stale_cleared = clear_stale_conversations(character)
# 7. Pre-compaction extraction - journal facts before compaction
pre_compact_result = yield run_pre_compaction_extraction(script, character)
# 8. Context compaction - summarize old conversation history
compaction_result = yield compact_conversation_history(script, character)
4. Memory Consolidation
Journal → Mem0 Flow
@inlineCallbacks
def run_sleep_consolidation(script, character, max_entries_per_tick=5):
"""
Process journal entries into semantic memory.
1. Find unconsolidated entries (not synthesis, not already processed)
2. Call mem0.add() with source trust metadata
3. Mark entries as consolidated
4. Track progress for atomic completion
"""
Consolidation Metadata:
result = yield memory_client.add(
content=content,
user_id=script.db.assistant_key,
metadata={
"source": "journal",
"entry_id": entry.get("id"),
"tags": entry.get("tags", []),
# O-MEM source trust metadata
"source_type": source_type, # observation, direct, etc.
"source_trust": source_trust, # 0.0-1.0
"source_entity": source_entity, # Who said it
# Generative Agents importance
"importance": entry.get("importance"),
"importance_method": entry.get("importance_method"), # llm/heuristic
},
)
A-MEM Link Generation
@inlineCallbacks
def run_dreaming_tick(script, character, batch_size=5):
"""
Discover semantic connections between memories.
1. Find memories not yet processed for links
2. Search for similar memories (similarity >= 0.7)
3. Store connections in script.db.memory_links
"""
Memory Link Structure:
script.db.memory_links = {
"mem_123": {
"linked_to": [
{"id": "mem_456", "score": 0.85},
{"id": "mem_789", "score": 0.73},
],
"processed_at": "2025-12-06T10:00:00Z",
},
}
5. Context Compaction
Two Trigger Modes
| Mode | Threshold | Trigger |
|---|---|---|
| Sleep-based | 70% | compact_sleep_threshold during sleep |
| Emergency | 80% | compact_emergency_threshold during awake |
Compaction Flow
@inlineCallbacks
def compact_conversation_history(script, character, force=False):
"""
1. Check token usage against threshold
2. Split: messages_to_compact | messages_to_preserve
3. Generate LLM summary of old messages
4. Store synthesis in journal
5. Replace history with [summary_marker] + preserved
"""
Pre-Compaction Extraction:
@inlineCallbacks
def run_pre_compaction_extraction(script, character):
"""
Give assistant one final chance to journal facts.
Uses pre_compaction context type with journal-only tools.
Runs ReAct loop before compaction destroys full context.
"""
6. Mode Transitions
Transition Mechanics
def transition_mode(script, target_mode, reason):
"""
1. Remove old ticker (TICKER_HANDLER.remove)
2. Add new ticker with adjusted rate
3. Update script.db.operating_mode
4. Log transition reason
5. Notify character if available
"""
Wake Conditions
def check_wake_conditions(script):
"""
Returns: (should_wake, reason, deferred)
Wake triggers:
1. Scheduled wake time reached
2. Urgent events (light sleep only)
Deferred when phase == "compacting" (atomic completion)
"""
Urgent Events (wake light sleepers):
- Direct messages
metadata.urgent = Truemetadata.priority >= 8- Classification:
direct_addressing,direct_message
Canonical Wake Transition
def perform_wake_transition(script, reason):
"""
1. Set cooldown timer (default: 60 minutes)
2. Reset activity counter
3. Clear sleep state attributes
4. Restore scheduled sleep if tool-disabled
5. Transition to awake mode
"""
7. Sleep Schedule
Automatic mode transitions based on time of day.
db.sleep_schedule = {
"enabled": False,
"sleep_start_hour": 2, # 2:00 AM
"sleep_duration_hours": 4, # Until 6:00 AM
"tick_rate_sleep": 60, # Slower ticks during sleep
"min_awake_ticks": 10, # Minimum before auto-sleep
}
Schedule Check Flow
def check_sleep_schedule(script):
"""
Returns: (should_transition, target_mode, reason)
1. Calculate if current_hour is in sleep window
2. Handle wrap-around (e.g., 22:00-02:00)
3. Check min_awake_ticks before transitioning
"""
8. Reflection System
Generative Agents-inspired periodic self-reflection.
Trigger Condition
# Reflection triggers when cumulative importance >= 150
def check_reflection_trigger(script):
state = script.db.reflection_state or {}
cumulative = state.get("cumulative_importance", 0)
threshold = state.get("threshold", 150)
return cumulative >= threshold
Reflection Flow
@inlineCallbacks
def run_reflection(script, character):
"""
1. Generate reflection questions from recent high-importance entries
2. Call LLM to produce insights
3. Store insights as high-importance journal entries
4. Reset cumulative importance counter
"""
Key Files
| File | Key Functions | Purpose |
|---|---|---|
rag_memory.py |
ASSISTANT_FACT_EXTRACTION_PROMPT |
Persona-safe extraction prompt |
rag_memory.py |
retrieve_relevant_memories() |
Two-stage memory retrieval |
rag_memory.py |
run_sleep_consolidation() |
Journal to Mem0 transfer |
rag_memory.py |
run_dreaming_tick() |
A-MEM link generation |
rag_memory.py |
compact_conversation_history() |
Context compaction |
rag_memory.py |
run_pre_compaction_extraction() |
Pre-compaction journaling |
rag_memory.py |
run_sleep_tick() |
Sleep tick orchestrator |
operating_mode.py |
transition_mode() |
Mode switching |
operating_mode.py |
check_wake_conditions() |
Wake trigger evaluation |
operating_mode.py |
perform_wake_transition() |
Wake transition logic |
helpers/entity_profiles.py |
create_entity_profile() |
O-Mem profile creation |
helpers/entity_context.py |
run_entity_consolidation_batch() |
Entity Pf → Pa synthesis |
helpers/episodic_index.py |
search_episodic_memory() |
Hybrid-scored journal search |
helpers/episodic_index.py |
prune_low_importance_entries() |
Journal cleanup |
helpers/working_memory.py |
clear_stale_conversations() |
Working memory maintenance |
See also: Architecture-Overview | Architecture-Context-System | Architecture-Tool-System
Updated: 2025-12-09 - Added helpers/ package references, converted to semantic refs