Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions python/packages/core/agent_framework/_harness/_memory.py
Original file line number Diff line number Diff line change
Expand Up @@ -506,10 +506,10 @@ def from_markdown(cls, markdown: str, *, fallback_topic: str | None = None) -> M
topic = stripped[2:].strip()
current_section = None
continue
if stripped.startswith("Updated: "):
if current_section is None and stripped.startswith("Updated: "):
updated_at = stripped.removeprefix("Updated: ").strip()
continue
if stripped.startswith("Sessions: "):
if current_section is None and stripped.startswith("Sessions: "):
raw_sessions = stripped.removeprefix("Sessions: ").strip()
session_ids = (
[]
Expand Down
54 changes: 54 additions & 0 deletions python/packages/core/tests/core/test_harness_memory.py
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,60 @@ def test_memory_topic_record_round_trips_through_dict_and_markdown() -> None:
assert "MemoryTopicRecord(" in repr(record)


@pytest.mark.parametrize(
"summary",
[
"Updated: the release date changed.",
"Sessions: keep the troubleshooting context.",
"The plan was Updated: yesterday and Sessions: remain useful.",
"Prefers concise answers.",
"## Summary is part of the stored text.",
],
)
def test_memory_file_store_preserves_metadata_like_summary_text(tmp_path: Path, summary: str) -> None:
"""Summary text must not replace metadata when a topic is reloaded from disk."""
store = MemoryFileStore(tmp_path, owner_state_key="owner_id")
session = AgentSession(session_id="session-1")
session.state["owner_id"] = "alice"
record = MemoryTopicRecord(
topic="preferences",
summary=summary,
memories=["Updated: the milestone moved.", "Sessions: retain previous notes."],
updated_at="2026-04-21T10:05:00+00:00",
session_ids=["session-1", "session-2"],
)

assert MemoryTopicRecord.from_markdown(record.to_markdown()) == record
store.write_topic(session, record, source_id=DEFAULT_MEMORY_SOURCE_ID)

assert store.get_topic(session, source_id=DEFAULT_MEMORY_SOURCE_ID, topic=record.slug) == record
assert store.list_topics(session, source_id=DEFAULT_MEMORY_SOURCE_ID) == [record]
entries = store.rebuild_index(session, source_id=DEFAULT_MEMORY_SOURCE_ID, line_limit=200, line_length=150)
assert entries == [MemoryIndexEntry.from_topic_record(record)]


@pytest.mark.parametrize("summary_line", ["Updated: the release date changed.", "Sessions: keep previous notes."])
def test_memory_topic_record_preserves_multiline_summary_metadata_text(summary_line: str) -> None:
"""Metadata labels inside a multiline summary remain content in that section."""
markdown = (
"# preferences\n\n"
"Updated: 2026-04-21T10:05:00+00:00\n"
"Sessions: session-1, session-2\n\n"
"## Summary\n\n"
f"Keep the release notes.\n{summary_line}\n\n"
"## Memories\n\n"
"- Updated: the milestone moved.\n"
"- Sessions: retain previous notes.\n"
)

record = MemoryTopicRecord.from_markdown(markdown)

assert record.summary == f"Keep the release notes. {summary_line}"
assert record.updated_at == "2026-04-21T10:05:00+00:00"
assert record.session_ids == ["session-1", "session-2"]
assert record.memories == ["Updated: the milestone moved.", "Sessions: retain previous notes."]


async def test_memory_file_store_writes_topics_index_state_and_transcripts(tmp_path) -> None:
"""The file-backed memory store should manage topics, ``MEMORY.md``, state, and transcript search."""
store = MemoryFileStore(
Expand Down
Loading