- M.2: ForgettingCurve, MemoryDecay, MemoryReinforcement (selective forgetting) - M.3: DailyDigestGenerator, ReminderScheduler, ProactiveInformer (proactive reminders) - M.4: MemoryExtractor with LLM-based memory extraction from conversations - M.5: MemoryRecallInjector with token budget control for prompt injection - All phases include comprehensive unit tests (109 tests passing) - Updated checklist.md to mark all tasks complete
73 lines
2.4 KiB
Python
73 lines
2.4 KiB
Python
"""
|
|
MemoryReinforcement
|
|
|
|
Triggers memory reinforcement on recall and handles auto-reinforcement.
|
|
"""
|
|
|
|
from datetime import UTC, datetime
|
|
from typing import TYPE_CHECKING
|
|
|
|
if TYPE_CHECKING:
|
|
from app.models.memory import UserMemory
|
|
|
|
|
|
class MemoryReinforcement:
|
|
"""Reinforce memories on recall to prevent forgetting."""
|
|
|
|
MAX_FREQUENCY = 10
|
|
AUTO_REINFORCE_BOOST = 1.1 # 10% boost per week
|
|
|
|
def trigger(self, memory: "UserMemory") -> "UserMemory":
|
|
"""Called when memory is recalled: reset decay_score, increment frequency.
|
|
|
|
This is the core reinforcement mechanism - each recall makes the memory
|
|
stickier by resetting its decay curve and incrementing frequency.
|
|
"""
|
|
from app.services.memory.forgetting_curve import ForgettingCurve
|
|
|
|
# Increment frequency count (capped at MAX_FREQUENCY)
|
|
current_freq = getattr(memory, "frequency_count", 0) or 0
|
|
memory.frequency_count = min(current_freq + 1, self.MAX_FREQUENCY)
|
|
|
|
# Update last accessed time
|
|
now = datetime.now(UTC)
|
|
memory.last_accessed_at = now
|
|
memory.last_recalled_at = now
|
|
|
|
# Reset decay score to near 1.0 (fully retained)
|
|
curve = ForgettingCurve()
|
|
memory.decay_score = min(0.95, curve.calculate_decay(memory) + 0.1)
|
|
|
|
return memory
|
|
|
|
def auto_reinforce(self, memories: list["UserMemory"]) -> list["UserMemory"]:
|
|
"""Weekly auto-reinforce for high-importance memories.
|
|
|
|
Applies a 10% boost to frequency_count for high-importance memories
|
|
that haven't been accessed recently, keeping them fresh.
|
|
"""
|
|
reinforced = []
|
|
now = datetime.now(UTC)
|
|
|
|
for memory in memories:
|
|
importance_level = getattr(memory, "importance_level", "medium") or "medium"
|
|
if importance_level != "high":
|
|
continue
|
|
|
|
current_freq = getattr(memory, "frequency_count", 0) or 0
|
|
if current_freq >= self.MAX_FREQUENCY:
|
|
continue
|
|
|
|
# Apply 10% boost, capped at MAX_FREQUENCY
|
|
new_freq = min(int(current_freq * self.AUTO_REINFORCE_BOOST + 1), self.MAX_FREQUENCY)
|
|
memory.frequency_count = new_freq
|
|
|
|
# Slightly improve decay score
|
|
current_decay = getattr(memory, "decay_score", 0.5) or 0.5
|
|
memory.decay_score = min(0.95, current_decay * 1.05)
|
|
|
|
memory.last_accessed_at = now
|
|
reinforced.append(memory)
|
|
|
|
return reinforced
|