Memoir Memento Theory & Architecture¶
Summary¶
The Memoir Memento module implements specialized memory collections that organize memories around specific dimensions of human experience:
- ProfileMemento: Manages identity and biographical information with definitive facts about a person
- TimelineMemento: Organizes chronological events and temporal memories by date
- LocationMemento: Handles spatial memories and geographic event associations
These mementos represent a paradigm shift from general-purpose memory storage to dimension-specific memory repositories that mirror how humans naturally organize experiences.
Core Philosophy¶
The Memento Pattern¶
The term "memento" is deliberately chosen over "manager" to emphasize that these are memory collections rather than controllers. Each memento:
- Represents a specific lens through which memories are viewed
- Maintains its own organizational schema
- Provides specialized retrieval and summarization capabilities
- Handles dimension-specific merging and deduplication
Key Innovation¶
flowchart TB
subgraph Trad[Traditional]
direction LR
t1[Flat memory storage] --> t2[complex queries] --> t3[mixed results]
end
subgraph Mem[Memoir]
direction LR
m1[Dimensional separation] --> m2[targeted storage] --> m3[coherent retrieval]
end
The memento system recognizes that human memory naturally organizes along three primary dimensions:
- Identity (Who am I?) → ProfileMemento
- Time (When did it happen?) → TimelineMemento
- Space (Where did it occur?) → LocationMemento
Architecture Overview¶
Common Patterns Across Mementos¶
All three mementos share fundamental patterns:
- Specialized Path Prefixes:
- ProfileMemento:
profile.* - TimelineMemento:
timeline.YYYYMMDD -
LocationMemento:
location.{normalized_name} -
Merge-on-Conflict Strategy:
- Detect existing memories at the same path
- Merge new information with existing content
-
Preserve all information while avoiding duplication
-
Dual Summary Generation:
- Structured summaries for deterministic output
-
LLM-enhanced narratives for natural language
-
Memory Type Tagging:
- Each memento tags its memories with specific types
- Enables filtered retrieval and specialized processing
1. ProfileMemento¶
Purpose & Design¶
ProfileMemento manages definitive biographical facts that replace previous information rather than accumulating over time.
Key Concepts¶
Profile Updates vs Regular Memories¶
Profile Update: "I'm 25 years old"
→ Replaces any previous age
→ Stored at: profile.personal.identity.age.current
Regular Memory: "I feel young for my age"
→ Adds to memories, doesn't replace
→ Stored at: context.conversation.reflections
Hierarchical Profile Structure¶
profile.
├── personal.
│ ├── identity.
│ │ ├── name.{first|last}
│ │ ├── age.current
│ │ └── gender.identity
│ └── location.
│ └── current.city
├── professional.
│ ├── current.
│ │ ├── company.name
│ │ └── position.title
│ └── education.
│ └── formal.{institutions|years}
└── health.
└── {physical|mental}
Algorithm Deep Dive¶
Stage 1: Profile Update Application¶
async def apply_profile_updates(profile_updates):
for update in profile_updates:
path = update["path"] # e.g., "profile.personal.identity.age.current"
value = update["value"] # e.g., "25"
# Create structured memory
memory_data = {
"raw_text": value,
"summary": f"Profile update: {field} = {value}",
"structured_data": {
"profile_field": path,
"profile_value": value,
"update_type": "profile_update" # Critical marker
}
}
# Store (replaces existing at same path)
await store.store_memory_async(namespace, memory_data, path)
Key Design Decisions:
- Replacement Semantics: New values overwrite old at the same path
- Type Tagging: update_type: "profile_update" distinguishes from regular memories
- Path Validation: Only accepts profile.* paths
Stage 2: Profile Data Organization¶
def _organize_profile_data(memories):
organized = {}
for path, data in memories:
if data["update_type"] != "profile_update":
continue # Skip non-profile memories
# Build nested dictionary from path
# "profile.personal.identity.age.current" →
# organized["personal"]["identity"]["age"]["current"] = value
parts = path.split(".")
current = organized
for part in parts[1:-1]: # Skip "profile" prefix
if part not in current:
current[part] = {}
current = current[part]
current[parts[-1]] = value
Hierarchical Construction: - Dynamically builds nested dictionaries from flat paths - Preserves semantic relationships in structure - Enables intuitive navigation of profile data
Stage 3: Summary Generation¶
Structured Summary:
=== USER PROFILE SUMMARY ===
Personal Information:
Identity:
- Name: John Smith
- Age: 25
- Gender Identity: Male
Professional Profile:
Current:
- Company Name: Google
- Position Title: Software Engineer
LLM-Enhanced Narrative:
John Smith is a 25-year-old software engineer currently working at Google.
His professional journey reflects a strong technical background...
Performance Characteristics¶
- Update Latency: 20-50ms per update
- Summary Generation: 10-30ms (structured), 200-500ms (LLM)
- Memory Usage: O(unique_profile_paths)
- Deduplication: Automatic via path-based storage
2. TimelineMemento¶
Purpose & Design¶
TimelineMemento manages chronological events organized by date, enabling temporal navigation through a person's history.
Key Concepts¶
Date-Based Path Structure¶
timeline.YYYYMMDD
├── timeline.20230315 → "Started new job at Google"
├── timeline.20230620 → "Attended conference | Met mentor"
└── timeline.20231201 → "Promoted to senior engineer"
Event Merging Strategy¶
When multiple events occur on the same day:
Existing: "Morning: Job interview"
New: "Evening: Got job offer"
Merged: "Morning: Job interview | Evening: Got job offer"
Algorithm Deep Dive¶
Stage 1: Date Validation & Normalization¶
def _validate_date_format(date_str):
if len(date_str) != 8:
return False
try:
datetime.strptime(date_str, "%Y%m%d")
return True
except ValueError:
return False
Date Precision: - Strict YYYYMMDD format enforced - No partial dates (must specify exact day) - Enables consistent sorting and range queries
Stage 2: Event Storage with Merging¶
async def apply_timeline_events(timeline_events):
for event in timeline_events:
date_str = event["date"] # "20230315"
description = event["description"]
path = f"timeline.{date_str}"
# Check for existing events on same day
existing = await store.asearch(namespace, path)
if existing:
content = merge_events(existing_content, description)
else:
content = description
memory_data = {
"raw_text": content,
"structured_data": {
"timeline_date": date_str,
"timeline_content": content,
"update_type": "timeline_event"
}
}
Merge Logic: - Concatenates with " | " separator - Preserves chronological order within day - Future enhancement: LLM-based summarization
Stage 3: Chronological Organization¶
def _organize_timeline_data(memories):
organized = {}
for key, data in memories:
date_str = key.split(".")[-1] # Extract YYYYMMDD
if validate_date(date_str):
organized[date_str] = data["timeline_content"]
# Sort by date
return {date: organized[date]
for date in sorted(organized.keys())}
Stage 4: Hierarchical Summary Generation¶
=== USER TIMELINE ===
2023:
December:
01: Promoted to senior engineer
June:
20: Attended AI conference | Met Dr. Smith as mentor
March:
15: Started new job at Google
14: Last day at previous company
Temporal Grouping: - Groups by year, then month - Reverse chronological within groups (recent first) - Clear visual hierarchy for scanning
Performance Characteristics¶
- Event Storage: 30-60ms (includes merge check)
- Range Queries: O(log n) for date filtering
- Summary Generation: O(n log n) for sorting
- Memory Efficiency: Single entry per day regardless of events
3. LocationMemento¶
Purpose & Design¶
LocationMemento manages spatial memories and geographic associations, linking experiences to places.
Key Concepts¶
Location Normalization¶
Input: "Los Angeles", "LA", "los angeles", "L.A."
Normalized: "los_angeles"
Path: "location.los_angeles"
Location Event Aggregation¶
location.san_francisco
├── "Attended LGBTQ support group"
├── "Started therapy sessions"
└── "Moved here in 2020"
Algorithm Deep Dive¶
Stage 1: Location Name Normalization¶
def _normalize_location_name(location_name):
normalized = location_name.strip().lower()
# Remove special characters, replace spaces
normalized = re.sub(r"[^\w\s-]", "", normalized)
normalized = re.sub(r"[\s-]+", "_", normalized)
# Apply common mappings
location_mappings = {
"nyc": "new_york_city",
"sf": "san_francisco",
"la": "los_angeles",
"usa": "united_states"
}
if normalized in location_mappings:
normalized = location_mappings[normalized]
return normalized if len(normalized) >= 2 else ""
Normalization Strategy: - Lowercase for case-insensitive matching - Underscore separation for consistency - Common abbreviation expansion - Minimum length validation
Stage 2: Event Merging & Deduplication¶
def _merge_location_descriptions(existing, new):
existing_events = existing.split(" | ")
# Check for duplicates (fuzzy)
new_lower = new.lower()
for event in existing_events:
if event.lower() == new_lower:
return existing # Skip duplicate
# Append new event
return f"{existing} | {new}"
Deduplication Logic: - Case-insensitive comparison - Exact match detection - Preserves event order - Future: Semantic similarity checking
Stage 3: Location Search & Filtering¶
async def get_location_events_for_search(query):
all_items = await store.asearch(namespace, "location.")
relevant_events = []
query_lower = query.lower()
for path, data in all_items:
location_name = path.split(".")[1].replace("_", " ")
content = data["raw_text"]
# Match location name or content
if query_lower in location_name.lower() or
query_lower in content.lower():
relevant_events.append({
"location": location_name.title(),
"content": content,
"path": path
})
Search Strategy:
- Prefix-based retrieval (location.*)
- Dual matching (name + content)
- Case-insensitive search
- Formatted results for display
Performance Characteristics¶
- Normalization: 1-5ms per location
- Event Storage: 20-40ms (includes merge)
- Search: O(n) where n = unique locations
- Memory Usage: O(unique_locations × avg_events)
Advanced Patterns¶
1. Cross-Dimensional Correlation¶
The three mementos can be correlated to provide rich context:
# Find what happened at a location on a specific date
timeline_event = timeline.get_event("20230315") # "Started new job"
location_event = location.get_event("san_francisco") # "Worked at Google HQ"
profile_update = profile.get_update("profile.professional.current.company") # "Google"
# Correlate: On March 15, 2023, started at Google in San Francisco
2. Temporal Profile Evolution¶
Track how profile facts change over time:
# Profile updates with timeline correlation
Timeline: "20230315" → "Started at Google"
Profile: "profile.professional.current.company" → "Google"
Timeline: "20231201" → "Promoted"
Profile: "profile.professional.current.position.title" → "Senior Engineer"
3. Spatial Activity Patterns¶
Analyze location-based behavior:
# Aggregate activities by location type
Workplaces: ["google_hq", "conference_center"]
Healthcare: ["therapist_office", "hospital"]
Social: ["support_group_location", "community_center"]
4. Memory Reconstruction¶
Combine all three dimensions for complete memory reconstruction:
async def reconstruct_memory(date=None, location=None, profile_aspect=None):
results = {}
if date:
results["timeline"] = await timeline.get_event(date)
if location:
results["location"] = await location.get_events(location)
if profile_aspect:
results["profile"] = await profile.get_aspect(profile_aspect)
return synthesize_memory(results)
Implementation Details¶
Memory Data Structure¶
All mementos use a consistent memory structure:
{
"raw_text": str, # Original content
"summary": str, # Brief description
"structured_data": { # Dimension-specific data
"{dimension}_field": value,
"{dimension}_value": value,
"update_type": "{dimension}_update"
},
"memory_type": "{dimension}_event",
"metadata": {} # Optional metadata
}
Storage Patterns¶
Path-Based Deduplication¶
# Same path = update/replace
store_memory("profile.personal.age", "24") # Stored
store_memory("profile.personal.age", "25") # Replaces 24
Content Merging¶
# Same path = merge content
store_memory("timeline.20230315", "Event A") # Stored
store_memory("timeline.20230315", "Event B") # Merged: "Event A | Event B"
Retrieval Patterns¶
Prefix-Based Search¶
# Get all memories of a type
profile_memories = await store.asearch(namespace, "profile.")
timeline_memories = await store.asearch(namespace, "timeline.")
location_memories = await store.asearch(namespace, "location.")
Range Queries (Timeline)¶
# Get events in date range
def filter_by_date_range(memories, start="20230101", end="20231231"):
return [m for m in memories
if start <= m.date <= end]
Performance Optimization¶
1. Caching Strategies¶
class MementoCache:
def __init__(self):
self.profile_cache = {} # Static, rarely changes
self.timeline_cache = LRU(1000) # Recent dates
self.location_cache = LRU(100) # Frequent locations
2. Batch Operations¶
# Batch profile updates
async def batch_apply_updates(updates):
tasks = [apply_update(u) for u in updates]
await asyncio.gather(*tasks)
3. Lazy Loading¶
# Load summaries on demand
class LazyMemento:
def __init__(self):
self._summary = None
async def get_summary(self):
if not self._summary:
self._summary = await self._generate_summary()
return self._summary
Theoretical Foundation¶
Memory Dimensionality Theory¶
Human memory naturally organizes along multiple dimensions:
- Episodic (What happened?) → TimelineMemento
- Spatial (Where was I?) → LocationMemento
- Semantic (What do I know?) → ProfileMemento
This tri-dimensional approach mirrors cognitive science understanding of memory organization.
Information Hierarchy¶
Each memento maintains a specific information hierarchy:
Specificity Gradient:
ProfileMemento: Highest (definitive facts)
TimelineMemento: Medium (dated events)
LocationMemento: Lowest (spatial associations)
Mutability Gradient:
ProfileMemento: High (facts change)
TimelineMemento: None (history is immutable)
LocationMemento: Low (places accumulate events)
Retrieval Efficiency¶
The dimensional separation enables:
- O(1) access to profile facts via direct paths
- O(log n) timeline navigation via date ordering
- O(k) location retrieval where k = events at location
Conclusion¶
The Memento architecture represents a sophisticated approach to memory organization that mirrors human cognitive patterns. By separating memories into dimensional repositories (Profile, Timeline, Location), the system achieves:
- Intuitive Organization: Memories stored where humans expect to find them
- Efficient Retrieval: Dimension-specific access patterns
- Natural Merging: Appropriate consolidation strategies per dimension
- Rich Summarization: Both structured and narrative outputs
The key insight is that memories are not uniform data points but multi-dimensional experiences that benefit from specialized storage and retrieval mechanisms tailored to their nature.