@199-bio/engram 0.1.0 → 0.3.0

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 CHANGED
@@ -31,18 +31,19 @@ Engram connects the dots—*avoid seafood restaurants, book Sarah a window seat,
31
31
  ### Install
32
32
 
33
33
  ```bash
34
- npm install -g engram-mcp
34
+ npm install -g @199-bio/engram
35
35
  ```
36
36
 
37
37
  ### Add to Your MCP Client
38
38
 
39
- **Claude Desktop** — add to `~/.claude/claude_desktop_config.json`:
39
+ **Claude Desktop** — add to `~/Library/Application Support/Claude/claude_desktop_config.json`:
40
40
 
41
41
  ```json
42
42
  {
43
43
  "mcpServers": {
44
44
  "engram": {
45
- "command": "engram"
45
+ "command": "npx",
46
+ "args": ["-y", "@199-bio/engram"]
46
47
  }
47
48
  }
48
49
  }
@@ -51,7 +52,7 @@ npm install -g engram-mcp
51
52
  **Claude Code:**
52
53
 
53
54
  ```bash
54
- claude mcp add engram -- engram
55
+ claude mcp add engram -- npx -y @199-bio/engram
55
56
  ```
56
57
 
57
58
  **Other MCP clients** — point to the `engram` command. It speaks standard MCP over stdio.
package/dist/index.js CHANGED
@@ -14,6 +14,7 @@ import { EngramDatabase } from "./storage/database.js";
14
14
  import { KnowledgeGraph } from "./graph/knowledge-graph.js";
15
15
  import { createRetriever } from "./retrieval/colbert.js";
16
16
  import { HybridSearch } from "./retrieval/hybrid.js";
17
+ import { EngramWebServer } from "./web/server.js";
17
18
  // ============ Configuration ============
18
19
  const DB_PATH = process.env.ENGRAM_DB_PATH
19
20
  ? path.resolve(process.env.ENGRAM_DB_PATH.replace("~", os.homedir()))
@@ -23,6 +24,7 @@ const DB_FILE = path.join(DB_PATH, "engram.db");
23
24
  let db;
24
25
  let graph;
25
26
  let search;
27
+ let webServer = null;
26
28
  async function initialize() {
27
29
  console.error(`[Engram] Initializing with database at ${DB_FILE}`);
28
30
  db = new EngramDatabase(DB_FILE);
@@ -40,13 +42,13 @@ async function initialize() {
40
42
  // ============ MCP Server ============
41
43
  const server = new Server({
42
44
  name: "engram",
43
- version: "0.1.0",
45
+ version: "0.3.0",
44
46
  }, {
45
47
  capabilities: {
46
48
  tools: {},
47
49
  },
48
50
  });
49
- // Tool definitions
51
+ // Tool definitions with MCP 2025-06-18 annotations
50
52
  const TOOLS = [
51
53
  {
52
54
  name: "remember",
@@ -73,6 +75,13 @@ const TOOLS = [
73
75
  },
74
76
  required: ["content"],
75
77
  },
78
+ annotations: {
79
+ title: "Store Memory",
80
+ readOnlyHint: false,
81
+ destructiveHint: false,
82
+ idempotentHint: false,
83
+ openWorldHint: false,
84
+ },
76
85
  },
77
86
  {
78
87
  name: "recall",
@@ -97,6 +106,13 @@ const TOOLS = [
97
106
  },
98
107
  required: ["query"],
99
108
  },
109
+ annotations: {
110
+ title: "Search Memories",
111
+ readOnlyHint: true,
112
+ destructiveHint: false,
113
+ idempotentHint: true,
114
+ openWorldHint: false,
115
+ },
100
116
  },
101
117
  {
102
118
  name: "forget",
@@ -111,6 +127,13 @@ const TOOLS = [
111
127
  },
112
128
  required: ["id"],
113
129
  },
130
+ annotations: {
131
+ title: "Delete Memory",
132
+ readOnlyHint: false,
133
+ destructiveHint: true,
134
+ idempotentHint: true,
135
+ openWorldHint: false,
136
+ },
114
137
  },
115
138
  {
116
139
  name: "create_entity",
@@ -130,6 +153,13 @@ const TOOLS = [
130
153
  },
131
154
  required: ["name", "type"],
132
155
  },
156
+ annotations: {
157
+ title: "Create Entity",
158
+ readOnlyHint: false,
159
+ destructiveHint: false,
160
+ idempotentHint: true,
161
+ openWorldHint: false,
162
+ },
133
163
  },
134
164
  {
135
165
  name: "observe",
@@ -153,6 +183,13 @@ const TOOLS = [
153
183
  },
154
184
  required: ["entity", "observation"],
155
185
  },
186
+ annotations: {
187
+ title: "Add Observation",
188
+ readOnlyHint: false,
189
+ destructiveHint: false,
190
+ idempotentHint: false,
191
+ openWorldHint: false,
192
+ },
156
193
  },
157
194
  {
158
195
  name: "relate",
@@ -175,6 +212,13 @@ const TOOLS = [
175
212
  },
176
213
  required: ["from", "to", "relation"],
177
214
  },
215
+ annotations: {
216
+ title: "Create Relationship",
217
+ readOnlyHint: false,
218
+ destructiveHint: false,
219
+ idempotentHint: true,
220
+ openWorldHint: false,
221
+ },
178
222
  },
179
223
  {
180
224
  name: "query_entity",
@@ -189,6 +233,13 @@ const TOOLS = [
189
233
  },
190
234
  required: ["entity"],
191
235
  },
236
+ annotations: {
237
+ title: "Query Entity",
238
+ readOnlyHint: true,
239
+ destructiveHint: false,
240
+ idempotentHint: true,
241
+ openWorldHint: false,
242
+ },
192
243
  },
193
244
  {
194
245
  name: "list_entities",
@@ -208,6 +259,13 @@ const TOOLS = [
208
259
  },
209
260
  },
210
261
  },
262
+ annotations: {
263
+ title: "List Entities",
264
+ readOnlyHint: true,
265
+ destructiveHint: false,
266
+ idempotentHint: true,
267
+ openWorldHint: false,
268
+ },
211
269
  },
212
270
  {
213
271
  name: "stats",
@@ -216,6 +274,34 @@ const TOOLS = [
216
274
  type: "object",
217
275
  properties: {},
218
276
  },
277
+ annotations: {
278
+ title: "Get Statistics",
279
+ readOnlyHint: true,
280
+ destructiveHint: false,
281
+ idempotentHint: true,
282
+ openWorldHint: false,
283
+ },
284
+ },
285
+ {
286
+ name: "engram_web",
287
+ description: "Launch the Engram web interface for browsing, searching, and editing memories visually. Returns a URL to open in your browser.",
288
+ inputSchema: {
289
+ type: "object",
290
+ properties: {
291
+ port: {
292
+ type: "number",
293
+ description: "Port to run the web server on (default: 3847)",
294
+ default: 3847,
295
+ },
296
+ },
297
+ },
298
+ annotations: {
299
+ title: "Launch Web Interface",
300
+ readOnlyHint: false,
301
+ destructiveHint: false,
302
+ idempotentHint: true,
303
+ openWorldHint: true,
304
+ },
219
305
  },
220
306
  ];
221
307
  // List available tools
@@ -442,6 +528,26 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
442
528
  ],
443
529
  };
444
530
  }
531
+ case "engram_web": {
532
+ const { port = 3847 } = args;
533
+ // Create or reuse web server
534
+ if (!webServer) {
535
+ webServer = new EngramWebServer({ db, graph, search, port });
536
+ }
537
+ const url = await webServer.start();
538
+ return {
539
+ content: [
540
+ {
541
+ type: "text",
542
+ text: JSON.stringify({
543
+ success: true,
544
+ url,
545
+ message: `Web interface running at ${url}`,
546
+ }, null, 2),
547
+ },
548
+ ],
549
+ };
550
+ }
445
551
  default:
446
552
  throw new Error(`Unknown tool: ${name}`);
447
553
  }
@@ -1 +1 @@
1
- {"version":3,"file":"hybrid.d.ts","sourceRoot":"","sources":["../../src/retrieval/hybrid.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAChE,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAC7D,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAA0B,MAAM,cAAc,CAAC;AAGzF,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE;QACP,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,KAAK,CAAC,EAAE,MAAM,CAAC;KAChB,CAAC;CACH;AAED,qBAAa,YAAY;IAErB,OAAO,CAAC,EAAE;IACV,OAAO,CAAC,KAAK;IACb,OAAO,CAAC,SAAS;gBAFT,EAAE,EAAE,cAAc,EAClB,KAAK,EAAE,cAAc,EACrB,SAAS,EAAE,gBAAgB,GAAG,eAAe;IAGvD;;OAEG;IACG,MAAM,CACV,KAAK,EAAE,MAAM,EACb,OAAO,GAAE;QACP,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,YAAY,CAAC,EAAE,OAAO,CAAC;QACvB,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,cAAc,CAAC,EAAE,MAAM,CAAC;QACxB,WAAW,CAAC,EAAE,MAAM,CAAC;KACjB,GACL,OAAO,CAAC,kBAAkB,EAAE,CAAC;IAyGhC;;OAEG;YACW,UAAU;IASxB;;OAEG;YACW,cAAc;IAS5B;;OAEG;YACW,WAAW;IAezB;;OAEG;IACG,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAOhD;;OAEG;IACG,YAAY,IAAI,OAAO,CAAC;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IAYhD;;OAEG;IACG,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAGvD"}
1
+ {"version":3,"file":"hybrid.d.ts","sourceRoot":"","sources":["../../src/retrieval/hybrid.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAChE,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAC7D,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAA0B,MAAM,cAAc,CAAC;AAGzF,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE;QACP,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,KAAK,CAAC,EAAE,MAAM,CAAC;KAChB,CAAC;CACH;AAED,qBAAa,YAAY;IAErB,OAAO,CAAC,EAAE;IACV,OAAO,CAAC,KAAK;IACb,OAAO,CAAC,SAAS;gBAFT,EAAE,EAAE,cAAc,EAClB,KAAK,EAAE,cAAc,EACrB,SAAS,EAAE,gBAAgB,GAAG,eAAe;IAGvD;;;;;OAKG;IACG,MAAM,CACV,KAAK,EAAE,MAAM,EACb,OAAO,GAAE;QACP,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,YAAY,CAAC,EAAE,OAAO,CAAC;QACvB,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,cAAc,CAAC,EAAE,MAAM,CAAC;QACxB,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,YAAY,CAAC,EAAE,OAAO,CAAC;KACnB,GACL,OAAO,CAAC,kBAAkB,EAAE,CAAC;IAqHhC;;OAEG;YACW,UAAU;IASxB;;OAEG;YACW,cAAc;IAS5B;;OAEG;YACW,WAAW;IAezB;;OAEG;IACG,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAOhD;;OAEG;IACG,YAAY,IAAI,OAAO,CAAC;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IAYhD;;OAEG;IACG,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAGvD"}
@@ -1 +1 @@
1
- {"version":3,"file":"database.d.ts","sourceRoot":"","sources":["../../src/storage/database.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"database.d.ts","sourceRoot":"","sources":["../../src/storage/database.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/web/server.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAMH,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAC7D,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAiBtD,UAAU,gBAAgB;IACxB,EAAE,EAAE,cAAc,CAAC;IACnB,KAAK,EAAE,cAAc,CAAC;IACtB,MAAM,EAAE,YAAY,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,qBAAa,eAAe;IAC1B,OAAO,CAAC,MAAM,CAA4B;IAC1C,OAAO,CAAC,EAAE,CAAiB;IAC3B,OAAO,CAAC,KAAK,CAAiB;IAC9B,OAAO,CAAC,MAAM,CAAe;IAC7B,OAAO,CAAC,IAAI,CAAS;gBAET,OAAO,EAAE,gBAAgB;IAO/B,KAAK,IAAI,OAAO,CAAC,MAAM,CAAC;IAkB9B,IAAI,IAAI,IAAI;YAOE,aAAa;YA+Bb,SAAS;YAgIT,WAAW;IAgCzB,OAAO,CAAC,SAAS;CAclB"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@199-bio/engram",
3
- "version": "0.1.0",
3
+ "version": "0.3.0",
4
4
  "description": "Give Claude a perfect memory. Local-first MCP server with hybrid search.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -46,11 +46,11 @@
46
46
  "node": ">=18.0.0"
47
47
  },
48
48
  "dependencies": {
49
- "@modelcontextprotocol/sdk": "^1.0.0",
50
- "better-sqlite3": "^11.0.0",
49
+ "@modelcontextprotocol/sdk": "^1.25.0",
50
+ "better-sqlite3": "^11.10.0",
51
51
  "chrono-node": "^2.7.0",
52
52
  "uuid": "^10.0.0",
53
- "zod": "^3.23.0"
53
+ "zod": "^3.24.0"
54
54
  },
55
55
  "devDependencies": {
56
56
  "@types/better-sqlite3": "^7.6.0",
package/src/index.ts CHANGED
@@ -19,6 +19,7 @@ import { EngramDatabase } from "./storage/database.js";
19
19
  import { KnowledgeGraph } from "./graph/knowledge-graph.js";
20
20
  import { createRetriever } from "./retrieval/colbert.js";
21
21
  import { HybridSearch } from "./retrieval/hybrid.js";
22
+ import { EngramWebServer } from "./web/server.js";
22
23
 
23
24
  // ============ Configuration ============
24
25
 
@@ -33,6 +34,7 @@ const DB_FILE = path.join(DB_PATH, "engram.db");
33
34
  let db: EngramDatabase;
34
35
  let graph: KnowledgeGraph;
35
36
  let search: HybridSearch;
37
+ let webServer: EngramWebServer | null = null;
36
38
 
37
39
  async function initialize(): Promise<void> {
38
40
  console.error(`[Engram] Initializing with database at ${DB_FILE}`);
@@ -58,7 +60,7 @@ async function initialize(): Promise<void> {
58
60
  const server = new Server(
59
61
  {
60
62
  name: "engram",
61
- version: "0.1.0",
63
+ version: "0.3.0",
62
64
  },
63
65
  {
64
66
  capabilities: {
@@ -67,7 +69,7 @@ const server = new Server(
67
69
  }
68
70
  );
69
71
 
70
- // Tool definitions
72
+ // Tool definitions with MCP 2025-06-18 annotations
71
73
  const TOOLS = [
72
74
  {
73
75
  name: "remember",
@@ -95,6 +97,13 @@ const TOOLS = [
95
97
  },
96
98
  required: ["content"],
97
99
  },
100
+ annotations: {
101
+ title: "Store Memory",
102
+ readOnlyHint: false,
103
+ destructiveHint: false,
104
+ idempotentHint: false,
105
+ openWorldHint: false,
106
+ },
98
107
  },
99
108
  {
100
109
  name: "recall",
@@ -120,6 +129,13 @@ const TOOLS = [
120
129
  },
121
130
  required: ["query"],
122
131
  },
132
+ annotations: {
133
+ title: "Search Memories",
134
+ readOnlyHint: true,
135
+ destructiveHint: false,
136
+ idempotentHint: true,
137
+ openWorldHint: false,
138
+ },
123
139
  },
124
140
  {
125
141
  name: "forget",
@@ -134,6 +150,13 @@ const TOOLS = [
134
150
  },
135
151
  required: ["id"],
136
152
  },
153
+ annotations: {
154
+ title: "Delete Memory",
155
+ readOnlyHint: false,
156
+ destructiveHint: true,
157
+ idempotentHint: true,
158
+ openWorldHint: false,
159
+ },
137
160
  },
138
161
  {
139
162
  name: "create_entity",
@@ -153,6 +176,13 @@ const TOOLS = [
153
176
  },
154
177
  required: ["name", "type"],
155
178
  },
179
+ annotations: {
180
+ title: "Create Entity",
181
+ readOnlyHint: false,
182
+ destructiveHint: false,
183
+ idempotentHint: true,
184
+ openWorldHint: false,
185
+ },
156
186
  },
157
187
  {
158
188
  name: "observe",
@@ -176,6 +206,13 @@ const TOOLS = [
176
206
  },
177
207
  required: ["entity", "observation"],
178
208
  },
209
+ annotations: {
210
+ title: "Add Observation",
211
+ readOnlyHint: false,
212
+ destructiveHint: false,
213
+ idempotentHint: false,
214
+ openWorldHint: false,
215
+ },
179
216
  },
180
217
  {
181
218
  name: "relate",
@@ -198,6 +235,13 @@ const TOOLS = [
198
235
  },
199
236
  required: ["from", "to", "relation"],
200
237
  },
238
+ annotations: {
239
+ title: "Create Relationship",
240
+ readOnlyHint: false,
241
+ destructiveHint: false,
242
+ idempotentHint: true,
243
+ openWorldHint: false,
244
+ },
201
245
  },
202
246
  {
203
247
  name: "query_entity",
@@ -212,6 +256,13 @@ const TOOLS = [
212
256
  },
213
257
  required: ["entity"],
214
258
  },
259
+ annotations: {
260
+ title: "Query Entity",
261
+ readOnlyHint: true,
262
+ destructiveHint: false,
263
+ idempotentHint: true,
264
+ openWorldHint: false,
265
+ },
215
266
  },
216
267
  {
217
268
  name: "list_entities",
@@ -231,6 +282,13 @@ const TOOLS = [
231
282
  },
232
283
  },
233
284
  },
285
+ annotations: {
286
+ title: "List Entities",
287
+ readOnlyHint: true,
288
+ destructiveHint: false,
289
+ idempotentHint: true,
290
+ openWorldHint: false,
291
+ },
234
292
  },
235
293
  {
236
294
  name: "stats",
@@ -239,6 +297,34 @@ const TOOLS = [
239
297
  type: "object" as const,
240
298
  properties: {},
241
299
  },
300
+ annotations: {
301
+ title: "Get Statistics",
302
+ readOnlyHint: true,
303
+ destructiveHint: false,
304
+ idempotentHint: true,
305
+ openWorldHint: false,
306
+ },
307
+ },
308
+ {
309
+ name: "engram_web",
310
+ description: "Launch the Engram web interface for browsing, searching, and editing memories visually. Returns a URL to open in your browser.",
311
+ inputSchema: {
312
+ type: "object" as const,
313
+ properties: {
314
+ port: {
315
+ type: "number",
316
+ description: "Port to run the web server on (default: 3847)",
317
+ default: 3847,
318
+ },
319
+ },
320
+ },
321
+ annotations: {
322
+ title: "Launch Web Interface",
323
+ readOnlyHint: false,
324
+ destructiveHint: false,
325
+ idempotentHint: true,
326
+ openWorldHint: true,
327
+ },
242
328
  },
243
329
  ];
244
330
 
@@ -524,6 +610,30 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
524
610
  };
525
611
  }
526
612
 
613
+ case "engram_web": {
614
+ const { port = 3847 } = args as { port?: number };
615
+
616
+ // Create or reuse web server
617
+ if (!webServer) {
618
+ webServer = new EngramWebServer({ db, graph, search, port });
619
+ }
620
+
621
+ const url = await webServer.start();
622
+
623
+ return {
624
+ content: [
625
+ {
626
+ type: "text" as const,
627
+ text: JSON.stringify({
628
+ success: true,
629
+ url,
630
+ message: `Web interface running at ${url}`,
631
+ }, null, 2),
632
+ },
633
+ ],
634
+ };
635
+ }
636
+
527
637
  default:
528
638
  throw new Error(`Unknown tool: ${name}`);
529
639
  }
@@ -27,6 +27,9 @@ export class HybridSearch {
27
27
 
28
28
  /**
29
29
  * Search using all available methods and fuse results
30
+ *
31
+ * Strategy: BM25 gets candidates fast, ColBERT reranks for quality
32
+ * This is both FASTER (fewer ColBERT computations) and BETTER (combines keyword + semantic)
30
33
  */
31
34
  async search(
32
35
  query: string,
@@ -36,6 +39,7 @@ export class HybridSearch {
36
39
  bm25Weight?: number;
37
40
  semanticWeight?: number;
38
41
  graphWeight?: number;
42
+ useReranking?: boolean; // Use ColBERT to rerank BM25 results
39
43
  } = {}
40
44
  ): Promise<HybridSearchResult[]> {
41
45
  const {
@@ -44,18 +48,30 @@ export class HybridSearch {
44
48
  bm25Weight = 1.0,
45
49
  semanticWeight = 1.0,
46
50
  graphWeight = 0.5,
51
+ useReranking = true, // Default: reranking mode for better quality
47
52
  } = options;
48
53
 
49
54
  // Fetch more candidates than needed for fusion
50
55
  const candidateLimit = Math.max(limit * 3, 30);
51
56
 
52
- // Run searches in parallel
53
- const [bm25Results, semanticResults, graphMemoryIds] = await Promise.all([
57
+ // Run BM25 and graph search in parallel (fast)
58
+ const [bm25Results, graphMemoryIds] = await Promise.all([
54
59
  this.searchBM25(query, candidateLimit),
55
- this.searchSemantic(query, candidateLimit),
56
60
  includeGraph ? this.searchGraph(query) : Promise.resolve([]),
57
61
  ]);
58
62
 
63
+ // For semantic: either rerank BM25 results (faster+better) or search full index
64
+ let semanticResults: Array<{ id: string; score: number }>;
65
+ if (useReranking && bm25Results.length > 0) {
66
+ // Rerank BM25 candidates with ColBERT - faster AND better quality
67
+ const docs = bm25Results.map(r => ({ id: r.id, content: this.db.getMemory(r.id)?.content || '' }));
68
+ const reranked = await this.retriever.rerank(query, docs, candidateLimit);
69
+ semanticResults = reranked.map(r => ({ id: r.id, score: r.score }));
70
+ } else {
71
+ // Full semantic search
72
+ semanticResults = await this.searchSemantic(query, candidateLimit);
73
+ }
74
+
59
75
  // Fetch graph memories
60
76
  const graphMemories = graphMemoryIds.length > 0
61
77
  ? graphMemoryIds.map(id => this.db.getMemory(id)).filter(Boolean) as Memory[]