/**
* Importance scoring system for memories
*/
import type { ImportanceFactors, MemoryType } from '../types/index.js';
import { calculateComplexity, isUserPreference, isExplicit } from '../extractors/fact-extractor.js';
/**
* Calculate importance score automatically (0-10)
*/
export function calculateImportance(
content: string,
type: MemoryType,
entities: string[],
metadata: Record<string, unknown>,
hasProvenance: boolean
): number {
const factors = analyzeImportanceFactors(content, type, entities, metadata, hasProvenance);
return calculateImportanceFromFactors(factors);
}
/**
* Analyze factors that contribute to importance
*/
export function analyzeImportanceFactors(
content: string,
type: MemoryType,
entities: string[],
metadata: Record<string, unknown>,
hasProvenance: boolean
): ImportanceFactors {
return {
contentComplexity: calculateComplexity(content),
entityCount: entities.length,
isUserPreference: isUserPreference(content),
hasProvenance,
hasMetadata: Object.keys(metadata).length > 0,
isExplicit: isExplicit(content),
typeBonus: calculateTypeBonus(type),
};
}
/**
* Calculate importance from analyzed factors
*/
export function calculateImportanceFromFactors(factors: ImportanceFactors): number {
// Start with baseline
let score = 3.0;
// Content complexity (0-3 points)
score += factors.contentComplexity * 3;
// Entity connections (0-2 points, max out at 4 entities)
score += Math.min(factors.entityCount * 0.5, 2.0);
// User preference boost (0 or 2 points)
if (factors.isUserPreference) {
score += 2.0;
}
// Provenance tracking (0 or 0.5 points)
if (factors.hasProvenance) {
score += 0.5;
}
// Rich metadata (0 or 0.5 points)
if (factors.hasMetadata) {
score += 0.5;
}
// Explicit facts are more trustworthy (0 or 1 point)
if (factors.isExplicit) {
score += 1.0;
}
// Type-specific bonus
score += factors.typeBonus;
// Clamp to 0-10 range
return Math.max(0, Math.min(10, Math.round(score * 10) / 10));
}
/**
* Calculate type-specific importance bonus
*/
function calculateTypeBonus(type: MemoryType): number {
switch (type) {
case 'relationship':
return 1.0; // Relationships connect knowledge
case 'entity':
return 0.5; // Entities are moderately important
case 'fact':
return 0.0; // Facts use default importance
default:
return 0.0;
}
}
/**
* Adjust importance based on context signals
*/
export function adjustImportanceForContext(
baseImportance: number,
signals: {
isSecuritySensitive?: boolean;
isUserIdentity?: boolean;
isProjectRequirement?: boolean;
isDeprecated?: boolean;
userExplicitlyMarked?: boolean;
}
): number {
let adjusted = baseImportance;
// Security-sensitive: max importance
if (signals.isSecuritySensitive) {
adjusted = Math.max(adjusted, 10);
}
// User identity: very high importance
if (signals.isUserIdentity) {
adjusted = Math.max(adjusted, 9);
}
// Project requirement: high importance
if (signals.isProjectRequirement) {
adjusted = Math.max(adjusted, 7);
}
// Deprecated: low importance
if (signals.isDeprecated) {
adjusted = Math.min(adjusted, 2);
}
// User explicitly marked: boost by 2 points
if (signals.userExplicitlyMarked) {
adjusted += 2;
}
return Math.max(0, Math.min(10, adjusted));
}
/**
* Get recommended TTL for importance level
*/
export function getRecommendedTTL(importance: number): number | null {
if (importance >= 10) return null; // Permanent
if (importance >= 8) return 365; // 1 year
if (importance >= 6) return 180; // 6 months
if (importance >= 4) return 90; // 3 months
if (importance >= 2) return 30; // 1 month
return 7; // 1 week
}
/**
* Calculate effective importance (with decay over time)
*/
export function calculateEffectiveImportance(
baseImportance: number,
lastAccessed: number,
now: number
): number {
const daysSinceAccess = (now - lastAccessed) / (1000 * 60 * 60 * 24);
if (baseImportance < 6) {
// Low-importance memories decay faster (1% per day)
const decayRate = 0.01;
const decayFactor = 1 - daysSinceAccess * decayRate * 2;
return baseImportance * Math.max(decayFactor, 0.5);
} else {
// High-importance memories resist decay (0.5% per day)
const decayRate = 0.005;
const decayFactor = 1 - daysSinceAccess * decayRate;
return baseImportance * Math.max(decayFactor, 0.8);
}
}
/**
* Boost importance on repeated access
*/
export function boostImportanceOnAccess(
currentImportance: number,
accessCount: number,
daysSinceCreated: number
): number {
// If accessed multiple times in short period, boost importance
const accessRate = accessCount / Math.max(daysSinceCreated, 1);
if (accessRate > 0.1) {
// Accessed frequently (>10% of days)
return Math.min(currentImportance + 1, 10);
} else if (accessRate > 0.05) {
// Accessed moderately (>5% of days)
return Math.min(currentImportance + 0.5, 10);
}
// No boost
return currentImportance;
}