"""Long_term — Qdrant-backed long-term memory interface. Provides the process-wide MemoryRetriever singleton over vector_memory.py; long-term records live only in Qdrant, while per-day short-term files are summarized and indexed at day handoff. Architecture: consumed by brain.py and the engine for retrieval; paired with Short_term.py (operational memory) and vector_memory.py (storage). Design: deliberately no JSON archive reader — Qdrant is the single long-term source of truth. """ from __future__ import annotations from typing import List, Optional, Protocol, runtime_checkable from src.core.log import get_logger logger = get_logger(__name__) @runtime_checkable class MemoryRetriever(Protocol): """Contract consumed by planning, conversation, and tick cognition.""" def store(self, agent_id: str, text: str, *, kind: str = "observation", importance: Optional[float] = None, date_str: Optional[str] = None) -> None: ... def retrieve(self, agent_id: str, query: str, k: int = 5) -> List[str]: ... def rolling_summary(self, agent_id: str, days: int = 3, before_date: Optional[str] = None) -> Optional[str]: ... _retriever_singleton: Optional[MemoryRetriever] = None def get_retriever() -> MemoryRetriever: """Return the process-wide Qdrant retriever. The retriever is intentionally fail-soft for reads: an unavailable cloud service yields no recalled context rather than allowing a memory outage to stop the simulation. It never reads a local long-term JSON archive. """ global _retriever_singleton if _retriever_singleton is None: from src.agents.vector_memory import VectorMemoryRetriever _retriever_singleton = VectorMemoryRetriever() logger.info("[Long_term] using Qdrant-only long-term memory") return _retriever_singleton