refactor(webui): keep sidebar index out of session manager
This commit is contained in:
@@ -96,48 +96,6 @@ def test_list_sessions_bounds_preview_scan(tmp_path):
|
||||
assert rows[0]["preview"] == "assistant trace 0"
|
||||
|
||||
|
||||
def test_list_sessions_reuses_valid_index_without_scanning_files(tmp_path, monkeypatch):
|
||||
manager = SessionManager(tmp_path)
|
||||
session = manager.get_or_create("websocket:indexed")
|
||||
session.add_message("user", "indexed preview")
|
||||
manager.save(session)
|
||||
|
||||
assert manager.list_sessions()[0]["preview"] == "indexed preview"
|
||||
|
||||
def fail_scan(path):
|
||||
raise AssertionError(f"unexpected session file scan: {path}")
|
||||
|
||||
monkeypatch.setattr(manager, "_session_index_row_from_file", fail_scan)
|
||||
|
||||
rows = manager.list_sessions()
|
||||
|
||||
assert rows[0]["key"] == "websocket:indexed"
|
||||
assert rows[0]["preview"] == "indexed preview"
|
||||
|
||||
|
||||
def test_list_sessions_index_updates_on_save_and_delete(tmp_path, monkeypatch):
|
||||
manager = SessionManager(tmp_path)
|
||||
session = manager.get_or_create("websocket:index-refresh")
|
||||
session.add_message("user", "before")
|
||||
manager.save(session)
|
||||
session.messages.clear()
|
||||
session.add_message("user", "after")
|
||||
session.metadata["title"] = "fresh title"
|
||||
manager.save(session)
|
||||
|
||||
def fail_scan(path):
|
||||
raise AssertionError(f"unexpected session file scan: {path}")
|
||||
|
||||
monkeypatch.setattr(manager, "_session_index_row_from_file", fail_scan)
|
||||
|
||||
rows = manager.list_sessions()
|
||||
assert rows[0]["title"] == "fresh title"
|
||||
assert rows[0]["preview"] == "after"
|
||||
|
||||
assert manager.delete_session("websocket:index-refresh") is True
|
||||
assert manager.list_sessions() == []
|
||||
|
||||
|
||||
# --- Original regression test (from PR 2075) ---
|
||||
|
||||
def test_get_history_drops_orphan_tool_results_when_window_cuts_tool_calls():
|
||||
|
||||
@@ -2618,15 +2618,16 @@ def test_parse_envelope_rejects_legacy_and_garbage() -> None:
|
||||
assert _parse_envelope('{"type":123}') is None
|
||||
|
||||
|
||||
def test_sessions_list_includes_active_run_started_at() -> None:
|
||||
def test_sessions_list_includes_active_run_started_at(monkeypatch) -> None:
|
||||
from websockets.datastructures import Headers
|
||||
from websockets.http11 import Request
|
||||
|
||||
from nanobot.session import webui_turns as wth
|
||||
from nanobot.webui import ws_http as ws_http_module
|
||||
|
||||
bus = MagicMock()
|
||||
session_manager = MagicMock()
|
||||
session_manager.list_sessions.return_value = [
|
||||
sessions = [
|
||||
{
|
||||
"key": "websocket:chat-1",
|
||||
"created_at": "2026-05-19T10:00:00Z",
|
||||
@@ -2641,6 +2642,7 @@ def test_sessions_list_includes_active_run_started_at() -> None:
|
||||
"updated_at": "2026-05-19T10:01:00Z",
|
||||
},
|
||||
]
|
||||
monkeypatch.setattr(ws_http_module, "list_webui_sessions", lambda _session_manager: sessions)
|
||||
channel = WebSocketChannel(
|
||||
{"enabled": True, "allowFrom": ["*"]},
|
||||
bus,
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
import nanobot.webui.session_list_index as session_list_index
|
||||
from nanobot.session.manager import SessionManager
|
||||
|
||||
|
||||
def test_webui_session_list_reuses_valid_index_without_scanning_files(
|
||||
tmp_path: Path,
|
||||
monkeypatch,
|
||||
) -> None:
|
||||
manager = SessionManager(tmp_path)
|
||||
session = manager.get_or_create("websocket:indexed")
|
||||
session.add_message("user", "indexed preview")
|
||||
manager.save(session)
|
||||
|
||||
assert list_webui_sessions(manager)[0]["preview"] == "indexed preview"
|
||||
|
||||
def fail_scan(session_manager: SessionManager, path: Path) -> None:
|
||||
raise AssertionError(f"unexpected session file scan: {path}")
|
||||
|
||||
monkeypatch.setattr(session_list_index, "_scan_session_row", fail_scan)
|
||||
|
||||
rows = list_webui_sessions(manager)
|
||||
|
||||
assert rows[0]["key"] == "websocket:indexed"
|
||||
assert rows[0]["preview"] == "indexed preview"
|
||||
|
||||
|
||||
def test_webui_session_list_rescans_only_changed_file(tmp_path: Path, monkeypatch) -> None:
|
||||
manager = SessionManager(tmp_path)
|
||||
first = manager.get_or_create("websocket:first")
|
||||
first.add_message("user", "first")
|
||||
manager.save(first)
|
||||
second = manager.get_or_create("websocket:second")
|
||||
second.add_message("user", "second before")
|
||||
manager.save(second)
|
||||
|
||||
assert {row["preview"] for row in list_webui_sessions(manager)} == {"first", "second before"}
|
||||
|
||||
second.messages.clear()
|
||||
second.add_message("user", "second after")
|
||||
manager.save(second)
|
||||
|
||||
original_scan = session_list_index._scan_session_row
|
||||
scanned: list[str] = []
|
||||
|
||||
def record_scan(session_manager: SessionManager, path: Path) -> dict | None:
|
||||
scanned.append(path.name)
|
||||
return original_scan(session_manager, path)
|
||||
|
||||
monkeypatch.setattr(session_list_index, "_scan_session_row", record_scan)
|
||||
|
||||
rows = list_webui_sessions(manager)
|
||||
|
||||
assert scanned == [manager._get_session_path("websocket:second").name]
|
||||
assert {row["preview"] for row in rows} == {"first", "second after"}
|
||||
|
||||
|
||||
def test_webui_session_list_drops_deleted_index_rows(tmp_path: Path) -> None:
|
||||
manager = SessionManager(tmp_path)
|
||||
session = manager.get_or_create("websocket:deleted")
|
||||
session.add_message("user", "gone")
|
||||
manager.save(session)
|
||||
|
||||
assert list_webui_sessions(manager)[0]["key"] == "websocket:deleted"
|
||||
|
||||
assert manager.delete_session("websocket:deleted") is True
|
||||
|
||||
assert list_webui_sessions(manager) == []
|
||||
|
||||
|
||||
def list_webui_sessions(manager: SessionManager) -> list[dict]:
|
||||
return session_list_index.list_webui_sessions(manager)
|
||||
Reference in New Issue
Block a user