@aeriondyseti/vector-memory-mcp 0.9.0-dev.5 → 0.9.0-dev.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/package.json +72 -0
- package/dist/scripts/test-runner.d.ts +9 -0
- package/dist/scripts/test-runner.d.ts.map +1 -0
- package/dist/scripts/test-runner.js +61 -0
- package/dist/scripts/test-runner.js.map +1 -0
- package/dist/scripts/warmup.d.ts +8 -0
- package/dist/scripts/warmup.d.ts.map +1 -0
- package/dist/scripts/warmup.js +61 -0
- package/dist/scripts/warmup.js.map +1 -0
- package/dist/src/config/index.d.ts +24 -0
- package/dist/src/config/index.d.ts.map +1 -0
- package/dist/src/config/index.js +48 -0
- package/dist/src/config/index.js.map +1 -0
- package/dist/src/db/connection.d.ts +3 -0
- package/dist/src/db/connection.d.ts.map +1 -0
- package/dist/src/db/connection.js +10 -0
- package/dist/src/db/connection.js.map +1 -0
- package/dist/src/db/memory.repository.d.ts +49 -0
- package/dist/src/db/memory.repository.d.ts.map +1 -0
- package/dist/src/db/memory.repository.js +215 -0
- package/dist/src/db/memory.repository.js.map +1 -0
- package/dist/src/db/schema.d.ts +4 -0
- package/dist/src/db/schema.d.ts.map +1 -0
- package/dist/src/db/schema.js +15 -0
- package/dist/src/db/schema.js.map +1 -0
- package/dist/src/http/mcp-transport.d.ts +19 -0
- package/dist/src/http/mcp-transport.d.ts.map +1 -0
- package/dist/src/http/mcp-transport.js +191 -0
- package/dist/src/http/mcp-transport.js.map +1 -0
- package/dist/src/http/server.d.ts +13 -0
- package/dist/src/http/server.d.ts.map +1 -0
- package/dist/src/http/server.js +210 -0
- package/dist/src/http/server.js.map +1 -0
- package/dist/src/index.d.ts +3 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +59 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/mcp/handlers.d.ts +12 -0
- package/dist/src/mcp/handlers.d.ts.map +1 -0
- package/dist/src/mcp/handlers.js +198 -0
- package/dist/src/mcp/handlers.js.map +1 -0
- package/dist/src/mcp/server.d.ts +5 -0
- package/dist/src/mcp/server.d.ts.map +1 -0
- package/dist/src/mcp/server.js +22 -0
- package/dist/src/mcp/server.js.map +1 -0
- package/dist/src/mcp/tools.d.ts +10 -0
- package/dist/src/mcp/tools.d.ts.map +1 -0
- package/dist/src/mcp/tools.js +272 -0
- package/dist/src/mcp/tools.js.map +1 -0
- package/dist/src/services/embeddings.service.d.ts +12 -0
- package/dist/src/services/embeddings.service.d.ts.map +1 -0
- package/dist/src/services/embeddings.service.js +37 -0
- package/dist/src/services/embeddings.service.js.map +1 -0
- package/dist/src/services/memory.service.d.ts +33 -0
- package/dist/src/services/memory.service.d.ts.map +1 -0
- package/dist/src/services/memory.service.js +200 -0
- package/dist/src/services/memory.service.js.map +1 -0
- package/dist/src/types/memory.d.ts +28 -0
- package/dist/src/types/memory.d.ts.map +1 -0
- package/dist/src/types/memory.js +18 -0
- package/dist/src/types/memory.js.map +1 -0
- package/package.json +11 -8
- package/src/config/index.ts +5 -2
- package/src/db/memory.repository.ts +48 -1
- package/src/http/server.ts +85 -12
- package/scripts/publish.ts +0 -61
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@aeriondyseti/vector-memory-mcp",
|
|
3
|
+
"version": "0.9.0-dev.9",
|
|
4
|
+
"description": "A zero-configuration RAG memory server for MCP clients",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/src/index.js",
|
|
7
|
+
"bin": {
|
|
8
|
+
"vector-memory-mcp": "dist/src/index.js"
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
"dist",
|
|
12
|
+
"src",
|
|
13
|
+
"scripts",
|
|
14
|
+
"hooks",
|
|
15
|
+
"README.md",
|
|
16
|
+
"LICENSE"
|
|
17
|
+
],
|
|
18
|
+
"repository": {
|
|
19
|
+
"type": "git",
|
|
20
|
+
"url": "git+https://github.com/AerionDyseti/vector-memory-mcp.git"
|
|
21
|
+
},
|
|
22
|
+
"author": "AerionDyseti",
|
|
23
|
+
"bugs": {
|
|
24
|
+
"url": "https://github.com/AerionDyseti/vector-memory-mcp/issues"
|
|
25
|
+
},
|
|
26
|
+
"homepage": "https://github.com/AerionDyseti/vector-memory-mcp#readme",
|
|
27
|
+
"scripts": {
|
|
28
|
+
"start": "node dist/src/index.js",
|
|
29
|
+
"start:bun": "bun run src/index.ts",
|
|
30
|
+
"dev": "bun --watch run src/index.ts",
|
|
31
|
+
"build": "tsc",
|
|
32
|
+
"prebuild": "rm -rf dist",
|
|
33
|
+
"typecheck": "bunx tsc --noEmit",
|
|
34
|
+
"test": "bun run scripts/test-runner.ts",
|
|
35
|
+
"test:raw": "bun test --preload ./tests/preload.ts",
|
|
36
|
+
"test:quick": "bun test",
|
|
37
|
+
"test:coverage": "bun test --preload ./tests/preload.ts --coverage",
|
|
38
|
+
"benchmark": "bun test tests/benchmark.test.ts --preload ./tests/preload.ts",
|
|
39
|
+
"test:preload": "bun run tests/preload.ts",
|
|
40
|
+
"warmup": "bun run scripts/warmup.ts",
|
|
41
|
+
"postinstall": "bun run scripts/warmup.ts",
|
|
42
|
+
"prepublishOnly": "bun run build"
|
|
43
|
+
},
|
|
44
|
+
"keywords": [
|
|
45
|
+
"mcp",
|
|
46
|
+
"memory",
|
|
47
|
+
"rag",
|
|
48
|
+
"embeddings",
|
|
49
|
+
"lancedb"
|
|
50
|
+
],
|
|
51
|
+
"license": "MIT",
|
|
52
|
+
"dependencies": {
|
|
53
|
+
"@hono/node-server": "^1.19.9",
|
|
54
|
+
"@huggingface/transformers": "^3.8.0",
|
|
55
|
+
"@lancedb/lancedb": "^0.22.3",
|
|
56
|
+
"@modelcontextprotocol/sdk": "^1.0.0",
|
|
57
|
+
"arg": "^5.0.2",
|
|
58
|
+
"hono": "^4.11.3"
|
|
59
|
+
},
|
|
60
|
+
"devDependencies": {
|
|
61
|
+
"@types/bun": "latest",
|
|
62
|
+
"typescript": "^5.0.0"
|
|
63
|
+
},
|
|
64
|
+
"trustedDependencies": [
|
|
65
|
+
"onnxruntime-node",
|
|
66
|
+
"protobufjs",
|
|
67
|
+
"sharp"
|
|
68
|
+
],
|
|
69
|
+
"overrides": {
|
|
70
|
+
"onnxruntime-node": "1.23.2"
|
|
71
|
+
}
|
|
72
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
/**
|
|
3
|
+
* Test runner wrapper that handles Bun's post-test crash gracefully.
|
|
4
|
+
*
|
|
5
|
+
* Bun crashes during native module cleanup after tests complete successfully.
|
|
6
|
+
* This wrapper captures the output, verifies tests passed, and exits cleanly.
|
|
7
|
+
*/
|
|
8
|
+
export {};
|
|
9
|
+
//# sourceMappingURL=test-runner.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"test-runner.d.ts","sourceRoot":"","sources":["../../scripts/test-runner.ts"],"names":[],"mappings":";AACA;;;;;GAKG"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
/**
|
|
3
|
+
* Test runner wrapper that handles Bun's post-test crash gracefully.
|
|
4
|
+
*
|
|
5
|
+
* Bun crashes during native module cleanup after tests complete successfully.
|
|
6
|
+
* This wrapper captures the output, verifies tests passed, and exits cleanly.
|
|
7
|
+
*/
|
|
8
|
+
import { spawn } from "bun";
|
|
9
|
+
const proc = spawn(["bun", "test", "--preload", "./tests/preload.ts"], {
|
|
10
|
+
stdout: "pipe",
|
|
11
|
+
stderr: "pipe",
|
|
12
|
+
env: { ...process.env, FORCE_COLOR: "1" },
|
|
13
|
+
});
|
|
14
|
+
let stdout = "";
|
|
15
|
+
let stderr = "";
|
|
16
|
+
const decoder = new TextDecoder();
|
|
17
|
+
// Stream stdout in real-time
|
|
18
|
+
const stdoutReader = proc.stdout.getReader();
|
|
19
|
+
(async () => {
|
|
20
|
+
while (true) {
|
|
21
|
+
const { done, value } = await stdoutReader.read();
|
|
22
|
+
if (done)
|
|
23
|
+
break;
|
|
24
|
+
const text = decoder.decode(value);
|
|
25
|
+
stdout += text;
|
|
26
|
+
process.stdout.write(text);
|
|
27
|
+
}
|
|
28
|
+
})();
|
|
29
|
+
// Stream stderr in real-time
|
|
30
|
+
const stderrReader = proc.stderr.getReader();
|
|
31
|
+
(async () => {
|
|
32
|
+
while (true) {
|
|
33
|
+
const { done, value } = await stderrReader.read();
|
|
34
|
+
if (done)
|
|
35
|
+
break;
|
|
36
|
+
const text = decoder.decode(value);
|
|
37
|
+
stderr += text;
|
|
38
|
+
process.stderr.write(text);
|
|
39
|
+
}
|
|
40
|
+
})();
|
|
41
|
+
await proc.exited;
|
|
42
|
+
// Check if tests actually passed by looking for the summary line
|
|
43
|
+
const output = stdout + stderr;
|
|
44
|
+
const passMatch = output.match(/(\d+) pass/);
|
|
45
|
+
const failMatch = output.match(/(\d+) fail/);
|
|
46
|
+
const passed = passMatch ? parseInt(passMatch[1], 10) : 0;
|
|
47
|
+
const failed = failMatch ? parseInt(failMatch[1], 10) : 0;
|
|
48
|
+
// Exit based on test results, not Bun's crash
|
|
49
|
+
if (failed > 0) {
|
|
50
|
+
console.error(`\n❌ ${failed} test(s) failed`);
|
|
51
|
+
process.exit(1);
|
|
52
|
+
}
|
|
53
|
+
else if (passed > 0) {
|
|
54
|
+
console.log(`\n✅ All ${passed} tests passed (ignoring Bun cleanup crash)`);
|
|
55
|
+
process.exit(0);
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
console.error("\n⚠️ Could not determine test results");
|
|
59
|
+
process.exit(1);
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=test-runner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"test-runner.js","sourceRoot":"","sources":["../../scripts/test-runner.ts"],"names":[],"mappings":";AACA;;;;;GAKG;AAEH,OAAO,EAAE,KAAK,EAAE,MAAM,KAAK,CAAC;AAE5B,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,oBAAoB,CAAC,EAAE;IACrE,MAAM,EAAE,MAAM;IACd,MAAM,EAAE,MAAM;IACd,GAAG,EAAE,EAAE,GAAG,OAAO,CAAC,GAAG,EAAE,WAAW,EAAE,GAAG,EAAE;CAC1C,CAAC,CAAC;AAEH,IAAI,MAAM,GAAG,EAAE,CAAC;AAChB,IAAI,MAAM,GAAG,EAAE,CAAC;AAEhB,MAAM,OAAO,GAAG,IAAI,WAAW,EAAE,CAAC;AAElC,6BAA6B;AAC7B,MAAM,YAAY,GAAG,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC;AAC7C,CAAC,KAAK,IAAI,EAAE;IACV,OAAO,IAAI,EAAE,CAAC;QACZ,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,MAAM,YAAY,CAAC,IAAI,EAAE,CAAC;QAClD,IAAI,IAAI;YAAE,MAAM;QAChB,MAAM,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QACnC,MAAM,IAAI,IAAI,CAAC;QACf,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC7B,CAAC;AACH,CAAC,CAAC,EAAE,CAAC;AAEL,6BAA6B;AAC7B,MAAM,YAAY,GAAG,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC;AAC7C,CAAC,KAAK,IAAI,EAAE;IACV,OAAO,IAAI,EAAE,CAAC;QACZ,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,MAAM,YAAY,CAAC,IAAI,EAAE,CAAC;QAClD,IAAI,IAAI;YAAE,MAAM;QAChB,MAAM,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QACnC,MAAM,IAAI,IAAI,CAAC;QACf,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC7B,CAAC;AACH,CAAC,CAAC,EAAE,CAAC;AAEL,MAAM,IAAI,CAAC,MAAM,CAAC;AAElB,iEAAiE;AACjE,MAAM,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC;AAC/B,MAAM,SAAS,GAAG,MAAM,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC;AAC7C,MAAM,SAAS,GAAG,MAAM,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC;AAE7C,MAAM,MAAM,GAAG,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC1D,MAAM,MAAM,GAAG,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAE1D,8CAA8C;AAC9C,IAAI,MAAM,GAAG,CAAC,EAAE,CAAC;IACf,OAAO,CAAC,KAAK,CAAC,OAAO,MAAM,iBAAiB,CAAC,CAAC;IAC9C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC;KAAM,IAAI,MAAM,GAAG,CAAC,EAAE,CAAC;IACtB,OAAO,CAAC,GAAG,CAAC,WAAW,MAAM,4CAA4C,CAAC,CAAC;IAC3E,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC;KAAM,CAAC;IACN,OAAO,CAAC,KAAK,CAAC,wCAAwC,CAAC,CAAC;IACxD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
/**
|
|
3
|
+
* Warmup script to pre-download ML models and verify dependencies
|
|
4
|
+
* This runs during installation to ensure everything is ready to use
|
|
5
|
+
*/
|
|
6
|
+
declare function warmup(): Promise<void>;
|
|
7
|
+
export { warmup };
|
|
8
|
+
//# sourceMappingURL=warmup.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"warmup.d.ts","sourceRoot":"","sources":["../../scripts/warmup.ts"],"names":[],"mappings":";AAEA;;;GAGG;AAKH,iBAAe,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC,CAsDrC;AAOD,OAAO,EAAE,MAAM,EAAE,CAAC"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
/**
|
|
3
|
+
* Warmup script to pre-download ML models and verify dependencies
|
|
4
|
+
* This runs during installation to ensure everything is ready to use
|
|
5
|
+
*/
|
|
6
|
+
import { config } from "../src/config/index.js";
|
|
7
|
+
import { EmbeddingsService } from "../src/services/embeddings.service.js";
|
|
8
|
+
async function warmup() {
|
|
9
|
+
console.log("🔥 Warming up vector-memory-mcp...");
|
|
10
|
+
console.log();
|
|
11
|
+
try {
|
|
12
|
+
// Check native dependencies
|
|
13
|
+
console.log("✓ Checking native dependencies...");
|
|
14
|
+
try {
|
|
15
|
+
await import("onnxruntime-node");
|
|
16
|
+
console.log(" ✓ onnxruntime-node loaded");
|
|
17
|
+
}
|
|
18
|
+
catch (e) {
|
|
19
|
+
console.error(" ✗ onnxruntime-node failed:", e.message);
|
|
20
|
+
process.exit(1);
|
|
21
|
+
}
|
|
22
|
+
try {
|
|
23
|
+
await import("sharp");
|
|
24
|
+
console.log(" ✓ sharp loaded");
|
|
25
|
+
}
|
|
26
|
+
catch (e) {
|
|
27
|
+
console.error(" ✗ sharp failed:", e.message);
|
|
28
|
+
process.exit(1);
|
|
29
|
+
}
|
|
30
|
+
console.log();
|
|
31
|
+
// Initialize embeddings service to download model
|
|
32
|
+
console.log("📥 Downloading ML model (this may take a minute)...");
|
|
33
|
+
console.log(` Model: ${config.embeddingModel}`);
|
|
34
|
+
console.log(` Cache: ~/.cache/huggingface/`);
|
|
35
|
+
console.log();
|
|
36
|
+
const embeddings = new EmbeddingsService(config.embeddingModel, config.embeddingDimension);
|
|
37
|
+
// Trigger model download by generating a test embedding
|
|
38
|
+
const startTime = Date.now();
|
|
39
|
+
await embeddings.embed("warmup test");
|
|
40
|
+
const duration = ((Date.now() - startTime) / 1000).toFixed(2);
|
|
41
|
+
console.log();
|
|
42
|
+
console.log(`✅ Warmup complete! (${duration}s)`);
|
|
43
|
+
console.log();
|
|
44
|
+
console.log("Ready to use! Configure your MCP client and restart to get started.");
|
|
45
|
+
console.log();
|
|
46
|
+
}
|
|
47
|
+
catch (error) {
|
|
48
|
+
console.error();
|
|
49
|
+
console.error("❌ Warmup failed:", error);
|
|
50
|
+
console.error();
|
|
51
|
+
console.error("This is not a critical error - the server will download models on first run.");
|
|
52
|
+
console.error("You can try running 'vector-memory-mcp warmup' manually later.");
|
|
53
|
+
process.exit(0); // Exit successfully to not block installation
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
// Only run if this is the main module
|
|
57
|
+
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
58
|
+
warmup();
|
|
59
|
+
}
|
|
60
|
+
export { warmup };
|
|
61
|
+
//# sourceMappingURL=warmup.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"warmup.js","sourceRoot":"","sources":["../../scripts/warmup.ts"],"names":[],"mappings":";AAEA;;;GAGG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAChD,OAAO,EAAE,iBAAiB,EAAE,MAAM,uCAAuC,CAAC;AAE1E,KAAK,UAAU,MAAM;IACnB,OAAO,CAAC,GAAG,CAAC,oCAAoC,CAAC,CAAC;IAClD,OAAO,CAAC,GAAG,EAAE,CAAC;IAEd,IAAI,CAAC;QACH,4BAA4B;QAC5B,OAAO,CAAC,GAAG,CAAC,mCAAmC,CAAC,CAAC;QACjD,IAAI,CAAC;YACH,MAAM,MAAM,CAAC,kBAAkB,CAAC,CAAC;YACjC,OAAO,CAAC,GAAG,CAAC,6BAA6B,CAAC,CAAC;QAC7C,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,OAAO,CAAC,KAAK,CAAC,8BAA8B,EAAG,CAAW,CAAC,OAAO,CAAC,CAAC;YACpE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QAED,IAAI,CAAC;YACH,MAAM,MAAM,CAAC,OAAO,CAAC,CAAC;YACtB,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAC;QAClC,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,OAAO,CAAC,KAAK,CAAC,mBAAmB,EAAG,CAAW,CAAC,OAAO,CAAC,CAAC;YACzD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QAED,OAAO,CAAC,GAAG,EAAE,CAAC;QAEd,kDAAkD;QAClD,OAAO,CAAC,GAAG,CAAC,qDAAqD,CAAC,CAAC;QACnE,OAAO,CAAC,GAAG,CAAC,aAAa,MAAM,CAAC,cAAc,EAAE,CAAC,CAAC;QAClD,OAAO,CAAC,GAAG,CAAC,iCAAiC,CAAC,CAAC;QAC/C,OAAO,CAAC,GAAG,EAAE,CAAC;QAEd,MAAM,UAAU,GAAG,IAAI,iBAAiB,CACtC,MAAM,CAAC,cAAc,EACrB,MAAM,CAAC,kBAAkB,CAC1B,CAAC;QAEF,wDAAwD;QACxD,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAC7B,MAAM,UAAU,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC;QACtC,MAAM,QAAQ,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC,GAAG,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;QAE9D,OAAO,CAAC,GAAG,EAAE,CAAC;QACd,OAAO,CAAC,GAAG,CAAC,uBAAuB,QAAQ,IAAI,CAAC,CAAC;QACjD,OAAO,CAAC,GAAG,EAAE,CAAC;QACd,OAAO,CAAC,GAAG,CAAC,qEAAqE,CAAC,CAAC;QACnF,OAAO,CAAC,GAAG,EAAE,CAAC;IAChB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,EAAE,CAAC;QAChB,OAAO,CAAC,KAAK,CAAC,kBAAkB,EAAE,KAAK,CAAC,CAAC;QACzC,OAAO,CAAC,KAAK,EAAE,CAAC;QAChB,OAAO,CAAC,KAAK,CAAC,8EAA8E,CAAC,CAAC;QAC9F,OAAO,CAAC,KAAK,CAAC,gEAAgE,CAAC,CAAC;QAChF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,8CAA8C;IACjE,CAAC;AACH,CAAC;AAED,sCAAsC;AACtC,IAAI,MAAM,CAAC,IAAI,CAAC,GAAG,KAAK,UAAU,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;IACpD,MAAM,EAAE,CAAC;AACX,CAAC;AAED,OAAO,EAAE,MAAM,EAAE,CAAC"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export declare const VERSION: string;
|
|
2
|
+
export type TransportMode = "stdio" | "http" | "both";
|
|
3
|
+
export interface Config {
|
|
4
|
+
dbPath: string;
|
|
5
|
+
embeddingModel: string;
|
|
6
|
+
embeddingDimension: number;
|
|
7
|
+
httpPort: number;
|
|
8
|
+
httpHost: string;
|
|
9
|
+
enableHttp: boolean;
|
|
10
|
+
transportMode: TransportMode;
|
|
11
|
+
}
|
|
12
|
+
export interface ConfigOverrides {
|
|
13
|
+
dbPath?: string;
|
|
14
|
+
httpPort?: number;
|
|
15
|
+
enableHttp?: boolean;
|
|
16
|
+
transportMode?: TransportMode;
|
|
17
|
+
}
|
|
18
|
+
export declare function loadConfig(overrides?: ConfigOverrides): Config;
|
|
19
|
+
/**
|
|
20
|
+
* Parse CLI arguments into config overrides.
|
|
21
|
+
*/
|
|
22
|
+
export declare function parseCliArgs(argv: string[]): ConfigOverrides;
|
|
23
|
+
export declare const config: Config;
|
|
24
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/config/index.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,OAAO,QAAsB,CAAC;AAE3C,MAAM,MAAM,aAAa,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,CAAC;AAEtD,MAAM,WAAW,MAAM;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,cAAc,EAAE,MAAM,CAAC;IACvB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,OAAO,CAAC;IACpB,aAAa,EAAE,aAAa,CAAC;CAC9B;AAED,MAAM,WAAW,eAAe;IAC9B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,aAAa,CAAC,EAAE,aAAa,CAAC;CAC/B;AAaD,wBAAgB,UAAU,CAAC,SAAS,GAAE,eAAoB,GAAG,MAAM,CAclE;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,eAAe,CAmB5D;AAGD,eAAO,MAAM,MAAM,QAAe,CAAC"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import arg from "arg";
|
|
2
|
+
import { isAbsolute, join } from "path";
|
|
3
|
+
import packageJson from "../../package.json" with { type: "json" };
|
|
4
|
+
export const VERSION = packageJson.version;
|
|
5
|
+
// Defaults - always use repo-local .vector-memory folder
|
|
6
|
+
const DEFAULT_DB_PATH = join(process.cwd(), ".vector-memory", "memories.db");
|
|
7
|
+
const DEFAULT_EMBEDDING_MODEL = "Xenova/all-MiniLM-L6-v2";
|
|
8
|
+
const DEFAULT_EMBEDDING_DIMENSION = 384;
|
|
9
|
+
const DEFAULT_HTTP_PORT = 3271;
|
|
10
|
+
const DEFAULT_HTTP_HOST = "127.0.0.1";
|
|
11
|
+
function resolvePath(path) {
|
|
12
|
+
return isAbsolute(path) ? path : join(process.cwd(), path);
|
|
13
|
+
}
|
|
14
|
+
export function loadConfig(overrides = {}) {
|
|
15
|
+
const transportMode = overrides.transportMode ?? "stdio";
|
|
16
|
+
// HTTP enabled by default (needed for hooks), can disable with --no-http
|
|
17
|
+
const enableHttp = overrides.enableHttp ?? true;
|
|
18
|
+
return {
|
|
19
|
+
dbPath: resolvePath(overrides.dbPath ?? DEFAULT_DB_PATH),
|
|
20
|
+
embeddingModel: DEFAULT_EMBEDDING_MODEL,
|
|
21
|
+
embeddingDimension: DEFAULT_EMBEDDING_DIMENSION,
|
|
22
|
+
httpPort: overrides.httpPort ?? DEFAULT_HTTP_PORT,
|
|
23
|
+
httpHost: DEFAULT_HTTP_HOST,
|
|
24
|
+
enableHttp,
|
|
25
|
+
transportMode,
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Parse CLI arguments into config overrides.
|
|
30
|
+
*/
|
|
31
|
+
export function parseCliArgs(argv) {
|
|
32
|
+
const args = arg({
|
|
33
|
+
"--db-file": String,
|
|
34
|
+
"--port": Number,
|
|
35
|
+
"--no-http": Boolean,
|
|
36
|
+
// Aliases
|
|
37
|
+
"-d": "--db-file",
|
|
38
|
+
"-p": "--port",
|
|
39
|
+
}, { argv, permissive: true });
|
|
40
|
+
return {
|
|
41
|
+
dbPath: args["--db-file"],
|
|
42
|
+
httpPort: args["--port"],
|
|
43
|
+
enableHttp: args["--no-http"] ? false : undefined,
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
// Default config for imports that don't use CLI args
|
|
47
|
+
export const config = loadConfig();
|
|
48
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/config/index.ts"],"names":[],"mappings":"AAAA,OAAO,GAAG,MAAM,KAAK,CAAC;AACtB,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AACxC,OAAO,WAAW,MAAM,oBAAoB,CAAC,OAAO,IAAI,EAAE,MAAM,EAAE,CAAC;AAEnE,MAAM,CAAC,MAAM,OAAO,GAAG,WAAW,CAAC,OAAO,CAAC;AAqB3C,yDAAyD;AACzD,MAAM,eAAe,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,gBAAgB,EAAE,aAAa,CAAC,CAAC;AAC7E,MAAM,uBAAuB,GAAG,yBAAyB,CAAC;AAC1D,MAAM,2BAA2B,GAAG,GAAG,CAAC;AACxC,MAAM,iBAAiB,GAAG,IAAI,CAAC;AAC/B,MAAM,iBAAiB,GAAG,WAAW,CAAC;AAEtC,SAAS,WAAW,CAAC,IAAY;IAC/B,OAAO,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,IAAI,CAAC,CAAC;AAC7D,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,YAA6B,EAAE;IACxD,MAAM,aAAa,GAAG,SAAS,CAAC,aAAa,IAAI,OAAO,CAAC;IACzD,yEAAyE;IACzE,MAAM,UAAU,GAAG,SAAS,CAAC,UAAU,IAAI,IAAI,CAAC;IAEhD,OAAO;QACL,MAAM,EAAE,WAAW,CAAC,SAAS,CAAC,MAAM,IAAI,eAAe,CAAC;QACxD,cAAc,EAAE,uBAAuB;QACvC,kBAAkB,EAAE,2BAA2B;QAC/C,QAAQ,EAAE,SAAS,CAAC,QAAQ,IAAI,iBAAiB;QACjD,QAAQ,EAAE,iBAAiB;QAC3B,UAAU;QACV,aAAa;KACd,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,YAAY,CAAC,IAAc;IACzC,MAAM,IAAI,GAAG,GAAG,CACd;QACE,WAAW,EAAE,MAAM;QACnB,QAAQ,EAAE,MAAM;QAChB,WAAW,EAAE,OAAO;QAEpB,UAAU;QACV,IAAI,EAAE,WAAW;QACjB,IAAI,EAAE,QAAQ;KACf,EACD,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,CAC3B,CAAC;IAEF,OAAO;QACL,MAAM,EAAE,IAAI,CAAC,WAAW,CAAC;QACzB,QAAQ,EAAE,IAAI,CAAC,QAAQ,CAAC;QACxB,UAAU,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS;KAClD,CAAC;AACJ,CAAC;AAED,qDAAqD;AACrD,MAAM,CAAC,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"connection.d.ts","sourceRoot":"","sources":["../../../src/db/connection.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,OAAO,MAAM,kBAAkB,CAAC;AAI5C,wBAAsB,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,UAAU,CAAC,CAMnF"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import * as lancedb from "@lancedb/lancedb";
|
|
2
|
+
import { mkdirSync } from "fs";
|
|
3
|
+
import { dirname } from "path";
|
|
4
|
+
export async function connectToDatabase(dbPath) {
|
|
5
|
+
// Ensure directory exists
|
|
6
|
+
mkdirSync(dirname(dbPath), { recursive: true });
|
|
7
|
+
const db = await lancedb.connect(dbPath);
|
|
8
|
+
return db;
|
|
9
|
+
}
|
|
10
|
+
//# sourceMappingURL=connection.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"connection.js","sourceRoot":"","sources":["../../../src/db/connection.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,OAAO,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,SAAS,EAAE,MAAM,IAAI,CAAC;AAC/B,OAAO,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAE/B,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,MAAc;IACpD,0BAA0B;IAC1B,SAAS,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAEhD,MAAM,EAAE,GAAG,MAAM,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IACzC,OAAO,EAAE,CAAC;AACZ,CAAC"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import * as lancedb from "@lancedb/lancedb";
|
|
2
|
+
import { type Memory, type HybridRow } from "../types/memory.js";
|
|
3
|
+
export declare class MemoryRepository {
|
|
4
|
+
private db;
|
|
5
|
+
private ftsIndexPromise;
|
|
6
|
+
private migrationPromise;
|
|
7
|
+
constructor(db: lancedb.Connection);
|
|
8
|
+
private getTable;
|
|
9
|
+
/**
|
|
10
|
+
* Ensures schema migration has run. Uses a mutex pattern identical to ensureFtsIndex.
|
|
11
|
+
* Adds columns introduced after the initial schema (usefulness, access_count, last_accessed).
|
|
12
|
+
*/
|
|
13
|
+
private ensureMigration;
|
|
14
|
+
/**
|
|
15
|
+
* Inspects the existing table schema and adds any missing columns with safe defaults.
|
|
16
|
+
* This handles databases created before the hybrid memory system was introduced.
|
|
17
|
+
*/
|
|
18
|
+
private migrateSchemaIfNeeded;
|
|
19
|
+
/**
|
|
20
|
+
* Ensures the FTS index exists on the content column.
|
|
21
|
+
* Uses a mutex pattern to prevent concurrent index creation.
|
|
22
|
+
* The key insight: we must capture the promise BEFORE any await.
|
|
23
|
+
*/
|
|
24
|
+
private ensureFtsIndex;
|
|
25
|
+
/**
|
|
26
|
+
* Creates the FTS index if it doesn't already exist.
|
|
27
|
+
* Gets its own table reference to ensure consistent index state.
|
|
28
|
+
*/
|
|
29
|
+
private createFtsIndexIfNeeded;
|
|
30
|
+
/**
|
|
31
|
+
* Converts a raw LanceDB row to a Memory object.
|
|
32
|
+
*/
|
|
33
|
+
private rowToMemory;
|
|
34
|
+
insert(memory: Memory): Promise<void>;
|
|
35
|
+
upsert(memory: Memory): Promise<void>;
|
|
36
|
+
findById(id: string): Promise<Memory | null>;
|
|
37
|
+
markDeleted(id: string): Promise<boolean>;
|
|
38
|
+
/**
|
|
39
|
+
* Performs hybrid search combining vector similarity and full-text search.
|
|
40
|
+
* Uses RRF (Reciprocal Rank Fusion) to combine rankings from both search methods.
|
|
41
|
+
*
|
|
42
|
+
* @param embedding - Query embedding vector
|
|
43
|
+
* @param query - Text query for full-text search
|
|
44
|
+
* @param limit - Maximum number of results to return
|
|
45
|
+
* @returns Array of HybridRow containing full Memory data plus RRF score
|
|
46
|
+
*/
|
|
47
|
+
findHybrid(embedding: number[], query: string, limit: number): Promise<HybridRow[]>;
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=memory.repository.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memory.repository.d.ts","sourceRoot":"","sources":["../../../src/db/memory.repository.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,OAAO,MAAM,kBAAkB,CAAC;AAG5C,OAAO,EACL,KAAK,MAAM,EACX,KAAK,SAAS,EAEf,MAAM,oBAAoB,CAAC;AAE5B,qBAAa,gBAAgB;IAQf,OAAO,CAAC,EAAE;IALtB,OAAO,CAAC,eAAe,CAA8B;IAGrD,OAAO,CAAC,gBAAgB,CAA8B;gBAElC,EAAE,EAAE,OAAO,CAAC,UAAU;YAE5B,QAAQ;IAWtB;;;OAGG;IACH,OAAO,CAAC,eAAe;IAavB;;;OAGG;YACW,qBAAqB;IAqBnC;;;;OAIG;IACH,OAAO,CAAC,cAAc;IAiBtB;;;OAGG;YACW,sBAAsB;IAgBpC;;OAEG;IACH,OAAO,CAAC,WAAW;IAwBb,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAkBrC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAwBrC,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAW5C,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAqB/C;;;;;;;;OAQG;IACG,UAAU,CAAC,SAAS,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC;CA2B1F"}
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
import { Index, rerankers } from "@lancedb/lancedb";
|
|
2
|
+
import { TABLE_NAME, memorySchema } from "./schema.js";
|
|
3
|
+
import { DELETED_TOMBSTONE, } from "../types/memory.js";
|
|
4
|
+
export class MemoryRepository {
|
|
5
|
+
db;
|
|
6
|
+
// Mutex for FTS index creation - ensures only one index creation runs at a time
|
|
7
|
+
// Once set, this promise is never cleared (FTS index persists in the database)
|
|
8
|
+
ftsIndexPromise = null;
|
|
9
|
+
// Mutex for schema migration - runs once per instance to add missing columns
|
|
10
|
+
migrationPromise = null;
|
|
11
|
+
constructor(db) {
|
|
12
|
+
this.db = db;
|
|
13
|
+
}
|
|
14
|
+
async getTable() {
|
|
15
|
+
const names = await this.db.tableNames();
|
|
16
|
+
if (names.includes(TABLE_NAME)) {
|
|
17
|
+
const table = await this.db.openTable(TABLE_NAME);
|
|
18
|
+
await this.ensureMigration(table);
|
|
19
|
+
return table;
|
|
20
|
+
}
|
|
21
|
+
// Create with empty data to initialize schema
|
|
22
|
+
return await this.db.createTable(TABLE_NAME, [], { schema: memorySchema });
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Ensures schema migration has run. Uses a mutex pattern identical to ensureFtsIndex.
|
|
26
|
+
* Adds columns introduced after the initial schema (usefulness, access_count, last_accessed).
|
|
27
|
+
*/
|
|
28
|
+
ensureMigration(table) {
|
|
29
|
+
if (this.migrationPromise) {
|
|
30
|
+
return this.migrationPromise;
|
|
31
|
+
}
|
|
32
|
+
this.migrationPromise = this.migrateSchemaIfNeeded(table).catch((error) => {
|
|
33
|
+
this.migrationPromise = null;
|
|
34
|
+
throw error;
|
|
35
|
+
});
|
|
36
|
+
return this.migrationPromise;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Inspects the existing table schema and adds any missing columns with safe defaults.
|
|
40
|
+
* This handles databases created before the hybrid memory system was introduced.
|
|
41
|
+
*/
|
|
42
|
+
async migrateSchemaIfNeeded(table) {
|
|
43
|
+
const schema = await table.schema();
|
|
44
|
+
const existingFields = new Set(schema.fields.map((f) => f.name));
|
|
45
|
+
const migrations = [];
|
|
46
|
+
if (!existingFields.has("usefulness")) {
|
|
47
|
+
migrations.push({ name: "usefulness", valueSql: "cast(0.0 as float)" });
|
|
48
|
+
}
|
|
49
|
+
if (!existingFields.has("access_count")) {
|
|
50
|
+
migrations.push({ name: "access_count", valueSql: "cast(0 as int)" });
|
|
51
|
+
}
|
|
52
|
+
if (!existingFields.has("last_accessed")) {
|
|
53
|
+
migrations.push({ name: "last_accessed", valueSql: "cast(NULL as timestamp)" });
|
|
54
|
+
}
|
|
55
|
+
if (migrations.length > 0) {
|
|
56
|
+
await table.addColumns(migrations);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Ensures the FTS index exists on the content column.
|
|
61
|
+
* Uses a mutex pattern to prevent concurrent index creation.
|
|
62
|
+
* The key insight: we must capture the promise BEFORE any await.
|
|
63
|
+
*/
|
|
64
|
+
ensureFtsIndex() {
|
|
65
|
+
// If there's already a pending or completed index creation, return that promise
|
|
66
|
+
if (this.ftsIndexPromise) {
|
|
67
|
+
return this.ftsIndexPromise;
|
|
68
|
+
}
|
|
69
|
+
// Synchronously set the promise BEFORE any await
|
|
70
|
+
// This is critical for proper mutex behavior in JS async code
|
|
71
|
+
this.ftsIndexPromise = this.createFtsIndexIfNeeded().catch((error) => {
|
|
72
|
+
// Reset on error so the next call can retry
|
|
73
|
+
this.ftsIndexPromise = null;
|
|
74
|
+
throw error;
|
|
75
|
+
});
|
|
76
|
+
return this.ftsIndexPromise;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Creates the FTS index if it doesn't already exist.
|
|
80
|
+
* Gets its own table reference to ensure consistent index state.
|
|
81
|
+
*/
|
|
82
|
+
async createFtsIndexIfNeeded() {
|
|
83
|
+
const table = await this.getTable();
|
|
84
|
+
const indices = await table.listIndices();
|
|
85
|
+
const hasFtsIndex = indices.some((idx) => idx.columns.includes("content") && idx.indexType === "FTS");
|
|
86
|
+
if (!hasFtsIndex) {
|
|
87
|
+
await table.createIndex("content", {
|
|
88
|
+
config: Index.fts(),
|
|
89
|
+
});
|
|
90
|
+
// Wait for the index to be fully created and available
|
|
91
|
+
await table.waitForIndex(["content_idx"], 30);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Converts a raw LanceDB row to a Memory object.
|
|
96
|
+
*/
|
|
97
|
+
rowToMemory(row) {
|
|
98
|
+
// Handle Arrow Vector type conversion
|
|
99
|
+
// LanceDB returns an Arrow Vector object which is iterable but not an array
|
|
100
|
+
const vectorData = row.vector;
|
|
101
|
+
const embedding = Array.isArray(vectorData)
|
|
102
|
+
? vectorData
|
|
103
|
+
: Array.from(vectorData);
|
|
104
|
+
return {
|
|
105
|
+
id: row.id,
|
|
106
|
+
content: row.content,
|
|
107
|
+
embedding,
|
|
108
|
+
metadata: JSON.parse(row.metadata),
|
|
109
|
+
createdAt: new Date(row.created_at),
|
|
110
|
+
updatedAt: new Date(row.updated_at),
|
|
111
|
+
supersededBy: row.superseded_by,
|
|
112
|
+
usefulness: row.usefulness ?? 0,
|
|
113
|
+
accessCount: row.access_count ?? 0,
|
|
114
|
+
lastAccessed: row.last_accessed
|
|
115
|
+
? new Date(row.last_accessed)
|
|
116
|
+
: null,
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
async insert(memory) {
|
|
120
|
+
const table = await this.getTable();
|
|
121
|
+
await table.add([
|
|
122
|
+
{
|
|
123
|
+
id: memory.id,
|
|
124
|
+
vector: memory.embedding,
|
|
125
|
+
content: memory.content,
|
|
126
|
+
metadata: JSON.stringify(memory.metadata),
|
|
127
|
+
created_at: memory.createdAt.getTime(),
|
|
128
|
+
updated_at: memory.updatedAt.getTime(),
|
|
129
|
+
superseded_by: memory.supersededBy,
|
|
130
|
+
usefulness: memory.usefulness,
|
|
131
|
+
access_count: memory.accessCount,
|
|
132
|
+
last_accessed: memory.lastAccessed?.getTime() ?? null,
|
|
133
|
+
},
|
|
134
|
+
]);
|
|
135
|
+
}
|
|
136
|
+
async upsert(memory) {
|
|
137
|
+
const table = await this.getTable();
|
|
138
|
+
const existing = await table.query().where(`id = '${memory.id}'`).limit(1).toArray();
|
|
139
|
+
if (existing.length === 0) {
|
|
140
|
+
return await this.insert(memory);
|
|
141
|
+
}
|
|
142
|
+
await table.update({
|
|
143
|
+
where: `id = '${memory.id}'`,
|
|
144
|
+
values: {
|
|
145
|
+
vector: memory.embedding,
|
|
146
|
+
content: memory.content,
|
|
147
|
+
metadata: JSON.stringify(memory.metadata),
|
|
148
|
+
created_at: memory.createdAt.getTime(),
|
|
149
|
+
updated_at: memory.updatedAt.getTime(),
|
|
150
|
+
superseded_by: memory.supersededBy,
|
|
151
|
+
usefulness: memory.usefulness,
|
|
152
|
+
access_count: memory.accessCount,
|
|
153
|
+
last_accessed: memory.lastAccessed?.getTime() ?? null,
|
|
154
|
+
},
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
async findById(id) {
|
|
158
|
+
const table = await this.getTable();
|
|
159
|
+
const results = await table.query().where(`id = '${id}'`).limit(1).toArray();
|
|
160
|
+
if (results.length === 0) {
|
|
161
|
+
return null;
|
|
162
|
+
}
|
|
163
|
+
return this.rowToMemory(results[0]);
|
|
164
|
+
}
|
|
165
|
+
async markDeleted(id) {
|
|
166
|
+
const table = await this.getTable();
|
|
167
|
+
// Verify existence first to match previous behavior (return false if not found)
|
|
168
|
+
const existing = await table.query().where(`id = '${id}'`).limit(1).toArray();
|
|
169
|
+
if (existing.length === 0) {
|
|
170
|
+
return false;
|
|
171
|
+
}
|
|
172
|
+
const now = Date.now();
|
|
173
|
+
await table.update({
|
|
174
|
+
where: `id = '${id}'`,
|
|
175
|
+
values: {
|
|
176
|
+
superseded_by: DELETED_TOMBSTONE,
|
|
177
|
+
updated_at: now,
|
|
178
|
+
},
|
|
179
|
+
});
|
|
180
|
+
return true;
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* Performs hybrid search combining vector similarity and full-text search.
|
|
184
|
+
* Uses RRF (Reciprocal Rank Fusion) to combine rankings from both search methods.
|
|
185
|
+
*
|
|
186
|
+
* @param embedding - Query embedding vector
|
|
187
|
+
* @param query - Text query for full-text search
|
|
188
|
+
* @param limit - Maximum number of results to return
|
|
189
|
+
* @returns Array of HybridRow containing full Memory data plus RRF score
|
|
190
|
+
*/
|
|
191
|
+
async findHybrid(embedding, query, limit) {
|
|
192
|
+
// Ensure FTS index exists (with mutex to prevent concurrent creation)
|
|
193
|
+
// This must happen BEFORE getTable to ensure proper mutex behavior
|
|
194
|
+
await this.ensureFtsIndex();
|
|
195
|
+
const table = await this.getTable();
|
|
196
|
+
// Create RRF reranker with k=60 (standard parameter)
|
|
197
|
+
const reranker = await rerankers.RRFReranker.create(60);
|
|
198
|
+
// Perform hybrid search: combine vector search and full-text search
|
|
199
|
+
const results = await table
|
|
200
|
+
.query()
|
|
201
|
+
.nearestTo(embedding)
|
|
202
|
+
.fullTextSearch(query)
|
|
203
|
+
.rerank(reranker)
|
|
204
|
+
.limit(limit)
|
|
205
|
+
.toArray();
|
|
206
|
+
return results.map((row) => {
|
|
207
|
+
const memory = this.rowToMemory(row);
|
|
208
|
+
return {
|
|
209
|
+
...memory,
|
|
210
|
+
rrfScore: row._relevance_score ?? 0,
|
|
211
|
+
};
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
//# sourceMappingURL=memory.repository.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memory.repository.js","sourceRoot":"","sources":["../../../src/db/memory.repository.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../../src/db/schema.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,MAAM,EAQP,MAAM,cAAc,CAAC;AAEtB,eAAO,MAAM,UAAU,aAAa,CAAC;AAErC,eAAO,MAAM,YAAY,aA2BvB,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Schema, Field, FixedSizeList, Float32, Utf8, Timestamp, TimeUnit, Int32, } from "apache-arrow";
|
|
2
|
+
export const TABLE_NAME = "memories";
|
|
3
|
+
export const memorySchema = new Schema([
|
|
4
|
+
new Field("id", new Utf8(), false),
|
|
5
|
+
new Field("vector", new FixedSizeList(384, new Field("item", new Float32())), false),
|
|
6
|
+
new Field("content", new Utf8(), false),
|
|
7
|
+
new Field("metadata", new Utf8(), false), // JSON string
|
|
8
|
+
new Field("created_at", new Timestamp(TimeUnit.MILLISECOND), false),
|
|
9
|
+
new Field("updated_at", new Timestamp(TimeUnit.MILLISECOND), false),
|
|
10
|
+
new Field("superseded_by", new Utf8(), true), // Nullable
|
|
11
|
+
new Field("usefulness", new Float32(), false),
|
|
12
|
+
new Field("access_count", new Int32(), false),
|
|
13
|
+
new Field("last_accessed", new Timestamp(TimeUnit.MILLISECOND), true),
|
|
14
|
+
]);
|
|
15
|
+
//# sourceMappingURL=schema.js.map
|