diff --git a/nanobot/session/manager.py b/nanobot/session/manager.py index 1febf10c9..efb5b475c 100644 --- a/nanobot/session/manager.py +++ b/nanobot/session/manager.py @@ -99,6 +99,11 @@ class Session: metadata: dict[str, Any] = field(default_factory=dict) last_consolidated: int = 0 # Number of messages already consolidated to files + def __post_init__(self) -> None: + # An out-of-range offset (corrupt metadata) would hide all history; reset it. + if not 0 <= self.last_consolidated <= len(self.messages): + self.last_consolidated = 0 + @staticmethod def _annotate_message_time(message: dict[str, Any], content: Any) -> Any: """Expose persisted turn timestamps to the model for relative-date reasoning. diff --git a/tests/agent/test_session_atomic.py b/tests/agent/test_session_atomic.py index 4720c028a..1fe5b9caa 100644 --- a/tests/agent/test_session_atomic.py +++ b/tests/agent/test_session_atomic.py @@ -205,7 +205,8 @@ class TestRepairCorruptFile: session = mgr._load("test:badts") assert session is not None - assert session.last_consolidated == 5 + # offset 5 exceeds the single loaded message; reset to avoid hiding history (#4066) + assert session.last_consolidated == 0 assert isinstance(session.created_at, datetime) def test_read_session_file_repairs_corrupt_jsonl(self, tmp_path: Path): diff --git a/tests/session/test_consolidated_offset_clamp.py b/tests/session/test_consolidated_offset_clamp.py new file mode 100644 index 000000000..6f9358ffc --- /dev/null +++ b/tests/session/test_consolidated_offset_clamp.py @@ -0,0 +1,19 @@ +"""Reset a corrupt last_consolidated offset instead of hiding history (#4066).""" + +from nanobot.session.manager import Session + + +def _session(count: int, last_consolidated: int) -> Session: + msgs = [{"role": "user", "content": f"msg{i}"} for i in range(count)] + return Session(key="chan:chat", messages=msgs, last_consolidated=last_consolidated) + + +def test_out_of_range_offset_is_reset(): + assert _session(10, 999).last_consolidated == 0 + assert _session(3, -5).last_consolidated == 0 + + +def test_valid_offset_is_preserved(): + session = _session(10, 4) + assert session.last_consolidated == 4 + assert len(session.get_history()) == 6