memory-improvements / src /smartFilter.ts
loudiman's picture
Add smartFilter module
43f1dd5 verified
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' };
}