@prom.codes/memory-mcp 0.15.1 → 0.15.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bin.js +75 -9
- package/package.json +1 -1
package/dist/bin.js
CHANGED
|
@@ -2688,7 +2688,8 @@ var SqliteMemoryBackend = class {
|
|
|
2688
2688
|
const rows = this.db.prepare(sql).all(...params);
|
|
2689
2689
|
const resolved = resolveScopeChain(rows.map(rowToRecord), query.chain);
|
|
2690
2690
|
const deduped = this.dedupeRecords(resolved);
|
|
2691
|
-
const
|
|
2691
|
+
const offset = query.offset ?? 0;
|
|
2692
|
+
const limited = query.limit !== void 0 ? deduped.slice(offset, offset + query.limit) : deduped.slice(offset);
|
|
2692
2693
|
const bump = this.db.prepare(`UPDATE agent_memory SET use_count = use_count + 1 WHERE id = ?`);
|
|
2693
2694
|
for (const rec of limited) {
|
|
2694
2695
|
bump.run(rec.id);
|
|
@@ -3984,8 +3985,10 @@ function weave(records, options = {}) {
|
|
|
3984
3985
|
|
|
3985
3986
|
// dist/tools.js
|
|
3986
3987
|
var MAX_LIMIT = 100;
|
|
3987
|
-
var DEFAULT_READ_LIMIT =
|
|
3988
|
+
var DEFAULT_READ_LIMIT = 25;
|
|
3988
3989
|
var MAX_VALUE_CHARS = 64 * 1024;
|
|
3990
|
+
var RECORDS_TOKEN_BUDGET = 5e3;
|
|
3991
|
+
var MAX_VALUE_CHARS_IN_VIEW = 4e3;
|
|
3989
3992
|
function textResult(payload) {
|
|
3990
3993
|
return {
|
|
3991
3994
|
content: [{ type: "text", text: JSON.stringify(payload, null, 2) }]
|
|
@@ -4009,6 +4012,52 @@ function recordToJson(rec) {
|
|
|
4009
4012
|
updatedAt: rec.updatedAt
|
|
4010
4013
|
};
|
|
4011
4014
|
}
|
|
4015
|
+
function recordToJsonPreview(rec, maxValueChars) {
|
|
4016
|
+
const view = recordToJson(rec);
|
|
4017
|
+
if (rec.value.length > maxValueChars) {
|
|
4018
|
+
const omitted = rec.value.length - maxValueChars;
|
|
4019
|
+
view.value = `${rec.value.slice(0, maxValueChars)}
|
|
4020
|
+
\u2026[+${omitted} chars omitted \u2014 use \`search\` for the full value]`;
|
|
4021
|
+
view.valueTruncated = true;
|
|
4022
|
+
view.valueChars = rec.value.length;
|
|
4023
|
+
}
|
|
4024
|
+
return view;
|
|
4025
|
+
}
|
|
4026
|
+
function boundRecordsForResult(records) {
|
|
4027
|
+
const views = [];
|
|
4028
|
+
let valuesPreviewed = 0;
|
|
4029
|
+
let tokens = 0;
|
|
4030
|
+
let overBudget = false;
|
|
4031
|
+
for (const rec of records) {
|
|
4032
|
+
const view = recordToJsonPreview(rec, MAX_VALUE_CHARS_IN_VIEW);
|
|
4033
|
+
if (view.valueTruncated === true)
|
|
4034
|
+
valuesPreviewed += 1;
|
|
4035
|
+
const cost = estimateTokens(JSON.stringify(view));
|
|
4036
|
+
if (views.length > 0 && tokens + cost > RECORDS_TOKEN_BUDGET) {
|
|
4037
|
+
overBudget = true;
|
|
4038
|
+
break;
|
|
4039
|
+
}
|
|
4040
|
+
views.push(view);
|
|
4041
|
+
tokens += cost;
|
|
4042
|
+
}
|
|
4043
|
+
return { views, shown: views.length, fetched: records.length, valuesPreviewed, overBudget };
|
|
4044
|
+
}
|
|
4045
|
+
function boundedRecordsNote(b, opts) {
|
|
4046
|
+
if (!b.overBudget && b.valuesPreviewed === 0 && b.fetched < opts.limit)
|
|
4047
|
+
return void 0;
|
|
4048
|
+
const parts = [];
|
|
4049
|
+
if (b.overBudget) {
|
|
4050
|
+
parts.push(`Showing ${b.shown} of ${b.fetched} fetched records \u2014 the result was trimmed to stay under the token budget. The \`woven\` block already carries the highest-value facts within its own cap.`);
|
|
4051
|
+
}
|
|
4052
|
+
if (b.valuesPreviewed > 0) {
|
|
4053
|
+
parts.push(`${b.valuesPreviewed} value(s) previewed to ${MAX_VALUE_CHARS_IN_VIEW} chars.`);
|
|
4054
|
+
}
|
|
4055
|
+
if (b.fetched >= opts.limit) {
|
|
4056
|
+
parts.push(`More records may exist beyond limit=${opts.limit}.`);
|
|
4057
|
+
}
|
|
4058
|
+
parts.push(`To see more: narrow with \`types\`, page with \`offset\` (e.g. offset=${(opts.offset ?? 0) + b.shown}), raise \`limit\`, or use \`search\` for specific facts.`);
|
|
4059
|
+
return parts.join(" ");
|
|
4060
|
+
}
|
|
4012
4061
|
function clampLimit(limit, def) {
|
|
4013
4062
|
if (limit === void 0)
|
|
4014
4063
|
return def;
|
|
@@ -4026,7 +4075,9 @@ var scopeEnum = z.enum(MEMORY_SCOPES);
|
|
|
4026
4075
|
var typeEnum = z.enum(MEMORY_TYPES);
|
|
4027
4076
|
var readInput = {
|
|
4028
4077
|
types: z.array(typeEnum).min(1).optional(),
|
|
4029
|
-
limit: z.number().int().positive().max(MAX_LIMIT).optional()
|
|
4078
|
+
limit: z.number().int().positive().max(MAX_LIMIT).optional(),
|
|
4079
|
+
/** Skip the first N resolved records — page through large memory sets. */
|
|
4080
|
+
offset: z.number().int().nonnegative().optional()
|
|
4030
4081
|
};
|
|
4031
4082
|
var writeInput = {
|
|
4032
4083
|
scope: scopeEnum.optional(),
|
|
@@ -4113,19 +4164,23 @@ function registerTools(server, source, hooks = {}) {
|
|
|
4113
4164
|
}));
|
|
4114
4165
|
reg("read", {
|
|
4115
4166
|
title: "Recall agent memory",
|
|
4116
|
-
description: "Read agent memory for this project along the scope chain (project \u2192 workspace \u2192 tenant \u2192 system; narrowest scope wins). Syncs `.prometheus/memories/*.md` first, then returns the resolved records plus a prompt-ready `woven` markdown block (token-capped). Call this at the START of a session or task to recall what earlier sessions learned.",
|
|
4167
|
+
description: "Read agent memory for this project along the scope chain (project \u2192 workspace \u2192 tenant \u2192 system; narrowest scope wins). Syncs `.prometheus/memories/*.md` first, then returns the resolved records plus a prompt-ready `woven` markdown block (token-capped). The `records` array is bounded to a token budget; a `note` explains how to page (`offset`) or narrow (`types`, `search`) when trimmed. Call this at the START of a session or task to recall what earlier sessions learned.",
|
|
4117
4168
|
inputSchema: readInput
|
|
4118
4169
|
}, async (args) => {
|
|
4119
4170
|
const deps = await ready();
|
|
4120
4171
|
const { backend, workspaceRoot, projectId, projectName } = deps;
|
|
4121
4172
|
const mirrorToFiles = !deps.rootIsHomeOrFsRoot;
|
|
4122
4173
|
const limit = clampLimit(args.limit, DEFAULT_READ_LIMIT);
|
|
4174
|
+
const offset = args.offset ?? 0;
|
|
4123
4175
|
const sync = mirrorToFiles ? await syncProjectFiles(backend, { projectId, workspaceRoot }) : { synced: 0, pruned: 0, skipped: [] };
|
|
4124
4176
|
const records = await backend.read({
|
|
4125
4177
|
chain: defaultScopeChain(projectId),
|
|
4126
4178
|
types: args.types,
|
|
4127
|
-
limit
|
|
4179
|
+
limit,
|
|
4180
|
+
offset
|
|
4128
4181
|
});
|
|
4182
|
+
const bounded = boundRecordsForResult(records);
|
|
4183
|
+
const note = boundedRecordsNote(bounded, { limit, offset });
|
|
4129
4184
|
return textResult({
|
|
4130
4185
|
projectId,
|
|
4131
4186
|
projectName,
|
|
@@ -4133,7 +4188,12 @@ function registerTools(server, source, hooks = {}) {
|
|
|
4133
4188
|
projectFilesPruned: sync.pruned,
|
|
4134
4189
|
...sync.skipped.length > 0 ? { skippedFiles: sync.skipped } : {},
|
|
4135
4190
|
woven: weave(records),
|
|
4136
|
-
|
|
4191
|
+
recordsShown: bounded.shown,
|
|
4192
|
+
recordsFetched: bounded.fetched,
|
|
4193
|
+
limit,
|
|
4194
|
+
offset,
|
|
4195
|
+
...note !== void 0 ? { note } : {},
|
|
4196
|
+
records: bounded.views
|
|
4137
4197
|
});
|
|
4138
4198
|
});
|
|
4139
4199
|
reg("write", {
|
|
@@ -4285,11 +4345,17 @@ ${f.value}`);
|
|
|
4285
4345
|
keyContains: args.keyContains,
|
|
4286
4346
|
limit
|
|
4287
4347
|
});
|
|
4348
|
+
const bounded = boundRecordsForResult(records);
|
|
4349
|
+
const note = boundedRecordsNote(bounded, { limit });
|
|
4288
4350
|
return textResult({
|
|
4289
4351
|
projectId,
|
|
4290
4352
|
projectName,
|
|
4291
4353
|
dbPath,
|
|
4292
|
-
|
|
4354
|
+
recordsShown: bounded.shown,
|
|
4355
|
+
recordsFetched: bounded.fetched,
|
|
4356
|
+
limit,
|
|
4357
|
+
...note !== void 0 ? { note } : {},
|
|
4358
|
+
records: bounded.views
|
|
4293
4359
|
});
|
|
4294
4360
|
});
|
|
4295
4361
|
reg("delete", {
|
|
@@ -4433,7 +4499,7 @@ ${f.value}`);
|
|
|
4433
4499
|
embeddingsError = err instanceof Error ? err.message : String(err);
|
|
4434
4500
|
}
|
|
4435
4501
|
}
|
|
4436
|
-
const update = await buildUpdateStatus("@prom.codes/memory-mcp", "0.15.
|
|
4502
|
+
const update = await buildUpdateStatus("@prom.codes/memory-mcp", "0.15.2", { isDevBuild: false });
|
|
4437
4503
|
let recorder;
|
|
4438
4504
|
try {
|
|
4439
4505
|
const scopes = ["project-local", "project", "user"];
|
|
@@ -4515,7 +4581,7 @@ ${f.value}`);
|
|
|
4515
4581
|
// dist/server.js
|
|
4516
4582
|
var SERVER_IDENTITY = {
|
|
4517
4583
|
name: "prometheus-memory-mcp",
|
|
4518
|
-
version: "0.15.
|
|
4584
|
+
version: "0.15.2",
|
|
4519
4585
|
title: "prom.codes Memory"
|
|
4520
4586
|
};
|
|
4521
4587
|
var SERVER_INSTRUCTIONS = "Persistent agent memory for this workspace \u2014 USE IT PROACTIVELY; the user will not tell you to. Protocol:\n1. ONE-TIME: if this workspace has no Prometheus memory rule yet, call memory_setup now (idempotent) so the protocol is installed into the runtime rule files and survives future sessions. (The server also auto-installs it on startup when a project rule file already exists \u2014 memory_setup covers the rest.)\n2. SESSION START: before any non-trivial task, call memory_read to recall facts, decisions and procedures from earlier sessions.\n3. DURING WORK: when the user states a durable preference, decision, correction or project fact, store it with memory_write (semantic for facts, procedural for how-tos) \u2014 without being asked.\n4. LOOK-UP: use memory_search for keyword recall when memory_read is not specific enough.\n5. SESSION END: consolidate what was learned with memory_capture.\nCall memory_status anytime to check what is stored and whether the rule is installed. Never store secrets, API keys or credentials \u2014 such writes are rejected.";
|