128 lines
3.8 KiB
JavaScript
128 lines
3.8 KiB
JavaScript
#!/usr/bin/env node
|
|
import { createQdrantHttpClient } from '../memory-v2-qdrant.mjs';
|
|
|
|
const DEFAULT_URL_ENV = 'MEMORY_QDRANT_URL';
|
|
|
|
function usage() {
|
|
return `
|
|
Usage:
|
|
node scripts/smoke-memory-v2-qdrant.mjs [options]
|
|
|
|
Runs a read-only Qdrant search smoke test. It does not create collections or write points.
|
|
|
|
Options:
|
|
--collection <name> Collection name. Default: MEMORY_QDRANT_COLLECTION or memind_memory.
|
|
--vector <csv> Query vector CSV. Default: 1,0,0.
|
|
--limit <number> Result limit. Default: 1.
|
|
--url-env <name> Env var containing Qdrant URL. Default: ${DEFAULT_URL_ENV}.
|
|
--api-key-env <name> Env var containing Qdrant API key. Default: MEMORY_QDRANT_API_KEY.
|
|
--timeout-ms <number> Request timeout. Default: 3000.
|
|
-h, --help Show this help.
|
|
`.trim();
|
|
}
|
|
|
|
function parseVector(value) {
|
|
const vector = String(value ?? '1,0,0')
|
|
.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;
|
|
}
|
|
|
|
export function parseMemoryQdrantSmokeArgs(argv = [], env = process.env) {
|
|
const options = {
|
|
collection: env.MEMORY_QDRANT_COLLECTION || 'memind_memory',
|
|
vector: [1, 0, 0],
|
|
limit: 1,
|
|
urlEnv: DEFAULT_URL_ENV,
|
|
apiKeyEnv: 'MEMORY_QDRANT_API_KEY',
|
|
timeoutMs: 3000,
|
|
help: false,
|
|
};
|
|
for (let i = 0; i < argv.length; i += 1) {
|
|
const arg = argv[i];
|
|
switch (arg) {
|
|
case '--collection':
|
|
options.collection = argv[++i] ?? '';
|
|
break;
|
|
case '--vector':
|
|
options.vector = parseVector(argv[++i]);
|
|
break;
|
|
case '--limit':
|
|
options.limit = Number(argv[++i]);
|
|
break;
|
|
case '--url-env':
|
|
options.urlEnv = argv[++i] ?? '';
|
|
break;
|
|
case '--api-key-env':
|
|
options.apiKeyEnv = argv[++i] ?? '';
|
|
break;
|
|
case '--timeout-ms':
|
|
options.timeoutMs = Number(argv[++i]);
|
|
break;
|
|
case '-h':
|
|
case '--help':
|
|
options.help = true;
|
|
break;
|
|
default:
|
|
throw new Error(`Unknown argument: ${arg}`);
|
|
}
|
|
}
|
|
if (!options.collection) throw new Error('--collection requires a value');
|
|
if (!Number.isInteger(options.limit) || options.limit < 1) {
|
|
throw new Error('--limit requires a positive integer');
|
|
}
|
|
if (!options.urlEnv) throw new Error('--url-env requires a value');
|
|
if (!options.apiKeyEnv) throw new Error('--api-key-env requires a value');
|
|
if (!Number.isFinite(options.timeoutMs) || options.timeoutMs < 1) {
|
|
throw new Error('--timeout-ms requires a positive number');
|
|
}
|
|
return options;
|
|
}
|
|
|
|
export async function runMemoryQdrantSmokeCli({
|
|
argv = process.argv.slice(2),
|
|
env = process.env,
|
|
stdout = process.stdout,
|
|
fetchImpl = globalThis.fetch,
|
|
} = {}) {
|
|
const options = parseMemoryQdrantSmokeArgs(argv, env);
|
|
if (options.help) {
|
|
stdout.write(`${usage()}\n`);
|
|
return { ok: true, mode: 'help' };
|
|
}
|
|
const url = env[options.urlEnv];
|
|
if (!url) throw new Error(`Qdrant smoke requires ${options.urlEnv} to be set`);
|
|
const client = createQdrantHttpClient({
|
|
url,
|
|
apiKey: env[options.apiKeyEnv],
|
|
fetchImpl,
|
|
timeoutMs: options.timeoutMs,
|
|
});
|
|
const points = await client.search({
|
|
collection: options.collection,
|
|
vector: options.vector,
|
|
limit: options.limit,
|
|
});
|
|
const report = {
|
|
ok: true,
|
|
checkedAt: new Date().toISOString(),
|
|
collection: options.collection,
|
|
resultCount: points.length,
|
|
readOnly: true,
|
|
};
|
|
stdout.write(`${JSON.stringify(report, null, 2)}\n`);
|
|
return report;
|
|
}
|
|
|
|
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
runMemoryQdrantSmokeCli().then((result) => {
|
|
process.exitCode = result.ok ? 0 : 1;
|
|
}).catch((err) => {
|
|
console.error(err instanceof Error ? err.message : err);
|
|
process.exitCode = 1;
|
|
});
|
|
}
|