Merge Memory V2 runtime facade
This commit is contained in:
@@ -0,0 +1,192 @@
|
||||
#!/usr/bin/env node
|
||||
import { createMemoryV2Runtime } from '../memory-v2-runtime.mjs';
|
||||
|
||||
const BACKENDS = new Set([
|
||||
'qdrant',
|
||||
'weaviate',
|
||||
'mem0',
|
||||
'letta',
|
||||
'neo4j',
|
||||
'redis-streams',
|
||||
'langgraph',
|
||||
]);
|
||||
|
||||
function usage() {
|
||||
return `
|
||||
Usage:
|
||||
node scripts/smoke-memory-v2-external.mjs --backend <name> [options]
|
||||
|
||||
Runs a Memory V2 external backend smoke through the real runtime wiring.
|
||||
|
||||
Options:
|
||||
--backend <name> qdrant | weaviate | mem0 | letta | neo4j | redis-streams | langgraph
|
||||
--operation <name> resolve | write | compact. Default resolves per backend.
|
||||
--query <text> Resolve query. Default: memory-chain smoke
|
||||
--limit <number> Resolve limit. Default: 1
|
||||
--vector <csv> Optional query embedding CSV for resolve.
|
||||
--user-id <id> Smoke user id. Default: memory-v2-smoke-user
|
||||
--session-id <id> Smoke session id. Default: memory-v2-smoke-session
|
||||
-h, --help Show this help.
|
||||
`.trim();
|
||||
}
|
||||
|
||||
function parseVector(value) {
|
||||
if (value == null || value === '') return null;
|
||||
const vector = String(value).split(',').map((item) => Number(item.trim()));
|
||||
if (!vector.length || vector.some((item) => !Number.isFinite(item))) {
|
||||
throw new Error('--vector must be a comma-separated list of numbers');
|
||||
}
|
||||
return vector;
|
||||
}
|
||||
|
||||
function defaultOperation(backend) {
|
||||
if (backend === 'mem0' || backend === 'redis-streams') return 'write';
|
||||
return 'resolve';
|
||||
}
|
||||
|
||||
export function parseMemoryV2ExternalSmokeArgs(argv = []) {
|
||||
const options = {
|
||||
backend: null,
|
||||
operation: null,
|
||||
query: 'memory-chain smoke',
|
||||
limit: 1,
|
||||
vector: null,
|
||||
userId: 'memory-v2-smoke-user',
|
||||
sessionId: 'memory-v2-smoke-session',
|
||||
help: false,
|
||||
};
|
||||
for (let i = 0; i < argv.length; i += 1) {
|
||||
const arg = argv[i];
|
||||
switch (arg) {
|
||||
case '--backend':
|
||||
options.backend = argv[++i] ?? '';
|
||||
break;
|
||||
case '--operation':
|
||||
options.operation = argv[++i] ?? '';
|
||||
break;
|
||||
case '--query':
|
||||
options.query = argv[++i] ?? '';
|
||||
break;
|
||||
case '--limit':
|
||||
options.limit = Number(argv[++i]);
|
||||
break;
|
||||
case '--vector':
|
||||
options.vector = parseVector(argv[++i]);
|
||||
break;
|
||||
case '--user-id':
|
||||
options.userId = argv[++i] ?? '';
|
||||
break;
|
||||
case '--session-id':
|
||||
options.sessionId = argv[++i] ?? '';
|
||||
break;
|
||||
case '-h':
|
||||
case '--help':
|
||||
options.help = true;
|
||||
break;
|
||||
default:
|
||||
throw new Error(`Unknown argument: ${arg}`);
|
||||
}
|
||||
}
|
||||
if (options.help) return options;
|
||||
if (!BACKENDS.has(options.backend)) {
|
||||
throw new Error(`--backend must be one of: ${[...BACKENDS].join(', ')}`);
|
||||
}
|
||||
options.operation ||= defaultOperation(options.backend);
|
||||
if (!['resolve', 'write', 'compact'].includes(options.operation)) {
|
||||
throw new Error('--operation must be resolve, write, or compact');
|
||||
}
|
||||
if (!options.query) throw new Error('--query requires a value');
|
||||
if (!Number.isInteger(options.limit) || options.limit < 1) {
|
||||
throw new Error('--limit requires a positive integer');
|
||||
}
|
||||
if (!options.userId) throw new Error('--user-id requires a value');
|
||||
if (!options.sessionId) throw new Error('--session-id requires a value');
|
||||
return options;
|
||||
}
|
||||
|
||||
function createSyntheticLegacyMemoryService() {
|
||||
return {
|
||||
async listMemories() {
|
||||
return [];
|
||||
},
|
||||
async saveAndAnalyze() {
|
||||
return { saved: 0, analyzed: 0, memories: 0 };
|
||||
},
|
||||
async analyzeUser() {
|
||||
return { analyzed: 0, memories: 0 };
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
async function runOperation(memory, options) {
|
||||
const input = {
|
||||
userId: options.userId,
|
||||
sessionId: options.sessionId,
|
||||
query: options.query,
|
||||
embedding: options.vector,
|
||||
limit: options.limit,
|
||||
messages: [{
|
||||
role: 'user',
|
||||
text: options.query,
|
||||
content: options.query,
|
||||
}],
|
||||
eventType: 'memory-v2.smoke',
|
||||
};
|
||||
if (options.operation === 'resolve') return memory.resolve(input);
|
||||
if (options.operation === 'write') return memory.write(input);
|
||||
return memory.compact(input);
|
||||
}
|
||||
|
||||
export async function runMemoryV2ExternalSmokeCli({
|
||||
argv = process.argv.slice(2),
|
||||
env = process.env,
|
||||
stdout = process.stdout,
|
||||
fetchImpl = globalThis.fetch,
|
||||
importRedis = (specifier) => import(specifier),
|
||||
importModule = (specifier) => import(specifier),
|
||||
} = {}) {
|
||||
const options = parseMemoryV2ExternalSmokeArgs(argv);
|
||||
if (options.help) {
|
||||
stdout.write(`${usage()}\n`);
|
||||
return { ok: true, mode: 'help' };
|
||||
}
|
||||
const memory = await createMemoryV2Runtime({
|
||||
legacyMemoryService: createSyntheticLegacyMemoryService(),
|
||||
env: {
|
||||
...env,
|
||||
MEMORY_ENABLED: '1',
|
||||
MEMORY_BACKEND: options.backend,
|
||||
},
|
||||
logger: console,
|
||||
fetchImpl,
|
||||
importRedis,
|
||||
importModule,
|
||||
});
|
||||
try {
|
||||
const result = await runOperation(memory, options);
|
||||
const backend = memory.getStatus().backends.find((item) => item.name === options.backend);
|
||||
const report = {
|
||||
ok: result?.ok !== false,
|
||||
checkedAt: new Date().toISOString(),
|
||||
backend: options.backend,
|
||||
operation: options.operation,
|
||||
selectedBackend: memory.getStatus().selectedBackend,
|
||||
backendAvailable: backend?.available ?? false,
|
||||
backendReason: backend?.reason ?? null,
|
||||
result,
|
||||
};
|
||||
stdout.write(`${JSON.stringify(report, null, 2)}\n`);
|
||||
return report;
|
||||
} finally {
|
||||
await memory.close?.();
|
||||
}
|
||||
}
|
||||
|
||||
if (import.meta.url === `file://${process.argv[1]}`) {
|
||||
runMemoryV2ExternalSmokeCli().then((result) => {
|
||||
process.exitCode = result.ok ? 0 : 1;
|
||||
}).catch((err) => {
|
||||
console.error(err instanceof Error ? err.message : err);
|
||||
process.exitCode = 1;
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user