File size: 3,371 Bytes
43f1dd5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
import { MemoryConfig, DEFAULT_MEMORY_CONFIG } from './types';

type MessageIntent = 'declarative' | 'interrogative' | 'imperative' | 'exclamatory' | 'social';

export function classifyMessageIntent(text: string): MessageIntent {
  const t = text.trim();
  if (t.endsWith('?')) return 'interrogative';
  if (/^(what|who|where|when|why|how|which|can|could|would|should|is|are|do|does|did|will|have|has)\s/i.test(t)) return 'interrogative';
  if (/^(tell|show|give|find|get|make|let|help|explain|describe|list|suggest|recommend)\s/i.test(t)) return 'imperative';
  if (/^(hi|hey|hello|bye|goodbye|thanks|thank\s+you|please|sorry|wow|oh|hmm|haha|lol|nice|cool|great|awesome)\b/i.test(t)) return 'social';
  if (t.endsWith('!') && /\b(love|hate|amazing|terrible|awful|great|best|worst)\b/i.test(t)) return 'exclamatory';
  return 'declarative';
}

export function scoreMessageForMemory(text: string, config: MemoryConfig = DEFAULT_MEMORY_CONFIG): { score: number; shouldStore: boolean; reason: string } {
  let score = 0; const reasons: string[] = []; const t = text.trim();
  if (t.length < config.minMessageLength) return { score: 0, shouldStore: false, reason: 'too_short' };
  if (config.skipPatterns.some(p => p.test(t))) return { score: 0, shouldStore: false, reason: 'skip_pattern' };
  const intent = classifyMessageIntent(t);
  switch (intent) {
    case 'declarative': score += 0.4; reasons.push('declarative'); break;
    case 'exclamatory': score += 0.3; reasons.push('exclamatory'); break;
    case 'interrogative': score += 0.05; reasons.push('question'); break;
    case 'imperative': if (/\b(always|never|remember|don't\s+forget)\b/i.test(t)) { score += 0.45; reasons.push('procedural'); } else { score += 0.05; reasons.push('command'); } break;
    case 'social': reasons.push('social'); break;
  }
  if (/\b(i\s+am|i'm|i\s+have|i've|i\s+live|i\s+work|my\s+\w+\s+is)\b/i.test(t)) { score += 0.25; reasons.push('personal_fact'); }
  if (/\b(i\s+(like|love|enjoy|prefer|hate|dislike|always|never))\b/i.test(t)) { score += 0.2; reasons.push('preference'); }
  if (/\b(allergic|can't\s+eat|don't\s+eat|vegetarian|vegan|intolerant|avoid)\b/i.test(t)) { score += 0.3; reasons.push('constraint'); }
  if (/\b(always|never|remember\s+to|remind\s+me|don't\s+forget)\b/i.test(t)) { score += 0.2; reasons.push('procedural_keywords'); }
  if (t.length > 40) score += 0.05;
  if (t.length > 80) score += 0.05;
  score = Math.min(score, 1.0);
  return { score, shouldStore: score >= 0.5, reason: reasons.join(', ') };
}

export function shouldStoreUserMessage(text: string, config: MemoryConfig = DEFAULT_MEMORY_CONFIG): { store: boolean; textToStore: string; reason: string } {
  const segments = text.split(/[.!?]+/).map(s => s.trim()).filter(s => s.length > 5);
  if (segments.length <= 1) {
    const result = scoreMessageForMemory(text, config);
    if (result.reason.includes('constraint') || result.reason.includes('preference'))
      return { store: true, textToStore: text, reason: result.reason };
    return { store: result.shouldStore, textToStore: text, reason: result.reason };
  }
  const storeable = segments.filter(s => scoreMessageForMemory(s, config).shouldStore);
  if (!storeable.length) return { store: false, textToStore: '', reason: 'no_storable_content' };
  return { store: true, textToStore: storeable.join('. ') + '.', reason: 'compound' };
}