File size: 3,138 Bytes
545787a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
import { MemoryConfig, DEFAULT_MEMORY_CONFIG, MemoryType, MemorySource } from './types';
import { storeMemoryWithDeduplication } from './deduplication';
import { evictLowHeatMemories, buildAccessUpdateQuery } from './memoryDecay';
import { getPrimaryMemoryType } from './typedMemory';
import { processAssistantForMemory } from './assistantMemory';
import { shouldStoreUserMessage } from './smartFilter';
import { computeRetrievalParams, buildDynamicRetrievalQuery, processRetrievedMemories } from './dynamicRetrieval';

export class ImprovedMemoryService {
  private db: any;
  private config: MemoryConfig;
  private embedFn: (t: string) => Promise<number[]>;
  private insertCount = 0;

  constructor(db: any, embedFn: (t: string) => Promise<number[]>, config = DEFAULT_MEMORY_CONFIG) {
    this.db = db;
    this.embedFn = embedFn;
    this.config = config;
  }

  async retrieve(userMessage: string, embedding: number[]) {
    const params = computeRetrievalParams(userMessage, this.config);
    const { sql, queryParams } = buildDynamicRetrievalQuery(embedding, params);
    const raw = await this.db.getAll(sql, queryParams);
    const typed = raw.map((r: any) => ({ record: { id: r.id, text: r.text, embedding: [], type: r.type, source: r.source, createdAt: r.created_at, lastAccessedAt: r.last_accessed_at, accessCount: r.access_count, importance: r.importance }, cosineSimilarity: r.similarity }));
    const { formattedContext, memoriesUsed } = processRetrievedMemories(typed, params, this.config);
    if (memoriesUsed.length) { const { sql: s, params: p } = buildAccessUpdateQuery(memoriesUsed); await this.db.run(s, p); }
    return { context: formattedContext, memoryIds: memoriesUsed };
  }

  async storeUserMessage(text: string, embedding: number[]) {
    const f = shouldStoreUserMessage(text, this.config);
    if (!f.store) return { stored: false, reason: f.reason };
    const result = await storeMemoryWithDeduplication(this.db, f.textToStore, embedding, getPrimaryMemoryType(f.textToStore), 'user', this.config);
    if (++this.insertCount % 50 === 0) await this.evict();
    return { stored: result.operation !== 'NOOP', operation: result.operation };
  }

  async storeAssistantReply(reply: string) {
    const c = await processAssistantForMemory(reply, this.embedFn);
    if (!c) return { stored: false };
    const r = await storeMemoryWithDeduplication(this.db, c.text, c.embedding, c.type, c.source, this.config);
    return { stored: r.operation !== 'NOOP', operation: r.operation };
  }

  async evict() { return evictLowHeatMemories(this.db, this.config); }
}

export * from './types';
export { cosineSimilarity } from './deduplication';
export { computeDecayFactor, computeHeatScore } from './memoryDecay';
export { routeToMemoryType, getPrimaryMemoryType, formatMemoriesByType } from './typedMemory';
export { shouldStoreAssistantMessage, extractAssistantMemory } from './assistantMemory';
export { scoreMessageForMemory, shouldStoreUserMessage, classifyMessageIntent } from './smartFilter';
export { computeRetrievalParams, estimateQueryComplexity, inferRelevantMemoryTypes } from './dynamicRetrieval';