diff --git a/nanobot/session/manager.py b/nanobot/session/manager.py index efb5b475c..e6d8e21c3 100644 --- a/nanobot/session/manager.py +++ b/nanobot/session/manager.py @@ -101,7 +101,11 @@ class Session: 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): + if ( + isinstance(self.last_consolidated, bool) + or not isinstance(self.last_consolidated, int) + or not 0 <= self.last_consolidated <= len(self.messages) + ): self.last_consolidated = 0 @staticmethod diff --git a/tests/session/test_consolidated_offset_clamp.py b/tests/session/test_consolidated_offset_clamp.py index 6f9358ffc..1bad7b1ae 100644 --- a/tests/session/test_consolidated_offset_clamp.py +++ b/tests/session/test_consolidated_offset_clamp.py @@ -1,9 +1,12 @@ """Reset a corrupt last_consolidated offset instead of hiding history (#4066).""" -from nanobot.session.manager import Session +import json +from pathlib import Path + +from nanobot.session.manager import Session, SessionManager -def _session(count: int, last_consolidated: int) -> Session: +def _session(count: int, last_consolidated: object) -> Session: msgs = [{"role": "user", "content": f"msg{i}"} for i in range(count)] return Session(key="chan:chat", messages=msgs, last_consolidated=last_consolidated) @@ -13,6 +16,44 @@ def test_out_of_range_offset_is_reset(): assert _session(3, -5).last_consolidated == 0 +def test_non_integer_offset_is_reset(): + for offset in ("999", None, 0.5, True): + assert _session(3, offset).last_consolidated == 0 + + +def test_loaded_corrupt_offset_keeps_messages(tmp_path: Path): + offsets = { + "string": "999", + "null": None, + "float": 0.5, + "bool": True, + } + + for name, offset in offsets.items(): + manager = SessionManager(tmp_path / name) + path = manager._get_session_path("chan:chat") + path.parent.mkdir(parents=True, exist_ok=True) + message = {"role": "user", "content": f"survived {name}"} + path.write_text( + "\n".join([ + json.dumps({ + "_type": "metadata", + "key": "chan:chat", + "metadata": {}, + "last_consolidated": offset, + }), + json.dumps(message), + ]) + "\n", + encoding="utf-8", + ) + + session = manager.get_or_create("chan:chat") + + assert session.messages == [message] + assert session.last_consolidated == 0 + assert session.get_history(max_messages=10) == [message] + + def test_valid_offset_is_preserved(): session = _session(10, 4) assert session.last_consolidated == 4