diff --git a/src/services/memory/index.js b/src/services/memory/index.js index 494dc1d..dc86c12 100644 --- a/src/services/memory/index.js +++ b/src/services/memory/index.js @@ -330,8 +330,9 @@ export async function unpinMemory(id, options = {}) { * @param {string} id * @param {string} mergedInto */ -export async function markMemoryMerged(id, mergedInto) { - const merged = await memoryRepository.markMerged(id, mergedInto); +export async function markMemoryMerged(id, mergedInto, options = {}) { + const repository = options.repository ?? memoryRepository; + const merged = await repository.markMerged(id, mergedInto); cache.clear(); return merged; } diff --git a/test/memory-admin.test.mjs b/test/memory-admin.test.mjs index 7f43e0e..d27942c 100644 --- a/test/memory-admin.test.mjs +++ b/test/memory-admin.test.mjs @@ -6,6 +6,7 @@ import { ingestEvents, inspectMemory, listMemories, + markMemoryMerged, memoryStats, pinMemory, runPruneCycle, @@ -133,3 +134,43 @@ test('runPruneCycle respects prune feature-flag modes', async () => { assert.equal(offResult.mode, 'off'); assert.equal(offResult.pruned.length, 0); }); + +test('markMemoryMerged delegates to repository and clears cache', async () => { + let callCount = 0; + const repository = { + async markMerged(id, mergedInto) { + callCount++; + return id === 'exists'; + } + }; + + const result1 = await markMemoryMerged('exists', 'target', { repository }); + assert.equal(result1, true); + assert.equal(callCount, 1); + + const result2 = await markMemoryMerged('missing', 'target', { repository }); + assert.equal(result2, false); + assert.equal(callCount, 2); + + // Verify cache clearing + const telemetry = []; + const emitTelemetry = (event, payload) => telemetry.push({ event, payload }); + + // 1. Populate cache + await getRelevantMemories({ agent_id: 'cache-test', emitTelemetry }); + const hit1 = telemetry.findLast(t => t.event === 'memory:retrieved'); + assert.equal(hit1.payload.cache_hit, false); + + // 2. Hit cache + await getRelevantMemories({ agent_id: 'cache-test', emitTelemetry }); + const hit2 = telemetry.findLast(t => t.event === 'memory:retrieved'); + assert.equal(hit2.payload.cache_hit, true); + + // 3. Clear cache via side-effect + await markMemoryMerged('exists', 'target', { repository }); + + // 4. Miss cache + await getRelevantMemories({ agent_id: 'cache-test', emitTelemetry }); + const hit3 = telemetry.findLast(t => t.event === 'memory:retrieved'); + assert.equal(hit3.payload.cache_hit, false); +});