Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
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
Prev Previous commit
Next Next commit
Python: fix(core): resolve unmigrated legacy memory topics in the index
list_topics parses a pre-digest file such as caf.md headed "# café"
and returns the current digested slug, but the file on disk still uses
the legacy name. before_run then calls get_topic(entry.slug) for the
selected entry, where neither the digested path nor a legacy candidate
derivable from that slug exists, so memory preparation dies with
FileNotFoundError. Consolidation silently skips the topic the same way.

A record whose file still sits at the pre-digest name for its topic is
now keyed by the on-disk stem, so MEMORY.md pointers and
get_topic(entry.slug) resolve to the persisted file before a rewrite
migrates it. The heading identity check on the fallback paths is
unchanged: a same-stem file owned by a different topic still does not
alias.

Verified with the full agent-framework-core suite: 8483 tests, 0
failures; ruff and pyright clean on the changed files.

Signed-off-by: Yufeng He <40085740+he-yufeng@users.noreply.github.com>
  • Loading branch information
he-yufeng committed Oct 9, 2026
commit 1ba70dbd4afd82d878eb9f1eed652520c8619c6b
5 changes: 5 additions & 0 deletions python/packages/core/agent_framework/_harness/_memory.py
Original file line number Diff line number Diff line change
Expand Up @@ -866,6 +866,11 @@ def list_topics(self, session: AgentSession, *, source_id: str) -> list[MemoryTo
topic_path.read_text(encoding="utf-8"),
fallback_topic=topic_path.stem.replace("-", " "),
)
if topic_path.stem == _legacy_slugify_topic(record.topic) and topic_path.stem != record.slug:
# Not yet migrated: the file still sits at its pre-digest name. Key the
# record by the stem that exists on disk so index pointers and
# get_topic(entry.slug) resolve to it before a rewrite migrates it.
record.slug = topic_path.stem
topics.append(record)
return sorted(topics, key=lambda record: (record.topic.lower(), record.updated_at))

Expand Down
43 changes: 43 additions & 0 deletions python/packages/core/tests/core/test_harness_memory.py
Original file line number Diff line number Diff line change
Expand Up @@ -1131,4 +1131,47 @@ def test_memory_file_store_legacy_fallback_requires_matching_stored_topic(tmp_pa
assert store.get_topic(session, source_id=DEFAULT_MEMORY_SOURCE_ID, topic="café").memories == ["legacy accent fact"]


def test_memory_file_store_lists_pre_digest_topic_under_its_on_disk_stem(tmp_path) -> None:
"""An unmigrated legacy file must be listed under the stem that exists on disk."""
store, session = _topic_store(tmp_path)
legacy_path = store._get_topics_directory(session, source_id=DEFAULT_MEMORY_SOURCE_ID) / "caf.md"
legacy_path.parent.mkdir(parents=True, exist_ok=True)
legacy_path.write_text(f"{_record('café', ['legacy accent fact']).to_markdown()}\n", encoding="utf-8")

(entry,) = store.list_topics(session, source_id=DEFAULT_MEMORY_SOURCE_ID)

assert entry.topic == "café"
assert entry.slug == "caf"
assert store.get_topic(session, source_id=DEFAULT_MEMORY_SOURCE_ID, topic=entry.slug).memories == [
"legacy accent fact"
]
store.rebuild_index(session, source_id=DEFAULT_MEMORY_SOURCE_ID, line_limit=50, line_length=200)
index_text = store._get_index_path(session, source_id=DEFAULT_MEMORY_SOURCE_ID).read_text(encoding="utf-8")
assert "topics/caf.md" in index_text
# Keying by the on-disk stem must not widen the fallback: a same-stem but
# different topic still does not alias this file.
with pytest.raises(FileNotFoundError):
store.get_topic(session, source_id=DEFAULT_MEMORY_SOURCE_ID, topic="cafè")


async def test_memory_context_provider_loads_unmigrated_legacy_topic(tmp_path) -> None:
"""``before_run`` must resolve an index entry whose file still uses its pre-digest name."""
store, session = _topic_store(tmp_path)
legacy_path = store._get_topics_directory(session, source_id=DEFAULT_MEMORY_SOURCE_ID) / "caf.md"
legacy_path.parent.mkdir(parents=True, exist_ok=True)
legacy_path.write_text(f"{_record('café', ['legacy accent fact']).to_markdown()}\n", encoding="utf-8")
provider = MemoryContextProvider(store=store, recent_turns=0, max_extractions=0)

from agent_framework._sessions import SessionContext

context = SessionContext(
session_id=session.session_id,
input_messages=[Message(role="user", contents=["tell me the legacy accent fact"])],
)

await provider.before_run(agent=None, session=session, context=context, state={})

assert any("legacy accent fact" in message.text for message in context.get_messages())


# endregion
Loading