Skip to content

refactor: runMemoryReflection should use bulkStore() instead of individual store.store() #680

@jlin53882

Description

@jlin53882

Issue: runMemoryReflection handler uses individual store.store() causing N lock acquisitions

Severity: Medium
Affected: index.tsrunMemoryReflection function


Problem

In the runMemoryReflection handler, mapped reflection memories are written using individual store.store() calls inside a loop:

for (const mapped of mappedReflectionMemories) {
  const vector = await embedder.embedPassage(mapped.text);
  // ... dedup check (vectorSearch) ...
  const storedEntry = await store.store({  // ← N lock acquisitions
    text: mapped.text, vector, importance,
    category: mapped.category, scope: targetScope, metadata
  });
}

Additionally, storeReflectionToLanceDB passes a callback store: (entry) => store.store(entry) which also uses individual writes.

Each store.store() call acquires a file lock. When multiple mapped memories are processed, this creates N lock acquisitions instead of 1.


Impact

  • Low frequency trigger: Only on /new or /reset command hooks — not a high-volume path
  • N lock acquisitions: If 3-5 reflection memories are extracted per session, each gets its own lock
  • Risk: Under simultaneous reflection generation (multiple agents), lock contention possible but less severe than auto-capture

Suggested Fix

Collect all mapped entries into an array, then call store.bulkStore() once:

const capturedEntries = [];
for (const mapped of mappedReflectionMemories) {
  // ... dedup check ...
  capturedEntries.push({
    text: mapped.text, vector, importance,
    category: mapped.category, scope: targetScope, metadata
  });
}
if (capturedEntries.length > 0) {
  await store.bulkStore(capturedEntries);
}

Similarly update the storeReflectionToLanceDB callback to collect and batch.


Related


Note

Unlike the auto-capture path (#675/#676), this is not a critical hot path since reflection generation only runs on session boundaries (/new, /reset). Recommend fixing separately after PR #678 is merged.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions