@lotargo/memory_plugin 1.3.2 → 1.4.5

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.
@@ -11,7 +11,7 @@ export function sanitizeFtsQuery(query) {
11
11
  return words.join(" OR ");
12
12
  }
13
13
 
14
- export function bm25Search(db, query, limit = 30) {
14
+ export async function bm25Search(db, query, limit = 30) {
15
15
  const ftsQuery = sanitizeFtsQuery(query);
16
16
  if (!ftsQuery) return [];
17
17
 
@@ -23,7 +23,7 @@ export function bm25Search(db, query, limit = 30) {
23
23
  ORDER BY rank
24
24
  LIMIT ?;
25
25
  `);
26
- const rows = stmt.all(ftsQuery, limit);
26
+ const rows = await stmt.all(ftsQuery, limit);
27
27
  return rows.map((r, i) => ({
28
28
  id: r.id,
29
29
  content: r.content,
@@ -37,7 +37,7 @@ export function bm25Search(db, query, limit = 30) {
37
37
  }
38
38
  }
39
39
 
40
- export function vectorSearch(db, queryVector, limit = 30, minSim = 0.25) {
40
+ export async function vectorSearch(db, queryVector, limit = 30, minSim = 0.25) {
41
41
  if (!queryVector || queryVector.length === 0) return [];
42
42
 
43
43
  const vectorDim = queryVector.length;
@@ -52,8 +52,17 @@ export function vectorSearch(db, queryVector, limit = 30, minSim = 0.25) {
52
52
  `);
53
53
 
54
54
  const scored = [];
55
- for (const r of stmt.iterate()) {
56
- tempView.set(r.vector.subarray(0, vectorDim * 4));
55
+ const rows = await stmt.all();
56
+ for (const r of rows) {
57
+ let vecSub = r.vector;
58
+ if (typeof vecSub === "string") {
59
+ vecSub = Buffer.from(vecSub, "base64");
60
+ } else if (vecSub.type === "Buffer" && Array.isArray(vecSub.data)) {
61
+ vecSub = Buffer.from(vecSub.data);
62
+ } else if (Array.isArray(vecSub)) {
63
+ vecSub = Buffer.from(vecSub);
64
+ }
65
+ tempView.set(vecSub.subarray(0, vectorDim * 4));
57
66
 
58
67
  const sim = cosineSimilarity(queryVector, tempVec);
59
68
  if (!isNaN(sim) && sim >= minSim) {
@@ -205,7 +214,7 @@ export async function hybridQuery({
205
214
  instruction = null,
206
215
  generateEmbeddings = true,
207
216
  }) {
208
- const db = customDb || getDatabase();
217
+ const db = customDb || await getDatabase();
209
218
  const activeConfig = getConfig();
210
219
 
211
220
  // If embeddings are disabled (e.g. fast/offline test mode or model not cached),
@@ -223,28 +232,28 @@ export async function hybridQuery({
223
232
  let fusedHits = [];
224
233
 
225
234
  if (algo === "lexical_only" || algo === "bm25_only") {
226
- const bm25Hits = bm25Search(db, query, limit * 4);
235
+ const bm25Hits = await bm25Search(db, query, limit * 4);
227
236
  fusedHits = bm25Hits.map((hit) => ({
228
237
  ...hit,
229
238
  score: 1.0 / hit.bm25_rank,
230
239
  }));
231
240
  } else if (algo === "semantic_only" || algo === "vector_only") {
232
241
  const queryVector = await embedText(query, true, embModel, null, instruction);
233
- const vectorHits = vectorSearch(db, queryVector, limit * 4, 0.10);
242
+ const vectorHits = await vectorSearch(db, queryVector, limit * 4, 0.10);
234
243
  fusedHits = vectorHits.map((hit) => ({
235
244
  ...hit,
236
245
  score: hit.cosine_sim,
237
246
  }));
238
247
  } else if (algo === "rrf") {
239
- const bm25Hits = bm25Search(db, query, 30);
248
+ const bm25Hits = await bm25Search(db, query, 30);
240
249
  const queryVector = await embedText(query, true, embModel, null, instruction);
241
- const vectorHits = vectorSearch(db, queryVector, 30, 0.10);
250
+ const vectorHits = await vectorSearch(db, queryVector, 30, 0.10);
242
251
  fusedHits = rrfFusion(bm25Hits, vectorHits, 60, scoreThreshold);
243
252
  } else {
244
253
  // Default: RSF
245
- const bm25Hits = bm25Search(db, query, 30);
254
+ const bm25Hits = await bm25Search(db, query, 30);
246
255
  const queryVector = await embedText(query, true, embModel, null, instruction);
247
- const vectorHits = vectorSearch(db, queryVector, 30, 0.10);
256
+ const vectorHits = await vectorSearch(db, queryVector, 30, 0.10);
248
257
  fusedHits = rsfFusion(bm25Hits, vectorHits, alphaWeight, scoreThreshold);
249
258
  }
250
259
 
@@ -260,7 +269,7 @@ export async function hybridQuery({
260
269
  `);
261
270
 
262
271
  for (const hit of fusedHits) {
263
- const row = parentLookupStmt.get(hit.id);
272
+ const row = await parentLookupStmt.get(hit.id);
264
273
  const parentKey = row ? (row.medium_id || row.section_id) : hit.id;
265
274
  if (!seenParents.has(parentKey)) {
266
275
  seenParents.add(parentKey);
@@ -282,12 +291,12 @@ export async function hybridQuery({
282
291
  `);
283
292
 
284
293
  for (const hit of topHits) {
285
- const detail = secStmt.get(hit.id);
294
+ const detail = await secStmt.get(hit.id);
286
295
  if (!detail) continue;
287
296
 
288
297
  let symbols = [];
289
298
  if (includeGraphContext) {
290
- symbols = getRelatedSymbols(db, detail.section_id);
299
+ symbols = await getRelatedSymbols(db, detail.section_id);
291
300
  }
292
301
 
293
302
  results.push({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lotargo/memory_plugin",
3
- "version": "1.3.2",
3
+ "version": "1.4.5",
4
4
  "description": "100% local hybrid RAG memory for AI coding agents (OpenCode, Claude Code, Codex, Antigravity). MCP server + plugin: persistent user facts, document ingestion, vector + SQLite FTS5 retrieval across sessions.",
5
5
  "type": "module",
6
6
  "main": "opencode-plugin/index.js",
@@ -68,8 +68,12 @@
68
68
  "url": "https://github.com/Lotargo/memory_pugin.git"
69
69
  },
70
70
  "dependencies": {
71
- "@modelcontextprotocol/sdk": "^1.29.0",
72
71
  "@huggingface/transformers": "^3.3.3",
72
+ "@libsql/client": "^0.17.4",
73
+ "@modelcontextprotocol/sdk": "^1.29.0",
74
+ "mammoth": "^1.12.0",
75
+ "pdf-parse": "^2.4.5",
76
+ "xlsx": "^0.18.5",
73
77
  "zod": "^4.1.0"
74
78
  }
75
79
  }