@199-bio/engram 0.4.0 → 0.4.2
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/dist/graph/index.d.ts.map +1 -1
- package/dist/graph/knowledge-graph.d.ts.map +1 -1
- package/dist/index.js +54 -14
- package/dist/retrieval/hybrid.d.ts.map +1 -1
- package/dist/storage/database.d.ts.map +1 -1
- package/dist/web/chat-handler.d.ts.map +1 -0
- package/dist/web/server.d.ts.map +1 -1
- package/package.json +2 -1
- package/src/graph/index.ts +0 -1
- package/src/graph/knowledge-graph.ts +0 -50
- package/src/index.ts +62 -14
- package/src/retrieval/hybrid.ts +8 -5
- package/src/storage/database.ts +12 -0
- package/src/web/chat-handler.ts +472 -0
- package/src/web/server.ts +40 -3
- package/src/web/static/app.js +137 -0
- package/src/web/static/index.html +28 -0
- package/src/web/static/style.css +202 -0
- package/src/graph/extractor.ts +0 -489
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/graph/index.ts"],"names":[],"mappings":"AAAA,cAAc,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/graph/index.ts"],"names":[],"mappings":"AAAA,cAAc,sBAAsB,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"knowledge-graph.d.ts","sourceRoot":"","sources":["../../src/graph/knowledge-graph.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EACL,cAAc,EACd,MAAM,EACN,WAAW,EACX,QAAQ,EACT,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"knowledge-graph.d.ts","sourceRoot":"","sources":["../../src/graph/knowledge-graph.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EACL,cAAc,EACd,MAAM,EACN,WAAW,EACX,QAAQ,EACT,MAAM,wBAAwB,CAAC;AAEhC,MAAM,WAAW,iBAAkB,SAAQ,MAAM;IAC/C,YAAY,EAAE,WAAW,EAAE,CAAC;IAC5B,aAAa,EAAE,KAAK,CAAC,QAAQ,GAAG;QAAE,YAAY,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC1D,WAAW,EAAE,KAAK,CAAC,QAAQ,GAAG;QAAE,YAAY,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACzD;AAED,MAAM,WAAW,cAAc;IAC7B,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,SAAS,EAAE,QAAQ,EAAE,CAAC;IACtB,YAAY,EAAE,WAAW,EAAE,CAAC;CAC7B;AAED,qBAAa,cAAc;IACb,OAAO,CAAC,EAAE;gBAAF,EAAE,EAAE,cAAc;IAItC;;OAEG;IACH,iBAAiB,CACf,IAAI,EAAE,MAAM,EACZ,IAAI,GAAE,MAAM,CAAC,MAAM,CAAY,GAC9B,MAAM;IAMT;;OAEG;IACH,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,iBAAiB,GAAG,IAAI;IAoC5D;;OAEG;IACH,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,CAAC,GAAG,MAAM,EAAE;IAI5D;;OAEG;IACH,YAAY,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,CAAC,EAAE,KAAK,GAAE,MAAY,GAAG,MAAM,EAAE;IAMlE;;OAEG;IACH,cAAc,CACZ,cAAc,EAAE,MAAM,EACtB,OAAO,EAAE,MAAM,EACf,cAAc,CAAC,EAAE,MAAM,EACvB,UAAU,GAAE,MAAY,GACvB,WAAW;IAWd;;OAEG;IACH,eAAe,CAAC,cAAc,EAAE,MAAM,GAAG,WAAW,EAAE;IAWtD;;OAEG;IACH,MAAM,CACJ,YAAY,EAAE,MAAM,EACpB,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,MAAM,EACZ,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GACnC,QAAQ;IAgBX;;OAEG;IACH,YAAY,CACV,cAAc,EAAE,MAAM,EACtB,SAAS,GAAE,MAAM,GAAG,IAAI,GAAG,MAAe,GACzC,QAAQ,EAAE;IAWb;;OAEG;IACH,QAAQ,CACN,cAAc,EAAE,MAAM,EACtB,KAAK,GAAE,MAAU,EACjB,aAAa,CAAC,EAAE,MAAM,EAAE,GACvB,cAAc,GAAG,IAAI;IAcxB;;OAEG;IACH,oBAAoB,CAClB,cAAc,EAAE,MAAM,EACtB,KAAK,GAAE,MAAU,GAChB,MAAM,EAAE;CAcZ"}
|
package/dist/index.js
CHANGED
|
@@ -42,7 +42,7 @@ async function initialize() {
|
|
|
42
42
|
// ============ MCP Server ============
|
|
43
43
|
const server = new Server({
|
|
44
44
|
name: "engram",
|
|
45
|
-
version: "0.4.
|
|
45
|
+
version: "0.4.2",
|
|
46
46
|
}, {
|
|
47
47
|
capabilities: {
|
|
48
48
|
tools: {},
|
|
@@ -53,26 +53,46 @@ const server = new Server({
|
|
|
53
53
|
const TOOLS = [
|
|
54
54
|
{
|
|
55
55
|
name: "remember",
|
|
56
|
-
description: "
|
|
56
|
+
description: "Store information with entities and relationships. Extract key people, organizations, and places from the content and pass them as entities. Include relationships between entities when mentioned (e.g., 'works_at', 'lives_in', 'knows').",
|
|
57
57
|
inputSchema: {
|
|
58
58
|
type: "object",
|
|
59
59
|
properties: {
|
|
60
60
|
content: {
|
|
61
61
|
type: "string",
|
|
62
|
-
description: "The information to store
|
|
63
|
-
},
|
|
64
|
-
source: {
|
|
65
|
-
type: "string",
|
|
66
|
-
description: "Source of the memory (e.g., 'conversation', 'note', 'import')",
|
|
67
|
-
default: "conversation",
|
|
62
|
+
description: "The information to store",
|
|
68
63
|
},
|
|
69
64
|
importance: {
|
|
70
65
|
type: "number",
|
|
71
|
-
description: "
|
|
66
|
+
description: "0-1 score. Use 0.8+ for key facts (names, preferences, important events), 0.5 for general info, 0.3- for trivial mentions",
|
|
72
67
|
minimum: 0,
|
|
73
68
|
maximum: 1,
|
|
74
69
|
default: 0.5,
|
|
75
70
|
},
|
|
71
|
+
entities: {
|
|
72
|
+
type: "array",
|
|
73
|
+
description: "Key entities mentioned (people, organizations, places). Only include clear, specific named entities.",
|
|
74
|
+
items: {
|
|
75
|
+
type: "object",
|
|
76
|
+
properties: {
|
|
77
|
+
name: { type: "string", description: "Entity name (e.g., 'Boris Djordjevic', 'Google', 'Paris')" },
|
|
78
|
+
type: { type: "string", enum: ["person", "organization", "place"], description: "Entity type" },
|
|
79
|
+
},
|
|
80
|
+
required: ["name", "type"],
|
|
81
|
+
},
|
|
82
|
+
},
|
|
83
|
+
relationships: {
|
|
84
|
+
type: "array",
|
|
85
|
+
description: "Relationships between entities mentioned in the content",
|
|
86
|
+
items: {
|
|
87
|
+
type: "object",
|
|
88
|
+
properties: {
|
|
89
|
+
from: { type: "string", description: "Source entity name" },
|
|
90
|
+
to: { type: "string", description: "Target entity name" },
|
|
91
|
+
type: { type: "string", description: "Relationship type (e.g., 'works_at', 'lives_in', 'sibling_of', 'knows')" },
|
|
92
|
+
},
|
|
93
|
+
required: ["from", "to", "type"],
|
|
94
|
+
},
|
|
95
|
+
},
|
|
76
96
|
},
|
|
77
97
|
required: ["content"],
|
|
78
98
|
},
|
|
@@ -168,13 +188,33 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
168
188
|
try {
|
|
169
189
|
switch (name) {
|
|
170
190
|
case "remember": {
|
|
171
|
-
const { content, source = "conversation", importance = 0.5 } = args;
|
|
191
|
+
const { content, source = "conversation", importance = 0.5, entities: providedEntities = [], relationships: providedRelationships = [], } = args;
|
|
172
192
|
// Create memory
|
|
173
193
|
const memory = db.createMemory(content, source, importance);
|
|
174
194
|
// Index for semantic search
|
|
175
195
|
await search.indexMemory(memory);
|
|
176
|
-
//
|
|
177
|
-
const
|
|
196
|
+
// Store Claude-provided entities and link to memory
|
|
197
|
+
const storedEntities = [];
|
|
198
|
+
for (const ent of providedEntities) {
|
|
199
|
+
const entity = graph.getOrCreateEntity(ent.name, ent.type);
|
|
200
|
+
storedEntities.push(entity.name);
|
|
201
|
+
// Create observation linking entity to this memory
|
|
202
|
+
db.addObservation(entity.id, content, memory.id, 1.0);
|
|
203
|
+
}
|
|
204
|
+
// Store Claude-provided relationships
|
|
205
|
+
const storedRelations = [];
|
|
206
|
+
for (const rel of providedRelationships) {
|
|
207
|
+
try {
|
|
208
|
+
// Ensure both entities exist (create if not provided explicitly)
|
|
209
|
+
const fromEntity = graph.getOrCreateEntity(rel.from, "person");
|
|
210
|
+
const toEntity = graph.getOrCreateEntity(rel.to, "person");
|
|
211
|
+
graph.relate(fromEntity.name, toEntity.name, rel.type);
|
|
212
|
+
storedRelations.push(`${rel.from} -[${rel.type}]-> ${rel.to}`);
|
|
213
|
+
}
|
|
214
|
+
catch {
|
|
215
|
+
// Skip invalid relationships
|
|
216
|
+
}
|
|
217
|
+
}
|
|
178
218
|
return {
|
|
179
219
|
content: [
|
|
180
220
|
{
|
|
@@ -182,8 +222,8 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
182
222
|
text: JSON.stringify({
|
|
183
223
|
success: true,
|
|
184
224
|
memory_id: memory.id,
|
|
185
|
-
|
|
186
|
-
|
|
225
|
+
entities_stored: storedEntities,
|
|
226
|
+
relationships_stored: storedRelations,
|
|
187
227
|
}, null, 2),
|
|
188
228
|
},
|
|
189
229
|
],
|
|
@@ -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;
|
|
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;AAEzF,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;IAmBzB;;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":"chat-handler.d.ts","sourceRoot":"","sources":["../../src/web/chat-handler.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,cAAc,EAAkB,MAAM,wBAAwB,CAAC;AACxE,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAC7D,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAiLtD,qBAAa,WAAW;IACtB,OAAO,CAAC,MAAM,CAA0B;IACxC,OAAO,CAAC,EAAE,CAAiB;IAC3B,OAAO,CAAC,KAAK,CAAiB;IAC9B,OAAO,CAAC,MAAM,CAAe;IAC7B,OAAO,CAAC,mBAAmB,CAAgC;gBAE/C,OAAO,EAAE;QACnB,EAAE,EAAE,cAAc,CAAC;QACnB,KAAK,EAAE,cAAc,CAAC;QACtB,MAAM,EAAE,YAAY,CAAC;KACtB;IAWD,YAAY,IAAI,OAAO;IAIvB,YAAY,IAAI,IAAI;IAId,IAAI,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;YAgFlC,WAAW;CAgL1B"}
|
package/dist/web/server.d.ts.map
CHANGED
|
@@ -1 +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;
|
|
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,CAAc;IAC1B,OAAO,CAAC,IAAI,CAAS;gBAET,OAAO,EAAE,gBAAgB;IAY/B,KAAK,IAAI,OAAO,CAAC,MAAM,CAAC;IAkB9B,IAAI,IAAI,IAAI;YAOE,aAAa;YA+Bb,SAAS;YAwMT,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.4.
|
|
3
|
+
"version": "0.4.2",
|
|
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,6 +46,7 @@
|
|
|
46
46
|
"node": ">=18.0.0"
|
|
47
47
|
},
|
|
48
48
|
"dependencies": {
|
|
49
|
+
"@anthropic-ai/sdk": "^0.71.2",
|
|
49
50
|
"@modelcontextprotocol/sdk": "^1.25.0",
|
|
50
51
|
"better-sqlite3": "^11.10.0",
|
|
51
52
|
"chrono-node": "^2.7.0",
|
package/src/graph/index.ts
CHANGED
|
@@ -9,7 +9,6 @@ import {
|
|
|
9
9
|
Observation,
|
|
10
10
|
Relation,
|
|
11
11
|
} from "../storage/database.js";
|
|
12
|
-
import { entityExtractor, ExtractedEntity } from "./extractor.js";
|
|
13
12
|
|
|
14
13
|
export interface EntityWithDetails extends Entity {
|
|
15
14
|
observations: Observation[];
|
|
@@ -191,55 +190,6 @@ export class KnowledgeGraph {
|
|
|
191
190
|
};
|
|
192
191
|
}
|
|
193
192
|
|
|
194
|
-
// ============ Auto-extraction ============
|
|
195
|
-
|
|
196
|
-
/**
|
|
197
|
-
* Extract entities from text and add them to the graph
|
|
198
|
-
*/
|
|
199
|
-
extractAndStore(
|
|
200
|
-
text: string,
|
|
201
|
-
sourceMemoryId?: string
|
|
202
|
-
): { entities: Entity[]; observations: Observation[] } {
|
|
203
|
-
const extracted = entityExtractor.extractAll(text);
|
|
204
|
-
const entities: Entity[] = [];
|
|
205
|
-
const observations: Observation[] = [];
|
|
206
|
-
|
|
207
|
-
for (const ext of extracted) {
|
|
208
|
-
// Only store high-confidence extractions
|
|
209
|
-
if (ext.confidence < 0.5) continue;
|
|
210
|
-
|
|
211
|
-
// Get or create entity
|
|
212
|
-
const entity = this.getOrCreateEntity(ext.name, ext.type);
|
|
213
|
-
entities.push(entity);
|
|
214
|
-
|
|
215
|
-
// Create observation linking this entity to the memory content
|
|
216
|
-
const obs = this.db.addObservation(
|
|
217
|
-
entity.id,
|
|
218
|
-
text,
|
|
219
|
-
sourceMemoryId || null,
|
|
220
|
-
ext.confidence
|
|
221
|
-
);
|
|
222
|
-
observations.push(obs);
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
// Extract and create relationships
|
|
226
|
-
const relationships = entityExtractor.extractRelationships(text);
|
|
227
|
-
for (const rel of relationships) {
|
|
228
|
-
try {
|
|
229
|
-
// Ensure both entities exist
|
|
230
|
-
const fromEntity = this.getOrCreateEntity(rel.subject, "person");
|
|
231
|
-
const toEntity = this.getOrCreateEntity(rel.object, "person");
|
|
232
|
-
|
|
233
|
-
// Create the relation
|
|
234
|
-
this.db.createRelation(fromEntity.id, toEntity.id, rel.relation);
|
|
235
|
-
} catch {
|
|
236
|
-
// Silently ignore relation creation failures
|
|
237
|
-
}
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
return { entities, observations };
|
|
241
|
-
}
|
|
242
|
-
|
|
243
193
|
/**
|
|
244
194
|
* Find memories related to an entity by traversing the graph
|
|
245
195
|
*/
|
package/src/index.ts
CHANGED
|
@@ -60,7 +60,7 @@ async function initialize(): Promise<void> {
|
|
|
60
60
|
const server = new Server(
|
|
61
61
|
{
|
|
62
62
|
name: "engram",
|
|
63
|
-
version: "0.4.
|
|
63
|
+
version: "0.4.2",
|
|
64
64
|
},
|
|
65
65
|
{
|
|
66
66
|
capabilities: {
|
|
@@ -75,26 +75,46 @@ const TOOLS = [
|
|
|
75
75
|
{
|
|
76
76
|
name: "remember",
|
|
77
77
|
description:
|
|
78
|
-
"
|
|
78
|
+
"Store information with entities and relationships. Extract key people, organizations, and places from the content and pass them as entities. Include relationships between entities when mentioned (e.g., 'works_at', 'lives_in', 'knows').",
|
|
79
79
|
inputSchema: {
|
|
80
80
|
type: "object" as const,
|
|
81
81
|
properties: {
|
|
82
82
|
content: {
|
|
83
83
|
type: "string",
|
|
84
|
-
description: "The information to store
|
|
85
|
-
},
|
|
86
|
-
source: {
|
|
87
|
-
type: "string",
|
|
88
|
-
description: "Source of the memory (e.g., 'conversation', 'note', 'import')",
|
|
89
|
-
default: "conversation",
|
|
84
|
+
description: "The information to store",
|
|
90
85
|
},
|
|
91
86
|
importance: {
|
|
92
87
|
type: "number",
|
|
93
|
-
description: "
|
|
88
|
+
description: "0-1 score. Use 0.8+ for key facts (names, preferences, important events), 0.5 for general info, 0.3- for trivial mentions",
|
|
94
89
|
minimum: 0,
|
|
95
90
|
maximum: 1,
|
|
96
91
|
default: 0.5,
|
|
97
92
|
},
|
|
93
|
+
entities: {
|
|
94
|
+
type: "array",
|
|
95
|
+
description: "Key entities mentioned (people, organizations, places). Only include clear, specific named entities.",
|
|
96
|
+
items: {
|
|
97
|
+
type: "object",
|
|
98
|
+
properties: {
|
|
99
|
+
name: { type: "string", description: "Entity name (e.g., 'Boris Djordjevic', 'Google', 'Paris')" },
|
|
100
|
+
type: { type: "string", enum: ["person", "organization", "place"], description: "Entity type" },
|
|
101
|
+
},
|
|
102
|
+
required: ["name", "type"],
|
|
103
|
+
},
|
|
104
|
+
},
|
|
105
|
+
relationships: {
|
|
106
|
+
type: "array",
|
|
107
|
+
description: "Relationships between entities mentioned in the content",
|
|
108
|
+
items: {
|
|
109
|
+
type: "object",
|
|
110
|
+
properties: {
|
|
111
|
+
from: { type: "string", description: "Source entity name" },
|
|
112
|
+
to: { type: "string", description: "Target entity name" },
|
|
113
|
+
type: { type: "string", description: "Relationship type (e.g., 'works_at', 'lives_in', 'sibling_of', 'knows')" },
|
|
114
|
+
},
|
|
115
|
+
required: ["from", "to", "type"],
|
|
116
|
+
},
|
|
117
|
+
},
|
|
98
118
|
},
|
|
99
119
|
required: ["content"],
|
|
100
120
|
},
|
|
@@ -194,10 +214,18 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
194
214
|
try {
|
|
195
215
|
switch (name) {
|
|
196
216
|
case "remember": {
|
|
197
|
-
const {
|
|
217
|
+
const {
|
|
218
|
+
content,
|
|
219
|
+
source = "conversation",
|
|
220
|
+
importance = 0.5,
|
|
221
|
+
entities: providedEntities = [],
|
|
222
|
+
relationships: providedRelationships = [],
|
|
223
|
+
} = args as {
|
|
198
224
|
content: string;
|
|
199
225
|
source?: string;
|
|
200
226
|
importance?: number;
|
|
227
|
+
entities?: Array<{ name: string; type: "person" | "organization" | "place" }>;
|
|
228
|
+
relationships?: Array<{ from: string; to: string; type: string }>;
|
|
201
229
|
};
|
|
202
230
|
|
|
203
231
|
// Create memory
|
|
@@ -206,8 +234,28 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
206
234
|
// Index for semantic search
|
|
207
235
|
await search.indexMemory(memory);
|
|
208
236
|
|
|
209
|
-
//
|
|
210
|
-
const
|
|
237
|
+
// Store Claude-provided entities and link to memory
|
|
238
|
+
const storedEntities: string[] = [];
|
|
239
|
+
for (const ent of providedEntities) {
|
|
240
|
+
const entity = graph.getOrCreateEntity(ent.name, ent.type);
|
|
241
|
+
storedEntities.push(entity.name);
|
|
242
|
+
// Create observation linking entity to this memory
|
|
243
|
+
db.addObservation(entity.id, content, memory.id, 1.0);
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
// Store Claude-provided relationships
|
|
247
|
+
const storedRelations: string[] = [];
|
|
248
|
+
for (const rel of providedRelationships) {
|
|
249
|
+
try {
|
|
250
|
+
// Ensure both entities exist (create if not provided explicitly)
|
|
251
|
+
const fromEntity = graph.getOrCreateEntity(rel.from, "person");
|
|
252
|
+
const toEntity = graph.getOrCreateEntity(rel.to, "person");
|
|
253
|
+
graph.relate(fromEntity.name, toEntity.name, rel.type);
|
|
254
|
+
storedRelations.push(`${rel.from} -[${rel.type}]-> ${rel.to}`);
|
|
255
|
+
} catch {
|
|
256
|
+
// Skip invalid relationships
|
|
257
|
+
}
|
|
258
|
+
}
|
|
211
259
|
|
|
212
260
|
return {
|
|
213
261
|
content: [
|
|
@@ -216,8 +264,8 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
216
264
|
text: JSON.stringify({
|
|
217
265
|
success: true,
|
|
218
266
|
memory_id: memory.id,
|
|
219
|
-
|
|
220
|
-
|
|
267
|
+
entities_stored: storedEntities,
|
|
268
|
+
relationships_stored: storedRelations,
|
|
221
269
|
}, null, 2),
|
|
222
270
|
},
|
|
223
271
|
],
|
package/src/retrieval/hybrid.ts
CHANGED
|
@@ -6,7 +6,6 @@
|
|
|
6
6
|
import { EngramDatabase, Memory } from "../storage/database.js";
|
|
7
7
|
import { KnowledgeGraph } from "../graph/knowledge-graph.js";
|
|
8
8
|
import { ColBERTRetriever, SimpleRetriever, SearchResult, Document } from "./colbert.js";
|
|
9
|
-
import { entityExtractor } from "../graph/extractor.js";
|
|
10
9
|
|
|
11
10
|
export interface HybridSearchResult {
|
|
12
11
|
memory: Memory;
|
|
@@ -183,15 +182,19 @@ export class HybridSearch {
|
|
|
183
182
|
}
|
|
184
183
|
|
|
185
184
|
/**
|
|
186
|
-
* Graph-based search: find entities in query, traverse graph
|
|
185
|
+
* Graph-based search: find known entities in query, traverse graph
|
|
187
186
|
*/
|
|
188
187
|
private async searchGraph(query: string): Promise<string[]> {
|
|
189
|
-
//
|
|
190
|
-
const
|
|
188
|
+
// Find known entities whose names appear in the query
|
|
189
|
+
const queryLower = query.toLowerCase();
|
|
190
|
+
const allEntities = this.graph.listEntities(undefined, 500);
|
|
191
|
+
const matchedEntities = allEntities.filter(e =>
|
|
192
|
+
queryLower.includes(e.name.toLowerCase())
|
|
193
|
+
);
|
|
191
194
|
|
|
192
195
|
const memoryIds = new Set<string>();
|
|
193
196
|
|
|
194
|
-
for (const entity of
|
|
197
|
+
for (const entity of matchedEntities) {
|
|
195
198
|
// Find related memory IDs through graph traversal
|
|
196
199
|
const relatedIds = this.graph.findRelatedMemoryIds(entity.name, 2);
|
|
197
200
|
relatedIds.forEach(id => memoryIds.add(id));
|
package/src/storage/database.ts
CHANGED
|
@@ -471,6 +471,18 @@ export class EngramDatabase {
|
|
|
471
471
|
return result.changes > 0;
|
|
472
472
|
}
|
|
473
473
|
|
|
474
|
+
updateEntity(id: string, updates: { name?: string; type?: Entity["type"] }): Entity | null {
|
|
475
|
+
const entity = this.getEntity(id);
|
|
476
|
+
if (!entity) return null;
|
|
477
|
+
|
|
478
|
+
const newName = updates.name ?? entity.name;
|
|
479
|
+
const newType = updates.type ?? entity.type;
|
|
480
|
+
|
|
481
|
+
const stmt = this.db.prepare("UPDATE entities SET name = ?, type = ? WHERE id = ?");
|
|
482
|
+
stmt.run(newName, newType, id);
|
|
483
|
+
return this.getEntity(id);
|
|
484
|
+
}
|
|
485
|
+
|
|
474
486
|
// ============ Observation Operations ============
|
|
475
487
|
|
|
476
488
|
addObservation(
|