From 31c154a7b8f7bc3178cc8a8fc2a4c9f8fa563d9f Mon Sep 17 00:00:00 2001 From: Lingao Meng Date: Tue, 7 Apr 2026 15:10:31 +0800 Subject: [PATCH] fix(memory): prevent potential loss of compressed session history When the Consolidator compresses old session messages into history.jsonl, those messages are immediately removed from the LLM's context. Dream processes history.jsonl into long-term memory (memory.md) on a cron schedule (default every 2h), creating a window where compressed content is invisible to the LLM. This change closes the gap by injecting unprocessed history entries (history.jsonl entries not yet consumed by Dream) directly into the system prompt as "# Recent History". Key design notes: - Uses read_unprocessed_history(since_cursor=last_dream_cursor) so only entries not yet reflected in long-term memory are included, avoiding duplication with memory.md - No overlap with session messages: Consolidator advances last_consolidated before returning, so archived messages are already removed from get_history() output - Token-safe: Consolidator's estimate_session_prompt_tokens calls build_system_prompt via the same build_messages function, so the injected entries are included in token budget calculations and will trigger further consolidation if needed Signed-off-by: Lingao Meng --- nanobot/agent/context.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/nanobot/agent/context.py b/nanobot/agent/context.py index 1f4064851..1b8cae050 100644 --- a/nanobot/agent/context.py +++ b/nanobot/agent/context.py @@ -48,6 +48,10 @@ class ContextBuilder: if skills_summary: parts.append(render_template("agent/skills_section.md", skills_summary=skills_summary)) + entries = self.memory.read_unprocessed_history(since_cursor=self.memory.get_last_dream_cursor()) + if entries: + parts.append("# Recent History\n\n" + "\n".join(f"- {entry['content']}" for entry in entries)) + return "\n\n---\n\n".join(parts) def _get_identity(self) -> str: