@aeriondyseti/vector-memory-mcp 2.3.0-rc.2 → 2.3.0-rc.3
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/package.json +1 -1
- package/server/core/migrations.ts +75 -17
- package/server/index.ts +3 -5
package/package.json
CHANGED
|
@@ -127,8 +127,43 @@ export async function backfillVectors(
|
|
|
127
127
|
db: Database,
|
|
128
128
|
embeddings: EmbeddingsService,
|
|
129
129
|
): Promise<void> {
|
|
130
|
+
// Fast sentinel check: skip the LEFT JOIN queries entirely when backfill is done
|
|
131
|
+
const sentinel = db
|
|
132
|
+
.prepare("SELECT 1 FROM memories_vec LIMIT 1")
|
|
133
|
+
.get();
|
|
134
|
+
const memoriesExist = db.prepare("SELECT 1 FROM memories LIMIT 1").get();
|
|
135
|
+
const convosExist = db.prepare("SELECT 1 FROM conversation_history LIMIT 1").get();
|
|
136
|
+
|
|
137
|
+
// If vec tables have data and source tables have data, backfill is likely complete.
|
|
138
|
+
// Only run the expensive LEFT JOIN when there's reason to suspect gaps.
|
|
139
|
+
const convoSentinel = db
|
|
140
|
+
.prepare("SELECT 1 FROM conversation_history_vec LIMIT 1")
|
|
141
|
+
.get();
|
|
142
|
+
const mayNeedMemoryBackfill = memoriesExist && !sentinel;
|
|
143
|
+
const mayNeedConvoBackfill = convosExist && !convoSentinel;
|
|
144
|
+
|
|
145
|
+
// If both vec tables are populated, do a quick count check to confirm
|
|
146
|
+
if (!mayNeedMemoryBackfill && !mayNeedConvoBackfill) {
|
|
147
|
+
if (memoriesExist) {
|
|
148
|
+
const gap = db.prepare(
|
|
149
|
+
`SELECT 1 FROM memories m LEFT JOIN memories_vec v ON m.id = v.id
|
|
150
|
+
WHERE v.id IS NULL OR length(v.vector) = 0 LIMIT 1`,
|
|
151
|
+
).get();
|
|
152
|
+
if (!gap && convosExist) {
|
|
153
|
+
const convoGap = db.prepare(
|
|
154
|
+
`SELECT 1 FROM conversation_history c LEFT JOIN conversation_history_vec v ON c.id = v.id
|
|
155
|
+
WHERE v.id IS NULL OR length(v.vector) = 0 LIMIT 1`,
|
|
156
|
+
).get();
|
|
157
|
+
if (!convoGap) return;
|
|
158
|
+
} else if (!gap && !convosExist) {
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
} else {
|
|
162
|
+
return; // No data at all
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
130
166
|
// ── Memories ──────────────────────────────────────────────────────
|
|
131
|
-
// Catch both missing rows (v.id IS NULL) and corrupt 0-byte BLOBs
|
|
132
167
|
const missingMemories = db
|
|
133
168
|
.prepare(
|
|
134
169
|
`SELECT m.id, m.content, json_extract(m.metadata, '$.type') AS type
|
|
@@ -151,14 +186,27 @@ export async function backfillVectors(
|
|
|
151
186
|
new Array(embeddings.dimension).fill(0),
|
|
152
187
|
);
|
|
153
188
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
189
|
+
// Separate waypoints from content that needs embedding
|
|
190
|
+
const toEmbed = missingMemories.filter((r) => r.type !== "waypoint");
|
|
191
|
+
const waypoints = missingMemories.filter((r) => r.type === "waypoint");
|
|
192
|
+
|
|
193
|
+
// Batch embed all non-waypoint content
|
|
194
|
+
const vectors = toEmbed.length > 0
|
|
195
|
+
? await embeddings.embedBatch(toEmbed.map((r) => r.content))
|
|
196
|
+
: [];
|
|
160
197
|
|
|
161
|
-
|
|
198
|
+
db.exec("BEGIN");
|
|
199
|
+
try {
|
|
200
|
+
for (const row of waypoints) {
|
|
201
|
+
insertVec.run(row.id, zeroVector);
|
|
202
|
+
}
|
|
203
|
+
for (let i = 0; i < toEmbed.length; i++) {
|
|
204
|
+
insertVec.run(toEmbed[i].id, serializeVector(vectors[i]));
|
|
205
|
+
}
|
|
206
|
+
db.exec("COMMIT");
|
|
207
|
+
} catch (e) {
|
|
208
|
+
db.exec("ROLLBACK");
|
|
209
|
+
throw e;
|
|
162
210
|
}
|
|
163
211
|
|
|
164
212
|
console.error(
|
|
@@ -185,17 +233,27 @@ export async function backfillVectors(
|
|
|
185
233
|
"INSERT OR REPLACE INTO conversation_history_vec (id, vector) VALUES (?, ?)",
|
|
186
234
|
);
|
|
187
235
|
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
236
|
+
// Batch embed in chunks of 32
|
|
237
|
+
const BATCH_SIZE = 32;
|
|
238
|
+
db.exec("BEGIN");
|
|
239
|
+
try {
|
|
240
|
+
for (let i = 0; i < missingConvos.length; i += BATCH_SIZE) {
|
|
241
|
+
const batch = missingConvos.slice(i, i + BATCH_SIZE);
|
|
242
|
+
const vecs = await embeddings.embedBatch(batch.map((r) => r.content));
|
|
243
|
+
for (let j = 0; j < batch.length; j++) {
|
|
244
|
+
insertConvoVec.run(batch[j].id, serializeVector(vecs[j]));
|
|
245
|
+
}
|
|
192
246
|
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
247
|
+
if ((i + BATCH_SIZE) % 100 < BATCH_SIZE) {
|
|
248
|
+
console.error(
|
|
249
|
+
`[vector-memory-mcp] ...${Math.min(i + BATCH_SIZE, missingConvos.length)}/${missingConvos.length} conversation chunks`,
|
|
250
|
+
);
|
|
251
|
+
}
|
|
198
252
|
}
|
|
253
|
+
db.exec("COMMIT");
|
|
254
|
+
} catch (e) {
|
|
255
|
+
db.exec("ROLLBACK");
|
|
256
|
+
throw e;
|
|
199
257
|
}
|
|
200
258
|
|
|
201
259
|
console.error(
|
package/server/index.ts
CHANGED
|
@@ -25,17 +25,15 @@ async function main(): Promise<void> {
|
|
|
25
25
|
const overrides = parseCliArgs(args);
|
|
26
26
|
const config = loadConfig(overrides);
|
|
27
27
|
|
|
28
|
-
// Initialize database
|
|
28
|
+
// Initialize database and backfill any missing vectors before services start
|
|
29
29
|
const db = connectToDatabase(config.dbPath);
|
|
30
|
+
const embeddings = new EmbeddingsService(config.embeddingModel, config.embeddingDimension);
|
|
31
|
+
await backfillVectors(db, embeddings);
|
|
30
32
|
|
|
31
33
|
// Initialize layers
|
|
32
34
|
const repository = new MemoryRepository(db);
|
|
33
|
-
const embeddings = new EmbeddingsService(config.embeddingModel, config.embeddingDimension);
|
|
34
35
|
const memoryService = new MemoryService(repository, embeddings);
|
|
35
36
|
|
|
36
|
-
// Backfill any missing vectors (e.g. after vec0-to-BLOB migration)
|
|
37
|
-
await backfillVectors(db, embeddings);
|
|
38
|
-
|
|
39
37
|
if (config.pluginMode) {
|
|
40
38
|
console.error("[vector-memory-mcp] Running in plugin mode");
|
|
41
39
|
}
|