memory-tiers.ts
1 import type { MemoryEntry } from '@/types' 2 3 export type MemoryTier = 'working' | 'durable' | 'archive' 4 5 const WORKING_CATEGORIES = new Set(['execution', 'working', 'scratch', 'breadcrumb']) 6 const ARCHIVE_CATEGORIES = new Set(['session_archive']) 7 8 export function getMemoryTierForCategory(category: unknown): MemoryTier { 9 const normalized = typeof category === 'string' ? category.trim().toLowerCase() : '' 10 if (ARCHIVE_CATEGORIES.has(normalized)) return 'archive' 11 if (normalized.startsWith('session_archive/')) return 'archive' 12 if (normalized === 'operations/execution' || normalized.startsWith('operations/execution/')) return 'working' 13 if (normalized === 'working/scratch' || normalized.startsWith('working/')) return 'working' 14 if (normalized === 'execution' || normalized.startsWith('execution/')) return 'working' 15 if (WORKING_CATEGORIES.has(normalized)) return 'working' 16 return 'durable' 17 } 18 19 export function getMemoryTier(entry: Pick<MemoryEntry, 'category' | 'metadata'>): MemoryTier { 20 const metadataTier = typeof entry.metadata?.tier === 'string' ? entry.metadata.tier.trim().toLowerCase() : '' 21 if (metadataTier === 'archive' || metadataTier === 'session_archive') return 'archive' 22 if (metadataTier === 'working') return 'working' 23 if (metadataTier === 'durable') return 'durable' 24 return getMemoryTierForCategory(entry.category) 25 } 26 27 export function partitionMemoriesByTier<T extends Pick<MemoryEntry, 'category' | 'metadata'>>(entries: T[]) { 28 const working: T[] = [] 29 const durable: T[] = [] 30 const archive: T[] = [] 31 32 for (const entry of entries) { 33 const tier = getMemoryTier(entry) 34 if (tier === 'working') working.push(entry) 35 else if (tier === 'archive') archive.push(entry) 36 else durable.push(entry) 37 } 38 39 return { working, durable, archive } 40 } 41 42 export function isWorkingMemoryCategory(category: unknown): boolean { 43 return getMemoryTierForCategory(category) === 'working' 44 } 45 46 export function shouldHideFromDurableRecall( 47 entry: Pick<MemoryEntry, 'title' | 'metadata'>, 48 ): boolean { 49 const metadata = entry.metadata || {} 50 const origin = typeof metadata.origin === 'string' ? metadata.origin.trim().toLowerCase() : '' 51 if (origin === 'auto-consolidated') return true 52 if (typeof metadata.supersededBy === 'string' && metadata.supersededBy.trim()) return true 53 if (typeof metadata.supersededAt === 'number' && Number.isFinite(metadata.supersededAt)) return true 54 const title = typeof entry.title === 'string' ? entry.title.trim().toLowerCase() : '' 55 return title.startsWith('[auto-consolidated]') 56 }