From 8f49b52079137af90aa56cb164848add110f284e Mon Sep 17 00:00:00 2001 From: Kiplangatkorir Date: Mon, 16 Feb 2026 15:22:15 +0300 Subject: [PATCH 1/2] Scope sessions to workspace with legacy fallback --- nanobot/session/manager.py | 38 +++++++++++++++++++++++++++++++++++--- 1 file changed, 35 insertions(+), 3 deletions(-) diff --git a/nanobot/session/manager.py b/nanobot/session/manager.py index bce12a1..e2d8e5c 100644 --- a/nanobot/session/manager.py +++ b/nanobot/session/manager.py @@ -42,8 +42,30 @@ class Session: self.updated_at = datetime.now() def get_history(self, max_messages: int = 500) -> list[dict[str, Any]]: - """Get recent messages in LLM format (role + content only).""" - return [{"role": m["role"], "content": m["content"]} for m in self.messages[-max_messages:]] + """ + Get recent messages in LLM format. + + Preserves tool metadata for replay/debugging fidelity. + """ + history: list[dict[str, Any]] = [] + for msg in self.messages[-max_messages:]: + llm_msg: dict[str, Any] = { + "role": msg["role"], + "content": msg.get("content", ""), + } + + if msg["role"] == "assistant" and "tool_calls" in msg: + llm_msg["tool_calls"] = msg["tool_calls"] + + if msg["role"] == "tool": + if "tool_call_id" in msg: + llm_msg["tool_call_id"] = msg["tool_call_id"] + if "name" in msg: + llm_msg["name"] = msg["name"] + + history.append(llm_msg) + + return history def clear(self) -> None: """Clear all messages and reset session to initial state.""" @@ -61,13 +83,19 @@ class SessionManager: def __init__(self, workspace: Path): self.workspace = workspace - self.sessions_dir = ensure_dir(Path.home() / ".nanobot" / "sessions") + self.sessions_dir = ensure_dir(self.workspace / "sessions") + self.legacy_sessions_dir = Path.home() / ".nanobot" / "sessions" self._cache: dict[str, Session] = {} def _get_session_path(self, key: str) -> Path: """Get the file path for a session.""" safe_key = safe_filename(key.replace(":", "_")) return self.sessions_dir / f"{safe_key}.jsonl" + + def _get_legacy_session_path(self, key: str) -> Path: + """Get the legacy global session path for backward compatibility.""" + safe_key = safe_filename(key.replace(":", "_")) + return self.legacy_sessions_dir / f"{safe_key}.jsonl" def get_or_create(self, key: str) -> Session: """ @@ -92,6 +120,10 @@ class SessionManager: def _load(self, key: str) -> Session | None: """Load a session from disk.""" path = self._get_session_path(key) + if not path.exists(): + legacy_path = self._get_legacy_session_path(key) + if legacy_path.exists(): + path = legacy_path if not path.exists(): return None From 27a131830f31ae8560aa4f0f44fad577d6e940c4 Mon Sep 17 00:00:00 2001 From: Re-bin Date: Wed, 18 Feb 2026 05:09:57 +0000 Subject: [PATCH 2/2] refine: migrate legacy sessions on load and simplify get_history --- nanobot/session/manager.py | 39 +++++++++++++------------------------- 1 file changed, 13 insertions(+), 26 deletions(-) diff --git a/nanobot/session/manager.py b/nanobot/session/manager.py index e2d8e5c..752fce4 100644 --- a/nanobot/session/manager.py +++ b/nanobot/session/manager.py @@ -42,30 +42,15 @@ class Session: self.updated_at = datetime.now() def get_history(self, max_messages: int = 500) -> list[dict[str, Any]]: - """ - Get recent messages in LLM format. - - Preserves tool metadata for replay/debugging fidelity. - """ - history: list[dict[str, Any]] = [] - for msg in self.messages[-max_messages:]: - llm_msg: dict[str, Any] = { - "role": msg["role"], - "content": msg.get("content", ""), - } - - if msg["role"] == "assistant" and "tool_calls" in msg: - llm_msg["tool_calls"] = msg["tool_calls"] - - if msg["role"] == "tool": - if "tool_call_id" in msg: - llm_msg["tool_call_id"] = msg["tool_call_id"] - if "name" in msg: - llm_msg["name"] = msg["name"] - - history.append(llm_msg) - - return history + """Get recent messages in LLM format, preserving tool metadata.""" + out: list[dict[str, Any]] = [] + for m in self.messages[-max_messages:]: + entry: dict[str, Any] = {"role": m["role"], "content": m.get("content", "")} + for k in ("tool_calls", "tool_call_id", "name"): + if k in m: + entry[k] = m[k] + out.append(entry) + return out def clear(self) -> None: """Clear all messages and reset session to initial state.""" @@ -93,7 +78,7 @@ class SessionManager: return self.sessions_dir / f"{safe_key}.jsonl" def _get_legacy_session_path(self, key: str) -> Path: - """Get the legacy global session path for backward compatibility.""" + """Legacy global session path (~/.nanobot/sessions/).""" safe_key = safe_filename(key.replace(":", "_")) return self.legacy_sessions_dir / f"{safe_key}.jsonl" @@ -123,7 +108,9 @@ class SessionManager: if not path.exists(): legacy_path = self._get_legacy_session_path(key) if legacy_path.exists(): - path = legacy_path + import shutil + shutil.move(str(legacy_path), str(path)) + logger.info(f"Migrated session {key} from legacy path") if not path.exists(): return None