@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 +5 -4
- package/dist/index.js +108 -2
- package/dist/retrieval/hybrid.d.ts.map +1 -1
- package/dist/storage/database.d.ts.map +1 -1
- package/dist/web/server.d.ts.map +1 -0
- package/package.json +4 -4
- package/src/index.ts +112 -2
- package/src/retrieval/hybrid.ts +19 -3
- package/src/storage/database.ts +41 -30
- package/src/web/server.ts +280 -0
- package/src/web/static/app.js +362 -0
- package/src/web/static/index.html +95 -0
- package/src/web/static/style.css +457 -0
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
|
|
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
|
|
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": "
|
|
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.
|
|
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
|
|
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":"AAAA;;;GAGG;AAOH,MAAM,WAAW,MAAM;IACrB,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,IAAI,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,EAAE,IAAI,GAAG,IAAI,CAAC;CAC5B;AAED,MAAM,WAAW,MAAM;IACrB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,QAAQ,GAAG,OAAO,GAAG,SAAS,GAAG,OAAO,GAAG,cAAc,CAAC;IAChE,UAAU,EAAE,IAAI,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;CAC1C;AAED,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,IAAI,CAAC;IACjB,WAAW,EAAE,IAAI,GAAG,IAAI,CAAC;CAC1B;AAED,MAAM,WAAW,QAAQ;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IAC3C,UAAU,EAAE,IAAI,CAAC;CAClB;AAED,qBAAa,cAAc;IACzB,OAAO,CAAC,EAAE,CAAoB;
|
|
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.
|
|
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.
|
|
50
|
-
"better-sqlite3": "^11.
|
|
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.
|
|
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.
|
|
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
|
}
|
package/src/retrieval/hybrid.ts
CHANGED
|
@@ -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
|
|
53
|
-
const [bm25Results,
|
|
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[]
|