@199-bio/engram 0.3.0 → 0.3.1
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/index.js +14 -13
- package/dist/storage/database.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/index.ts +14 -13
- package/src/storage/database.ts +130 -2
package/dist/index.js
CHANGED
|
@@ -42,23 +42,24 @@ async function initialize() {
|
|
|
42
42
|
// ============ MCP Server ============
|
|
43
43
|
const server = new Server({
|
|
44
44
|
name: "engram",
|
|
45
|
-
version: "0.3.
|
|
45
|
+
version: "0.3.1",
|
|
46
46
|
}, {
|
|
47
47
|
capabilities: {
|
|
48
48
|
tools: {},
|
|
49
49
|
},
|
|
50
50
|
});
|
|
51
51
|
// Tool definitions with MCP 2025-06-18 annotations
|
|
52
|
+
// Descriptions are carefully written to guide Claude on when to use each tool
|
|
52
53
|
const TOOLS = [
|
|
53
54
|
{
|
|
54
55
|
name: "remember",
|
|
55
|
-
description: "
|
|
56
|
+
description: "PRIMARY STORAGE TOOL. Use this for ALL new information - conversations, facts, observations, notes. Automatically extracts people, organizations, and places as entities and creates relationships. Do NOT also call create_entity/observe/relate - remember handles entity extraction automatically. Only use remember once per piece of information.",
|
|
56
57
|
inputSchema: {
|
|
57
58
|
type: "object",
|
|
58
59
|
properties: {
|
|
59
60
|
content: {
|
|
60
61
|
type: "string",
|
|
61
|
-
description: "The
|
|
62
|
+
description: "The information to store - can be a conversation snippet, fact, observation, or note",
|
|
62
63
|
},
|
|
63
64
|
source: {
|
|
64
65
|
type: "string",
|
|
@@ -67,7 +68,7 @@ const TOOLS = [
|
|
|
67
68
|
},
|
|
68
69
|
importance: {
|
|
69
70
|
type: "number",
|
|
70
|
-
description: "Importance score from 0 to 1 (higher = more important)",
|
|
71
|
+
description: "Importance score from 0 to 1 (higher = more important). Use 0.7+ for key facts, 0.3- for casual mentions",
|
|
71
72
|
minimum: 0,
|
|
72
73
|
maximum: 1,
|
|
73
74
|
default: 0.5,
|
|
@@ -85,7 +86,7 @@ const TOOLS = [
|
|
|
85
86
|
},
|
|
86
87
|
{
|
|
87
88
|
name: "recall",
|
|
88
|
-
description: "
|
|
89
|
+
description: "PRIMARY SEARCH TOOL. Use this FIRST when answering any question about stored information. Searches across all memories using semantic understanding, keywords, and knowledge graph connections. Returns relevant memories with context.",
|
|
89
90
|
inputSchema: {
|
|
90
91
|
type: "object",
|
|
91
92
|
properties: {
|
|
@@ -116,7 +117,7 @@ const TOOLS = [
|
|
|
116
117
|
},
|
|
117
118
|
{
|
|
118
119
|
name: "forget",
|
|
119
|
-
description: "
|
|
120
|
+
description: "Delete a specific memory by its ID. Use only when explicitly asked to remove information.",
|
|
120
121
|
inputSchema: {
|
|
121
122
|
type: "object",
|
|
122
123
|
properties: {
|
|
@@ -137,13 +138,13 @@ const TOOLS = [
|
|
|
137
138
|
},
|
|
138
139
|
{
|
|
139
140
|
name: "create_entity",
|
|
140
|
-
description: "
|
|
141
|
+
description: "ADVANCED: Manually create an entity. Rarely needed - remember auto-extracts entities. Only use when: (1) creating an entity that won't appear in any memory content, or (2) correcting entity type after auto-extraction.",
|
|
141
142
|
inputSchema: {
|
|
142
143
|
type: "object",
|
|
143
144
|
properties: {
|
|
144
145
|
name: {
|
|
145
146
|
type: "string",
|
|
146
|
-
description: "Entity name (e.g., 'John', 'Paris', 'Machine Learning')",
|
|
147
|
+
description: "Entity name (e.g., 'John Smith', 'Paris', 'Machine Learning')",
|
|
147
148
|
},
|
|
148
149
|
type: {
|
|
149
150
|
type: "string",
|
|
@@ -163,13 +164,13 @@ const TOOLS = [
|
|
|
163
164
|
},
|
|
164
165
|
{
|
|
165
166
|
name: "observe",
|
|
166
|
-
description: "Add an
|
|
167
|
+
description: "ADVANCED: Add a fact to an EXISTING entity without creating a memory. Rarely needed - use remember instead, which stores the content AND links it to entities. Only use observe for adding metadata or corrections to entities.",
|
|
167
168
|
inputSchema: {
|
|
168
169
|
type: "object",
|
|
169
170
|
properties: {
|
|
170
171
|
entity: {
|
|
171
172
|
type: "string",
|
|
172
|
-
description: "Entity name to add observation to",
|
|
173
|
+
description: "Entity name to add observation to (must already exist)",
|
|
173
174
|
},
|
|
174
175
|
observation: {
|
|
175
176
|
type: "string",
|
|
@@ -193,7 +194,7 @@ const TOOLS = [
|
|
|
193
194
|
},
|
|
194
195
|
{
|
|
195
196
|
name: "relate",
|
|
196
|
-
description: "
|
|
197
|
+
description: "ADVANCED: Manually create a relationship between two entities. Rarely needed - remember auto-extracts relationships from text. Only use when: (1) the relationship wasn't captured by auto-extraction, or (2) you need to add a relationship not mentioned in any memory.",
|
|
197
198
|
inputSchema: {
|
|
198
199
|
type: "object",
|
|
199
200
|
properties: {
|
|
@@ -222,7 +223,7 @@ const TOOLS = [
|
|
|
222
223
|
},
|
|
223
224
|
{
|
|
224
225
|
name: "query_entity",
|
|
225
|
-
description: "Get
|
|
226
|
+
description: "Get all stored information about a specific person, place, or organization. Use after recall to get deeper details about an entity mentioned in search results.",
|
|
226
227
|
inputSchema: {
|
|
227
228
|
type: "object",
|
|
228
229
|
properties: {
|
|
@@ -243,7 +244,7 @@ const TOOLS = [
|
|
|
243
244
|
},
|
|
244
245
|
{
|
|
245
246
|
name: "list_entities",
|
|
246
|
-
description: "List all entities,
|
|
247
|
+
description: "List all known entities (people, places, organizations, etc.). Use to browse the knowledge graph or find entity names for query_entity.",
|
|
247
248
|
inputSchema: {
|
|
248
249
|
type: "object",
|
|
249
250
|
properties: {
|
|
@@ -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;IAC9B,OAAO,CAAC,SAAS,CAA8C;gBAEnD,MAAM,EAAE,MAAM;IAoB1B,OAAO,CAAC,UAAU;IAyFlB,YAAY,CACV,OAAO,EAAE,MAAM,EACf,MAAM,GAAE,MAAuB,EAC/B,UAAU,GAAE,MAAY,GACvB,MAAM;IAUT,SAAS,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAKpC,YAAY,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE,SAAS,GAAG,YAAY,CAAC,CAAC,GAAG,MAAM,GAAG,IAAI;IAqBjG,YAAY,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO;IAMjC,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI;IAI7B,cAAc,CAAC,KAAK,GAAE,MAAa,GAAG,MAAM,EAAE;IAO9C,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,GAAE,MAAW,GAAG,KAAK,CAAC,MAAM,GAAG;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IAkBhF,OAAO,CAAC,eAAe;IAavB,YAAY,CACV,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,CAAC,MAAM,CAAC,EACpB,QAAQ,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAW,GAC9C,MAAM;IAUT,SAAS,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAKpC,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;
|
|
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;IAC9B,OAAO,CAAC,SAAS,CAA8C;gBAEnD,MAAM,EAAE,MAAM;IAoB1B,OAAO,CAAC,UAAU;IAyFlB,YAAY,CACV,OAAO,EAAE,MAAM,EACf,MAAM,GAAE,MAAuB,EAC/B,UAAU,GAAE,MAAY,GACvB,MAAM;IAUT,SAAS,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAKpC,YAAY,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE,SAAS,GAAG,YAAY,CAAC,CAAC,GAAG,MAAM,GAAG,IAAI;IAqBjG,YAAY,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO;IAMjC,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI;IAI7B,cAAc,CAAC,KAAK,GAAE,MAAa,GAAG,MAAM,EAAE;IAO9C,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,GAAE,MAAW,GAAG,KAAK,CAAC,MAAM,GAAG;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IAkBhF,OAAO,CAAC,eAAe;IAavB,YAAY,CACV,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,CAAC,MAAM,CAAC,EACpB,QAAQ,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAW,GAC9C,MAAM;IAUT,SAAS,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAKpC,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAU7C;;;OAGG;IACH,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,GAAE,MAAY,GAAG,MAAM,GAAG,IAAI;IA+BvE;;;OAGG;IACH,OAAO,CAAC,uBAAuB;IA4C/B;;OAEG;IACH,qBAAqB,IAAI,KAAK,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,mBAAmB,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC;IAoCjF,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,CAAC,GAAG,MAAM,EAAE;IAgB9D,YAAY,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,CAAC,EAAE,KAAK,GAAE,MAAY,GAAG,MAAM,EAAE;IAiBlE,YAAY,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO;IAQjC,cAAc,CACZ,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,EACf,cAAc,GAAE,MAAM,GAAG,IAAW,EACpC,UAAU,GAAE,MAAY,GACvB,WAAW;IAUd,cAAc,CAAC,EAAE,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI;IAK9C,qBAAqB,CAAC,QAAQ,EAAE,MAAM,EAAE,cAAc,GAAE,OAAe,GAAG,WAAW,EAAE;IAYvF,iBAAiB,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI;IAOnC,cAAc,CACZ,YAAY,EAAE,MAAM,EACpB,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,MAAM,EACZ,UAAU,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAW,GAChD,QAAQ;IAUX,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,QAAQ,GAAG,IAAI;IAKxC,kBAAkB,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,GAAE,MAAM,GAAG,IAAI,GAAG,MAAe,GAAG,QAAQ,EAAE;IAiB5F,YAAY,CAAC,YAAY,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,QAAQ,GAAG,IAAI;IActF,cAAc,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO;IAQnC,QAAQ,CACN,aAAa,EAAE,MAAM,EACrB,KAAK,GAAE,MAAU,EACjB,aAAa,CAAC,EAAE,MAAM,EAAE,GACvB;QAAE,QAAQ,EAAE,MAAM,EAAE,CAAC;QAAC,SAAS,EAAE,QAAQ,EAAE,CAAC;QAAC,YAAY,EAAE,WAAW,EAAE,CAAA;KAAE;IA2C7E,QAAQ,IAAI;QACV,QAAQ,EAAE,MAAM,CAAC;QACjB,QAAQ,EAAE,MAAM,CAAC;QACjB,SAAS,EAAE,MAAM,CAAC;QAClB,YAAY,EAAE,MAAM,CAAC;KACtB;IAeD,KAAK,IAAI,IAAI;IAIb;;OAEG;IACH,OAAO,CAAC,IAAI;IASZ,OAAO,CAAC,WAAW;IAYnB,OAAO,CAAC,WAAW;IAUnB,OAAO,CAAC,gBAAgB;IAYxB,OAAO,CAAC,aAAa;CAUtB"}
|
package/package.json
CHANGED
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.3.
|
|
63
|
+
version: "0.3.1",
|
|
64
64
|
},
|
|
65
65
|
{
|
|
66
66
|
capabilities: {
|
|
@@ -70,17 +70,18 @@ const server = new Server(
|
|
|
70
70
|
);
|
|
71
71
|
|
|
72
72
|
// Tool definitions with MCP 2025-06-18 annotations
|
|
73
|
+
// Descriptions are carefully written to guide Claude on when to use each tool
|
|
73
74
|
const TOOLS = [
|
|
74
75
|
{
|
|
75
76
|
name: "remember",
|
|
76
77
|
description:
|
|
77
|
-
"
|
|
78
|
+
"PRIMARY STORAGE TOOL. Use this for ALL new information - conversations, facts, observations, notes. Automatically extracts people, organizations, and places as entities and creates relationships. Do NOT also call create_entity/observe/relate - remember handles entity extraction automatically. Only use remember once per piece of information.",
|
|
78
79
|
inputSchema: {
|
|
79
80
|
type: "object" as const,
|
|
80
81
|
properties: {
|
|
81
82
|
content: {
|
|
82
83
|
type: "string",
|
|
83
|
-
description: "The
|
|
84
|
+
description: "The information to store - can be a conversation snippet, fact, observation, or note",
|
|
84
85
|
},
|
|
85
86
|
source: {
|
|
86
87
|
type: "string",
|
|
@@ -89,7 +90,7 @@ const TOOLS = [
|
|
|
89
90
|
},
|
|
90
91
|
importance: {
|
|
91
92
|
type: "number",
|
|
92
|
-
description: "Importance score from 0 to 1 (higher = more important)",
|
|
93
|
+
description: "Importance score from 0 to 1 (higher = more important). Use 0.7+ for key facts, 0.3- for casual mentions",
|
|
93
94
|
minimum: 0,
|
|
94
95
|
maximum: 1,
|
|
95
96
|
default: 0.5,
|
|
@@ -108,7 +109,7 @@ const TOOLS = [
|
|
|
108
109
|
{
|
|
109
110
|
name: "recall",
|
|
110
111
|
description:
|
|
111
|
-
"
|
|
112
|
+
"PRIMARY SEARCH TOOL. Use this FIRST when answering any question about stored information. Searches across all memories using semantic understanding, keywords, and knowledge graph connections. Returns relevant memories with context.",
|
|
112
113
|
inputSchema: {
|
|
113
114
|
type: "object" as const,
|
|
114
115
|
properties: {
|
|
@@ -139,7 +140,7 @@ const TOOLS = [
|
|
|
139
140
|
},
|
|
140
141
|
{
|
|
141
142
|
name: "forget",
|
|
142
|
-
description: "
|
|
143
|
+
description: "Delete a specific memory by its ID. Use only when explicitly asked to remove information.",
|
|
143
144
|
inputSchema: {
|
|
144
145
|
type: "object" as const,
|
|
145
146
|
properties: {
|
|
@@ -160,13 +161,13 @@ const TOOLS = [
|
|
|
160
161
|
},
|
|
161
162
|
{
|
|
162
163
|
name: "create_entity",
|
|
163
|
-
description: "
|
|
164
|
+
description: "ADVANCED: Manually create an entity. Rarely needed - remember auto-extracts entities. Only use when: (1) creating an entity that won't appear in any memory content, or (2) correcting entity type after auto-extraction.",
|
|
164
165
|
inputSchema: {
|
|
165
166
|
type: "object" as const,
|
|
166
167
|
properties: {
|
|
167
168
|
name: {
|
|
168
169
|
type: "string",
|
|
169
|
-
description: "Entity name (e.g., 'John', 'Paris', 'Machine Learning')",
|
|
170
|
+
description: "Entity name (e.g., 'John Smith', 'Paris', 'Machine Learning')",
|
|
170
171
|
},
|
|
171
172
|
type: {
|
|
172
173
|
type: "string",
|
|
@@ -186,13 +187,13 @@ const TOOLS = [
|
|
|
186
187
|
},
|
|
187
188
|
{
|
|
188
189
|
name: "observe",
|
|
189
|
-
description: "Add an
|
|
190
|
+
description: "ADVANCED: Add a fact to an EXISTING entity without creating a memory. Rarely needed - use remember instead, which stores the content AND links it to entities. Only use observe for adding metadata or corrections to entities.",
|
|
190
191
|
inputSchema: {
|
|
191
192
|
type: "object" as const,
|
|
192
193
|
properties: {
|
|
193
194
|
entity: {
|
|
194
195
|
type: "string",
|
|
195
|
-
description: "Entity name to add observation to",
|
|
196
|
+
description: "Entity name to add observation to (must already exist)",
|
|
196
197
|
},
|
|
197
198
|
observation: {
|
|
198
199
|
type: "string",
|
|
@@ -216,7 +217,7 @@ const TOOLS = [
|
|
|
216
217
|
},
|
|
217
218
|
{
|
|
218
219
|
name: "relate",
|
|
219
|
-
description: "
|
|
220
|
+
description: "ADVANCED: Manually create a relationship between two entities. Rarely needed - remember auto-extracts relationships from text. Only use when: (1) the relationship wasn't captured by auto-extraction, or (2) you need to add a relationship not mentioned in any memory.",
|
|
220
221
|
inputSchema: {
|
|
221
222
|
type: "object" as const,
|
|
222
223
|
properties: {
|
|
@@ -245,7 +246,7 @@ const TOOLS = [
|
|
|
245
246
|
},
|
|
246
247
|
{
|
|
247
248
|
name: "query_entity",
|
|
248
|
-
description: "Get
|
|
249
|
+
description: "Get all stored information about a specific person, place, or organization. Use after recall to get deeper details about an entity mentioned in search results.",
|
|
249
250
|
inputSchema: {
|
|
250
251
|
type: "object" as const,
|
|
251
252
|
properties: {
|
|
@@ -266,7 +267,7 @@ const TOOLS = [
|
|
|
266
267
|
},
|
|
267
268
|
{
|
|
268
269
|
name: "list_entities",
|
|
269
|
-
description: "List all entities,
|
|
270
|
+
description: "List all known entities (people, places, organizations, etc.). Use to browse the knowledge graph or find entity names for query_entity.",
|
|
270
271
|
inputSchema: {
|
|
271
272
|
type: "object" as const,
|
|
272
273
|
properties: {
|
package/src/storage/database.ts
CHANGED
|
@@ -266,12 +266,140 @@ export class EngramDatabase {
|
|
|
266
266
|
}
|
|
267
267
|
|
|
268
268
|
findEntityByName(name: string): Entity | null {
|
|
269
|
+
// First try exact match (case-insensitive)
|
|
269
270
|
const row = this.stmt("SELECT * FROM entities WHERE LOWER(name) = LOWER(?)").get(name) as Record<string, unknown> | undefined;
|
|
270
|
-
|
|
271
|
+
if (row) return this.rowToEntity(row);
|
|
272
|
+
|
|
273
|
+
// If no exact match, try fuzzy match for potential duplicates
|
|
274
|
+
const fuzzyMatch = this.findSimilarEntity(name);
|
|
275
|
+
return fuzzyMatch;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
/**
|
|
279
|
+
* Find a similar entity using fuzzy matching
|
|
280
|
+
* Catches "Boris D" matching "Boris Djordjevic", "John" matching "John Smith"
|
|
281
|
+
*/
|
|
282
|
+
findSimilarEntity(name: string, threshold: number = 0.8): Entity | null {
|
|
283
|
+
const normalizedName = name.toLowerCase().trim();
|
|
284
|
+
const nameWords = normalizedName.split(/\s+/);
|
|
285
|
+
|
|
286
|
+
// Get candidates: entities that share at least one word with the query
|
|
287
|
+
const candidates = this.stmt(`
|
|
288
|
+
SELECT * FROM entities
|
|
289
|
+
WHERE LOWER(name) LIKE ?
|
|
290
|
+
LIMIT 100
|
|
291
|
+
`).all(`%${nameWords[0]}%`) as Record<string, unknown>[];
|
|
292
|
+
|
|
293
|
+
let bestMatch: Entity | null = null;
|
|
294
|
+
let bestScore = 0;
|
|
295
|
+
|
|
296
|
+
for (const row of candidates) {
|
|
297
|
+
const entity = this.rowToEntity(row);
|
|
298
|
+
const entityName = entity.name.toLowerCase();
|
|
299
|
+
const entityWords = entityName.split(/\s+/);
|
|
300
|
+
|
|
301
|
+
// Calculate similarity score
|
|
302
|
+
const score = this.calculateNameSimilarity(nameWords, entityWords, normalizedName, entityName);
|
|
303
|
+
|
|
304
|
+
if (score >= threshold && score > bestScore) {
|
|
305
|
+
bestScore = score;
|
|
306
|
+
bestMatch = entity;
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
return bestMatch;
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
/**
|
|
314
|
+
* Calculate similarity between two names
|
|
315
|
+
* Returns 0-1 score (1 = identical)
|
|
316
|
+
*/
|
|
317
|
+
private calculateNameSimilarity(
|
|
318
|
+
words1: string[],
|
|
319
|
+
words2: string[],
|
|
320
|
+
full1: string,
|
|
321
|
+
full2: string
|
|
322
|
+
): number {
|
|
323
|
+
// Exact match
|
|
324
|
+
if (full1 === full2) return 1.0;
|
|
325
|
+
|
|
326
|
+
// One is prefix of the other (e.g., "Boris" vs "Boris Djordjevic")
|
|
327
|
+
if (full1.startsWith(full2 + " ") || full2.startsWith(full1 + " ")) {
|
|
328
|
+
return 0.9;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
// First word matches (e.g., "John" vs "John Smith")
|
|
332
|
+
if (words1[0] === words2[0]) {
|
|
333
|
+
// Same first word, different lengths
|
|
334
|
+
const longer = Math.max(words1.length, words2.length);
|
|
335
|
+
const shorter = Math.min(words1.length, words2.length);
|
|
336
|
+
return 0.7 + (0.2 * shorter / longer);
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
// Check for abbreviated names (e.g., "Boris D" vs "Boris Djordjevic")
|
|
340
|
+
if (words1.length >= 2 && words2.length >= 2) {
|
|
341
|
+
const last1 = words1[words1.length - 1];
|
|
342
|
+
const last2 = words2[words2.length - 1];
|
|
343
|
+
|
|
344
|
+
// Check if one is abbreviation of the other
|
|
345
|
+
if (last1.length === 1 && last2.startsWith(last1)) {
|
|
346
|
+
return 0.85;
|
|
347
|
+
}
|
|
348
|
+
if (last2.length === 1 && last1.startsWith(last2)) {
|
|
349
|
+
return 0.85;
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
// Count shared words
|
|
354
|
+
const set1 = new Set(words1);
|
|
355
|
+
const shared = words2.filter(w => set1.has(w)).length;
|
|
356
|
+
const total = Math.max(words1.length, words2.length);
|
|
357
|
+
|
|
358
|
+
return shared / total * 0.7;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
/**
|
|
362
|
+
* Find all potential duplicate entities
|
|
363
|
+
*/
|
|
364
|
+
findDuplicateEntities(): Array<{ entity: Entity; potentialDuplicates: Entity[] }> {
|
|
365
|
+
const entities = this.listEntities(undefined, 1000);
|
|
366
|
+
const duplicates: Array<{ entity: Entity; potentialDuplicates: Entity[] }> = [];
|
|
367
|
+
const processed = new Set<string>();
|
|
368
|
+
|
|
369
|
+
for (const entity of entities) {
|
|
370
|
+
if (processed.has(entity.id)) continue;
|
|
371
|
+
|
|
372
|
+
const potentialDupes: Entity[] = [];
|
|
373
|
+
const words = entity.name.toLowerCase().split(/\s+/);
|
|
374
|
+
|
|
375
|
+
for (const other of entities) {
|
|
376
|
+
if (other.id === entity.id || processed.has(other.id)) continue;
|
|
377
|
+
|
|
378
|
+
const otherWords = other.name.toLowerCase().split(/\s+/);
|
|
379
|
+
const score = this.calculateNameSimilarity(
|
|
380
|
+
words, otherWords,
|
|
381
|
+
entity.name.toLowerCase(),
|
|
382
|
+
other.name.toLowerCase()
|
|
383
|
+
);
|
|
384
|
+
|
|
385
|
+
if (score >= 0.8) {
|
|
386
|
+
potentialDupes.push(other);
|
|
387
|
+
processed.add(other.id);
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
if (potentialDupes.length > 0) {
|
|
392
|
+
duplicates.push({ entity, potentialDuplicates: potentialDupes });
|
|
393
|
+
processed.add(entity.id);
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
return duplicates;
|
|
271
398
|
}
|
|
272
399
|
|
|
273
400
|
searchEntities(query: string, type?: Entity["type"]): Entity[] {
|
|
274
|
-
|
|
401
|
+
// Case-insensitive search
|
|
402
|
+
let sql = "SELECT * FROM entities WHERE LOWER(name) LIKE LOWER(?)";
|
|
275
403
|
const params: unknown[] = [`%${query}%`];
|
|
276
404
|
|
|
277
405
|
if (type) {
|