File size: 3,600 Bytes
1a772d8 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 | // ============================================================
// TYPES — Memory system type definitions
// ============================================================
/**
* Memory types following ENGRAM's categorization (arxiv 2511.12960):
* - episodic: Events that happened ("We discussed X on Tuesday")
* - semantic: Stable facts/preferences ("User is allergic to peanuts")
* - procedural: Instructions/workflows ("Always format code with black")
*/
export type MemoryType = 'episodic' | 'semantic' | 'procedural';
/**
* Source of the memory — who said it
*/
export type MemorySource = 'user' | 'assistant';
/**
* Memory record stored in SQLite
*/
export interface MemoryRecord {
id: string;
text: string;
embedding: number[]; // float32 vector from embedding model
type: MemoryType; // ENGRAM-style typed classification
source: MemorySource; // who said this
createdAt: number; // Unix timestamp (ms)
lastAccessedAt: number; // For decay calculation
accessCount: number; // Heat score (MemoryOS-style)
importance: number; // 0-1 importance score
conversationId?: string; // Which conversation this came from
metadata?: Record<string, unknown>;
}
/**
* Retrieved memory with computed relevance score
*/
export interface ScoredMemory extends MemoryRecord {
cosineSimilarity: number; // Raw cosine similarity
decayedScore: number; // After time-decay weighting
finalScore: number; // Combined relevance score
}
/**
* Memory operation (Mem0-style ADD/UPDATE/DELETE/NOOP)
*/
export type MemoryOperation = 'ADD' | 'UPDATE' | 'DELETE' | 'NOOP';
/**
* Result of the deduplication check
*/
export interface DeduplicationResult {
operation: MemoryOperation;
existingMemoryId?: string; // ID of the memory to update/delete
mergedText?: string; // New text if merging
}
/**
* Configuration for the improved memory system
*/
export interface MemoryConfig {
// Deduplication
deduplicationThreshold: number; // Cosine sim above this = duplicate (default: 0.85)
mergeThreshold: number; // Between this and dedup = merge (default: 0.70)
// Decay
decayHalfLifeHours: number; // Time for memory relevance to halve (default: 168 = 1 week)
minDecayFactor: number; // Floor for decay (default: 0.3 — never fully forgotten)
// Retrieval
defaultTopK: number; // Default number of memories to retrieve (default: 7)
minSimilarityThreshold: number; // Minimum cosine similarity (default: 0.40)
maxContextTokens: number; // Max tokens budget for injected memories (default: 300)
// Storage
maxMemories: number; // Max total memories before eviction (default: 500)
evictionBatchSize: number; // How many to evict at once (default: 50)
// Smart filtering
minMessageLength: number; // Skip messages shorter than this (default: 15 chars)
skipPatterns: RegExp[]; // Patterns to always skip
}
/**
* Default configuration
*/
export const DEFAULT_MEMORY_CONFIG: MemoryConfig = {
deduplicationThreshold: 0.85,
mergeThreshold: 0.70,
decayHalfLifeHours: 168, // 1 week
minDecayFactor: 0.3,
defaultTopK: 7,
minSimilarityThreshold: 0.40,
maxContextTokens: 300,
maxMemories: 500,
evictionBatchSize: 50,
minMessageLength: 15,
skipPatterns: [
/^(hi|hey|hello|yo|sup|ok|okay|yes|no|yeah|nah|sure|thanks|ty|thx|lol|haha|hmm|brb|gtg|bye|gn|gm)[\s!.?]*$/i,
/^[^a-zA-Z]*$/, // Only emojis/symbols
/^.{1,5}$/, // Very short (1-5 chars)
],
};
|