""" modules/context_carry.py - Phase 7 context carry across restarts Stores: - last mode - last few user/assistant interactions (compact) - last active tasks snapshot Used to: - rebuild a small "resume" hint for the brain - show continuity after a crash/reboot """ from __future__ import annotations import json import os import time from datetime import datetime from config import DATA_DIR CTX_FILE = os.path.join(DATA_DIR, "session_context.json") def _load() -> dict: if not os.path.exists(CTX_FILE): return {} try: with open(CTX_FILE, "r") as f: data = json.load(f) if isinstance(data, dict): return data except Exception: pass return {} def _save(data: dict) -> None: os.makedirs(os.path.dirname(CTX_FILE), exist_ok=True) try: with open(CTX_FILE, "w") as f: json.dump(data, f, indent=2) except Exception: pass def snapshot(mode: str | None = None) -> None: """ Save a compact snapshot for resuming context. """ data = _load() data["time"] = time.time() data["iso"] = datetime.now().isoformat() if mode: data["mode"] = mode # last interactions (small) try: from modules.memory import INTERACTION_FILE with open(INTERACTION_FILE, "r") as f: interactions = json.load(f) if not isinstance(interactions, list): interactions = [] compact = interactions[-12:] data["recent"] = [ {"role": it.get("role", ""), "text": (it.get("text", "")[:180]), "time": it.get("time", 0)} for it in compact ] except Exception: pass # tasks snapshot try: from modules.memory import get_unfinished_tasks tasks = get_unfinished_tasks() data["tasks"] = tasks[:10] except Exception: pass _save(data) def resume_block(max_lines: int = 12) -> str: """ Return a short block injected into prompts for continuity. """ data = _load() if not data: return "" lines: list[str] = [] ts = data.get("iso") or "" if ts: lines.append(f"[SESSION CONTEXT] Last snapshot: {ts}") mode = data.get("mode") if mode: lines.append(f"[LAST MODE] {mode}") tasks = data.get("tasks") or [] if tasks: lines.append("[PENDING] " + "; ".join(tasks[:3])) recent = data.get("recent") or [] if recent: lines.append("[RECENT]") for it in recent[-8:]: r = (it.get("role") or "").upper() t = it.get("text") or "" if r and t: lines.append(f"{r}: {t}") return "\n".join(lines[:max_lines])