@aeriondyseti/vector-memory-mcp 2.2.3 → 2.2.6-dev.1
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/README.md +33 -13
- package/package.json +12 -12
- package/{src → server}/config/index.ts +10 -2
- package/{src/db → server/core}/connection.ts +10 -2
- package/{src/db → server/core}/conversation.repository.ts +1 -1
- package/{src/services → server/core}/conversation.service.ts +2 -2
- package/server/core/embeddings.service.ts +125 -0
- package/{src/db → server/core}/memory.repository.ts +5 -1
- package/{src/services → server/core}/memory.service.ts +20 -4
- package/server/core/migration.service.ts +882 -0
- package/server/core/migrations.ts +263 -0
- package/{src/services → server/core}/parsers/claude-code.parser.ts +1 -1
- package/{src/services → server/core}/parsers/types.ts +1 -1
- package/{src → server}/index.ts +16 -48
- package/{src → server/transports}/http/mcp-transport.ts +2 -2
- package/{src → server/transports}/http/server.ts +6 -4
- package/{src → server/transports}/mcp/handlers.ts +5 -5
- package/server/transports/mcp/resources.ts +20 -0
- package/{src → server/transports}/mcp/server.ts +14 -3
- package/server/utils/formatting.ts +143 -0
- package/scripts/lancedb-extract.ts +0 -181
- package/scripts/migrate-from-lancedb.ts +0 -56
- package/scripts/smoke-test.ts +0 -699
- package/scripts/test-runner.ts +0 -76
- package/scripts/warmup.ts +0 -72
- package/src/db/migrations.ts +0 -108
- package/src/migration.ts +0 -203
- package/src/services/embeddings.service.ts +0 -48
- /package/{src/types → server/core}/conversation.ts +0 -0
- /package/{src/types → server/core}/memory.ts +0 -0
- /package/{src/db → server/core}/sqlite-utils.ts +0 -0
- /package/{src → server/transports}/mcp/tools.ts +0 -0
package/scripts/test-runner.ts
DELETED
|
@@ -1,76 +0,0 @@
|
|
|
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
|
-
|
|
9
|
-
import { spawn } from "bun";
|
|
10
|
-
|
|
11
|
-
// Exclude benchmark tests — they're probabilistic quality metrics, not pass/fail gates.
|
|
12
|
-
// Run benchmarks separately with: bun run benchmark
|
|
13
|
-
const args = ["bun", "test", "--preload", "./tests/preload.ts"];
|
|
14
|
-
|
|
15
|
-
// Collect all test files except benchmarks
|
|
16
|
-
const glob = new Bun.Glob("tests/**/*.test.ts");
|
|
17
|
-
for (const path of glob.scanSync(".")) {
|
|
18
|
-
if (!path.includes("benchmark")) args.push(path);
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
const proc = spawn(args, {
|
|
22
|
-
stdout: "pipe",
|
|
23
|
-
stderr: "pipe",
|
|
24
|
-
env: { ...process.env, FORCE_COLOR: "1" },
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
let stdout = "";
|
|
28
|
-
let stderr = "";
|
|
29
|
-
|
|
30
|
-
const decoder = new TextDecoder();
|
|
31
|
-
|
|
32
|
-
// Stream stdout in real-time
|
|
33
|
-
const stdoutReader = proc.stdout.getReader();
|
|
34
|
-
(async () => {
|
|
35
|
-
while (true) {
|
|
36
|
-
const { done, value } = await stdoutReader.read();
|
|
37
|
-
if (done) break;
|
|
38
|
-
const text = decoder.decode(value);
|
|
39
|
-
stdout += text;
|
|
40
|
-
process.stdout.write(text);
|
|
41
|
-
}
|
|
42
|
-
})();
|
|
43
|
-
|
|
44
|
-
// Stream stderr in real-time
|
|
45
|
-
const stderrReader = proc.stderr.getReader();
|
|
46
|
-
(async () => {
|
|
47
|
-
while (true) {
|
|
48
|
-
const { done, value } = await stderrReader.read();
|
|
49
|
-
if (done) break;
|
|
50
|
-
const text = decoder.decode(value);
|
|
51
|
-
stderr += text;
|
|
52
|
-
process.stderr.write(text);
|
|
53
|
-
}
|
|
54
|
-
})();
|
|
55
|
-
|
|
56
|
-
await proc.exited;
|
|
57
|
-
|
|
58
|
-
// Check if tests actually passed by looking for the summary line
|
|
59
|
-
const output = stdout + stderr;
|
|
60
|
-
const passMatch = output.match(/(\d+) pass/);
|
|
61
|
-
const failMatch = output.match(/(\d+) fail/);
|
|
62
|
-
|
|
63
|
-
const passed = passMatch ? parseInt(passMatch[1], 10) : 0;
|
|
64
|
-
const failed = failMatch ? parseInt(failMatch[1], 10) : 0;
|
|
65
|
-
|
|
66
|
-
// Exit based on test results, not Bun's crash
|
|
67
|
-
if (failed > 0) {
|
|
68
|
-
console.error(`\n❌ ${failed} test(s) failed`);
|
|
69
|
-
process.exit(1);
|
|
70
|
-
} else if (passed > 0) {
|
|
71
|
-
console.log(`\n✅ All ${passed} tests passed (ignoring Bun cleanup crash)`);
|
|
72
|
-
process.exit(0);
|
|
73
|
-
} else {
|
|
74
|
-
console.error("\n⚠️ Could not determine test results");
|
|
75
|
-
process.exit(1);
|
|
76
|
-
}
|
package/scripts/warmup.ts
DELETED
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bun
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Warmup script to pre-download ML models and verify dependencies
|
|
5
|
-
* This runs during installation to ensure everything is ready to use
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import { config } from "../src/config/index.js";
|
|
9
|
-
import { EmbeddingsService } from "../src/services/embeddings.service.js";
|
|
10
|
-
|
|
11
|
-
async function warmup(): Promise<void> {
|
|
12
|
-
console.log("🔥 Warming up vector-memory-mcp...");
|
|
13
|
-
console.log();
|
|
14
|
-
|
|
15
|
-
try {
|
|
16
|
-
// Check native dependencies
|
|
17
|
-
console.log("✓ Checking native dependencies...");
|
|
18
|
-
try {
|
|
19
|
-
await import("onnxruntime-node");
|
|
20
|
-
console.log(" ✓ onnxruntime-node loaded");
|
|
21
|
-
} catch (e) {
|
|
22
|
-
console.error(" ✗ onnxruntime-node failed:", (e as Error).message);
|
|
23
|
-
process.exit(1);
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
try {
|
|
27
|
-
await import("sharp");
|
|
28
|
-
console.log(" ✓ sharp loaded");
|
|
29
|
-
} catch (e) {
|
|
30
|
-
console.error(" ✗ sharp failed:", (e as Error).message);
|
|
31
|
-
process.exit(1);
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
console.log();
|
|
35
|
-
|
|
36
|
-
// Initialize embeddings service to download model
|
|
37
|
-
console.log("📥 Downloading ML model (this may take a minute)...");
|
|
38
|
-
console.log(` Model: ${config.embeddingModel}`);
|
|
39
|
-
console.log(` Cache: ~/.cache/huggingface/`);
|
|
40
|
-
console.log();
|
|
41
|
-
|
|
42
|
-
const embeddings = new EmbeddingsService(
|
|
43
|
-
config.embeddingModel,
|
|
44
|
-
config.embeddingDimension
|
|
45
|
-
);
|
|
46
|
-
|
|
47
|
-
// Trigger model download by generating a test embedding
|
|
48
|
-
const startTime = Date.now();
|
|
49
|
-
await embeddings.embed("warmup test");
|
|
50
|
-
const duration = ((Date.now() - startTime) / 1000).toFixed(2);
|
|
51
|
-
|
|
52
|
-
console.log();
|
|
53
|
-
console.log(`✅ Warmup complete! (${duration}s)`);
|
|
54
|
-
console.log();
|
|
55
|
-
console.log("Ready to use! Configure your MCP client and restart to get started.");
|
|
56
|
-
console.log();
|
|
57
|
-
} catch (error) {
|
|
58
|
-
console.error();
|
|
59
|
-
console.error("❌ Warmup failed:", error);
|
|
60
|
-
console.error();
|
|
61
|
-
console.error("This is not a critical error - the server will download models on first run.");
|
|
62
|
-
console.error("You can try running 'vector-memory-mcp warmup' manually later.");
|
|
63
|
-
process.exit(0); // Exit successfully to not block installation
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
// Only run if this is the main module
|
|
68
|
-
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
69
|
-
warmup();
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
export { warmup };
|
package/src/db/migrations.ts
DELETED
|
@@ -1,108 +0,0 @@
|
|
|
1
|
-
import type { Database } from "bun:sqlite";
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Check if a table exists and is a vec0 virtual table (from the old sqlite-vec schema).
|
|
5
|
-
*/
|
|
6
|
-
function isVec0Table(db: Database, tableName: string): boolean {
|
|
7
|
-
const row = db
|
|
8
|
-
.prepare(
|
|
9
|
-
`SELECT sql FROM sqlite_master WHERE type = 'table' AND name = ?`,
|
|
10
|
-
)
|
|
11
|
-
.get(tableName) as { sql: string } | null;
|
|
12
|
-
return row?.sql?.toLowerCase().includes("vec0") ?? false;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* Migrate a vec0 virtual table to a plain BLOB table.
|
|
17
|
-
* Copies id + vector data, drops the vec0 table and its shadow tables, then
|
|
18
|
-
* creates the new plain table with the copied data.
|
|
19
|
-
*/
|
|
20
|
-
function migrateVec0ToBlob(db: Database, tableName: string): void {
|
|
21
|
-
const tmpTable = `${tableName}_migration_tmp`;
|
|
22
|
-
|
|
23
|
-
db.exec(`CREATE TABLE IF NOT EXISTS ${tmpTable} (id TEXT PRIMARY KEY, vector BLOB NOT NULL)`);
|
|
24
|
-
db.exec(`INSERT OR IGNORE INTO ${tmpTable} (id, vector) SELECT id, vector FROM ${tableName}`);
|
|
25
|
-
db.exec(`DROP TABLE ${tableName}`);
|
|
26
|
-
db.exec(`CREATE TABLE ${tableName} (id TEXT PRIMARY KEY, vector BLOB NOT NULL)`);
|
|
27
|
-
db.exec(`INSERT INTO ${tableName} (id, vector) SELECT id, vector FROM ${tmpTable}`);
|
|
28
|
-
db.exec(`DROP TABLE ${tmpTable}`);
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* Run all schema migrations. Safe to call on every startup (uses IF NOT EXISTS).
|
|
33
|
-
*/
|
|
34
|
-
export function runMigrations(db: Database): void {
|
|
35
|
-
// -- Memories --
|
|
36
|
-
db.exec(`
|
|
37
|
-
CREATE TABLE IF NOT EXISTS memories (
|
|
38
|
-
id TEXT PRIMARY KEY,
|
|
39
|
-
content TEXT NOT NULL,
|
|
40
|
-
metadata TEXT NOT NULL DEFAULT '{}',
|
|
41
|
-
created_at INTEGER NOT NULL,
|
|
42
|
-
updated_at INTEGER NOT NULL,
|
|
43
|
-
superseded_by TEXT,
|
|
44
|
-
usefulness REAL NOT NULL DEFAULT 0.0,
|
|
45
|
-
access_count INTEGER NOT NULL DEFAULT 0,
|
|
46
|
-
last_accessed INTEGER
|
|
47
|
-
)
|
|
48
|
-
`);
|
|
49
|
-
|
|
50
|
-
// Migrate vec0 -> plain blob table if upgrading from sqlite-vec schema
|
|
51
|
-
if (isVec0Table(db, "memories_vec")) {
|
|
52
|
-
migrateVec0ToBlob(db, "memories_vec");
|
|
53
|
-
} else {
|
|
54
|
-
db.exec(`
|
|
55
|
-
CREATE TABLE IF NOT EXISTS memories_vec (
|
|
56
|
-
id TEXT PRIMARY KEY,
|
|
57
|
-
vector BLOB NOT NULL
|
|
58
|
-
)
|
|
59
|
-
`);
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
db.exec(`
|
|
63
|
-
CREATE VIRTUAL TABLE IF NOT EXISTS memories_fts USING fts5(
|
|
64
|
-
id UNINDEXED,
|
|
65
|
-
content
|
|
66
|
-
)
|
|
67
|
-
`);
|
|
68
|
-
|
|
69
|
-
// -- Conversation History --
|
|
70
|
-
db.exec(`
|
|
71
|
-
CREATE TABLE IF NOT EXISTS conversation_history (
|
|
72
|
-
id TEXT PRIMARY KEY,
|
|
73
|
-
content TEXT NOT NULL,
|
|
74
|
-
metadata TEXT NOT NULL DEFAULT '{}',
|
|
75
|
-
created_at INTEGER NOT NULL,
|
|
76
|
-
session_id TEXT NOT NULL,
|
|
77
|
-
role TEXT NOT NULL,
|
|
78
|
-
message_index_start INTEGER NOT NULL,
|
|
79
|
-
message_index_end INTEGER NOT NULL,
|
|
80
|
-
project TEXT NOT NULL
|
|
81
|
-
)
|
|
82
|
-
`);
|
|
83
|
-
|
|
84
|
-
// Migrate vec0 -> plain blob table if upgrading from sqlite-vec schema
|
|
85
|
-
if (isVec0Table(db, "conversation_history_vec")) {
|
|
86
|
-
migrateVec0ToBlob(db, "conversation_history_vec");
|
|
87
|
-
} else {
|
|
88
|
-
db.exec(`
|
|
89
|
-
CREATE TABLE IF NOT EXISTS conversation_history_vec (
|
|
90
|
-
id TEXT PRIMARY KEY,
|
|
91
|
-
vector BLOB NOT NULL
|
|
92
|
-
)
|
|
93
|
-
`);
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
db.exec(`
|
|
97
|
-
CREATE VIRTUAL TABLE IF NOT EXISTS conversation_history_fts USING fts5(
|
|
98
|
-
id UNINDEXED,
|
|
99
|
-
content
|
|
100
|
-
)
|
|
101
|
-
`);
|
|
102
|
-
|
|
103
|
-
// -- Indexes --
|
|
104
|
-
db.exec(`CREATE INDEX IF NOT EXISTS idx_conversation_session_id ON conversation_history(session_id)`);
|
|
105
|
-
db.exec(`CREATE INDEX IF NOT EXISTS idx_conversation_project ON conversation_history(project)`);
|
|
106
|
-
db.exec(`CREATE INDEX IF NOT EXISTS idx_conversation_role ON conversation_history(role)`);
|
|
107
|
-
db.exec(`CREATE INDEX IF NOT EXISTS idx_conversation_created_at ON conversation_history(created_at)`);
|
|
108
|
-
}
|
package/src/migration.ts
DELETED
|
@@ -1,203 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* LanceDB -> SQLite migration logic.
|
|
3
|
-
*
|
|
4
|
-
* Reads LanceDB data in a child process (scripts/lancedb-extract.ts) to avoid
|
|
5
|
-
* a native symbol collision between @lancedb/lancedb and bun:sqlite.
|
|
6
|
-
* The extracted JSON is then written to SQLite in-process.
|
|
7
|
-
*
|
|
8
|
-
* @deprecated Will be removed in the next major version once LanceDB
|
|
9
|
-
* support is dropped.
|
|
10
|
-
*/
|
|
11
|
-
|
|
12
|
-
import { existsSync, statSync } from "fs";
|
|
13
|
-
import { resolve, dirname } from "path";
|
|
14
|
-
import { fileURLToPath } from "url";
|
|
15
|
-
import { connectToDatabase } from "./db/connection.js";
|
|
16
|
-
import { serializeVector } from "./db/sqlite-utils.js";
|
|
17
|
-
|
|
18
|
-
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
19
|
-
|
|
20
|
-
// ── Detection ───────────────────────────────────────────────────────
|
|
21
|
-
|
|
22
|
-
export function isLanceDbDirectory(dbPath: string): boolean {
|
|
23
|
-
return existsSync(dbPath) && statSync(dbPath).isDirectory();
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
// ── Types ───────────────────────────────────────────────────────────
|
|
27
|
-
|
|
28
|
-
export interface MigrateOptions {
|
|
29
|
-
source: string;
|
|
30
|
-
target: string;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
export interface MigrateResult {
|
|
34
|
-
memoriesMigrated: number;
|
|
35
|
-
conversationChunksMigrated: number;
|
|
36
|
-
outputSizeMB: string;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
interface ExtractedData {
|
|
40
|
-
memories: Array<{
|
|
41
|
-
id: string;
|
|
42
|
-
content: string;
|
|
43
|
-
metadata: string;
|
|
44
|
-
vector: number[];
|
|
45
|
-
created_at: number;
|
|
46
|
-
updated_at: number;
|
|
47
|
-
last_accessed: number | null;
|
|
48
|
-
superseded_by: string | null;
|
|
49
|
-
usefulness: number;
|
|
50
|
-
access_count: number;
|
|
51
|
-
}>;
|
|
52
|
-
conversations: Array<{
|
|
53
|
-
id: string;
|
|
54
|
-
content: string;
|
|
55
|
-
metadata: string;
|
|
56
|
-
vector: number[];
|
|
57
|
-
created_at: number;
|
|
58
|
-
session_id: string;
|
|
59
|
-
role: string;
|
|
60
|
-
message_index_start: number;
|
|
61
|
-
message_index_end: number;
|
|
62
|
-
project: string;
|
|
63
|
-
}>;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
// ── Migration ───────────────────────────────────────────────────────
|
|
67
|
-
|
|
68
|
-
export async function migrate(opts: MigrateOptions): Promise<MigrateResult> {
|
|
69
|
-
const { source, target } = opts;
|
|
70
|
-
|
|
71
|
-
if (!existsSync(source)) {
|
|
72
|
-
throw new Error(`Source not found: ${source}`);
|
|
73
|
-
}
|
|
74
|
-
if (!statSync(source).isDirectory()) {
|
|
75
|
-
throw new Error(`Source is not a directory (expected LanceDB): ${source}`);
|
|
76
|
-
}
|
|
77
|
-
if (existsSync(target)) {
|
|
78
|
-
throw new Error(
|
|
79
|
-
`Target already exists: ${target}\n Delete it first or choose a different target path.`
|
|
80
|
-
);
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
console.error(`📂 Source (LanceDB): ${source}`);
|
|
84
|
-
console.error(`📄 Target (SQLite): ${target}`);
|
|
85
|
-
console.error();
|
|
86
|
-
|
|
87
|
-
// Phase 1: Extract data from LanceDB in a subprocess.
|
|
88
|
-
// This avoids a native symbol collision between @lancedb/lancedb and bun:sqlite.
|
|
89
|
-
const extractScript = resolve(__dirname, "..", "scripts", "lancedb-extract.ts");
|
|
90
|
-
const proc = Bun.spawn(["bun", extractScript, source], {
|
|
91
|
-
stdout: "pipe",
|
|
92
|
-
stderr: "inherit",
|
|
93
|
-
});
|
|
94
|
-
|
|
95
|
-
const output = await new Response(proc.stdout).text();
|
|
96
|
-
const exitCode = await proc.exited;
|
|
97
|
-
|
|
98
|
-
if (exitCode !== 0) {
|
|
99
|
-
throw new Error(`LanceDB extraction failed (exit code ${exitCode})`);
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
const data: ExtractedData = JSON.parse(output);
|
|
103
|
-
|
|
104
|
-
// Phase 2: Write to SQLite (no LanceDB in this process).
|
|
105
|
-
const sqliteDb = connectToDatabase(target);
|
|
106
|
-
|
|
107
|
-
let memoriesMigrated = 0;
|
|
108
|
-
let conversationChunksMigrated = 0;
|
|
109
|
-
|
|
110
|
-
if (data.memories.length > 0) {
|
|
111
|
-
console.error(`\n🧠 Writing ${data.memories.length} memories to SQLite...`);
|
|
112
|
-
|
|
113
|
-
const insertMain = sqliteDb.prepare(
|
|
114
|
-
`INSERT OR REPLACE INTO memories
|
|
115
|
-
(id, content, metadata, created_at, updated_at, superseded_by, usefulness, access_count, last_accessed)
|
|
116
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`
|
|
117
|
-
);
|
|
118
|
-
const deleteVec = sqliteDb.prepare(`DELETE FROM memories_vec WHERE id = ?`);
|
|
119
|
-
const insertVec = sqliteDb.prepare(
|
|
120
|
-
`INSERT INTO memories_vec (id, vector) VALUES (?, ?)`
|
|
121
|
-
);
|
|
122
|
-
const insertFts = sqliteDb.prepare(
|
|
123
|
-
`INSERT OR REPLACE INTO memories_fts (id, content) VALUES (?, ?)`
|
|
124
|
-
);
|
|
125
|
-
|
|
126
|
-
const tx = sqliteDb.transaction(() => {
|
|
127
|
-
for (const row of data.memories) {
|
|
128
|
-
insertMain.run(
|
|
129
|
-
row.id, row.content, row.metadata,
|
|
130
|
-
row.created_at, row.updated_at,
|
|
131
|
-
row.superseded_by, row.usefulness,
|
|
132
|
-
row.access_count, row.last_accessed,
|
|
133
|
-
);
|
|
134
|
-
if (row.vector.length > 0) {
|
|
135
|
-
deleteVec.run(row.id);
|
|
136
|
-
insertVec.run(row.id, serializeVector(row.vector));
|
|
137
|
-
}
|
|
138
|
-
insertFts.run(row.id, row.content);
|
|
139
|
-
}
|
|
140
|
-
});
|
|
141
|
-
tx();
|
|
142
|
-
memoriesMigrated = data.memories.length;
|
|
143
|
-
console.error(` ✅ ${memoriesMigrated} memories migrated`);
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
if (data.conversations.length > 0) {
|
|
147
|
-
console.error(`\n💬 Writing ${data.conversations.length} conversation chunks to SQLite...`);
|
|
148
|
-
|
|
149
|
-
const insertMain = sqliteDb.prepare(
|
|
150
|
-
`INSERT OR REPLACE INTO conversation_history
|
|
151
|
-
(id, content, metadata, created_at, session_id, role, message_index_start, message_index_end, project)
|
|
152
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`
|
|
153
|
-
);
|
|
154
|
-
const deleteVec = sqliteDb.prepare(`DELETE FROM conversation_history_vec WHERE id = ?`);
|
|
155
|
-
const insertVec = sqliteDb.prepare(
|
|
156
|
-
`INSERT INTO conversation_history_vec (id, vector) VALUES (?, ?)`
|
|
157
|
-
);
|
|
158
|
-
const insertFts = sqliteDb.prepare(
|
|
159
|
-
`INSERT OR REPLACE INTO conversation_history_fts (id, content) VALUES (?, ?)`
|
|
160
|
-
);
|
|
161
|
-
|
|
162
|
-
const tx = sqliteDb.transaction(() => {
|
|
163
|
-
for (const row of data.conversations) {
|
|
164
|
-
insertMain.run(
|
|
165
|
-
row.id, row.content, row.metadata,
|
|
166
|
-
row.created_at, row.session_id, row.role,
|
|
167
|
-
row.message_index_start, row.message_index_end, row.project,
|
|
168
|
-
);
|
|
169
|
-
if (row.vector.length > 0) {
|
|
170
|
-
deleteVec.run(row.id);
|
|
171
|
-
insertVec.run(row.id, serializeVector(row.vector));
|
|
172
|
-
}
|
|
173
|
-
insertFts.run(row.id, row.content);
|
|
174
|
-
}
|
|
175
|
-
});
|
|
176
|
-
tx();
|
|
177
|
-
conversationChunksMigrated = data.conversations.length;
|
|
178
|
-
console.error(` ✅ ${conversationChunksMigrated} conversation chunks migrated`);
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
sqliteDb.close();
|
|
182
|
-
|
|
183
|
-
const { size } = statSync(target);
|
|
184
|
-
const outputSizeMB = (size / 1024 / 1024).toFixed(2);
|
|
185
|
-
|
|
186
|
-
return { memoriesMigrated, conversationChunksMigrated, outputSizeMB };
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
export function formatMigrationSummary(
|
|
190
|
-
source: string,
|
|
191
|
-
target: string,
|
|
192
|
-
result: MigrateResult,
|
|
193
|
-
): string {
|
|
194
|
-
return `
|
|
195
|
-
✅ Migration complete! (${result.outputSizeMB} MB)
|
|
196
|
-
${result.memoriesMigrated} memories, ${result.conversationChunksMigrated} conversation chunks
|
|
197
|
-
|
|
198
|
-
Next steps:
|
|
199
|
-
1. Backup: mv "${source}" "${source}.lance-backup"
|
|
200
|
-
2. Activate: mv "${target}" "${source}"
|
|
201
|
-
3. Restart your MCP server
|
|
202
|
-
`;
|
|
203
|
-
}
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
import { pipeline, type FeatureExtractionPipeline } from "@huggingface/transformers";
|
|
2
|
-
|
|
3
|
-
export class EmbeddingsService {
|
|
4
|
-
private modelName: string;
|
|
5
|
-
private extractor: FeatureExtractionPipeline | null = null;
|
|
6
|
-
private initPromise: Promise<FeatureExtractionPipeline> | null = null;
|
|
7
|
-
private _dimension: number;
|
|
8
|
-
|
|
9
|
-
constructor(modelName: string, dimension: number) {
|
|
10
|
-
this.modelName = modelName;
|
|
11
|
-
this._dimension = dimension;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
get dimension(): number {
|
|
15
|
-
return this._dimension;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
private async getExtractor(): Promise<FeatureExtractionPipeline> {
|
|
19
|
-
if (this.extractor) {
|
|
20
|
-
return this.extractor;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
if (!this.initPromise) {
|
|
24
|
-
this.initPromise = pipeline(
|
|
25
|
-
"feature-extraction",
|
|
26
|
-
this.modelName,
|
|
27
|
-
{ dtype: "fp32" } as any
|
|
28
|
-
) as Promise<FeatureExtractionPipeline>;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
this.extractor = await this.initPromise;
|
|
32
|
-
return this.extractor;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
async embed(text: string): Promise<number[]> {
|
|
36
|
-
const extractor = await this.getExtractor();
|
|
37
|
-
const output = await extractor(text, { pooling: "mean", normalize: true });
|
|
38
|
-
return Array.from(output.data as Float32Array);
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
async embedBatch(texts: string[]): Promise<number[][]> {
|
|
42
|
-
const results: number[][] = [];
|
|
43
|
-
for (const text of texts) {
|
|
44
|
-
results.push(await this.embed(text));
|
|
45
|
-
}
|
|
46
|
-
return results;
|
|
47
|
-
}
|
|
48
|
-
}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|