""" Session Store - Persistent storage for conversation memory Saves and loads user sessions across app restarts """ import json import os from datetime import datetime from pathlib import Path from typing import Optional, Dict, Any class SessionStore: """Manages persistent storage of conversation sessions""" def __init__(self, storage_dir: str = "sessions"): self.storage_dir = Path(storage_dir) self.storage_dir.mkdir(parents=True, exist_ok=True) def save_session(self, user_id: str, session_data: Dict[str, Any]) -> None: """ Save user session to disk Args: user_id: Unique user identifier session_data: Session data to save (memory state) """ session_file = self.storage_dir / f"{user_id}.json" # Add metadata session_data['last_updated'] = datetime.now().isoformat() session_data['user_id'] = user_id with open(session_file, 'w', encoding='utf-8') as f: json.dump(session_data, f, ensure_ascii=False, indent=2) def load_session(self, user_id: str) -> Optional[Dict[str, Any]]: """ Load user session from disk Args: user_id: Unique user identifier Returns: Session data or None if not found """ session_file = self.storage_dir / f"{user_id}.json" if not session_file.exists(): return None try: with open(session_file, 'r', encoding='utf-8') as f: return json.load(f) except (json.JSONDecodeError, IOError) as e: print(f"⚠️ Error loading session for {user_id}: {e}") return None def delete_session(self, user_id: str) -> bool: """ Delete user session Args: user_id: Unique user identifier Returns: True if deleted, False if not found """ session_file = self.storage_dir / f"{user_id}.json" if session_file.exists(): session_file.unlink() return True return False def list_sessions(self) -> list: """ List all stored sessions Returns: List of user IDs with sessions """ return [f.stem for f in self.storage_dir.glob("*.json")] def get_session_info(self, user_id: str) -> Optional[Dict[str, Any]]: """ Get session metadata without loading full data Args: user_id: Unique user identifier Returns: Session metadata or None """ session_file = self.storage_dir / f"{user_id}.json" if not session_file.exists(): return None try: with open(session_file, 'r', encoding='utf-8') as f: data = json.load(f) return { 'user_id': data.get('user_id'), 'last_updated': data.get('last_updated'), 'has_profile': bool(data.get('user_profile')), 'current_agent': data.get('current_agent'), 'conversation_count': len(data.get('conversation_history', [])) } except (json.JSONDecodeError, IOError): return None def cleanup_old_sessions(self, days: int = 30) -> int: """ Delete sessions older than specified days Args: days: Number of days to keep sessions Returns: Number of sessions deleted """ from datetime import timedelta cutoff_date = datetime.now() - timedelta(days=days) deleted_count = 0 for session_file in self.storage_dir.glob("*.json"): try: with open(session_file, 'r', encoding='utf-8') as f: data = json.load(f) last_updated = datetime.fromisoformat(data.get('last_updated', '')) if last_updated < cutoff_date: session_file.unlink() deleted_count += 1 except (json.JSONDecodeError, IOError, ValueError): continue return deleted_count # Global instance _session_store = None def get_session_store() -> SessionStore: """Get global session store instance""" global _session_store if _session_store is None: _session_store = SessionStore() return _session_store