Persona Memory System¶
Overview¶
The Persona Memory System gives personas (like Sage) their own memories, experiences, and personalities that they can naturally reference in conversations. This makes interactions feel more authentic and helps personas continue conversations naturally by sharing about themselves or asking relevant questions.
Key Features¶
- Personal Memories: Personas have their own memories (experiences, preferences, opinions, learned facts)
- Conversation Continuation: Personas ask questions or share about themselves ~50% of the time
- Privacy-First Learning: Personas learn from conversations but always anonymize user data
- Admin Interface: Web UI to manage persona memories and profiles
- JSON + mem0 Storage: Memories stored in version-controlled JSON files, synced to mem0 for semantic search
Architecture¶
Components¶
app/
├── persona/
│ ├── memories/
│ │ └── sage/
│ │ └── persona_memories.json # Sage's memory file
│ ├── persona_memory_loader.py # Loads JSON memories
│ └── passports/
│ └── sage.json # Includes continuation settings
├── memory/
│ ├── persona_memory_service.py # Syncs JSON to mem0
│ └── persona_memory_classifier.py # Privacy-safe learning
├── messaging/
│ ├── continuation_coordinator.py # Manages conversation continuations
│ ├── reflex.py # Updated with continuation support
│ └── burst_planner.py # Updated with continuation support
├── models/
│ └── schemas.py # PersonaContext dataclass
└── api/
└── admin_routes.py # Admin API endpoints
scripts/
└── sync_persona_memories.py # Sync script
web/
└── admin.html # Admin interface
Data Flow¶
- Startup:
sync_persona_memories.pyloads JSON files into mem0 - Message Handling:
- MessageHandler creates PersonaContext with relevant memories
- PersonaEngine includes memories in system prompt
- Sage can naturally reference her own experiences
- Continuation Logic:
- ReflexResponder may add quick question (~25% of banter)
- BurstPlanner may add share/question (~50% overall)
- ContinuationCoordinator prevents double-questioning
- Learning:
- PersonaMemoryClassifier analyzes conversation
- If interesting (importance >= 7/10), stores anonymized memory
- Runtime memories stored in mem0, can be exported to JSON later
persona_memories.json Format¶
{
"persona_id": "sage",
"version": "1.0",
"metadata": {
"last_updated": "2025-10-31",
"total_memories": 8,
"source": "manual_curation"
},
"memories": [
{
"id": "sage_mem_001",
"category": "experience",
"text": "I spent a summer working at a coffee shop and learned to make latte art",
"tags": ["work", "coffee", "skills", "summer"],
"emotional_tone": "nostalgic",
"timestamp": "2023-06-01",
"importance": 6,
"can_reference": true
}
]
}
Memory Categories¶
- experience: Something the persona experienced
- preference: Something the persona likes/dislikes
- opinion: The persona's opinion on something
- learned_fact: Something the persona learned
- interest: The persona's interests/hobbies
- relationship: Connections to people/places
- emotional_pattern: Emotional patterns the persona has noticed
Importance Scale (1-10)¶
- 1-3: Not worth storing (routine, boring)
- 4-6: Somewhat interesting but not enough to store
- 7-8: Interesting, worth storing
- 9-10: Very impactful, definitely store
Continuation System¶
Settings (in persona passport)¶
{
"continuation": {
"enabled": true,
"probability": 0.5,
"reflex_question_probability": 0.25,
"types": ["question", "share"],
"share_from_memories": true
}
}
How It Works¶
- Reflex Stage (ReflexResponder):
- May add a quick question (~25% for banter/sharing)
- Examples: "what about u?", "how'd that go?", "u excited?"
-
Tracked per conversation to prevent duplication
-
Burst Stage (BurstPlanner):
- If reflex didn't ask question, may add continuation (~50%)
- Types:
- Share: References persona's own memories
- Question: Asks relevant follow-up question
-
Prefers share if relevant memories exist
-
Coordination (ContinuationCoordinator):
- Single source of truth for continuation decisions
- Prevents asking two questions in one response
- Uses conversation ID to track state
Example Flow¶
User: "I tried pineapple pizza for the first time"
Reflex: "ooh how was it?" (quick question, 25% chance)
Since reflex asked a question, burst skips continuation.
---
User: "I tried pineapple pizza for the first time"
Reflex: "OMG" (no question)
Burst: [normal bubbles] + "honestly I think pineapple on pizza is amazing"
(share from Sage's memories, since no reflex question)
Privacy-Safe Learning¶
PersonaMemoryClassifier¶
The classifier analyzes conversations to determine if the persona should remember them, with strict privacy protections:
Anonymization Rules¶
- Names → "someone" or "a friend"
- Companies → "their workplace" or "a tech company"
- Locations → "a city" or omit entirely
- Contact Info → REMOVE completely (phone, email, address)
- Specifics → Generalize
Examples¶
User: "John at Google told me about their new AI project" Stored: "I had a fascinating conversation about AI projects"
User: "I live at 123 Main St in San Francisco" Stored: Nothing (not interesting enough + too much PII)
User: "I'm terrified of deep water" Stored: "Someone shared they're afraid of deep water" (generalized but interesting pattern)
What Gets Stored¶
Only conversations that are: - Highly interesting/impactful (importance >= 7/10) - About topics, ideas, emotions, patterns - Something persona learned or experienced - General insights without specific PII
PersonaContext Dataclass¶
Bundles all persona-related data to reduce parameter pollution:
@dataclass
class PersonaContext:
persona_id: str
passport: dict # Full persona passport
memories: List[dict] # Relevant persona memories
relationship_stage: str # User relationship stage
continuation_settings: dict # Continuation config
Used throughout: - PersonaEngine (includes memories in prompt) - BurstPlanner (for continuation logic) - MessageHandler (creates and passes context)
Admin Panel¶
Access¶
Navigate to http://localhost:8000/admin (or your deployed URL)
Features¶
- Persona Selector: Switch between personas
- Memories Tab:
- View all memories (JSON + runtime)
- Search and filter by category/source
- Add new runtime memories
- Sync JSON to mem0
- Profile Tab: View persona passport (read-only)
- Stats Tab: Memory statistics and breakdowns
Memory Management Workflow¶
- Edit JSON Files:
- Edit
app/persona/memories/{persona_id}/persona_memories.json - Add/edit memories in structured format
-
Commit to version control
-
Sync to mem0:
- Click "Sync from JSON" in admin panel
- Or run:
python scripts/sync_persona_memories.py --persona sage -
Only new/changed memories are synced (use
--forceto re-sync all) -
Add Runtime Memories:
- Use "Add Memory" button in admin panel
- Runtime memories stored in mem0 only
- Can be exported to JSON later for persistence
API Endpoints¶
Admin Routes (/admin)¶
GET /admin- Serve admin HTMLGET /admin/personas- List all personas with statsGET /admin/personas/{persona_id}/profile- Get persona passportGET /admin/personas/{persona_id}/memories- Get all memoriesPOST /admin/personas/{persona_id}/memories- Add runtime memoryDELETE /admin/personas/{persona_id}/memories/{memory_id}- Delete memoryPOST /admin/personas/{persona_id}/memories/sync- Sync JSON to mem0GET /admin/personas/{persona_id}/memories/stats- Get memory statistics
Sync Script¶
Usage¶
# Sync all personas
python scripts/sync_persona_memories.py
# Sync specific persona
python scripts/sync_persona_memories.py --persona sage
# Force re-sync (even if already synced)
python scripts/sync_persona_memories.py --force
When to Sync¶
- Startup: Automatically sync all personas (can be configured)
- After JSON edits: Manually sync to update mem0
- Development: Sync after adding test memories
Integration with Message Flow¶
Old Flow (Before Persona Memories)¶
1. User message → MessageHandler
2. Search user memories (about user)
3. Generate response with PersonaEngine
4. Send response
New Flow (With Persona Memories)¶
1. User message → MessageHandler
2. Search user memories (about user)
3. Create PersonaContext:
- Load persona passport
- Search persona memories (about Sage)
- Get continuation settings
4. Generate response with PersonaEngine + PersonaContext:
- System prompt includes "ABOUT YOU" section
- Sage can reference her own memories
5. Reflex + Burst coordination:
- May add continuation (question/share)
6. Send response
7. Classify conversation:
- If interesting, store anonymized persona memory
Example: Sage's Memories¶
{
"id": "sage_mem_002",
"category": "opinion",
"text": "I think pineapple on pizza is actually amazing and people are too judgy about it",
"tags": ["food", "opinions", "controversial"],
"emotional_tone": "playful_defensive",
"importance": 4,
"can_reference": true
}
How it appears in conversation:
User: "I tried pineapple pizza for the first time"
Sage: "ooh how was it?"
User: "actually pretty good!"
Sage: "RIGHT?? honestly i think pineapple on pizza is amazing and people are too judgy about it"
Best Practices¶
Creating Memories¶
- Be specific but general: "I went to Venice" not "I went to Venice with John on June 15, 2024"
- Use natural language: Write as Sage would say it
- Set appropriate importance: Most memories should be 5-7
- Add relevant tags: Helps with search and filtering
- Use can_reference: false for sensitive memories you don't want referenced
Privacy¶
- Never store user PII in persona memories
- Always anonymize in PersonaMemoryClassifier
- Review runtime memories periodically to ensure no leaks
- Use importance >= 7 threshold for storing
Continuation Tuning¶
Adjust in persona passport:
- probability: Overall continuation rate (default 0.5)
- reflex_question_probability: Quick questions rate (default 0.25)
- types: ["question", "share"] or just one
- share_from_memories: Whether to use memories for shares
Performance¶
- mem0 search is fast: Semantic search across all memories
- JSON keyword search: Fallback if needed
- Cache: PersonaMemoryLoader caches JSON files
- Sync is incremental: Only new memories synced by default
Testing¶
Manual Testing¶
- Start server:
python -m uvicorn app.main:app --reload - Sync memories:
python scripts/sync_persona_memories.py - Access admin:
http://localhost:8000/admin - Send test messages via Telegram or API
- Check continuation: Observe Sage asking questions or sharing
Verification¶
# Check memories loaded
from app.persona.persona_memory_loader import get_persona_memory_loader
loader = get_persona_memory_loader()
memories = loader.get_all_memories("sage")
print(f"Loaded {len(memories)} memories for Sage")
# Check mem0 sync
from app.memory.persona_memory_service import get_persona_memory_service
service = get_persona_memory_service()
status = service.get_sync_status("sage")
print(f"Last sync: {status}")
# Search memories
results = service.search_persona_memories("sage", "pizza", limit=3)
print(f"Found {len(results)} memories about pizza")
Troubleshooting¶
Memories not appearing¶
- Check JSON file exists:
app/persona/memories/sage/persona_memories.json - Validate JSON syntax
- Run sync script:
python scripts/sync_persona_memories.py --persona sage --force - Check logs for errors
Continuation not working¶
- Check persona passport has
continuationsettings - Verify
continuation.enabled = true - Check logs for coordinator decisions
- Try multiple messages (it's probabilistic)
Privacy concerns¶
- Review runtime memories in admin panel
- Check PersonaMemoryClassifier logs
- Verify anonymization is working
- Set higher importance threshold if needed
Future Enhancements¶
- Photo upload: Process images to create memories
- Conversation import: Bulk import from chat logs
- Memory relationships: Link related memories
- Memory decay: Reduce importance over time
- Export runtime memories: Save to JSON for persistence
- Multi-persona sharing: Personas share certain memories
- Memory conflicts: Detect and resolve contradictions
File Locations¶
- JSON Memories:
app/persona/memories/{persona_id}/persona_memories.json - Persona Passports:
app/persona/passports/{persona_id}.json - Admin Panel:
web/admin.html - Sync Script:
scripts/sync_persona_memories.py - Services:
app/memory/persona_memory_service.py - Classifier:
app/memory/persona_memory_classifier.py - Coordinator:
app/messaging/continuation_coordinator.py
Summary¶
The Persona Memory System gives Sage a realistic personality with her own memories and experiences. She can:
- Reference her past: "I spent a summer working at a coffee shop"
- Share opinions: "I think pineapple on pizza is amazing"
- Continue conversations: Asks questions or shares naturally
- Learn safely: Forms new memories while protecting user privacy
This makes interactions feel more natural and authentic, as Sage becomes a character with her own history rather than just a response generator.