import assert from 'node:assert/strict'; import test from 'node:test'; import { applyRecallFusionToMemoryMerge, fuseRecallCandidates, normalizeRecallCandidate, reciprocalRankFusion, resolveRecallFusionMode, } from './recall-fusion.mjs'; test('resolveRecallFusionMode defaults to off', () => { assert.equal(resolveRecallFusionMode({}), 'off'); assert.equal(resolveRecallFusionMode({ MEMIND_RECALL_FUSION_MODE: 'shadow' }), 'shadow'); }); test('reciprocalRankFusion boosts items appearing in multiple lists', () => { const shared = normalizeRecallCandidate( { id: 'm1', text: '用户偏好简洁回答' }, { source: 'personal', rank: 0, query: '偏好' }, ); const episodicOnly = normalizeRecallCandidate( { id: 'm2', text: '上次讨论了苏州旅行' }, { source: 'episodic', rank: 0, query: '苏州' }, ); const fused = reciprocalRankFusion([ { source: 'personal', candidates: [shared] }, { source: 'episodic', candidates: [shared, episodicOnly] }, ], { k: 60 }); assert.equal(fused[0].id, 'm1'); assert.ok(fused[0].sources.includes('personal')); assert.ok(fused[0].sources.includes('episodic')); }); test('fuseRecallCandidates dedupes duplicate fingerprints across sources', () => { const duplicate = '用户喜欢咖啡'; const fusion = fuseRecallCandidates({ query: '咖啡偏好', personalMemories: [{ id: 'p1', text: duplicate }], episodicMemories: [{ id: 'e1', text: duplicate }], limit: 3, env: { MEMIND_RECALL_FUSION_MODE: 'active' }, }); assert.equal(fusion.keptCount, 1); assert.equal(fusion.duplicateCount, 1); }); test('applyRecallFusionToMemoryMerge keeps legacy merge in shadow mode', () => { const applied = applyRecallFusionToMemoryMerge({ personalMemories: [{ id: 'p1', text: 'alpha' }], episodicMemories: [{ id: 'e1', text: 'beta' }], query: 'alpha', limit: 1, legacyMerge: () => [{ id: 'legacy', text: 'legacy-only' }], env: { MEMIND_RECALL_FUSION_MODE: 'shadow' }, }); assert.equal(applied.applied, false); assert.equal(applied.memories[0].id, 'legacy'); assert.ok(applied.fusion); }); test('applyRecallFusionToMemoryMerge uses fused ranking in active mode', () => { const duplicate = '共享记忆'; const applied = applyRecallFusionToMemoryMerge({ personalMemories: [{ id: 'p1', text: duplicate }], episodicMemories: [{ id: 'e1', text: duplicate }, { id: 'e2', text: 'unique episodic' }], query: '共享', limit: 2, legacyMerge: () => [{ id: 'legacy', text: 'legacy-only' }], env: { MEMIND_RECALL_FUSION_MODE: 'active' }, }); assert.equal(applied.applied, true); assert.equal(applied.memories.length, 2); assert.notEqual(applied.memories[0].id, 'legacy'); });