import assert from 'node:assert/strict'; import test from 'node:test'; import { createMemoryV2 } from './memory-v2.mjs'; import { createPgvectorMemoryBackend } from './memory-v2-pgvector.mjs'; test('pgvector backend is disabled by default and does not query storage', async () => { let queried = false; const backend = createPgvectorMemoryBackend({ pool: { async query() { queried = true; return { rows: [] }; }, }, }); assert.equal(backend.isAvailable(), false); assert.deepEqual(await backend.resolve({ userId: 'user-1', embedding: [0.1, 0.2], }), { memories: [], semanticMemories: [], }); assert.equal(queried, false); }); test('pgvector backend returns empty semantic result when embedding is unavailable', async () => { let queried = false; const backend = createPgvectorMemoryBackend({ enabled: true, pool: { async query() { queried = true; return { rows: [] }; }, }, }); const result = await backend.resolve({ userId: 'user-1', query: 'memory-chain', }); assert.deepEqual(result, { memories: [], semanticMemories: [], }); assert.equal(queried, false); }); test('pgvector backend performs parameterized vector lookup when explicitly enabled', async () => { const queries = []; const backend = createPgvectorMemoryBackend({ enabled: true, tableName: 'memory_embeddings', pool: { async query(sql, params) { queries.push({ sql, params }); return { rows: [ { id: 7, content: '用户关注 Memory V2 的 facade 边界', type: 'fact', score: '0.87', created_at: '2026-07-02T00:00:00.000Z', }, ], }; }, }, embedQuery: async (query) => { assert.equal(query, 'memory-chain'); return [0.25, 0.5, 0.75]; }, }); assert.equal(backend.isAvailable(), true); const result = await backend.resolve({ userId: 'user-1', query: 'memory-chain', limit: 5, }); assert.equal(queries.length, 1); assert.match(queries[0].sql, /FROM memory_embeddings/); assert.deepEqual(queries[0].params, ['user-1', '[0.25,0.5,0.75]', 5]); assert.deepEqual(result.semanticMemories, ['用户关注 Memory V2 的 facade 边界']); assert.deepEqual(result.memories, [ { id: '7', label: 'fact', text: '用户关注 Memory V2 的 facade 边界', score: 0.87, createdAt: '2026-07-02T00:00:00.000Z', }, ]); }); test('pgvector backend validates table names before building SQL', () => { assert.throws( () => createPgvectorMemoryBackend({ tableName: 'memory_embeddings;DROP TABLE users' }), /Invalid pgvector table name/, ); }); test('Memory V2 can expose pgvector as unavailable plugin without selecting it', async () => { const memory = createMemoryV2({ logger: { warn() {} }, backends: [ createPgvectorMemoryBackend({ enabled: false }), { name: 'legacy-conversation-memory', async resolve() { return { memories: [{ label: 'fact', text: 'legacy survives' }] }; }, }, ], env: { MEMORY_ENABLED: '1', MEMORY_BACKEND: 'pgvector', MEMORY_VECTOR_ENABLED: '1', }, }); const status = memory.getStatus(); const result = await memory.resolve({ userId: 'user-1', query: 'memory-chain' }); assert.equal(status.vectorEnabled, true); assert.equal(status.selectedBackend, 'legacy-conversation-memory'); assert.equal(status.backends.find((item) => item.name === 'pgvector')?.available, false); assert.deepEqual(result.memories, [{ label: 'fact', text: 'legacy survives' }]); });