| """Memory Manager β coordinates short-term, long-term, and working memory.""" |
|
|
| from typing import Optional |
|
|
| from agentic_rag.data.models import Message |
|
|
|
|
| class MemoryManager: |
| """Coordinates the three-tier memory system. |
| |
| - ShortTermMemory: Sliding window of recent messages |
| - LongTermMemory: Vector-indexed semantic memories (Milvus-backed, future) |
| - WorkingMemory: Ephemeral scratchpad per turn |
| """ |
|
|
| def __init__(self, max_short_term_tokens: int = 8000): |
| self.max_short_term_tokens = max_short_term_tokens |
| self._short_term: dict[str, list[Message]] = {} |
| self._working: dict[str, dict] = {} |
|
|
| |
|
|
| def add_message(self, session_id: str, message: Message) -> None: |
| """Add a message to short-term memory.""" |
| if session_id not in self._short_term: |
| self._short_term[session_id] = [] |
| self._short_term[session_id].append(message) |
| self._trim(session_id) |
|
|
| def get_messages(self, session_id: str, limit: int = 50) -> list[Message]: |
| """Get recent messages for a session.""" |
| messages = self._short_term.get(session_id, []) |
| return messages[-limit:] if len(messages) > limit else messages |
|
|
| def clear_short_term(self, session_id: str) -> None: |
| """Clear short-term memory for a session.""" |
| self._short_term.pop(session_id, None) |
|
|
| def _trim(self, session_id: str) -> None: |
| """Trim messages to fit within token budget (approximate).""" |
| messages = self._short_term.get(session_id, []) |
| total_tokens = sum(len(str(m.content)) // 4 for m in messages) |
| while total_tokens > self.max_short_term_tokens and len(messages) > 2: |
| removed = messages.pop(0) |
| total_tokens -= len(str(removed.content)) // 4 |
|
|
| |
|
|
| def set_working(self, session_id: str, key: str, value) -> None: |
| """Set a working memory value for the current turn.""" |
| if session_id not in self._working: |
| self._working[session_id] = {} |
| self._working[session_id][key] = value |
|
|
| def get_working(self, session_id: str, key: str, default=None): |
| """Get a working memory value.""" |
| return self._working.get(session_id, {}).get(key, default) |
|
|
| def clear_working(self, session_id: str) -> None: |
| """Clear working memory at end of turn.""" |
| self._working.pop(session_id, None) |
|
|
| |
|
|
| async def search_long_term(self, session_id: str, query: str, top_k: int = 10) -> list[dict]: |
| """Search long-term memory for relevant past interactions.""" |
| |
| return [] |
|
|
| async def store_long_term(self, session_id: str, fact: str, metadata: dict | None = None) -> None: |
| """Store a fact in long-term memory.""" |
| |
| pass |
|
|
|
|
| |
| _memory_manager: Optional[MemoryManager] = None |
|
|
|
|
| def get_memory_manager() -> MemoryManager: |
| global _memory_manager |
| if _memory_manager is None: |
| from agentic_rag.config.settings import get_settings |
| _memory_manager = MemoryManager( |
| max_short_term_tokens=get_settings().memory.short_term_max_tokens, |
| ) |
| return _memory_manager |
|
|