Skip to content
Open
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
37 changes: 31 additions & 6 deletions python/packages/core/agent_framework/_harness/_memory.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,19 +108,44 @@ def _normalize_memory_text(memory: str) -> str:
return normalized


_LEADING_BACKSLASHES_BEFORE_HASH: re.Pattern[str] = re.compile(r"^(\\+)#")


def _escape_markdown_line(line: str) -> str:
"""Escape a markdown line so it cannot be re-interpreted as a heading on a later read."""
if line.lstrip().startswith(("#", "\\#")):
return f"\\{line}"
"""Escape a markdown line so it cannot be re-interpreted as a heading on a later read.

A line starting with ``#`` gets one backslash. A line that already starts
with backslashes before ``#`` gets one more than it had, so a reader can
always recover the exact original run: prepending a single backslash to an
escaped hash produced a two backslash prefix the old reader never stripped,
corrupting the round trip.
"""
leading_whitespace_length = len(line) - len(line.lstrip())
body = line[leading_whitespace_length:]
match = _LEADING_BACKSLASHES_BEFORE_HASH.match(body)
if match:
run_length = len(match.group(1))
escaped_run = "\\" * (2 * run_length + 1)
return line[:leading_whitespace_length] + escaped_run + body[run_length:]
if body.startswith("#"):
return "\\" + line
return line


def _unescape_markdown_line(line: str) -> str:
"""Reverse :func:`_escape_markdown_line` when reading persisted memory content."""
"""Reverse :func:`_escape_markdown_line` when reading persisted memory content.

An odd backslash run before ``#`` is one this module wrote (``n`` originals
become ``n + 1``), so the reader keeps ``(run - 1) // 2`` originals. An even
run was not produced here and is left untouched.
"""
leading_whitespace_length = len(line) - len(line.lstrip())
body = line[leading_whitespace_length:]
if body.startswith("\\#"):
return f"{line[:leading_whitespace_length]}{body[1:]}"
match = _LEADING_BACKSLASHES_BEFORE_HASH.match(body)
if match and len(match.group(1)) % 2 == 1:
original_length = (len(match.group(1)) - 1) // 2
original_run = "\\" * original_length
return line[:leading_whitespace_length] + original_run + body[len(match.group(1)) :]
return line


Expand Down
18 changes: 18 additions & 0 deletions python/packages/core/tests/core/test_harness_memory.py
Original file line number Diff line number Diff line change
Expand Up @@ -1046,6 +1046,24 @@ def test_memory_file_store_encodes_non_ascii_owner_ids(tmp_path) -> None:
assert roots[0] != roots[1]


def test_memory_topic_record_round_trips_backslash_hash_lines() -> None:
"""Lines starting with backslash hash must survive a round trip unchanged.

Escaping such a line used to add a second backslash the reader never
stripped, so every reload corrupted the memory a little more.
"""
record = MemoryTopicRecord(
topic="notes",
summary="\\# summary line",
memories=["\\# literal fact", "# heading shaped memory", "\\\\# two backslashes"],
updated_at="2026-10-26T00:00:00+00:00",
)

parsed = MemoryTopicRecord.from_markdown(record.to_markdown(), fallback_topic="notes")

assert parsed.memories == ["\\# literal fact", "# heading shaped memory", "\\\\# two backslashes"]


def test_memory_file_store_uses_literal_folders_for_safe_identifiers(tmp_path) -> None:
"""Safe identifiers are readable on disk rather than opaque encoded segments."""
store = MemoryFileStore(tmp_path, owner_prefix="user_", owner_state_key="owner_id")
Expand Down
Loading