""" episodic_store.py Lazy loader for all_sessions.json. Keeps the full raw-turn data in memory and returns sessions on demand by session ID, avoiding loading all sessions into ChatHistory upfront. """ import json from datetime import datetime from typing import Dict, List, Optional class EpisodicMemoryStore: def __init__(self, all_sessions_path: str): print(f"[EpisodicMemoryStore] Loading {all_sessions_path} ...") with open(all_sessions_path) as f: self._data: Dict[str, List] = json.load(f) print(f"[EpisodicMemoryStore] Loaded {len(self._data)} sessions.") @staticmethod def _parse_date(date_str: str) -> datetime: """Convert '2023/04/10 (Mon) 17:50' to datetime.""" date_part = date_str.split('(')[0].strip() time_part = date_str.split(')')[-1].strip() return datetime.strptime(date_part + time_part, "%Y/%m/%d%H:%M") def get_raw_sessions( self, sess_ids: List[str], date_lookup: Dict[str, str], topic_lookup: Optional[Dict[str, List[str]]] = None, ) -> List[dict]: """ Return a list of session dicts compatible with ChatHistory(sessions=...). Args: sess_ids: Ordered list of session IDs to load. date_lookup: Mapping sess_id -> date string (e.g. '2023/04/10 (Mon) 17:50'). topic_lookup: Optional mapping sess_id -> list of topic strings. Returns: List of session dicts, each with keys: session_id, session_date, session, topic, timestamp """ sessions = [] for sid in sess_ids: if sid not in self._data: continue date_str = date_lookup.get(sid, "") try: ts = self._parse_date(date_str) if date_str else datetime.min except Exception: ts = datetime.min sessions.append({ "session_id": sid, "session_date": date_str, "session": self._data[sid], "topic": topic_lookup.get(sid, []) if topic_lookup else [], "timestamp": ts, }) return sessions