Examples
Real-world examples and patterns for using Recall in production applications.
Chat Applications
Stateful Conversation Management
import { Recall } from '@n3wth/recall';
import OpenAI from 'openai';
class ConversationManager {
private recall: Recall;
private openai: OpenAI;
constructor() {
this.recall = new Recall({
apiKey: process.env.MEM0_API_KEY,
cacheStrategy: 'aggressive'
});
this.openai = new OpenAI({
apiKey: process.env.OPENAI_API_KEY
});
}
async chat(userId: string, message: string) {
// Retrieve conversation context
const memories = await this.recall.search({
query: message,
userId,
limit: 10
});
// Build contextual prompt
const context = memories
.map(m => m.content)
.join('\n');
const response = await this.openai.chat.completions.create({
model: 'gpt-4',
messages: [
{
role: 'system',
content: `Previous context:\n${context}`
},
{
role: 'user',
content: message
}
]
});
const reply = response.choices[0].message.content;
// Store the exchange
await this.recall.add({
content: `User: ${message}\nAssistant: ${reply}`,
userId,
metadata: {
type: 'conversation',
timestamp: Date.now()
}
});
return reply;
}
}
Personalization Engine
User Preference Learning
TypeScript
1class PersonalizationEngine {2 private recall: Recall;3
4 async learnPreference(userId: string, action: any) {5 // Extract preference signals6 const preference = this.extractPreference(action);7
8 // Check for existing similar preferences9 const existing = await this.recall.search({10 query: preference.category,11 userId,12 metadata_filter: { type: "preference" },13 });14
15 if (existing.length > 0) {16 // Update existing preference17 await this.recall.update(existing[0].id, {18 content: preference.description,19 metadata: {20 ...existing[0].metadata,21 weight: (existing[0].metadata.weight || 1) + 1,22 last_updated: Date.now(),23 },24 });25 } else {26 // Add new preference27 await this.recall.add({28 content: preference.description,29 userId,30 priority: "high",31 metadata: {32 type: "preference",33 category: preference.category,34 weight: 1,35 },36 });37 }38 }39
40 async getRecommendations(userId: string, context: string) {41 const preferences = await this.recall.search({42 query: context,43 userId,44 metadata_filter: { type: "preference" },45 });46
47 // Sort by weight and recency48 return preferences49 .sort((a, b) => {50 const weightDiff = b.metadata.weight - a.metadata.weight;51 if (weightDiff !== 0) return weightDiff;52 return b.metadata.last_updated - a.metadata.last_updated;53 })54 .slice(0, 5);55 }56}
RAG (Retrieval-Augmented Generation)
Document Q&A System
TypeScript
1class DocumentQA {2 private recall: Recall;3 private documents: Map<string, string> = new Map();4
5 async indexDocument(docId: string, content: string) {6 // Split document into chunks7 const chunks = this.chunkDocument(content, 500);8
9 // Store each chunk with metadata10 for (let i = 0; i < chunks.length; i++) {11 await this.recall.add({12 content: chunks[i],13 userId: "system",14 metadata: {15 doc_id: docId,16 chunk_index: i,17 total_chunks: chunks.length,18 type: "document",19 },20 });21 }22
23 this.documents.set(docId, content);24 }25
26 async answer(question: string) {27 // Search for relevant chunks28 const relevantChunks = await this.recall.search({29 query: question,30 userId: "system",31 metadata_filter: { type: "document" },32 limit: 5,33 });34
35 // Build context from chunks36 const context = relevantChunks.map((chunk) => chunk.content).join("\n\n");37
38 // Generate answer using context39 return this.generateAnswer(question, context);40 }41
42 private chunkDocument(content: string, chunkSize: number): string[] {43 const words = content.split(" ");44 const chunks: string[] = [];45
46 for (let i = 0; i < words.length; i += chunkSize) {47 chunks.push(words.slice(i, i + chunkSize).join(" "));48 }49
50 return chunks;51 }52}
Multi-Agent Systems
Agent Memory Sharing
TypeScript
1class AgentMemoryPool {2 private recall: Recall;3 private agents: Map<string, Agent> = new Map();4
5 constructor() {6 this.recall = new Recall({7 apiKey: process.env.MEM0_API_KEY,8 cacheStrategy: "balanced",9 });10 }11
12 async shareMemory(fromAgent: string, toAgent: string, memory: any) {13 await this.recall.add({14 content: memory.content,15 userId: toAgent,16 metadata: {17 source_agent: fromAgent,18 shared_at: Date.now(),19 visibility: "shared",20 ...memory.metadata,21 },22 });23 }24
25 async getSharedMemories(agentId: string) {26 return await this.recall.search({27 query: "",28 userId: agentId,29 metadata_filter: { visibility: "shared" },30 });31 }32
33 async broadcastMemory(memory: any) {34 const agents = Array.from(this.agents.keys());35
36 await Promise.all(37 agents.map((agentId) =>38 this.recall.add({39 content: memory.content,40 userId: agentId,41 priority: "high",42 metadata: {43 type: "broadcast",44 timestamp: Date.now(),45 },46 }),47 ),48 );49 }50}
Analytics & Insights
User Behavior Tracking
TypeScript
1class BehaviorAnalytics {2 private recall: Recall;3
4 async trackEvent(userId: string, event: any) {5 await this.recall.add({6 content: JSON.stringify(event),7 userId,8 metadata: {9 type: "event",10 category: event.category,11 action: event.action,12 timestamp: Date.now(),13 },14 });15 }16
17 async getUserJourney(userId: string, timeRange: number) {18 const endTime = Date.now();19 const startTime = endTime - timeRange;20
21 const events = await this.recall.search({22 query: "",23 userId,24 metadata_filter: {25 type: "event",26 timestamp: { $gte: startTime, $lte: endTime },27 },28 limit: 100,29 });30
31 return events32 .sort((a, b) => a.metadata.timestamp - b.metadata.timestamp)33 .map((e) => JSON.parse(e.content));34 }35
36 async getInsights(userId: string) {37 const journey = await this.getUserJourney(38 userId,39 7 * 24 * 60 * 60 * 1000, // Last 7 days40 );41
42 return {43 total_events: journey.length,44 most_common_action: this.getMostCommon(journey, "action"),45 peak_activity_hour: this.getPeakHour(journey),46 engagement_score: this.calculateEngagement(journey),47 };48 }49}
Performance Patterns
Cache Warming
TypeScript
1class CacheWarmer {2 private recall: Recall;3
4 async warmCache(userIds: string[]) {5 const results = await Promise.allSettled(6 userIds.map(async userId => {7 // Get user's most accessed memories8 const memories = await this.recall.get_all_memories({9 user_id: userId10 });11
12 // Sort by access count13 const topMemories = memories14 .sort((a, b) => b.access_count - a.access_count)15 .slice(0, 100);16
17 // Force cache population18 return Promise.all(19 topMemories.map(m =>20 this.recall.get(m.id)21 )22 );23 })24 );25
26 const successful = results.filter(r => r.status === 'fulfilled').length;27 console.log(\`Warmed cache for \${successful}/\${userIds.length} users\`);28 }29
30 async scheduleWarmup() {31 // Run every 5 minutes32 setInterval(() => {33 this.warmActiveUsers();34 }, 5 * 60 * 1000);35 }36
37 private async warmActiveUsers() {38 // Get active users from your system39 const activeUsers = await this.getActiveUsers();40 await this.warmCache(activeUsers);41 }42}
Error Handling
Resilient Memory Operations
TypeScript
1class ResilientRecall {2 private recall: Recall;3 private fallbackStore: Map<string, any> = new Map();4
5 async safeAdd(params: any, maxRetries = 3) {6 for (let i = 0; i < maxRetries; i++) {7 try {8 return await this.recall.add(params);9 } catch (error) {10 if (i === maxRetries - 1) {11 // Final attempt failed, use fallback12 return this.addToFallback(params);13 }14
15 // Exponential backoff16 await this.sleep(Math.pow(2, i) * 1000);17 }18 }19 }20
21 async safeSearch(params: any) {22 try {23 return await this.recall.search(params);24 } catch (error) {25 // Try fallback store26 return this.searchFallback(params);27 }28 }29
30 private addToFallback(params: any) {31 const id = \`fallback_\${Date.now()}\`;32 this.fallbackStore.set(id, params);33
34 // Schedule retry35 setTimeout(() => {36 this.syncFallback(id);37 }, 60000);38
39 return { id, status: 'fallback' };40 }41
42 private async syncFallback(id: string) {43 const params = this.fallbackStore.get(id);44 if (!params) return;45
46 try {47 await this.recall.add(params);48 this.fallbackStore.delete(id);49 } catch (error) {50 // Retry later51 setTimeout(() => this.syncFallback(id), 300000);52 }53 }54}
Testing Patterns
Memory Mocking for Tests
TypeScript
1class MockRecall {2 private memories: Map<string, any> = new Map();3
4 async add(params: any) {5 const id = \`mock_\${Date.now()}\`;6 this.memories.set(id, params);7 return { id, status: 'completed' };8 }9
10 async search(params: any) {11 const results = Array.from(this.memories.values())12 .filter(m => m.userId === params.user_id)13 .filter(m => m.content.includes(params.query))14 .slice(0, params.limit || 10);15
16 return {17 memories: results,18 source: 'mock'19 };20 }21
22 async clear() {23 this.memories.clear();24 }25}26
27// Usage in tests28describe('ConversationManager', () => {29 let manager: ConversationManager;30 let mockRecall: MockRecall;31
32 beforeEach(() => {33 mockRecall = new MockRecall();34 manager = new ConversationManager(mockRecall as any);35 });36
37 afterEach(() => {38 mockRecall.clear();39 });40
41 it('should remember context', async () => {42 await manager.chat('user123', 'My name is Alice');43 const response = await manager.chat('user123', 'What is my name?');44 expect(response).toContain('Alice');45 });46});