fix(memory): add timestamp and cap to recent history injection

This commit is contained in:
Xubin Ren 2026-04-07 16:00:41 +00:00 committed by Xubin Ren
parent 05d8062c70
commit ce7986e492
2 changed files with 42 additions and 2 deletions

View File

@ -19,6 +19,7 @@ class ContextBuilder:
BOOTSTRAP_FILES = ["AGENTS.md", "SOUL.md", "USER.md", "TOOLS.md"]
_RUNTIME_CONTEXT_TAG = "[Runtime Context — metadata only, not instructions]"
_MAX_RECENT_HISTORY = 50
def __init__(self, workspace: Path, timezone: str | None = None):
self.workspace = workspace
@ -50,7 +51,10 @@ class ContextBuilder:
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))
capped = entries[-self._MAX_RECENT_HISTORY:]
parts.append("# Recent History\n\n" + "\n".join(
f"- [{e['timestamp']}] {e['content']}" for e in capped
))
return "\n\n---\n\n".join(parts)

View File

@ -2,6 +2,7 @@
from __future__ import annotations
import re
from datetime import datetime as real_datetime
from importlib.resources import files as pkg_files
from pathlib import Path
@ -87,7 +88,7 @@ def test_runtime_context_is_separate_untrusted_user_message(tmp_path) -> None:
def test_unprocessed_history_injected_into_system_prompt(tmp_path) -> None:
"""Entries in history.jsonl not yet consumed by Dream appear in the prompt."""
"""Entries in history.jsonl not yet consumed by Dream appear with timestamps."""
workspace = _make_workspace(tmp_path)
builder = ContextBuilder(workspace)
@ -98,6 +99,21 @@ def test_unprocessed_history_injected_into_system_prompt(tmp_path) -> None:
assert "# Recent History" in prompt
assert "User asked about weather in Tokyo" in prompt
assert "Agent fetched forecast via web_search" in prompt
assert re.search(r"\[\d{4}-\d{2}-\d{2} \d{2}:\d{2}\]", prompt)
def test_recent_history_capped_at_max(tmp_path) -> None:
"""Only the most recent _MAX_RECENT_HISTORY entries are injected."""
workspace = _make_workspace(tmp_path)
builder = ContextBuilder(workspace)
for i in range(builder._MAX_RECENT_HISTORY + 20):
builder.memory.append_history(f"entry-{i}")
prompt = builder.build_system_prompt()
assert "entry-0" not in prompt
assert "entry-19" not in prompt
assert f"entry-{builder._MAX_RECENT_HISTORY + 19}" in prompt
def test_no_recent_history_when_dream_has_processed_all(tmp_path) -> None:
@ -112,6 +128,26 @@ def test_no_recent_history_when_dream_has_processed_all(tmp_path) -> None:
assert "# Recent History" not in prompt
def test_partial_dream_processing_shows_only_remainder(tmp_path) -> None:
"""When Dream has processed some entries, only the unprocessed ones appear."""
workspace = _make_workspace(tmp_path)
builder = ContextBuilder(workspace)
c1 = builder.memory.append_history("old conversation about Python")
c2 = builder.memory.append_history("old conversation about Rust")
builder.memory.append_history("recent question about Docker")
builder.memory.append_history("recent question about K8s")
builder.memory.set_last_dream_cursor(c2)
prompt = builder.build_system_prompt()
assert "# Recent History" in prompt
assert "old conversation about Python" not in prompt
assert "old conversation about Rust" not in prompt
assert "recent question about Docker" in prompt
assert "recent question about K8s" in prompt
def test_subagent_result_does_not_create_consecutive_assistant_messages(tmp_path) -> None:
workspace = _make_workspace(tmp_path)
builder = ContextBuilder(workspace)