Skip to content

Commit 668d61e

Browse files
committed
fix(memory): skip working-memory cleanup during reorganize pass
MemoryManager.add(mode='sync') previously always invoked _cleanup_working_memory which prunes the oldest WorkingMemory nodes to stay within the configured cap. During a reorganize pass the working pool is being rebuilt from long-term material, so that cleanup would silently drop freshly reconstructed nodes. Guard the cleanup call with the existing is_reorganize flag so reorganize preserves the rebuilt working-memory population while non-reorganize mode keeps the original eviction behaviour. Closes #1952.
1 parent 19bd86d commit 668d61e

2 files changed

Lines changed: 42 additions & 1 deletion

File tree

‎src/memos/memories/textual/tree_text_memory/organize/manager.py‎

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,11 @@ def add(
112112
else:
113113
added_ids = self._add_memories_parallel(memories, user_name)
114114

115-
if mode == "sync":
115+
# When running inside a reorganize pass, the working-memory pool is
116+
# being reconstructed from long-term material, so we must not drop
117+
# nodes via ``remove_oldest_memory`` and must not refresh the
118+
# aggregated size counters against a temporary population.
119+
if mode == "sync" and not self.is_reorganize:
116120
self._cleanup_working_memory(user_name)
117121

118122
return added_ids

‎tests/memories/textual/test_tree_manager.py‎

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,3 +142,40 @@ def test_add_returns_written_node_ids(memory_manager):
142142
assert isinstance(ids, list)
143143
assert all(isinstance(i, str) for i in ids)
144144
assert len(ids) > 0
145+
146+
147+
def test_add_in_reorganize_mode_skips_working_memory_cleanup(
148+
mock_graph_store, mock_embedder, mock_llm
149+
):
150+
"""In reorganize mode we must not evict working-memory nodes."""
151+
mgr = MemoryManager(
152+
graph_store=mock_graph_store,
153+
embedder=mock_embedder,
154+
llm=mock_llm,
155+
is_reorganize=True,
156+
)
157+
memory = TextualMemoryItem(
158+
memory="keep me during reorg",
159+
metadata=TreeNodeTextualMemoryMetadata(embedding=[0.1] * 5, memory_type="WorkingMemory"),
160+
)
161+
before_calls = mock_graph_store.remove_oldest_memory.call_count
162+
mgr.add([memory], mode="sync")
163+
# remove_oldest_memory must NOT have been called for WorkingMemory cleanup
164+
assert mock_graph_store.remove_oldest_memory.call_count == before_calls
165+
166+
167+
def test_add_normal_mode_still_cleans_up_working_memory(mock_graph_store, mock_embedder, mock_llm):
168+
"""Non-reorganize mode preserves the original cleanup behavior."""
169+
mgr = MemoryManager(
170+
graph_store=mock_graph_store,
171+
embedder=mock_embedder,
172+
llm=mock_llm,
173+
is_reorganize=False,
174+
)
175+
memory = TextualMemoryItem(
176+
memory="normal add",
177+
metadata=TreeNodeTextualMemoryMetadata(embedding=[0.1] * 5, memory_type="WorkingMemory"),
178+
)
179+
before_calls = mock_graph_store.remove_oldest_memory.call_count
180+
mgr.add([memory], mode="sync")
181+
assert mock_graph_store.remove_oldest_memory.call_count > before_calls

0 commit comments

Comments
 (0)