@j0hanz/memory-mcp 0.1.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 +363 -0
- package/dist/assets/logo.svg +36 -0
- package/dist/completions/index.d.ts +3 -0
- package/dist/completions/index.d.ts.map +1 -0
- package/dist/completions/index.js +17 -0
- package/dist/completions/index.js.map +1 -0
- package/dist/db/index.d.ts +6 -0
- package/dist/db/index.d.ts.map +1 -0
- package/dist/db/index.js +102 -0
- package/dist/db/index.js.map +1 -0
- package/dist/db/typed.d.ts +15 -0
- package/dist/db/typed.d.ts.map +1 -0
- package/dist/db/typed.js +24 -0
- package/dist/db/typed.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +60 -0
- package/dist/index.js.map +1 -0
- package/dist/instructions.md +144 -0
- package/dist/lib/errors.d.ts +5 -0
- package/dist/lib/errors.d.ts.map +1 -0
- package/dist/lib/errors.js +12 -0
- package/dist/lib/errors.js.map +1 -0
- package/dist/lib/hash.d.ts +2 -0
- package/dist/lib/hash.d.ts.map +1 -0
- package/dist/lib/hash.js +11 -0
- package/dist/lib/hash.js.map +1 -0
- package/dist/lib/pagination.d.ts +8 -0
- package/dist/lib/pagination.d.ts.map +1 -0
- package/dist/lib/pagination.js +40 -0
- package/dist/lib/pagination.js.map +1 -0
- package/dist/lib/search.d.ts +14 -0
- package/dist/lib/search.d.ts.map +1 -0
- package/dist/lib/search.js +36 -0
- package/dist/lib/search.js.map +1 -0
- package/dist/lib/tool-response.d.ts +8 -0
- package/dist/lib/tool-response.d.ts.map +1 -0
- package/dist/lib/tool-response.js +21 -0
- package/dist/lib/tool-response.js.map +1 -0
- package/dist/lib/types.d.ts +75 -0
- package/dist/lib/types.d.ts.map +1 -0
- package/dist/lib/types.js +25 -0
- package/dist/lib/types.js.map +1 -0
- package/dist/prompts/index.d.ts +3 -0
- package/dist/prompts/index.d.ts.map +1 -0
- package/dist/prompts/index.js +46 -0
- package/dist/prompts/index.js.map +1 -0
- package/dist/resources/index.d.ts +4 -0
- package/dist/resources/index.d.ts.map +1 -0
- package/dist/resources/index.js +89 -0
- package/dist/resources/index.js.map +1 -0
- package/dist/schemas/index.d.ts +3 -0
- package/dist/schemas/index.d.ts.map +1 -0
- package/dist/schemas/index.js +4 -0
- package/dist/schemas/index.js.map +1 -0
- package/dist/schemas/inputs.d.ts +128 -0
- package/dist/schemas/inputs.d.ts.map +1 -0
- package/dist/schemas/inputs.js +176 -0
- package/dist/schemas/inputs.js.map +1 -0
- package/dist/schemas/outputs.d.ts +202 -0
- package/dist/schemas/outputs.d.ts.map +1 -0
- package/dist/schemas/outputs.js +104 -0
- package/dist/schemas/outputs.js.map +1 -0
- package/dist/server.d.ts +4 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +73 -0
- package/dist/server.js.map +1 -0
- package/dist/tools/create-relationship.d.ts +4 -0
- package/dist/tools/create-relationship.d.ts.map +1 -0
- package/dist/tools/create-relationship.js +49 -0
- package/dist/tools/create-relationship.js.map +1 -0
- package/dist/tools/delete-memories.d.ts +4 -0
- package/dist/tools/delete-memories.d.ts.map +1 -0
- package/dist/tools/delete-memories.js +55 -0
- package/dist/tools/delete-memories.js.map +1 -0
- package/dist/tools/delete-memory.d.ts +4 -0
- package/dist/tools/delete-memory.d.ts.map +1 -0
- package/dist/tools/delete-memory.js +35 -0
- package/dist/tools/delete-memory.js.map +1 -0
- package/dist/tools/delete-relationship.d.ts +4 -0
- package/dist/tools/delete-relationship.d.ts.map +1 -0
- package/dist/tools/delete-relationship.js +35 -0
- package/dist/tools/delete-relationship.js.map +1 -0
- package/dist/tools/get-memory.d.ts +4 -0
- package/dist/tools/get-memory.d.ts.map +1 -0
- package/dist/tools/get-memory.js +30 -0
- package/dist/tools/get-memory.js.map +1 -0
- package/dist/tools/get-relationships.d.ts +4 -0
- package/dist/tools/get-relationships.d.ts.map +1 -0
- package/dist/tools/get-relationships.js +57 -0
- package/dist/tools/get-relationships.js.map +1 -0
- package/dist/tools/helpers.d.ts +13 -0
- package/dist/tools/helpers.d.ts.map +1 -0
- package/dist/tools/helpers.js +49 -0
- package/dist/tools/helpers.js.map +1 -0
- package/dist/tools/index.d.ts +15 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +29 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/memory-stats.d.ts +4 -0
- package/dist/tools/memory-stats.d.ts.map +1 -0
- package/dist/tools/memory-stats.js +60 -0
- package/dist/tools/memory-stats.js.map +1 -0
- package/dist/tools/recall.d.ts +4 -0
- package/dist/tools/recall.d.ts.map +1 -0
- package/dist/tools/recall.js +192 -0
- package/dist/tools/recall.js.map +1 -0
- package/dist/tools/retrieve-context.d.ts +4 -0
- package/dist/tools/retrieve-context.d.ts.map +1 -0
- package/dist/tools/retrieve-context.js +75 -0
- package/dist/tools/retrieve-context.js.map +1 -0
- package/dist/tools/search-memories.d.ts +4 -0
- package/dist/tools/search-memories.d.ts.map +1 -0
- package/dist/tools/search-memories.js +62 -0
- package/dist/tools/search-memories.js.map +1 -0
- package/dist/tools/store-memories.d.ts +4 -0
- package/dist/tools/store-memories.d.ts.map +1 -0
- package/dist/tools/store-memories.js +52 -0
- package/dist/tools/store-memories.js.map +1 -0
- package/dist/tools/store-memory.d.ts +4 -0
- package/dist/tools/store-memory.d.ts.map +1 -0
- package/dist/tools/store-memory.js +35 -0
- package/dist/tools/store-memory.js.map +1 -0
- package/dist/tools/update-memory.d.ts +4 -0
- package/dist/tools/update-memory.d.ts.map +1 -0
- package/dist/tools/update-memory.js +49 -0
- package/dist/tools/update-memory.js.map +1 -0
- package/package.json +84 -0
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { E_UNKNOWN, getErrorMessage } from '../lib/errors.js';
|
|
2
|
+
import { createErrorResponse, createToolResponse, } from '../lib/tool-response.js';
|
|
3
|
+
import { MemoryStatsInputSchema } from '../schemas/inputs.js';
|
|
4
|
+
import { StatsResultSchema } from '../schemas/outputs.js';
|
|
5
|
+
const TOTAL_MEMORIES_SQL = 'SELECT COUNT(*) AS total FROM memories';
|
|
6
|
+
const TOTAL_RELATIONSHIPS_SQL = 'SELECT COUNT(*) AS total FROM relationships';
|
|
7
|
+
const TYPE_COUNTS_SQL = 'SELECT memory_type, COUNT(*) AS count FROM memories GROUP BY memory_type ORDER BY count DESC';
|
|
8
|
+
const OLDEST_MEMORY_SQL = 'SELECT MIN(created_at) AS oldest FROM memories';
|
|
9
|
+
const NEWEST_MEMORY_SQL = 'SELECT MAX(created_at) AS newest FROM memories';
|
|
10
|
+
const AVG_IMPORTANCE_SQL = 'SELECT AVG(importance) AS avg_importance FROM memories';
|
|
11
|
+
function toTypeCounts(rows) {
|
|
12
|
+
const byType = {};
|
|
13
|
+
for (const row of rows) {
|
|
14
|
+
byType[row.memory_type] = row.count;
|
|
15
|
+
}
|
|
16
|
+
return byType;
|
|
17
|
+
}
|
|
18
|
+
function getTotalCount(db, sql) {
|
|
19
|
+
return db.prepare(sql).get()?.total ?? 0;
|
|
20
|
+
}
|
|
21
|
+
export function registerMemoryStats(server, db) {
|
|
22
|
+
server.registerTool('memory_stats', {
|
|
23
|
+
title: 'Memory Stats',
|
|
24
|
+
description: 'Return aggregate statistics about the memory store (counts, oldest/newest timestamps, breakdown by type).',
|
|
25
|
+
inputSchema: MemoryStatsInputSchema,
|
|
26
|
+
outputSchema: StatsResultSchema,
|
|
27
|
+
annotations: { readOnlyHint: true, openWorldHint: false },
|
|
28
|
+
}, () => {
|
|
29
|
+
try {
|
|
30
|
+
const totalMemories = getTotalCount(db, TOTAL_MEMORIES_SQL);
|
|
31
|
+
const totalRelationships = getTotalCount(db, TOTAL_RELATIONSHIPS_SQL);
|
|
32
|
+
const typeRows = db.prepare(TYPE_COUNTS_SQL).all();
|
|
33
|
+
const oldestRow = db.prepare(OLDEST_MEMORY_SQL).get();
|
|
34
|
+
const newestRow = db.prepare(NEWEST_MEMORY_SQL).get();
|
|
35
|
+
const avgImportanceRow = db
|
|
36
|
+
.prepare(AVG_IMPORTANCE_SQL)
|
|
37
|
+
.get();
|
|
38
|
+
const byType = toTypeCounts(typeRows);
|
|
39
|
+
return createToolResponse({
|
|
40
|
+
ok: true,
|
|
41
|
+
result: {
|
|
42
|
+
memories: {
|
|
43
|
+
total: totalMemories,
|
|
44
|
+
oldest: oldestRow?.oldest ?? null,
|
|
45
|
+
newest: newestRow?.newest ?? null,
|
|
46
|
+
avg_importance: avgImportanceRow?.avg_importance ?? null,
|
|
47
|
+
},
|
|
48
|
+
relationships: {
|
|
49
|
+
total: totalRelationships,
|
|
50
|
+
},
|
|
51
|
+
by_type: byType,
|
|
52
|
+
},
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
catch (err) {
|
|
56
|
+
return createErrorResponse(E_UNKNOWN, getErrorMessage(err));
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
//# sourceMappingURL=memory-stats.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memory-stats.js","sourceRoot":"","sources":["../../src/tools/memory-stats.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAC9D,OAAO,EACL,mBAAmB,EACnB,kBAAkB,GACnB,MAAM,yBAAyB,CAAC;AAEjC,OAAO,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAM1D,MAAM,kBAAkB,GAAG,wCAAwC,CAAC;AACpE,MAAM,uBAAuB,GAAG,6CAA6C,CAAC;AAC9E,MAAM,eAAe,GACnB,8FAA8F,CAAC;AACjG,MAAM,iBAAiB,GAAG,gDAAgD,CAAC;AAC3E,MAAM,iBAAiB,GAAG,gDAAgD,CAAC;AAC3E,MAAM,kBAAkB,GACtB,wDAAwD,CAAC;AAE3D,SAAS,YAAY,CAAC,IAAe;IACnC,MAAM,MAAM,GAA2B,EAAE,CAAC;IAC1C,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;QACvB,MAAM,CAAC,GAAG,CAAC,WAAW,CAAC,GAAG,GAAG,CAAC,KAAK,CAAC;IACtC,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,SAAS,aAAa,CAAC,EAAW,EAAE,GAAW;IAC7C,OAAO,EAAE,CAAC,OAAO,CAAW,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,KAAK,IAAI,CAAC,CAAC;AACrD,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,MAAiB,EAAE,EAAW;IAChE,MAAM,CAAC,YAAY,CACjB,cAAc,EACd;QACE,KAAK,EAAE,cAAc;QACrB,WAAW,EACT,2GAA2G;QAC7G,WAAW,EAAE,sBAAsB;QACnC,YAAY,EAAE,iBAAiB;QAC/B,WAAW,EAAE,EAAE,YAAY,EAAE,IAAI,EAAE,aAAa,EAAE,KAAK,EAAE;KAC1D,EACD,GAAG,EAAE;QACH,IAAI,CAAC;YACH,MAAM,aAAa,GAAG,aAAa,CAAC,EAAE,EAAE,kBAAkB,CAAC,CAAC;YAC5D,MAAM,kBAAkB,GAAG,aAAa,CAAC,EAAE,EAAE,uBAAuB,CAAC,CAAC;YAEtE,MAAM,QAAQ,GAAG,EAAE,CAAC,OAAO,CAAU,eAAe,CAAC,CAAC,GAAG,EAAE,CAAC;YAE5D,MAAM,SAAS,GAAG,EAAE,CAAC,OAAO,CAAY,iBAAiB,CAAC,CAAC,GAAG,EAAE,CAAC;YAEjE,MAAM,SAAS,GAAG,EAAE,CAAC,OAAO,CAAY,iBAAiB,CAAC,CAAC,GAAG,EAAE,CAAC;YAEjE,MAAM,gBAAgB,GAAG,EAAE;iBACxB,OAAO,CAAmB,kBAAkB,CAAC;iBAC7C,GAAG,EAAE,CAAC;YAET,MAAM,MAAM,GAAG,YAAY,CAAC,QAAQ,CAAC,CAAC;YAEtC,OAAO,kBAAkB,CAAC;gBACxB,EAAE,EAAE,IAAI;gBACR,MAAM,EAAE;oBACN,QAAQ,EAAE;wBACR,KAAK,EAAE,aAAa;wBACpB,MAAM,EAAE,SAAS,EAAE,MAAM,IAAI,IAAI;wBACjC,MAAM,EAAE,SAAS,EAAE,MAAM,IAAI,IAAI;wBACjC,cAAc,EAAE,gBAAgB,EAAE,cAAc,IAAI,IAAI;qBACzD;oBACD,aAAa,EAAE;wBACb,KAAK,EAAE,kBAAkB;qBAC1B;oBACD,OAAO,EAAE,MAAM;iBAChB;aACF,CAAC,CAAC;QACL,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,mBAAmB,CAAC,SAAS,EAAE,eAAe,CAAC,GAAG,CAAC,CAAC,CAAC;QAC9D,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"recall.d.ts","sourceRoot":"","sources":["../../src/tools/recall.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAMzE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AAqO9C,wBAAgB,cAAc,CAAC,MAAM,EAAE,SAAS,EAAE,EAAE,EAAE,OAAO,GAAG,IAAI,CA8DnE"}
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
import process from 'node:process';
|
|
2
|
+
import { E_UNKNOWN, getErrorMessage } from '../lib/errors.js';
|
|
3
|
+
import { decodeCursor, encodeCursor, splitPage } from '../lib/pagination.js';
|
|
4
|
+
import { buildAndWhereClause, buildFilterClauses, sanitizeFtsQuery, } from '../lib/search.js';
|
|
5
|
+
import { createErrorResponse, createToolResponse, } from '../lib/tool-response.js';
|
|
6
|
+
import { parseMemoryRow } from '../lib/types.js';
|
|
7
|
+
import { RecallInputSchema } from '../schemas/inputs.js';
|
|
8
|
+
import { RecallResultSchema } from '../schemas/outputs.js';
|
|
9
|
+
function parseEnvInt(name, fallback, min, max) {
|
|
10
|
+
const raw = process.env[name];
|
|
11
|
+
if (raw == null)
|
|
12
|
+
return fallback;
|
|
13
|
+
const parsed = parseInt(raw, 10);
|
|
14
|
+
if (Number.isNaN(parsed))
|
|
15
|
+
return fallback;
|
|
16
|
+
return Math.max(min, Math.min(max, parsed));
|
|
17
|
+
}
|
|
18
|
+
const MAX_FRONTIER_SIZE = parseEnvInt('RECALL_MAX_FRONTIER_SIZE', 1000, 100, 50000);
|
|
19
|
+
const MAX_EDGE_ROWS = parseEnvInt('RECALL_MAX_EDGE_ROWS', 5000, 100, 50000);
|
|
20
|
+
const MAX_VISITED_NODES = parseEnvInt('RECALL_MAX_VISITED_NODES', 5000, 100, 50000);
|
|
21
|
+
function toMemoryFilters(params) {
|
|
22
|
+
const filters = {};
|
|
23
|
+
if (params.min_importance != null) {
|
|
24
|
+
filters.min_importance = params.min_importance;
|
|
25
|
+
}
|
|
26
|
+
if (params.max_importance != null) {
|
|
27
|
+
filters.max_importance = params.max_importance;
|
|
28
|
+
}
|
|
29
|
+
if (params.memory_type != null) {
|
|
30
|
+
filters.memory_type = params.memory_type;
|
|
31
|
+
}
|
|
32
|
+
return filters;
|
|
33
|
+
}
|
|
34
|
+
function createPlaceholders(count) {
|
|
35
|
+
return new Array(count).fill('?').join(',');
|
|
36
|
+
}
|
|
37
|
+
function loadSeedRows(db, query, limit, offset, filters) {
|
|
38
|
+
const ftsQuery = sanitizeFtsQuery(query);
|
|
39
|
+
const filter = buildFilterClauses(filters);
|
|
40
|
+
const whereExtra = buildAndWhereClause(filter.clauses);
|
|
41
|
+
return db
|
|
42
|
+
.prepare(`SELECT m.*, memories_fts.rank AS rank FROM memories m
|
|
43
|
+
JOIN memories_fts ON memories_fts.rowid = m.rowid
|
|
44
|
+
WHERE memories_fts MATCH ?${whereExtra}
|
|
45
|
+
ORDER BY memories_fts.rank
|
|
46
|
+
LIMIT ? OFFSET ?`)
|
|
47
|
+
.all(ftsQuery, ...filter.params, limit + 1, offset);
|
|
48
|
+
}
|
|
49
|
+
function traverseGraph(db, seeds, depth, signal, onHop) {
|
|
50
|
+
const visited = new Set(seeds.map((r) => r.hash));
|
|
51
|
+
const edges = [];
|
|
52
|
+
const seenEdges = new Set();
|
|
53
|
+
let frontier = seeds.map((r) => r.hash);
|
|
54
|
+
let depthReached = 0;
|
|
55
|
+
let aborted = false;
|
|
56
|
+
for (let hop = 0; hop < depth && frontier.length > 0; hop++) {
|
|
57
|
+
if (signal?.aborted) {
|
|
58
|
+
aborted = true;
|
|
59
|
+
break;
|
|
60
|
+
}
|
|
61
|
+
depthReached = hop + 1;
|
|
62
|
+
onHop?.(hop, depth);
|
|
63
|
+
if (frontier.length > MAX_FRONTIER_SIZE) {
|
|
64
|
+
frontier = frontier.slice(0, MAX_FRONTIER_SIZE);
|
|
65
|
+
aborted = true;
|
|
66
|
+
}
|
|
67
|
+
const remainingEdgeBudget = MAX_EDGE_ROWS - edges.length;
|
|
68
|
+
const remainingNodeBudget = MAX_VISITED_NODES - visited.size;
|
|
69
|
+
if (remainingEdgeBudget <= 0 || remainingNodeBudget <= 0) {
|
|
70
|
+
aborted = true;
|
|
71
|
+
break;
|
|
72
|
+
}
|
|
73
|
+
const placeholders = createPlaceholders(frontier.length);
|
|
74
|
+
const edgeRows = db
|
|
75
|
+
.prepare(`SELECT from_hash, to_hash, relation_type FROM relationships
|
|
76
|
+
WHERE from_hash IN (${placeholders}) OR to_hash IN (${placeholders})
|
|
77
|
+
LIMIT ?`)
|
|
78
|
+
.all(...frontier, ...frontier, remainingEdgeBudget + 1);
|
|
79
|
+
const rows = edgeRows.length > remainingEdgeBudget
|
|
80
|
+
? edgeRows.slice(0, remainingEdgeBudget)
|
|
81
|
+
: edgeRows;
|
|
82
|
+
if (edgeRows.length > remainingEdgeBudget) {
|
|
83
|
+
aborted = true;
|
|
84
|
+
}
|
|
85
|
+
const nextHashes = [];
|
|
86
|
+
for (const edge of rows) {
|
|
87
|
+
const edgeKey = `${edge.from_hash}|${edge.to_hash}|${edge.relation_type}`;
|
|
88
|
+
if (!seenEdges.has(edgeKey)) {
|
|
89
|
+
seenEdges.add(edgeKey);
|
|
90
|
+
edges.push({
|
|
91
|
+
from_hash: edge.from_hash,
|
|
92
|
+
to_hash: edge.to_hash,
|
|
93
|
+
relation_type: edge.relation_type,
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
for (const h of [edge.from_hash, edge.to_hash]) {
|
|
97
|
+
if (!visited.has(h)) {
|
|
98
|
+
if (visited.size >= MAX_VISITED_NODES) {
|
|
99
|
+
aborted = true;
|
|
100
|
+
break;
|
|
101
|
+
}
|
|
102
|
+
visited.add(h);
|
|
103
|
+
if (nextHashes.length < MAX_FRONTIER_SIZE) {
|
|
104
|
+
nextHashes.push(h);
|
|
105
|
+
}
|
|
106
|
+
else {
|
|
107
|
+
aborted = true;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
if (aborted &&
|
|
112
|
+
(edges.length >= MAX_EDGE_ROWS || visited.size >= MAX_VISITED_NODES)) {
|
|
113
|
+
break;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
frontier = nextHashes;
|
|
117
|
+
}
|
|
118
|
+
return { edges, visited, depthReached, aborted };
|
|
119
|
+
}
|
|
120
|
+
function loadMemoriesByHashes(db, hashes) {
|
|
121
|
+
if (hashes.length === 0) {
|
|
122
|
+
return [];
|
|
123
|
+
}
|
|
124
|
+
const placeholders = createPlaceholders(hashes.length);
|
|
125
|
+
const memRows = db
|
|
126
|
+
.prepare(`SELECT * FROM memories WHERE hash IN (${placeholders})`)
|
|
127
|
+
.all(...hashes);
|
|
128
|
+
return memRows.map(parseMemoryRow);
|
|
129
|
+
}
|
|
130
|
+
function createHopNotifier(progressToken, sendNotification) {
|
|
131
|
+
if (progressToken == null) {
|
|
132
|
+
return undefined;
|
|
133
|
+
}
|
|
134
|
+
return (hop, total) => {
|
|
135
|
+
void sendNotification({
|
|
136
|
+
method: 'notifications/progress',
|
|
137
|
+
params: { progressToken, progress: hop + 1, total },
|
|
138
|
+
}).catch(() => { });
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
function toProgressToken(value) {
|
|
142
|
+
if (typeof value === 'string' || typeof value === 'number') {
|
|
143
|
+
return value;
|
|
144
|
+
}
|
|
145
|
+
return undefined;
|
|
146
|
+
}
|
|
147
|
+
export function registerRecall(server, db) {
|
|
148
|
+
server.registerTool('recall', {
|
|
149
|
+
title: 'Recall (BFS Graph Traversal)',
|
|
150
|
+
description: 'Search memories by full-text query, then traverse the relationship graph up to `depth` hops via BFS. Returns all discovered memories and the edges connecting them.',
|
|
151
|
+
inputSchema: RecallInputSchema,
|
|
152
|
+
outputSchema: RecallResultSchema,
|
|
153
|
+
annotations: { readOnlyHint: true, openWorldHint: false },
|
|
154
|
+
}, (params, { signal, _meta, sendNotification }) => {
|
|
155
|
+
try {
|
|
156
|
+
const { depth, limit, cursor } = params;
|
|
157
|
+
const offset = cursor ? decodeCursor(cursor) : 0;
|
|
158
|
+
const onHop = createHopNotifier(toProgressToken(_meta?.progressToken), sendNotification);
|
|
159
|
+
// Step 1: FTS seed search
|
|
160
|
+
const seedRows = loadSeedRows(db, params.query, limit, offset, toMemoryFilters(params));
|
|
161
|
+
const { page: pageSeeds, hasMore } = splitPage(seedRows, limit);
|
|
162
|
+
// Step 2: BFS traversal up to `depth` hops
|
|
163
|
+
const traversal = traverseGraph(db, pageSeeds, depth, signal, onHop);
|
|
164
|
+
// Step 3: Load all discovered memory rows
|
|
165
|
+
const allHashes = Array.from(traversal.visited);
|
|
166
|
+
const seedRelevance = new Map();
|
|
167
|
+
for (const seed of pageSeeds) {
|
|
168
|
+
if (seed.rank != null)
|
|
169
|
+
seedRelevance.set(seed.hash, -seed.rank);
|
|
170
|
+
}
|
|
171
|
+
const memories = loadMemoriesByHashes(db, allHashes).map((m) => {
|
|
172
|
+
const rel = seedRelevance.get(m.hash);
|
|
173
|
+
return rel != null ? { ...m, relevance: rel } : m;
|
|
174
|
+
});
|
|
175
|
+
const nextCursor = hasMore ? encodeCursor(offset + limit) : undefined;
|
|
176
|
+
return createToolResponse({
|
|
177
|
+
ok: true,
|
|
178
|
+
result: {
|
|
179
|
+
memories,
|
|
180
|
+
graph: traversal.edges,
|
|
181
|
+
depth_reached: traversal.depthReached,
|
|
182
|
+
...(traversal.aborted ? { aborted: true } : {}),
|
|
183
|
+
...(nextCursor ? { nextCursor } : {}),
|
|
184
|
+
},
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
catch (err) {
|
|
188
|
+
return createErrorResponse(E_UNKNOWN, getErrorMessage(err));
|
|
189
|
+
}
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
//# sourceMappingURL=recall.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"recall.js","sourceRoot":"","sources":["../../src/tools/recall.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"retrieve-context.d.ts","sourceRoot":"","sources":["../../src/tools/retrieve-context.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAIzE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AAiD9C,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,SAAS,EAAE,EAAE,EAAE,OAAO,GAAG,IAAI,CAkD5E"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { E_UNKNOWN, getErrorMessage } from '../lib/errors.js';
|
|
2
|
+
import { sanitizeFtsQuery } from '../lib/search.js';
|
|
3
|
+
import { createErrorResponse, createToolResponse, } from '../lib/tool-response.js';
|
|
4
|
+
import { parseMemoryRow } from '../lib/types.js';
|
|
5
|
+
import { RetrieveContextInputSchema } from '../schemas/inputs.js';
|
|
6
|
+
import { RetrieveContextResultSchema } from '../schemas/outputs.js';
|
|
7
|
+
const RETRIEVE_CONTEXT_LIMIT = 200;
|
|
8
|
+
const ESTIMATED_CHARS_PER_TOKEN = 4;
|
|
9
|
+
function getOrderBy(strategy) {
|
|
10
|
+
if (strategy === 'importance') {
|
|
11
|
+
return 'm.importance DESC, memories_fts.rank';
|
|
12
|
+
}
|
|
13
|
+
if (strategy === 'recency') {
|
|
14
|
+
return 'm.created_at DESC, memories_fts.rank';
|
|
15
|
+
}
|
|
16
|
+
return 'memories_fts.rank';
|
|
17
|
+
}
|
|
18
|
+
function estimateTokens(content) {
|
|
19
|
+
return Math.ceil(content.length / ESTIMATED_CHARS_PER_TOKEN);
|
|
20
|
+
}
|
|
21
|
+
function loadContextRows(db, query, orderBy) {
|
|
22
|
+
const ftsQuery = sanitizeFtsQuery(query);
|
|
23
|
+
return db
|
|
24
|
+
.prepare(`SELECT m.*, memories_fts.rank AS rank FROM memories m
|
|
25
|
+
JOIN memories_fts ON memories_fts.rowid = m.rowid
|
|
26
|
+
WHERE memories_fts MATCH ?
|
|
27
|
+
ORDER BY ${orderBy}
|
|
28
|
+
LIMIT ${RETRIEVE_CONTEXT_LIMIT + 1}`)
|
|
29
|
+
.all(ftsQuery);
|
|
30
|
+
}
|
|
31
|
+
export function registerRetrieveContext(server, db) {
|
|
32
|
+
server.registerTool('retrieve_context', {
|
|
33
|
+
title: 'Retrieve Context',
|
|
34
|
+
description: 'Search memories and return relevance-ranked results that fit within a caller-specified token budget. Eliminates manual pagination and token counting for context window management.',
|
|
35
|
+
inputSchema: RetrieveContextInputSchema,
|
|
36
|
+
outputSchema: RetrieveContextResultSchema,
|
|
37
|
+
annotations: { readOnlyHint: true, openWorldHint: false },
|
|
38
|
+
}, (params) => {
|
|
39
|
+
try {
|
|
40
|
+
const { query, strategy } = params;
|
|
41
|
+
const tokenBudget = params.token_budget;
|
|
42
|
+
const orderBy = getOrderBy(strategy);
|
|
43
|
+
const rows = loadContextRows(db, query, orderBy);
|
|
44
|
+
const rowCapExceeded = rows.length > RETRIEVE_CONTEXT_LIMIT;
|
|
45
|
+
const candidateRows = rowCapExceeded
|
|
46
|
+
? rows.slice(0, RETRIEVE_CONTEXT_LIMIT)
|
|
47
|
+
: rows;
|
|
48
|
+
let estimatedTokens = 0;
|
|
49
|
+
let truncated = rowCapExceeded;
|
|
50
|
+
const selected = [];
|
|
51
|
+
for (const row of candidateRows) {
|
|
52
|
+
const mem = parseMemoryRow(row);
|
|
53
|
+
const tokens = estimateTokens(mem.content);
|
|
54
|
+
if (estimatedTokens + tokens > tokenBudget) {
|
|
55
|
+
truncated = true;
|
|
56
|
+
break;
|
|
57
|
+
}
|
|
58
|
+
estimatedTokens += tokens;
|
|
59
|
+
selected.push(mem);
|
|
60
|
+
}
|
|
61
|
+
return createToolResponse({
|
|
62
|
+
ok: true,
|
|
63
|
+
result: {
|
|
64
|
+
memories: selected,
|
|
65
|
+
estimated_tokens: estimatedTokens,
|
|
66
|
+
truncated,
|
|
67
|
+
},
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
catch (err) {
|
|
71
|
+
return createErrorResponse(E_UNKNOWN, getErrorMessage(err));
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
//# sourceMappingURL=retrieve-context.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"retrieve-context.js","sourceRoot":"","sources":["../../src/tools/retrieve-context.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search-memories.d.ts","sourceRoot":"","sources":["../../src/tools/search-memories.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAIzE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AAuD9C,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,SAAS,EAAE,EAAE,EAAE,OAAO,GAAG,IAAI,CAwC3E"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { E_UNKNOWN, getErrorMessage } from '../lib/errors.js';
|
|
2
|
+
import { decodeCursor, encodeCursor, splitPage } from '../lib/pagination.js';
|
|
3
|
+
import { buildAndWhereClause, buildFilterClauses, sanitizeFtsQuery, } from '../lib/search.js';
|
|
4
|
+
import { createErrorResponse, createToolResponse, } from '../lib/tool-response.js';
|
|
5
|
+
import { parseMemoryRow } from '../lib/types.js';
|
|
6
|
+
import { SearchMemoriesInputSchema } from '../schemas/inputs.js';
|
|
7
|
+
import { SearchResultSchema } from '../schemas/outputs.js';
|
|
8
|
+
function toMemoryFilters(params) {
|
|
9
|
+
const filters = {};
|
|
10
|
+
if (params.min_importance != null) {
|
|
11
|
+
filters.min_importance = params.min_importance;
|
|
12
|
+
}
|
|
13
|
+
if (params.max_importance != null) {
|
|
14
|
+
filters.max_importance = params.max_importance;
|
|
15
|
+
}
|
|
16
|
+
if (params.memory_type != null) {
|
|
17
|
+
filters.memory_type = params.memory_type;
|
|
18
|
+
}
|
|
19
|
+
return filters;
|
|
20
|
+
}
|
|
21
|
+
function loadSearchRows(db, query, limit, offset, filters) {
|
|
22
|
+
const ftsQuery = sanitizeFtsQuery(query);
|
|
23
|
+
const filter = buildFilterClauses(filters);
|
|
24
|
+
const whereExtra = buildAndWhereClause(filter.clauses);
|
|
25
|
+
return db
|
|
26
|
+
.prepare(`SELECT m.*, memories_fts.rank AS rank FROM memories m
|
|
27
|
+
JOIN memories_fts ON memories_fts.rowid = m.rowid
|
|
28
|
+
WHERE memories_fts MATCH ?${whereExtra}
|
|
29
|
+
ORDER BY memories_fts.rank
|
|
30
|
+
LIMIT ? OFFSET ?`)
|
|
31
|
+
.all(ftsQuery, ...filter.params, limit + 1, offset);
|
|
32
|
+
}
|
|
33
|
+
export function registerSearchMemories(server, db) {
|
|
34
|
+
server.registerTool('search_memories', {
|
|
35
|
+
title: 'Search Memories',
|
|
36
|
+
description: 'Full-text search over memory content and tags using FTS5. Returns ranked results with pagination support via cursor.',
|
|
37
|
+
inputSchema: SearchMemoriesInputSchema,
|
|
38
|
+
outputSchema: SearchResultSchema,
|
|
39
|
+
annotations: { readOnlyHint: true, openWorldHint: false },
|
|
40
|
+
}, (params) => {
|
|
41
|
+
try {
|
|
42
|
+
const { limit, cursor } = params;
|
|
43
|
+
const offset = cursor ? decodeCursor(cursor) : 0;
|
|
44
|
+
const rows = loadSearchRows(db, params.query, limit, offset, toMemoryFilters(params));
|
|
45
|
+
const { page: pageRows, hasMore } = splitPage(rows, limit);
|
|
46
|
+
const memories = pageRows.map(parseMemoryRow);
|
|
47
|
+
const nextCursor = hasMore ? encodeCursor(offset + limit) : undefined;
|
|
48
|
+
return createToolResponse({
|
|
49
|
+
ok: true,
|
|
50
|
+
result: {
|
|
51
|
+
memories,
|
|
52
|
+
total_returned: memories.length,
|
|
53
|
+
...(nextCursor ? { nextCursor } : {}),
|
|
54
|
+
},
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
catch (err) {
|
|
58
|
+
return createErrorResponse(E_UNKNOWN, getErrorMessage(err));
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=search-memories.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search-memories.js","sourceRoot":"","sources":["../../src/tools/search-memories.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"store-memories.d.ts","sourceRoot":"","sources":["../../src/tools/store-memories.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAIzE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AA6B9C,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,SAAS,EAAE,EAAE,EAAE,OAAO,GAAG,IAAI,CAqD1E"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { E_UNKNOWN, getErrorMessage } from '../lib/errors.js';
|
|
2
|
+
import { computeMemoryHash } from '../lib/hash.js';
|
|
3
|
+
import { createErrorResponse, createToolResponse, } from '../lib/tool-response.js';
|
|
4
|
+
import { StoreMemoriesInputSchema } from '../schemas/inputs.js';
|
|
5
|
+
import { BatchResultSchema } from '../schemas/outputs.js';
|
|
6
|
+
import { logToolEvent, normalizeMemoryType, nowIso, withImmediateTransaction, } from './helpers.js';
|
|
7
|
+
const INSERT_MEMORY_SQL = `INSERT OR IGNORE INTO memories (hash, content, tags, memory_type, importance, created_at, updated_at)
|
|
8
|
+
VALUES (?, ?, ?, ?, ?, ?, ?)`;
|
|
9
|
+
function summarizeBatch(items) {
|
|
10
|
+
const succeeded = items.filter((item) => item.ok).length;
|
|
11
|
+
return { succeeded, failed: items.length - succeeded };
|
|
12
|
+
}
|
|
13
|
+
export function registerStoreMemories(server, db) {
|
|
14
|
+
server.registerTool('store_memories', {
|
|
15
|
+
title: 'Store Memories (Batch)',
|
|
16
|
+
description: 'Store up to 50 memories in a single atomic transaction. Returns per-item results so callers can detect partial failures. All items succeed or the transaction rolls back.',
|
|
17
|
+
inputSchema: StoreMemoriesInputSchema,
|
|
18
|
+
outputSchema: BatchResultSchema,
|
|
19
|
+
annotations: { idempotentHint: true, openWorldHint: false },
|
|
20
|
+
}, async (params) => {
|
|
21
|
+
try {
|
|
22
|
+
const now = nowIso();
|
|
23
|
+
const results = withImmediateTransaction(db, () => {
|
|
24
|
+
const items = [];
|
|
25
|
+
const stmt = db.prepare(INSERT_MEMORY_SQL);
|
|
26
|
+
for (const item of params.items) {
|
|
27
|
+
const { importance, memory_type: rawMemoryType } = item;
|
|
28
|
+
const memoryType = normalizeMemoryType(rawMemoryType);
|
|
29
|
+
const hash = computeMemoryHash(item.content, item.tags);
|
|
30
|
+
const tagsJson = JSON.stringify(item.tags);
|
|
31
|
+
const result = stmt.run(hash, item.content, tagsJson, memoryType, importance, now, now);
|
|
32
|
+
items.push({ hash, ok: true, created: result.changes > 0 });
|
|
33
|
+
}
|
|
34
|
+
return items;
|
|
35
|
+
});
|
|
36
|
+
const created = results.filter((r) => r.created).length;
|
|
37
|
+
const { succeeded, failed } = summarizeBatch(results);
|
|
38
|
+
await logToolEvent(server, 'store_memories', {
|
|
39
|
+
total: results.length,
|
|
40
|
+
created,
|
|
41
|
+
});
|
|
42
|
+
return createToolResponse({
|
|
43
|
+
ok: true,
|
|
44
|
+
result: { items: results, succeeded, failed },
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
catch (err) {
|
|
48
|
+
return createErrorResponse(E_UNKNOWN, getErrorMessage(err));
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=store-memories.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"store-memories.js","sourceRoot":"","sources":["../../src/tools/store-memories.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"store-memory.d.ts","sourceRoot":"","sources":["../../src/tools/store-memory.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAIzE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AAe9C,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,SAAS,EAAE,EAAE,EAAE,OAAO,GAAG,IAAI,CAwCxE"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { E_UNKNOWN, getErrorMessage } from '../lib/errors.js';
|
|
2
|
+
import { computeMemoryHash } from '../lib/hash.js';
|
|
3
|
+
import { createErrorResponse, createToolResponse, } from '../lib/tool-response.js';
|
|
4
|
+
import { StoreMemoryInputSchema } from '../schemas/inputs.js';
|
|
5
|
+
import { StoreResultSchema } from '../schemas/outputs.js';
|
|
6
|
+
import { logToolEvent, normalizeMemoryType, nowIso } from './helpers.js';
|
|
7
|
+
const INSERT_MEMORY_SQL = `INSERT OR IGNORE INTO memories (hash, content, tags, memory_type, importance, created_at, updated_at)
|
|
8
|
+
VALUES (?, ?, ?, ?, ?, ?, ?)`;
|
|
9
|
+
export function registerStoreMemory(server, db) {
|
|
10
|
+
server.registerTool('store_memory', {
|
|
11
|
+
title: 'Store Memory',
|
|
12
|
+
description: 'Store a new memory with content, tags, and optional type/importance. Returns the SHA-256 hash. Idempotent — storing the same content+tags returns the existing hash with created:false.',
|
|
13
|
+
inputSchema: StoreMemoryInputSchema,
|
|
14
|
+
outputSchema: StoreResultSchema,
|
|
15
|
+
annotations: { idempotentHint: true, openWorldHint: false },
|
|
16
|
+
}, async (params) => {
|
|
17
|
+
try {
|
|
18
|
+
const { importance } = params;
|
|
19
|
+
const memoryType = normalizeMemoryType(params.memory_type);
|
|
20
|
+
const hash = computeMemoryHash(params.content, params.tags);
|
|
21
|
+
const now = nowIso();
|
|
22
|
+
const tagsJson = JSON.stringify(params.tags);
|
|
23
|
+
const insertResult = db
|
|
24
|
+
.prepare(INSERT_MEMORY_SQL)
|
|
25
|
+
.run(hash, params.content, tagsJson, memoryType, importance, now, now);
|
|
26
|
+
const created = insertResult.changes > 0;
|
|
27
|
+
await logToolEvent(server, 'store', { hash, created });
|
|
28
|
+
return createToolResponse({ ok: true, result: { hash, created } });
|
|
29
|
+
}
|
|
30
|
+
catch (err) {
|
|
31
|
+
return createErrorResponse(E_UNKNOWN, getErrorMessage(err));
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=store-memory.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"store-memory.js","sourceRoot":"","sources":["../../src/tools/store-memory.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAC9D,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACnD,OAAO,EACL,mBAAmB,EACnB,kBAAkB,GACnB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAC1D,OAAO,EAAE,YAAY,EAAE,mBAAmB,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAGzE,MAAM,iBAAiB,GAAG;+BACK,CAAC;AAEhC,MAAM,UAAU,mBAAmB,CAAC,MAAiB,EAAE,EAAW;IAChE,MAAM,CAAC,YAAY,CACjB,cAAc,EACd;QACE,KAAK,EAAE,cAAc;QACrB,WAAW,EACT,yLAAyL;QAC3L,WAAW,EAAE,sBAAsB;QACnC,YAAY,EAAE,iBAAiB;QAC/B,WAAW,EAAE,EAAE,cAAc,EAAE,IAAI,EAAE,aAAa,EAAE,KAAK,EAAE;KAC5D,EACD,KAAK,EAAE,MAAkB,EAAE,EAAE;QAC3B,IAAI,CAAC;YACH,MAAM,EAAE,UAAU,EAAE,GAAG,MAAM,CAAC;YAC9B,MAAM,UAAU,GAAG,mBAAmB,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;YAC3D,MAAM,IAAI,GAAG,iBAAiB,CAAC,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC;YAC5D,MAAM,GAAG,GAAG,MAAM,EAAE,CAAC;YACrB,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;YAE7C,MAAM,YAAY,GAAG,EAAE;iBACpB,OAAO,CAAC,iBAAiB,CAAC;iBAC1B,GAAG,CACF,IAAI,EACJ,MAAM,CAAC,OAAO,EACd,QAAQ,EACR,UAAU,EACV,UAAU,EACV,GAAG,EACH,GAAG,CACJ,CAAC;YAEJ,MAAM,OAAO,GAAG,YAAY,CAAC,OAAO,GAAG,CAAC,CAAC;YACzC,MAAM,YAAY,CAAC,MAAM,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC;YAEvD,OAAO,kBAAkB,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,CAAC,CAAC;QACrE,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,mBAAmB,CAAC,SAAS,EAAE,eAAe,CAAC,GAAG,CAAC,CAAC,CAAC;QAC9D,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"update-memory.d.ts","sourceRoot":"","sources":["../../src/tools/update-memory.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAIzE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AA0B9C,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,SAAS,EAAE,EAAE,EAAE,OAAO,GAAG,IAAI,CAoDzE"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { E_NOT_FOUND, E_UNKNOWN, getErrorMessage } from '../lib/errors.js';
|
|
2
|
+
import { computeMemoryHash } from '../lib/hash.js';
|
|
3
|
+
import { createErrorResponse, createToolResponse, } from '../lib/tool-response.js';
|
|
4
|
+
import { parseTags } from '../lib/types.js';
|
|
5
|
+
import { UpdateMemoryInputSchema } from '../schemas/inputs.js';
|
|
6
|
+
import { UpdateResultSchema } from '../schemas/outputs.js';
|
|
7
|
+
import { getMemoryRow, logToolEvent, notifyMemoryResourceUpdated, nowIso, withImmediateTransaction, } from './helpers.js';
|
|
8
|
+
const UPDATE_MEMORY_SQL = `UPDATE memories
|
|
9
|
+
SET hash = ?, content = ?, tags = ?, updated_at = ?
|
|
10
|
+
WHERE hash = ?`;
|
|
11
|
+
function formatMemoryNotFound(hash) {
|
|
12
|
+
return `Memory not found: ${hash}`;
|
|
13
|
+
}
|
|
14
|
+
export function registerUpdateMemory(server, db) {
|
|
15
|
+
server.registerTool('update_memory', {
|
|
16
|
+
title: 'Update Memory',
|
|
17
|
+
description: 'Replace the content of an existing memory identified by its hash. Tags may optionally be replaced. Returns the new hash.',
|
|
18
|
+
inputSchema: UpdateMemoryInputSchema,
|
|
19
|
+
outputSchema: UpdateResultSchema,
|
|
20
|
+
annotations: { destructiveHint: true, openWorldHint: false },
|
|
21
|
+
}, async (params) => {
|
|
22
|
+
try {
|
|
23
|
+
const existing = getMemoryRow(db, params.hash);
|
|
24
|
+
if (!existing) {
|
|
25
|
+
return createErrorResponse(E_NOT_FOUND, formatMemoryNotFound(params.hash));
|
|
26
|
+
}
|
|
27
|
+
const existingTags = parseTags(existing.tags);
|
|
28
|
+
const newTags = params.tags ?? existingTags;
|
|
29
|
+
const newHash = computeMemoryHash(params.content, newTags);
|
|
30
|
+
const now = nowIso();
|
|
31
|
+
withImmediateTransaction(db, () => {
|
|
32
|
+
db.prepare(UPDATE_MEMORY_SQL).run(newHash, params.content, JSON.stringify(newTags), now, params.hash);
|
|
33
|
+
});
|
|
34
|
+
await logToolEvent(server, 'update', {
|
|
35
|
+
oldHash: params.hash,
|
|
36
|
+
newHash,
|
|
37
|
+
});
|
|
38
|
+
await notifyMemoryResourceUpdated(server, params.hash);
|
|
39
|
+
return createToolResponse({
|
|
40
|
+
ok: true,
|
|
41
|
+
result: { old_hash: params.hash, new_hash: newHash },
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
catch (err) {
|
|
45
|
+
return createErrorResponse(E_UNKNOWN, getErrorMessage(err));
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=update-memory.js.map
|