Building with Episodic Memory
Episodic memories capture discrete events with full context -- what happened, when it happened, the emotional tone, and why it mattered. This guide covers creating, searching, filtering, and extracting insights from episodic memories.
Overview
Episodic memory is the foundation of an agent's experience. Each memory represents a single event: a user request, a debugging session, a deployment, a conversation turn. Unlike raw logs, episodic memories are semantically searchable and carry structured metadata about timing, emotional context, and importance.
When to use Episodic Memory
Use episodic memory when you need to record what happened rather than what something is (semantic) or how to do something (procedural). Think conversation turns, debugging sessions, user interactions, and noteworthy events.
Creating Episodic Memories
To create an episodic memory, you need at minimum a content string. The Rekall API will automatically generate embeddings, detect emotional tone, and assign a default importance score.
import Rekall from '@rekall/agent-sdk';const rekall = new Rekall({ apiKey: 'rk_your_key' });const memory = await rekall.memories.create({type: 'episodic',content: 'User asked me to refactor the auth module to use JWT tokens instead of session cookies.',metadata: {source: 'conversation',tags: ['refactoring', 'auth', 'jwt'],},});console.log(memory.id); // mem_abc123console.log(memory.importance); // 0.72 (auto-calculated)
Adding Rich Metadata
Episodic memories support structured metadata that enables powerful filtering later. You can specify emotional tone, importance, participants, location context, and custom tags.
const memory = await rekall.memories.create({type: 'episodic',content: 'Successfully debugged the race condition in the payment processing pipeline. The issue was a missing mutex on the balance check.',metadata: {source: 'debugging-session',tags: ['bug-fix', 'payments', 'concurrency'],participants: ['user:adam', 'agent:claude'],project: 'payments-service',},emotionalTone: 'satisfied', // auto-detected if omittedimportance: 0.85, // override auto-calculationcontext: {sessionId: 'sess_xyz789',platform: 'cursor',file: 'src/payments/processor.ts',},});
Auto-detection
If you omit emotionalTone and importance, Rekall automatically analyzes the content to detect emotional tone and calculate an importance score between 0 and 1. You can always override these values if needed.
Semantic Search
Episodic memories are indexed with vector embeddings, so you can search using natural language queries rather than exact keyword matches. The search engine understands meaning and context.
// Natural language semantic searchconst results = await rekall.memories.search({query: 'authentication bugs we fixed recently',type: 'episodic',limit: 10,});for (const result of results.memories) {console.log(`[${result.similarity.toFixed(2)}] ${result.content}`);console.log(` Created: ${result.createdAt}`);console.log(` Importance: ${result.importance}`);}
The search returns results ranked by semantic similarity. A score of 1.0 is a perfect match; anything above 0.7 is generally a strong result.
Filtering by Time, Emotion & Importance
Combine semantic search with structured filters to narrow results precisely. You can filter on timestamps, emotional tone, importance thresholds, tags, and custom metadata.
Time-Based Filters
// Memories from the last 7 daysconst recent = await rekall.memories.search({query: 'deployment issues',type: 'episodic',filters: {createdAfter: new Date(Date.now() - 7 * 24 * 60 * 60 * 1000).toISOString(),},});// Memories from a specific date rangeconst ranged = await rekall.memories.search({query: 'deployment issues',type: 'episodic',filters: {createdAfter: '2025-01-01T00:00:00Z',createdBefore: '2025-01-31T23:59:59Z',},});
Emotion Filters
Filter memories by their detected emotional tone. Useful for finding frustrating debugging sessions or satisfying breakthroughs.
// Find frustrating experiences (to avoid repeating them)const frustrating = await rekall.memories.search({query: 'configuration problems',type: 'episodic',filters: {emotionalTone: ['frustrated', 'confused'],},});// Find positive breakthroughsconst breakthroughs = await rekall.memories.search({query: 'solved the problem',type: 'episodic',filters: {emotionalTone: ['satisfied', 'excited'],},});
Importance Filters
// Only high-importance memoriesconst critical = await rekall.memories.search({query: 'production incidents',type: 'episodic',filters: {minImportance: 0.8,},});// Combine all filtersconst filtered = await rekall.memories.search({query: 'auth module changes',type: 'episodic',filters: {createdAfter: '2025-01-01T00:00:00Z',minImportance: 0.6,emotionalTone: ['neutral', 'satisfied'],tags: ['auth'],},limit: 5,});
Building Conversation History
A common pattern is to store each conversation turn as an episodic memory, creating a searchable history that persists across sessions. Group related turns using session IDs.
// Store each turn as an episodic memoryasync function recordConversationTurn(sessionId: string,role: 'user' | 'assistant',message: string,turnIndex: number,) {return rekall.memories.create({type: 'episodic',content: `[${role}] ${message}`,metadata: {source: 'conversation',tags: ['conversation-turn'],role,turnIndex,},context: {sessionId,},});}// Later, retrieve the full conversationconst history = await rekall.memories.search({query: '*',type: 'episodic',filters: {metadata: {source: 'conversation',},context: {sessionId: 'sess_abc123',},},sort: 'createdAt',order: 'asc',limit: 100,});// Or search across all conversations semanticallyconst relevant = await rekall.memories.search({query: 'when the user asked about database migrations',type: 'episodic',filters: {metadata: { source: 'conversation' },},});
Session grouping
Use the context.sessionId field to group memories from the same conversation. This lets you retrieve an entire conversation thread or search across all threads simultaneously.
Extracting Insights from Events
Episodic memories become more powerful when you analyze patterns across them. Use aggregation queries to surface trends, frequent issues, and recurring themes.
// Get a summary of recent activityconst summary = await rekall.memories.summarize({type: 'episodic',filters: {createdAfter: new Date(Date.now() - 7 * 24 * 60 * 60 * 1000).toISOString(),},});console.log(summary.overview);// "This week you primarily worked on auth refactoring (12 events),// payment bug fixes (8 events), and documentation updates (5 events)."console.log(summary.emotionalBreakdown);// { satisfied: 14, frustrated: 6, neutral: 5 }console.log(summary.topTags);// ['auth', 'payments', 'refactoring', 'bug-fix', 'docs']// Find recurring frustration pointsconst painPoints = await rekall.memories.search({query: 'problems and issues encountered',type: 'episodic',filters: {emotionalTone: ['frustrated', 'confused', 'stuck'],minImportance: 0.5,},limit: 20,});// Use memories to build context for the next interactionconst recentContext = await rekall.memories.search({query: 'what have we been working on',type: 'episodic',filters: {createdAfter: new Date(Date.now() - 24 * 60 * 60 * 1000).toISOString(),},limit: 10,});
Memory consolidation
Over time, Rekall automatically consolidates episodic memories into long-term memory. High-importance memories are preserved longer, while low-importance ones naturally decay. See the Decay & Consolidation guide for details.
Next Steps
- •Knowledge Graphs -- Connect episodic memories to entities and relationships
- •Preference Learning -- Detect patterns in user behavior from episodic data
- •Episodic Memory Concepts -- Deep dive into the theory behind episodic memory
- •Memories API Reference -- Full endpoint documentation
