Merge Memory V2 runtime facade
This commit is contained in:
@@ -0,0 +1,126 @@
|
||||
import assert from 'node:assert/strict';
|
||||
import test from 'node:test';
|
||||
import {
|
||||
MEMORY_V2_PLUGIN_BACKEND_SPECS,
|
||||
createMemoryV2PluginBackends,
|
||||
createUnavailableMemoryBackend,
|
||||
} from './memory-v2-plugin-backends.mjs';
|
||||
import { createMemoryV2 } from './memory-v2.mjs';
|
||||
|
||||
function silentLogger() {
|
||||
return { warn() {} };
|
||||
}
|
||||
|
||||
test('Memory V2 plugin specs cover optional future backend families', () => {
|
||||
assert.deepEqual(
|
||||
MEMORY_V2_PLUGIN_BACKEND_SPECS.map((spec) => [spec.name, spec.category]),
|
||||
[
|
||||
['pgvector', 'semantic'],
|
||||
['qdrant', 'semantic'],
|
||||
['weaviate', 'semantic'],
|
||||
['mem0', 'extraction'],
|
||||
['letta', 'lifecycle'],
|
||||
['neo4j', 'behavior'],
|
||||
['redis-streams', 'behavior'],
|
||||
['langgraph', 'policy'],
|
||||
],
|
||||
);
|
||||
});
|
||||
|
||||
test('createUnavailableMemoryBackend exposes declared capabilities without availability', async () => {
|
||||
const backend = createUnavailableMemoryBackend({
|
||||
name: 'mem0',
|
||||
category: 'extraction',
|
||||
role: 'automatic-memory-generation',
|
||||
capabilities: ['write', 'compact'],
|
||||
flag: 'MEMORY_MEM0_ENABLED',
|
||||
});
|
||||
|
||||
assert.equal(backend.name, 'mem0');
|
||||
assert.equal(backend.category, 'extraction');
|
||||
assert.equal(backend.role, 'automatic-memory-generation');
|
||||
assert.equal(backend.flag, 'MEMORY_MEM0_ENABLED');
|
||||
assert.equal(backend.isAvailable(), false);
|
||||
assert.equal(backend.getUnavailableReason(), 'not_configured');
|
||||
assert.equal(typeof backend.resolve, 'undefined');
|
||||
assert.deepEqual(await backend.write({}), { saved: 0, analyzed: 0, memories: 0 });
|
||||
assert.deepEqual(await backend.compact({}), { analyzed: 0, memories: 0 });
|
||||
});
|
||||
|
||||
test('createMemoryV2PluginBackends can exclude a real injected backend', () => {
|
||||
const backends = createMemoryV2PluginBackends({ exclude: ['pgvector'] });
|
||||
|
||||
assert.equal(backends.some((backend) => backend.name === 'pgvector'), false);
|
||||
assert.equal(backends.some((backend) => backend.name === 'qdrant'), true);
|
||||
});
|
||||
|
||||
test('Memory V2 default status lists future plugin slots without selecting them', () => {
|
||||
const memory = createMemoryV2({
|
||||
logger: silentLogger(),
|
||||
legacyMemoryService: {
|
||||
async listMemories() {
|
||||
return [];
|
||||
},
|
||||
},
|
||||
env: {
|
||||
MEMORY_ENABLED: '1',
|
||||
MEMORY_BACKEND: 'legacy',
|
||||
},
|
||||
});
|
||||
|
||||
const status = memory.getStatus();
|
||||
const byName = new Map(status.backends.map((backend) => [backend.name, backend]));
|
||||
|
||||
assert.equal(status.selectedBackend, 'legacy-conversation-memory');
|
||||
assert.equal(byName.get('legacy-conversation-memory').available, true);
|
||||
assert.deepEqual(
|
||||
[...byName.keys()],
|
||||
[
|
||||
'legacy-conversation-memory',
|
||||
'pgvector',
|
||||
'qdrant',
|
||||
'weaviate',
|
||||
'mem0',
|
||||
'letta',
|
||||
'neo4j',
|
||||
'redis-streams',
|
||||
'langgraph',
|
||||
],
|
||||
);
|
||||
assert.deepEqual(byName.get('qdrant'), {
|
||||
name: 'qdrant',
|
||||
available: false,
|
||||
supports: {
|
||||
resolve: true,
|
||||
write: false,
|
||||
compact: false,
|
||||
},
|
||||
category: 'semantic',
|
||||
role: 'scale-out-vector-store',
|
||||
flag: 'MEMORY_QDRANT_ENABLED',
|
||||
reason: 'not_configured',
|
||||
});
|
||||
});
|
||||
|
||||
test('Memory V2 falls back to legacy when a future plugin is configured but unavailable', async () => {
|
||||
const memory = createMemoryV2({
|
||||
logger: silentLogger(),
|
||||
legacyMemoryService: {
|
||||
async listMemories() {
|
||||
return [{ label: 'fact', text: 'legacy remains the safe path' }];
|
||||
},
|
||||
},
|
||||
env: {
|
||||
MEMORY_ENABLED: '1',
|
||||
MEMORY_BACKEND: 'qdrant',
|
||||
},
|
||||
});
|
||||
|
||||
const result = await memory.resolve({ userId: 'u1', query: 'memory-chain' });
|
||||
|
||||
assert.equal(memory.getStatus().selectedBackend, 'legacy-conversation-memory');
|
||||
assert.equal(result.source, 'legacy-conversation-memory');
|
||||
assert.deepEqual(result.memories, [
|
||||
{ label: 'fact', text: 'legacy remains the safe path' },
|
||||
]);
|
||||
});
|
||||
Reference in New Issue
Block a user