@j0hanz/memory-mcp 1.4.0 → 1.6.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/dist/completions/index.d.ts +1 -0
- package/dist/completions/index.d.ts.map +1 -0
- package/dist/db/index.d.ts +1 -0
- package/dist/db/index.d.ts.map +1 -0
- package/dist/db/index.js +10 -8
- package/dist/db/typed.d.ts +1 -0
- package/dist/db/typed.d.ts.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/lib/errors.d.ts +1 -0
- package/dist/lib/errors.d.ts.map +1 -0
- package/dist/lib/hash.d.ts +1 -0
- package/dist/lib/hash.d.ts.map +1 -0
- package/dist/lib/instructions.d.ts +1 -0
- package/dist/lib/instructions.d.ts.map +1 -0
- package/dist/lib/json-schema.d.ts +1 -0
- package/dist/lib/json-schema.d.ts.map +1 -0
- package/dist/lib/mcp-utils.d.ts +1 -0
- package/dist/lib/mcp-utils.d.ts.map +1 -0
- package/dist/lib/pagination.d.ts +1 -0
- package/dist/lib/pagination.d.ts.map +1 -0
- package/dist/lib/search-cursor.d.ts +1 -0
- package/dist/lib/search-cursor.d.ts.map +1 -0
- package/dist/lib/search.d.ts +1 -0
- package/dist/lib/search.d.ts.map +1 -0
- package/dist/lib/search.js +31 -23
- package/dist/lib/sql.d.ts +1 -0
- package/dist/lib/sql.d.ts.map +1 -0
- package/dist/lib/tool-contracts.d.ts +1 -0
- package/dist/lib/tool-contracts.d.ts.map +1 -0
- package/dist/lib/tool-contracts.js +65 -93
- package/dist/lib/tool-execution.d.ts +13 -0
- package/dist/lib/tool-execution.d.ts.map +1 -0
- package/dist/lib/tool-execution.js +28 -0
- package/dist/lib/tool-response.d.ts +1 -0
- package/dist/lib/tool-response.d.ts.map +1 -0
- package/dist/lib/types.d.ts +1 -0
- package/dist/lib/types.d.ts.map +1 -0
- package/dist/prompts/index.d.ts +1 -0
- package/dist/prompts/index.d.ts.map +1 -0
- package/dist/prompts/index.js +12 -8
- package/dist/resources/index.d.ts +1 -0
- package/dist/resources/index.d.ts.map +1 -0
- package/dist/resources/index.js +65 -38
- package/dist/resources/instructions.d.ts +1 -0
- package/dist/resources/instructions.d.ts.map +1 -0
- package/dist/resources/instructions.js +44 -37
- package/dist/resources/server-config.d.ts +1 -0
- package/dist/resources/server-config.d.ts.map +1 -0
- package/dist/resources/server-config.js +33 -22
- package/dist/resources/tool-catalog.d.ts +1 -0
- package/dist/resources/tool-catalog.d.ts.map +1 -0
- package/dist/resources/tool-catalog.js +10 -5
- package/dist/resources/tool-info.d.ts +1 -0
- package/dist/resources/tool-info.d.ts.map +1 -0
- package/dist/resources/tool-info.js +17 -8
- package/dist/resources/workflows.d.ts +1 -0
- package/dist/resources/workflows.d.ts.map +1 -0
- package/dist/resources/workflows.js +69 -40
- package/dist/schemas/index.d.ts +1 -0
- package/dist/schemas/index.d.ts.map +1 -0
- package/dist/schemas/inputs.d.ts +1 -0
- package/dist/schemas/inputs.d.ts.map +1 -0
- package/dist/schemas/inputs.js +14 -10
- package/dist/schemas/outputs.d.ts +7 -6
- package/dist/schemas/outputs.d.ts.map +1 -0
- package/dist/schemas/outputs.js +7 -6
- package/dist/server.d.ts +1 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +11 -4
- package/dist/tools/create-relationship.d.ts +1 -0
- package/dist/tools/create-relationship.d.ts.map +1 -0
- package/dist/tools/create-relationship.js +14 -19
- package/dist/tools/delete-memories.d.ts +1 -0
- package/dist/tools/delete-memories.d.ts.map +1 -0
- package/dist/tools/delete-memories.js +27 -37
- package/dist/tools/delete-memory.d.ts +1 -0
- package/dist/tools/delete-memory.d.ts.map +1 -0
- package/dist/tools/delete-memory.js +9 -15
- package/dist/tools/delete-relationship.d.ts +1 -0
- package/dist/tools/delete-relationship.d.ts.map +1 -0
- package/dist/tools/delete-relationship.js +7 -12
- package/dist/tools/get-memory.d.ts +1 -0
- package/dist/tools/get-memory.d.ts.map +1 -0
- package/dist/tools/get-memory.js +9 -14
- package/dist/tools/get-relationships.d.ts +1 -0
- package/dist/tools/get-relationships.d.ts.map +1 -0
- package/dist/tools/get-relationships.js +12 -17
- package/dist/tools/index.d.ts +1 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/memory-stats.d.ts +1 -0
- package/dist/tools/memory-stats.d.ts.map +1 -0
- package/dist/tools/memory-stats.js +22 -28
- package/dist/tools/progress.d.ts +1 -0
- package/dist/tools/progress.d.ts.map +1 -0
- package/dist/tools/progress.js +30 -23
- package/dist/tools/recall.d.ts +1 -0
- package/dist/tools/recall.d.ts.map +1 -0
- package/dist/tools/recall.js +77 -48
- package/dist/tools/register-contract.d.ts +1 -0
- package/dist/tools/register-contract.d.ts.map +1 -0
- package/dist/tools/result.d.ts +1 -0
- package/dist/tools/result.d.ts.map +1 -0
- package/dist/tools/retrieve-context.d.ts +1 -0
- package/dist/tools/retrieve-context.d.ts.map +1 -0
- package/dist/tools/retrieve-context.js +47 -33
- package/dist/tools/search-memories.d.ts +1 -0
- package/dist/tools/search-memories.d.ts.map +1 -0
- package/dist/tools/search-memories.js +24 -30
- package/dist/tools/store-memories.d.ts +1 -0
- package/dist/tools/store-memories.d.ts.map +1 -0
- package/dist/tools/store-memories.js +32 -42
- package/dist/tools/store-memory.d.ts +1 -0
- package/dist/tools/store-memory.d.ts.map +1 -0
- package/dist/tools/store-memory.js +12 -18
- package/dist/tools/update-memory.d.ts +1 -0
- package/dist/tools/update-memory.d.ts.map +1 -0
- package/dist/tools/update-memory.js +41 -46
- package/package.json +2 -2
package/dist/tools/progress.js
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import { E_CANCELLED } from '../lib/errors.js';
|
|
2
2
|
import { getToolResultText } from './result.js';
|
|
3
3
|
const DEFAULT_PROGRESS_INTERVAL_MS = 250;
|
|
4
|
+
const TOOL_HANDLER_PROGRESS_TOTAL = 1;
|
|
5
|
+
function hasProgressTransport(extra, progressToken) {
|
|
6
|
+
return (progressToken !== undefined && typeof extra.sendNotification === 'function');
|
|
7
|
+
}
|
|
4
8
|
function toProgressToken(value) {
|
|
5
9
|
if (typeof value === 'string' || typeof value === 'number') {
|
|
6
10
|
return value;
|
|
@@ -20,6 +24,19 @@ function toNotificationParams(progressToken, progress) {
|
|
|
20
24
|
}
|
|
21
25
|
return params;
|
|
22
26
|
}
|
|
27
|
+
function toProgressNotification(progressToken, progress) {
|
|
28
|
+
return {
|
|
29
|
+
method: 'notifications/progress',
|
|
30
|
+
params: toNotificationParams(progressToken, progress),
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
function toProgressPayload(progress, current) {
|
|
34
|
+
return {
|
|
35
|
+
current,
|
|
36
|
+
...(progress.total !== undefined ? { total: progress.total } : {}),
|
|
37
|
+
...(progress.message !== undefined ? { message: progress.message } : {}),
|
|
38
|
+
};
|
|
39
|
+
}
|
|
23
40
|
function getResultOutcome(result) {
|
|
24
41
|
if (result.isError) {
|
|
25
42
|
const text = getToolResultText(result);
|
|
@@ -41,14 +58,11 @@ export async function notifyProgress(extra, progress) {
|
|
|
41
58
|
if (progressToken === undefined) {
|
|
42
59
|
return;
|
|
43
60
|
}
|
|
44
|
-
if (
|
|
61
|
+
if (!hasProgressTransport(extra, progressToken)) {
|
|
45
62
|
return;
|
|
46
63
|
}
|
|
47
64
|
try {
|
|
48
|
-
await extra.sendNotification(
|
|
49
|
-
method: 'notifications/progress',
|
|
50
|
-
params: toNotificationParams(progressToken, progress),
|
|
51
|
-
});
|
|
65
|
+
await extra.sendNotification(toProgressNotification(progressToken, progress));
|
|
52
66
|
}
|
|
53
67
|
catch {
|
|
54
68
|
// best-effort progress
|
|
@@ -75,13 +89,7 @@ export function createProgressReporter(extra, options = {}) {
|
|
|
75
89
|
lastReportedAt = now;
|
|
76
90
|
isCompleted =
|
|
77
91
|
progress.total !== undefined && monotonicCurrent >= progress.total;
|
|
78
|
-
const payload =
|
|
79
|
-
if (progress.total !== undefined) {
|
|
80
|
-
payload.total = progress.total;
|
|
81
|
-
}
|
|
82
|
-
if (progress.message !== undefined) {
|
|
83
|
-
payload.message = progress.message;
|
|
84
|
-
}
|
|
92
|
+
const payload = toProgressPayload(progress, monotonicCurrent);
|
|
85
93
|
notificationChain = notificationChain.then(() => notifyProgress(extra, payload));
|
|
86
94
|
});
|
|
87
95
|
reporter.flush = async () => {
|
|
@@ -102,11 +110,18 @@ export function progressWithMessage(reporter, getMessage) {
|
|
|
102
110
|
return wrapped;
|
|
103
111
|
}
|
|
104
112
|
export function wrapToolHandler(handler, options) {
|
|
113
|
+
const notifyTerminalProgress = async (extra, startMessage, outcome, completionMessage) => {
|
|
114
|
+
await notifyProgress(extra, {
|
|
115
|
+
current: TOOL_HANDLER_PROGRESS_TOTAL,
|
|
116
|
+
total: TOOL_HANDLER_PROGRESS_TOTAL,
|
|
117
|
+
message: completionMessage ?? `${startMessage} • ${outcome}`,
|
|
118
|
+
});
|
|
119
|
+
};
|
|
105
120
|
return async (args, extra) => {
|
|
106
121
|
const startMessage = options.progressMessage(args);
|
|
107
122
|
await notifyProgress(extra, {
|
|
108
123
|
current: 0,
|
|
109
|
-
total:
|
|
124
|
+
total: TOOL_HANDLER_PROGRESS_TOTAL,
|
|
110
125
|
message: startMessage,
|
|
111
126
|
});
|
|
112
127
|
let result;
|
|
@@ -115,20 +130,12 @@ export function wrapToolHandler(handler, options) {
|
|
|
115
130
|
}
|
|
116
131
|
catch (error) {
|
|
117
132
|
const isCancelled = error instanceof Error && error.message === E_CANCELLED;
|
|
118
|
-
await
|
|
119
|
-
current: 1,
|
|
120
|
-
total: 1,
|
|
121
|
-
message: `${startMessage} • ${isCancelled ? 'cancelled' : 'failed'}`,
|
|
122
|
-
});
|
|
133
|
+
await notifyTerminalProgress(extra, startMessage, isCancelled ? 'cancelled' : 'failed');
|
|
123
134
|
throw error;
|
|
124
135
|
}
|
|
125
136
|
const completionMessage = options.completionMessage?.(args, result) ??
|
|
126
137
|
defaultCompletionMessage(startMessage, result);
|
|
127
|
-
await
|
|
128
|
-
current: 1,
|
|
129
|
-
total: 1,
|
|
130
|
-
message: completionMessage,
|
|
131
|
-
});
|
|
138
|
+
await notifyTerminalProgress(extra, startMessage, 'completed', completionMessage);
|
|
132
139
|
return result;
|
|
133
140
|
};
|
|
134
141
|
}
|
package/dist/tools/recall.d.ts
CHANGED
|
@@ -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;AAUzE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AAoX9C,wBAAgB,cAAc,CAAC,MAAM,EAAE,SAAS,EAAE,EAAE,EAAE,OAAO,GAAG,IAAI,CAqFnE"}
|
package/dist/tools/recall.js
CHANGED
|
@@ -145,9 +145,71 @@ function formatRecallCompletionMessage(query, result) {
|
|
|
145
145
|
const aborted = 'aborted' in payload && payload.aborted === true;
|
|
146
146
|
return `⊙ recall: ${query} • ${memoriesCount} memories, ${edgesCount} edges${aborted ? ' [aborted]' : ''}`;
|
|
147
147
|
}
|
|
148
|
+
function decodeCursorForRecall(cursor, scope) {
|
|
149
|
+
if (!cursor) {
|
|
150
|
+
return undefined;
|
|
151
|
+
}
|
|
152
|
+
return decodeSearchCursor(cursor, scope);
|
|
153
|
+
}
|
|
154
|
+
function buildSeedRelevanceMap(seeds) {
|
|
155
|
+
const seedRelevance = new Map();
|
|
156
|
+
for (const seed of seeds) {
|
|
157
|
+
if (seed.rank != null) {
|
|
158
|
+
seedRelevance.set(seed.hash, -seed.rank);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
return seedRelevance;
|
|
162
|
+
}
|
|
163
|
+
function toMemoriesWithRelevance(rows, seedRelevance) {
|
|
164
|
+
return rows.map((row) => {
|
|
165
|
+
const memory = parseMemoryRow(row);
|
|
166
|
+
const relevance = seedRelevance.get(memory.hash);
|
|
167
|
+
if (relevance != null) {
|
|
168
|
+
memory.relevance = relevance;
|
|
169
|
+
}
|
|
170
|
+
return memory;
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
function buildNextCursor(hasMore, pageSeeds, scope) {
|
|
174
|
+
if (!hasMore || pageSeeds.length === 0) {
|
|
175
|
+
return undefined;
|
|
176
|
+
}
|
|
177
|
+
const lastSeed = pageSeeds[pageSeeds.length - 1];
|
|
178
|
+
if (!lastSeed) {
|
|
179
|
+
return undefined;
|
|
180
|
+
}
|
|
181
|
+
const rank = lastSeed.rank ?? 0;
|
|
182
|
+
return encodeSearchCursor(scope, rank, lastSeed.hash);
|
|
183
|
+
}
|
|
184
|
+
function createHopReporter(extra, query, completionCurrent) {
|
|
185
|
+
const reporter = progressWithMessage(createProgressReporter(extra), ({ current, total }) => `⊙ recall: ${query} [hop ${current}/${Math.max((total ?? current) - 1, current)}]`);
|
|
186
|
+
const onHop = (hop) => {
|
|
187
|
+
reporter({ current: hop + 1, total: completionCurrent });
|
|
188
|
+
};
|
|
189
|
+
return { reporter, onHop };
|
|
190
|
+
}
|
|
191
|
+
async function computeRecall(db, params, scope, signal, onHop) {
|
|
192
|
+
const decodedCursor = decodeCursorForRecall(params.cursor, scope);
|
|
193
|
+
const seedRows = loadRankedSearchRows(db, params.query, params.limit, decodedCursor, toMemoryFilters(params));
|
|
194
|
+
const { page: pageSeeds, hasMore } = splitPage(seedRows, params.limit);
|
|
195
|
+
const traversal = await traverseGraph(db, pageSeeds, params.depth, signal, onHop);
|
|
196
|
+
const allHashes = Array.from(traversal.visited);
|
|
197
|
+
const seedRelevance = buildSeedRelevanceMap(pageSeeds);
|
|
198
|
+
const memoryRows = loadMemoriesByHashes(db, allHashes);
|
|
199
|
+
const nextCursor = buildNextCursor(hasMore, pageSeeds, scope);
|
|
200
|
+
return {
|
|
201
|
+
memories: toMemoriesWithRelevance(memoryRows, seedRelevance),
|
|
202
|
+
edges: traversal.edges,
|
|
203
|
+
depthReached: traversal.depthReached,
|
|
204
|
+
aborted: traversal.aborted,
|
|
205
|
+
...(nextCursor ? { nextCursor } : {}),
|
|
206
|
+
seedCount: pageSeeds.length,
|
|
207
|
+
visitedCount: traversal.visited.size,
|
|
208
|
+
};
|
|
209
|
+
}
|
|
148
210
|
export function registerRecall(server, db) {
|
|
149
211
|
registerToolWithContract(server, 'recall', RecallInputSchema, RecallResultSchema, async (params, extra) => {
|
|
150
|
-
const { depth
|
|
212
|
+
const { depth } = params;
|
|
151
213
|
const filters = toMemoryFilters(params);
|
|
152
214
|
const scope = buildSearchCursorScope(params.query, filters);
|
|
153
215
|
const contextLabel = `⊙ recall: ${params.query} [depth ${depth}]`;
|
|
@@ -157,62 +219,29 @@ export function registerRecall(server, db) {
|
|
|
157
219
|
total: completionCurrent,
|
|
158
220
|
message: contextLabel,
|
|
159
221
|
});
|
|
160
|
-
const
|
|
161
|
-
const onHop = (hop) => {
|
|
162
|
-
hopReporter({ current: hop + 1, total: completionCurrent });
|
|
163
|
-
};
|
|
222
|
+
const { reporter: hopReporter, onHop } = createHopReporter(extra, params.query, completionCurrent);
|
|
164
223
|
let result;
|
|
165
224
|
let thrownError;
|
|
166
225
|
try {
|
|
167
226
|
throwIfAborted(extra.signal);
|
|
168
|
-
const
|
|
169
|
-
? decodeSearchCursor(cursor, scope)
|
|
170
|
-
: undefined;
|
|
171
|
-
// Step 1: FTS seed search
|
|
172
|
-
const seedRows = loadRankedSearchRows(db, params.query, limit, decodedCursor, filters);
|
|
227
|
+
const computation = await computeRecall(db, params, scope, extra.signal, onHop);
|
|
173
228
|
throwIfAborted(extra.signal);
|
|
174
|
-
const { page: pageSeeds, hasMore } = splitPage(seedRows, limit);
|
|
175
|
-
// Step 2: BFS traversal up to `depth` hops
|
|
176
|
-
const traversal = await traverseGraph(db, pageSeeds, depth, extra.signal, onHop);
|
|
177
|
-
throwIfAborted(extra.signal);
|
|
178
|
-
// Step 3: Load all discovered memory rows
|
|
179
|
-
const allHashes = Array.from(traversal.visited);
|
|
180
|
-
const seedRelevance = new Map();
|
|
181
|
-
for (const seed of pageSeeds) {
|
|
182
|
-
if (seed.rank != null)
|
|
183
|
-
seedRelevance.set(seed.hash, -seed.rank);
|
|
184
|
-
}
|
|
185
|
-
const memoryRows = loadMemoriesByHashes(db, allHashes);
|
|
186
|
-
const memories = memoryRows.map((row) => {
|
|
187
|
-
const memory = parseMemoryRow(row);
|
|
188
|
-
const rel = seedRelevance.get(memory.hash);
|
|
189
|
-
if (rel != null) {
|
|
190
|
-
memory.relevance = rel;
|
|
191
|
-
}
|
|
192
|
-
return memory;
|
|
193
|
-
});
|
|
194
|
-
let nextCursor;
|
|
195
|
-
if (hasMore && pageSeeds.length > 0) {
|
|
196
|
-
const lastSeed = pageSeeds[pageSeeds.length - 1];
|
|
197
|
-
if (lastSeed !== undefined) {
|
|
198
|
-
const rank = lastSeed.rank ?? 0;
|
|
199
|
-
nextCursor = encodeSearchCursor(scope, rank, lastSeed.hash);
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
229
|
await logToolEvent(server, 'recall', {
|
|
203
230
|
depth,
|
|
204
|
-
depth_reached:
|
|
205
|
-
seed_count:
|
|
206
|
-
visited_nodes:
|
|
207
|
-
edge_count:
|
|
208
|
-
aborted:
|
|
231
|
+
depth_reached: computation.depthReached,
|
|
232
|
+
seed_count: computation.seedCount,
|
|
233
|
+
visited_nodes: computation.visitedCount,
|
|
234
|
+
edge_count: computation.edges.length,
|
|
235
|
+
aborted: computation.aborted,
|
|
209
236
|
});
|
|
210
237
|
result = createToolResponse({
|
|
211
|
-
memories,
|
|
212
|
-
graph:
|
|
213
|
-
depth_reached:
|
|
214
|
-
...(
|
|
215
|
-
...(nextCursor
|
|
238
|
+
memories: computation.memories,
|
|
239
|
+
graph: computation.edges,
|
|
240
|
+
depth_reached: computation.depthReached,
|
|
241
|
+
...(computation.aborted ? { aborted: true } : {}),
|
|
242
|
+
...(computation.nextCursor
|
|
243
|
+
? { nextCursor: computation.nextCursor }
|
|
244
|
+
: {}),
|
|
216
245
|
});
|
|
217
246
|
}
|
|
218
247
|
catch (err) {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
1
|
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
2
|
import type { z } from 'zod/v4';
|
|
3
3
|
export declare function registerToolWithContract(server: McpServer, toolName: string, _inputSchema: z.ZodType, _outputSchema: z.ZodType, handler: unknown): void;
|
|
4
|
+
//# sourceMappingURL=register-contract.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"register-contract.d.ts","sourceRoot":"","sources":["../../src/tools/register-contract.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEzE,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,QAAQ,CAAC;AAIhC,wBAAgB,wBAAwB,CACtC,MAAM,EAAE,SAAS,EACjB,QAAQ,EAAE,MAAM,EAChB,YAAY,EAAE,CAAC,CAAC,OAAO,EACvB,aAAa,EAAE,CAAC,CAAC,OAAO,EACxB,OAAO,EAAE,OAAO,GACf,IAAI,CAcN"}
|
package/dist/tools/result.d.ts
CHANGED
|
@@ -5,3 +5,4 @@ export declare function getToolResultPayload(result: CallToolResult): ToolResult
|
|
|
5
5
|
export declare function getToolResultText(result: CallToolResult): string;
|
|
6
6
|
/** Count items in a named array field of a tool result payload. */
|
|
7
7
|
export declare function countPayloadArrayItems(payload: Record<string, unknown>, key: string): number;
|
|
8
|
+
//# sourceMappingURL=result.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"result.d.ts","sourceRoot":"","sources":["../../src/tools/result.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AAEzE,MAAM,MAAM,iBAAiB,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAMxD,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,cAAc,GAAG,OAAO,CAExE;AAED,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,cAAc,GACrB,iBAAiB,GAAG,SAAS,CAO/B;AAED,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,cAAc,GAAG,MAAM,CAGhE;AAED,mEAAmE;AACnE,wBAAgB,sBAAsB,CACpC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAChC,GAAG,EAAE,MAAM,GACV,MAAM,CAGR"}
|
|
@@ -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;AAMzE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AA8N9C,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,SAAS,EAAE,EAAE,EAAE,OAAO,GAAG,IAAI,CA0E5E"}
|
|
@@ -74,15 +74,54 @@ function throwIfAborted(signal) {
|
|
|
74
74
|
}
|
|
75
75
|
throw new Error(E_CANCELLED);
|
|
76
76
|
}
|
|
77
|
+
function computeCandidateLimit(tokenBudget) {
|
|
78
|
+
const estimatedCandidates = Math.ceil(tokenBudget / ESTIMATED_TOKENS_PER_MEMORY);
|
|
79
|
+
return Math.min(Math.max(MIN_CANDIDATE_ROWS, estimatedCandidates), MAX_CANDIDATE_ROWS);
|
|
80
|
+
}
|
|
81
|
+
function selectMemoriesWithinBudget(rows, candidateCount, tokenBudget, completionCurrent, signal, onProgress) {
|
|
82
|
+
let estimatedTokens = 0;
|
|
83
|
+
let truncated = rows.length > candidateCount;
|
|
84
|
+
const selected = [];
|
|
85
|
+
let scanned = 0;
|
|
86
|
+
for (let i = 0; i < candidateCount; i += 1) {
|
|
87
|
+
throwIfAborted(signal);
|
|
88
|
+
const row = rows[i];
|
|
89
|
+
if (!row) {
|
|
90
|
+
break;
|
|
91
|
+
}
|
|
92
|
+
const memory = parseMemoryRow(row);
|
|
93
|
+
const tokens = estimateTokens(memory.content);
|
|
94
|
+
scanned += 1;
|
|
95
|
+
reportSelectionProgress(onProgress, scanned, completionCurrent, false);
|
|
96
|
+
if (estimatedTokens + tokens > tokenBudget) {
|
|
97
|
+
truncated = true;
|
|
98
|
+
break;
|
|
99
|
+
}
|
|
100
|
+
estimatedTokens += tokens;
|
|
101
|
+
selected.push(memory);
|
|
102
|
+
}
|
|
103
|
+
reportSelectionProgress(onProgress, scanned, completionCurrent, true);
|
|
104
|
+
return { selected, estimatedTokens, truncated };
|
|
105
|
+
}
|
|
106
|
+
function computeRetrieveContextResult(db, params, limit, signal, onProgress) {
|
|
107
|
+
const orderBy = ORDER_BY_MAP[params.strategy];
|
|
108
|
+
const rows = loadContextRows(db, params.query, orderBy, limit);
|
|
109
|
+
const rowCapExceeded = rows.length > limit;
|
|
110
|
+
const candidateCount = rowCapExceeded ? limit : rows.length;
|
|
111
|
+
const completionCurrent = candidateCount + 1;
|
|
112
|
+
return {
|
|
113
|
+
selection: selectMemoriesWithinBudget(rows, candidateCount, params.token_budget, completionCurrent, signal, onProgress),
|
|
114
|
+
completionCurrent,
|
|
115
|
+
};
|
|
116
|
+
}
|
|
77
117
|
export function registerRetrieveContext(server, db) {
|
|
78
118
|
registerToolWithContract(server, 'retrieve_context', RetrieveContextInputSchema, RetrieveContextResultSchema, async (params, extra) => {
|
|
79
119
|
const { query, strategy } = params;
|
|
80
120
|
const tokenBudget = params.token_budget;
|
|
81
121
|
const contextLabel = `⊙ retrieve_context: ${query} [${strategy}]`;
|
|
82
122
|
let completionCurrent = 1;
|
|
83
|
-
// Heuristic: Load enough candidates to likely fill the budget, but cap to avoid massive queries
|
|
84
|
-
const
|
|
85
|
-
const limit = Math.min(Math.max(MIN_CANDIDATE_ROWS, estimatedCandidates), MAX_CANDIDATE_ROWS);
|
|
123
|
+
// Heuristic: Load enough candidates to likely fill the budget, but cap to avoid massive queries.
|
|
124
|
+
const limit = computeCandidateLimit(tokenBudget);
|
|
86
125
|
await notifyProgress(extra, {
|
|
87
126
|
current: 0,
|
|
88
127
|
message: `${contextLabel} [budget ${tokenBudget}]`,
|
|
@@ -92,37 +131,12 @@ export function registerRetrieveContext(server, db) {
|
|
|
92
131
|
let thrownError;
|
|
93
132
|
try {
|
|
94
133
|
throwIfAborted(extra.signal);
|
|
95
|
-
const
|
|
96
|
-
|
|
97
|
-
const rowCapExceeded = rows.length > limit;
|
|
98
|
-
const candidateCount = rowCapExceeded ? limit : rows.length;
|
|
99
|
-
completionCurrent = candidateCount + 1;
|
|
100
|
-
let estimatedTokens = 0;
|
|
101
|
-
let truncated = rowCapExceeded;
|
|
102
|
-
const selected = [];
|
|
103
|
-
let scanned = 0;
|
|
104
|
-
for (let i = 0; i < candidateCount; i += 1) {
|
|
105
|
-
throwIfAborted(extra.signal);
|
|
106
|
-
const row = rows[i];
|
|
107
|
-
if (row === undefined) {
|
|
108
|
-
break;
|
|
109
|
-
}
|
|
110
|
-
const mem = parseMemoryRow(row);
|
|
111
|
-
const tokens = estimateTokens(mem.content);
|
|
112
|
-
scanned += 1;
|
|
113
|
-
reportSelectionProgress(loopProgress, scanned, completionCurrent, false);
|
|
114
|
-
if (estimatedTokens + tokens > tokenBudget) {
|
|
115
|
-
truncated = true;
|
|
116
|
-
break;
|
|
117
|
-
}
|
|
118
|
-
estimatedTokens += tokens;
|
|
119
|
-
selected.push(mem);
|
|
120
|
-
}
|
|
121
|
-
reportSelectionProgress(loopProgress, scanned, completionCurrent, true);
|
|
134
|
+
const { selection, completionCurrent: nextCompletionCurrent } = computeRetrieveContextResult(db, params, limit, extra.signal, loopProgress);
|
|
135
|
+
completionCurrent = nextCompletionCurrent;
|
|
122
136
|
result = createToolResponse({
|
|
123
|
-
memories: selected,
|
|
124
|
-
estimated_tokens: estimatedTokens,
|
|
125
|
-
truncated,
|
|
137
|
+
memories: selection.selected,
|
|
138
|
+
estimated_tokens: selection.estimatedTokens,
|
|
139
|
+
truncated: selection.truncated,
|
|
126
140
|
});
|
|
127
141
|
}
|
|
128
142
|
catch (err) {
|
|
@@ -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;AAmB9C,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,SAAS,EAAE,EAAE,EAAE,OAAO,GAAG,IAAI,CA8C3E"}
|
|
@@ -1,44 +1,38 @@
|
|
|
1
|
-
import { E_UNKNOWN, getErrorMessage, rethrowMcpError } from '../lib/errors.js';
|
|
2
1
|
import { splitPage } from '../lib/pagination.js';
|
|
3
2
|
import { buildSearchCursorScope, decodeSearchCursor, encodeSearchCursor, } from '../lib/search-cursor.js';
|
|
4
3
|
import { loadRankedSearchRows, toMemoryFilters } from '../lib/search.js';
|
|
5
|
-
import {
|
|
4
|
+
import { executeToolSafely } from '../lib/tool-execution.js';
|
|
5
|
+
import { createToolResponse } from '../lib/tool-response.js';
|
|
6
6
|
import { parseMemoryRow } from '../lib/types.js';
|
|
7
7
|
import { SearchMemoriesInputSchema } from '../schemas/inputs.js';
|
|
8
8
|
import { SearchResultSchema } from '../schemas/outputs.js';
|
|
9
9
|
import { wrapToolHandler } from './progress.js';
|
|
10
10
|
import { registerToolWithContract } from './register-contract.js';
|
|
11
11
|
export function registerSearchMemories(server, db) {
|
|
12
|
-
registerToolWithContract(server, 'search_memories', SearchMemoriesInputSchema, SearchResultSchema, wrapToolHandler((params) => {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
nextCursor = encodeSearchCursor(scope, rank, lastRow.hash);
|
|
29
|
-
}
|
|
12
|
+
registerToolWithContract(server, 'search_memories', SearchMemoriesInputSchema, SearchResultSchema, wrapToolHandler((params) => executeToolSafely(() => {
|
|
13
|
+
const { limit, cursor } = params;
|
|
14
|
+
const filters = toMemoryFilters(params);
|
|
15
|
+
const scope = buildSearchCursorScope(params.query, filters);
|
|
16
|
+
const decodedCursor = cursor
|
|
17
|
+
? decodeSearchCursor(cursor, scope)
|
|
18
|
+
: undefined;
|
|
19
|
+
const rows = loadRankedSearchRows(db, params.query, limit, decodedCursor, filters);
|
|
20
|
+
const { page: pageRows, hasMore } = splitPage(rows, limit);
|
|
21
|
+
const memories = pageRows.map(parseMemoryRow);
|
|
22
|
+
let nextCursor;
|
|
23
|
+
if (hasMore && pageRows.length > 0) {
|
|
24
|
+
const lastRow = pageRows[pageRows.length - 1];
|
|
25
|
+
if (lastRow !== undefined) {
|
|
26
|
+
const rank = lastRow.rank ?? 0;
|
|
27
|
+
nextCursor = encodeSearchCursor(scope, rank, lastRow.hash);
|
|
30
28
|
}
|
|
31
|
-
return createToolResponse({
|
|
32
|
-
memories,
|
|
33
|
-
total_returned: memories.length,
|
|
34
|
-
...(nextCursor ? { nextCursor } : {}),
|
|
35
|
-
});
|
|
36
29
|
}
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
30
|
+
return createToolResponse({
|
|
31
|
+
memories,
|
|
32
|
+
total_returned: memories.length,
|
|
33
|
+
...(nextCursor ? { nextCursor } : {}),
|
|
34
|
+
});
|
|
35
|
+
}), {
|
|
42
36
|
progressMessage: (params) => `⊙ search_memories: ${params.query} [limit ${params.limit}]`,
|
|
43
37
|
}));
|
|
44
38
|
}
|
|
@@ -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;AAwB9C,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,SAAS,EAAE,EAAE,EAAE,OAAO,GAAG,IAAI,CA2D1E"}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { E_UNKNOWN, getErrorMessage, rethrowMcpError } from '../lib/errors.js';
|
|
2
1
|
import { computeMemoryHash } from '../lib/hash.js';
|
|
3
2
|
import { logToolEvent, notifyMemoryResourceUpdated } from '../lib/mcp-utils.js';
|
|
4
3
|
import { INSERT_MEMORY_SQL } from '../lib/sql.js';
|
|
5
|
-
import {
|
|
4
|
+
import { executeToolSafely, summarizeBatch } from '../lib/tool-execution.js';
|
|
5
|
+
import { createToolResponse } from '../lib/tool-response.js';
|
|
6
6
|
import { StoreMemoriesInputSchema } from '../schemas/inputs.js';
|
|
7
7
|
import { BatchResultSchema } from '../schemas/outputs.js';
|
|
8
8
|
import { wrapToolHandler } from './progress.js';
|
|
@@ -14,47 +14,37 @@ async function notifyCreatedResources(server, items) {
|
|
|
14
14
|
await Promise.allSettled(notifications);
|
|
15
15
|
}
|
|
16
16
|
export function registerStoreMemories(server, db) {
|
|
17
|
-
registerToolWithContract(server, 'store_memories', StoreMemoriesInputSchema, BatchResultSchema, wrapToolHandler(async (params) => {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
const
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
});
|
|
34
|
-
}
|
|
35
|
-
return items;
|
|
36
|
-
});
|
|
37
|
-
let created = 0;
|
|
38
|
-
let succeeded = 0;
|
|
39
|
-
for (const item of results) {
|
|
40
|
-
if (item.ok)
|
|
41
|
-
succeeded += 1;
|
|
42
|
-
if (item.created)
|
|
43
|
-
created += 1;
|
|
17
|
+
registerToolWithContract(server, 'store_memories', StoreMemoriesInputSchema, BatchResultSchema, wrapToolHandler(async (params) => executeToolSafely(async () => {
|
|
18
|
+
const now = new Date().toISOString();
|
|
19
|
+
const results = db.transaction(() => {
|
|
20
|
+
const items = [];
|
|
21
|
+
const stmt = db.prepareOnce(INSERT_MEMORY_SQL);
|
|
22
|
+
for (const item of params.items) {
|
|
23
|
+
const { importance, memory_type: rawMemoryType } = item;
|
|
24
|
+
const memoryType = rawMemoryType ?? 'general';
|
|
25
|
+
const hash = computeMemoryHash(item.content, item.tags);
|
|
26
|
+
const tagsJson = JSON.stringify(item.tags);
|
|
27
|
+
const result = stmt.run(hash, item.content, tagsJson, memoryType, importance, now, now);
|
|
28
|
+
items.push({
|
|
29
|
+
hash,
|
|
30
|
+
ok: true,
|
|
31
|
+
created: result.changes > 0,
|
|
32
|
+
});
|
|
44
33
|
}
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
34
|
+
return items;
|
|
35
|
+
});
|
|
36
|
+
const summary = summarizeBatch(results, (item) => item.created === true);
|
|
37
|
+
await logToolEvent(server, 'store_memories', {
|
|
38
|
+
total: results.length,
|
|
39
|
+
created: summary.matched,
|
|
40
|
+
});
|
|
41
|
+
await notifyCreatedResources(server, results);
|
|
42
|
+
return createToolResponse({
|
|
43
|
+
items: results,
|
|
44
|
+
succeeded: summary.succeeded,
|
|
45
|
+
failed: summary.failed,
|
|
46
|
+
});
|
|
47
|
+
}), {
|
|
58
48
|
progressMessage: (params) => `⊕ store_memories: ${params.items.length} items [batch]`,
|
|
59
49
|
}));
|
|
60
50
|
}
|
|
@@ -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;AA2C9C,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,SAAS,EAAE,EAAE,EAAE,OAAO,GAAG,IAAI,CA0BxE"}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { E_UNKNOWN, getErrorMessage, rethrowMcpError } from '../lib/errors.js';
|
|
2
1
|
import { computeMemoryHash } from '../lib/hash.js';
|
|
3
2
|
import { logToolEvent, notifyMemoryResourceUpdated } from '../lib/mcp-utils.js';
|
|
4
3
|
import { INSERT_MEMORY_SQL } from '../lib/sql.js';
|
|
5
|
-
import {
|
|
4
|
+
import { executeToolSafely } from '../lib/tool-execution.js';
|
|
5
|
+
import { createToolResponse } from '../lib/tool-response.js';
|
|
6
6
|
import { StoreMemoryInputSchema } from '../schemas/inputs.js';
|
|
7
7
|
import { StoreResultSchema } from '../schemas/outputs.js';
|
|
8
8
|
import { wrapToolHandler } from './progress.js';
|
|
@@ -25,23 +25,17 @@ function insertMemory(db, params, hash, memoryType, now) {
|
|
|
25
25
|
return insertResult.changes > 0;
|
|
26
26
|
}
|
|
27
27
|
export function registerStoreMemory(server, db) {
|
|
28
|
-
registerToolWithContract(server, 'store_memory', StoreMemoryInputSchema, StoreResultSchema, wrapToolHandler(async (params) => {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
await notifyMemoryResourceUpdated(server, hash);
|
|
37
|
-
}
|
|
38
|
-
return createToolResponse({ hash, created });
|
|
28
|
+
registerToolWithContract(server, 'store_memory', StoreMemoryInputSchema, StoreResultSchema, wrapToolHandler(async (params) => executeToolSafely(async () => {
|
|
29
|
+
const memoryType = params.memory_type ?? 'general';
|
|
30
|
+
const hash = computeMemoryHash(params.content, params.tags);
|
|
31
|
+
const now = new Date().toISOString();
|
|
32
|
+
const created = insertMemory(db, params, hash, memoryType, now);
|
|
33
|
+
await logToolEvent(server, 'store', { hash, created });
|
|
34
|
+
if (created) {
|
|
35
|
+
await notifyMemoryResourceUpdated(server, hash);
|
|
39
36
|
}
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
return createErrorResponse(E_UNKNOWN, getErrorMessage(err));
|
|
43
|
-
}
|
|
44
|
-
}, {
|
|
37
|
+
return createToolResponse({ hash, created });
|
|
38
|
+
}), {
|
|
45
39
|
progressMessage: (params) => `⊕ store_memory: ${params.tags.length} tags [single]`,
|
|
46
40
|
}));
|
|
47
41
|
}
|
|
@@ -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;AAyC9C,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,SAAS,EAAE,EAAE,EAAE,OAAO,GAAG,IAAI,CA6EzE"}
|