@agentmemory/agentmemory 0.8.12 → 0.9.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 +69 -2
- package/dist/cli.mjs +47 -5
- package/dist/cli.mjs.map +1 -1
- package/dist/index.mjs +576 -30
- package/dist/index.mjs.map +1 -1
- package/dist/{src-68MXysnV.mjs → src-B3pEsBSb.mjs} +568 -26
- package/dist/src-B3pEsBSb.mjs.map +1 -0
- package/dist/standalone-DXc-BEqr.mjs +457 -0
- package/dist/standalone-DXc-BEqr.mjs.map +1 -0
- package/dist/standalone.d.mts.map +1 -1
- package/dist/standalone.mjs +210 -67
- package/dist/standalone.mjs.map +1 -1
- package/dist/{tools-registry-D96ukJg4.mjs → tools-registry-DXIK5CxQ.mjs} +11 -7
- package/dist/tools-registry-DXIK5CxQ.mjs.map +1 -0
- package/dist/viewer/index.html +264 -0
- package/package.json +1 -1
- package/plugin/.claude-plugin/plugin.json +1 -1
- package/dist/src-68MXysnV.mjs.map +0 -1
- package/dist/standalone-c2xiEQJ9.mjs +0 -314
- package/dist/standalone-c2xiEQJ9.mjs.map +0 -1
- package/dist/tools-registry-D96ukJg4.mjs.map +0 -1
package/dist/standalone.mjs
CHANGED
|
@@ -1110,7 +1110,7 @@ function getStandalonePersistPath() {
|
|
|
1110
1110
|
|
|
1111
1111
|
//#endregion
|
|
1112
1112
|
//#region src/version.ts
|
|
1113
|
-
const VERSION = "0.
|
|
1113
|
+
const VERSION = "0.9.0";
|
|
1114
1114
|
|
|
1115
1115
|
//#endregion
|
|
1116
1116
|
//#region src/state/schema.ts
|
|
@@ -1118,6 +1118,81 @@ function generateId(prefix) {
|
|
|
1118
1118
|
return `${prefix}_${Date.now().toString(36)}_${crypto.randomUUID().replace(/-/g, "").slice(0, 12)}`;
|
|
1119
1119
|
}
|
|
1120
1120
|
|
|
1121
|
+
//#endregion
|
|
1122
|
+
//#region src/mcp/rest-proxy.ts
|
|
1123
|
+
const DEFAULT_URL = "http://localhost:3111";
|
|
1124
|
+
const HEALTH_PROBE_TIMEOUT_MS = 500;
|
|
1125
|
+
const CALL_TIMEOUT_MS = 15e3;
|
|
1126
|
+
const LOCAL_MODE_TTL_MS = 3e4;
|
|
1127
|
+
let cached = null;
|
|
1128
|
+
let cachedAt = 0;
|
|
1129
|
+
let probeInFlight = null;
|
|
1130
|
+
function baseUrl() {
|
|
1131
|
+
return (process.env["AGENTMEMORY_URL"] || DEFAULT_URL).replace(/\/+$/, "");
|
|
1132
|
+
}
|
|
1133
|
+
function authHeader() {
|
|
1134
|
+
const secret = process.env["AGENTMEMORY_SECRET"];
|
|
1135
|
+
return secret ? { authorization: `Bearer ${secret}` } : {};
|
|
1136
|
+
}
|
|
1137
|
+
async function probe(url) {
|
|
1138
|
+
try {
|
|
1139
|
+
return (await fetch(`${url}/agentmemory/livez`, {
|
|
1140
|
+
method: "GET",
|
|
1141
|
+
headers: authHeader(),
|
|
1142
|
+
signal: AbortSignal.timeout(HEALTH_PROBE_TIMEOUT_MS)
|
|
1143
|
+
})).ok;
|
|
1144
|
+
} catch {
|
|
1145
|
+
return false;
|
|
1146
|
+
}
|
|
1147
|
+
}
|
|
1148
|
+
function invalidateHandle() {
|
|
1149
|
+
cached = null;
|
|
1150
|
+
cachedAt = 0;
|
|
1151
|
+
}
|
|
1152
|
+
async function resolveHandle() {
|
|
1153
|
+
const now = Date.now();
|
|
1154
|
+
if (cached) if (cached.mode === "local" && now - cachedAt >= LOCAL_MODE_TTL_MS) {
|
|
1155
|
+
cached = null;
|
|
1156
|
+
cachedAt = 0;
|
|
1157
|
+
} else return cached;
|
|
1158
|
+
if (probeInFlight) return probeInFlight;
|
|
1159
|
+
const url = baseUrl();
|
|
1160
|
+
probeInFlight = (async () => {
|
|
1161
|
+
if (await probe(url)) {
|
|
1162
|
+
const handle = {
|
|
1163
|
+
mode: "proxy",
|
|
1164
|
+
baseUrl: url,
|
|
1165
|
+
call: async (path, init) => {
|
|
1166
|
+
const res = await fetch(`${url}${path}`, {
|
|
1167
|
+
...init,
|
|
1168
|
+
headers: {
|
|
1169
|
+
"content-type": "application/json",
|
|
1170
|
+
...authHeader(),
|
|
1171
|
+
...init?.headers
|
|
1172
|
+
},
|
|
1173
|
+
signal: AbortSignal.timeout(CALL_TIMEOUT_MS)
|
|
1174
|
+
});
|
|
1175
|
+
if (!res.ok) throw new Error(`${init?.method || "GET"} ${path} -> ${res.status} ${res.statusText}`);
|
|
1176
|
+
const text = await res.text();
|
|
1177
|
+
return text ? JSON.parse(text) : null;
|
|
1178
|
+
}
|
|
1179
|
+
};
|
|
1180
|
+
cached = handle;
|
|
1181
|
+
cachedAt = Date.now();
|
|
1182
|
+
return handle;
|
|
1183
|
+
}
|
|
1184
|
+
const local = { mode: "local" };
|
|
1185
|
+
cached = local;
|
|
1186
|
+
cachedAt = Date.now();
|
|
1187
|
+
return local;
|
|
1188
|
+
})();
|
|
1189
|
+
try {
|
|
1190
|
+
return await probeInFlight;
|
|
1191
|
+
} finally {
|
|
1192
|
+
probeInFlight = null;
|
|
1193
|
+
}
|
|
1194
|
+
}
|
|
1195
|
+
|
|
1121
1196
|
//#endregion
|
|
1122
1197
|
//#region src/mcp/standalone.ts
|
|
1123
1198
|
const IMPLEMENTED_TOOLS = new Set([
|
|
@@ -1135,6 +1210,13 @@ const SERVER_INFO = {
|
|
|
1135
1210
|
protocolVersion: "2024-11-05"
|
|
1136
1211
|
};
|
|
1137
1212
|
const kv = new InMemoryKV(getStandalonePersistPath());
|
|
1213
|
+
let modeAnnounced = false;
|
|
1214
|
+
function announceMode(handle) {
|
|
1215
|
+
if (modeAnnounced) return;
|
|
1216
|
+
modeAnnounced = true;
|
|
1217
|
+
if (handle.mode === "proxy") process.stderr.write(`[@agentmemory/mcp] proxying to agentmemory server at ${handle.baseUrl}\n`);
|
|
1218
|
+
else process.stderr.write(`[@agentmemory/mcp] no server reachable at ${process.env["AGENTMEMORY_URL"] || "http://localhost:3111"}; falling back to local InMemoryKV\n`);
|
|
1219
|
+
}
|
|
1138
1220
|
function normalizeList(value) {
|
|
1139
1221
|
if (!value) return [];
|
|
1140
1222
|
if (Array.isArray(value)) return value.map((v) => typeof v === "string" ? v.trim() : "").filter((v) => v.length > 0);
|
|
@@ -1149,21 +1231,94 @@ function parseLimit(raw, fallback = DEFAULT_LIMIT) {
|
|
|
1149
1231
|
if (!Number.isFinite(n) || n <= 0) return fallback;
|
|
1150
1232
|
return Math.min(Math.floor(n), MAX_LIMIT);
|
|
1151
1233
|
}
|
|
1152
|
-
|
|
1234
|
+
function textResponse(payload, pretty = false) {
|
|
1235
|
+
return { content: [{
|
|
1236
|
+
type: "text",
|
|
1237
|
+
text: JSON.stringify(payload, null, pretty ? 2 : 0)
|
|
1238
|
+
}] };
|
|
1239
|
+
}
|
|
1240
|
+
function validate(toolName, args) {
|
|
1241
|
+
if (!IMPLEMENTED_TOOLS.has(toolName)) throw new Error(`Unknown tool: ${toolName}`);
|
|
1242
|
+
const v = { tool: toolName };
|
|
1153
1243
|
switch (toolName) {
|
|
1154
1244
|
case "memory_save": {
|
|
1155
|
-
const
|
|
1156
|
-
if (typeof
|
|
1157
|
-
|
|
1245
|
+
const content = args["content"];
|
|
1246
|
+
if (typeof content !== "string" || !content.trim()) throw new Error("content is required");
|
|
1247
|
+
v.content = content;
|
|
1248
|
+
v.type = args["type"] || "fact";
|
|
1249
|
+
v.concepts = normalizeList(args["concepts"]);
|
|
1250
|
+
v.files = normalizeList(args["files"]);
|
|
1251
|
+
return v;
|
|
1252
|
+
}
|
|
1253
|
+
case "memory_recall":
|
|
1254
|
+
case "memory_smart_search": {
|
|
1255
|
+
const query = args["query"];
|
|
1256
|
+
if (typeof query !== "string" || !query.trim()) throw new Error("query is required");
|
|
1257
|
+
v.query = query.trim();
|
|
1258
|
+
v.limit = parseLimit(args["limit"]);
|
|
1259
|
+
return v;
|
|
1260
|
+
}
|
|
1261
|
+
case "memory_sessions":
|
|
1262
|
+
v.limit = parseLimit(args["limit"], 20);
|
|
1263
|
+
return v;
|
|
1264
|
+
case "memory_governance_delete": {
|
|
1265
|
+
const ids = normalizeList(args["memoryIds"]);
|
|
1266
|
+
if (ids.length === 0) throw new Error("memoryIds is required");
|
|
1267
|
+
v.memoryIds = ids;
|
|
1268
|
+
v.reason = args["reason"] || "plugin skill request";
|
|
1269
|
+
return v;
|
|
1270
|
+
}
|
|
1271
|
+
case "memory_export": return v;
|
|
1272
|
+
case "memory_audit":
|
|
1273
|
+
v.limit = parseLimit(args["limit"], 50);
|
|
1274
|
+
return v;
|
|
1275
|
+
default: throw new Error(`Unknown tool: ${toolName}`);
|
|
1276
|
+
}
|
|
1277
|
+
}
|
|
1278
|
+
async function handleProxy(v, handle) {
|
|
1279
|
+
switch (v.tool) {
|
|
1280
|
+
case "memory_save": return textResponse(await handle.call("/agentmemory/remember", {
|
|
1281
|
+
method: "POST",
|
|
1282
|
+
body: JSON.stringify({
|
|
1283
|
+
content: v.content,
|
|
1284
|
+
type: v.type,
|
|
1285
|
+
concepts: v.concepts,
|
|
1286
|
+
files: v.files
|
|
1287
|
+
})
|
|
1288
|
+
}));
|
|
1289
|
+
case "memory_recall":
|
|
1290
|
+
case "memory_smart_search": return textResponse(await handle.call("/agentmemory/smart-search", {
|
|
1291
|
+
method: "POST",
|
|
1292
|
+
body: JSON.stringify({
|
|
1293
|
+
query: v.query,
|
|
1294
|
+
limit: v.limit
|
|
1295
|
+
})
|
|
1296
|
+
}), true);
|
|
1297
|
+
case "memory_sessions": return textResponse(await handle.call(`/agentmemory/sessions?limit=${v.limit}`, { method: "GET" }), true);
|
|
1298
|
+
case "memory_governance_delete": return textResponse(await handle.call("/agentmemory/governance/memories", {
|
|
1299
|
+
method: "POST",
|
|
1300
|
+
body: JSON.stringify({
|
|
1301
|
+
memoryIds: v.memoryIds,
|
|
1302
|
+
reason: v.reason
|
|
1303
|
+
})
|
|
1304
|
+
}));
|
|
1305
|
+
case "memory_export": return textResponse(await handle.call("/agentmemory/export", { method: "GET" }), true);
|
|
1306
|
+
case "memory_audit": return textResponse(await handle.call(`/agentmemory/audit?limit=${v.limit}`, { method: "GET" }), true);
|
|
1307
|
+
default: throw new Error(`Unknown tool: ${v.tool}`);
|
|
1308
|
+
}
|
|
1309
|
+
}
|
|
1310
|
+
async function handleLocal(v, kvInstance) {
|
|
1311
|
+
switch (v.tool) {
|
|
1312
|
+
case "memory_save": {
|
|
1158
1313
|
const id = generateId("mem");
|
|
1159
1314
|
const isoNow = (/* @__PURE__ */ new Date()).toISOString();
|
|
1160
1315
|
await kvInstance.set("mem:memories", id, {
|
|
1161
1316
|
id,
|
|
1162
|
-
type:
|
|
1163
|
-
title: content.slice(0, 80),
|
|
1164
|
-
content,
|
|
1165
|
-
concepts:
|
|
1166
|
-
files:
|
|
1317
|
+
type: v.type,
|
|
1318
|
+
title: (v.content || "").slice(0, 80),
|
|
1319
|
+
content: v.content,
|
|
1320
|
+
concepts: v.concepts,
|
|
1321
|
+
files: v.files,
|
|
1167
1322
|
createdAt: isoNow,
|
|
1168
1323
|
updatedAt: isoNow,
|
|
1169
1324
|
strength: 7,
|
|
@@ -1172,81 +1327,69 @@ async function handleToolCall(toolName, args, kvInstance = kv) {
|
|
|
1172
1327
|
sessionIds: []
|
|
1173
1328
|
});
|
|
1174
1329
|
kvInstance.persist();
|
|
1175
|
-
return {
|
|
1176
|
-
type: "text",
|
|
1177
|
-
text: JSON.stringify({ saved: id })
|
|
1178
|
-
}] };
|
|
1330
|
+
return textResponse({ saved: id });
|
|
1179
1331
|
}
|
|
1180
1332
|
case "memory_recall":
|
|
1181
1333
|
case "memory_smart_search": {
|
|
1182
|
-
const
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
type: "text",
|
|
1199
|
-
text: JSON.stringify(results, null, 2)
|
|
1200
|
-
}] };
|
|
1334
|
+
const query = (v.query || "").toLowerCase();
|
|
1335
|
+
const limit = v.limit ?? DEFAULT_LIMIT;
|
|
1336
|
+
return textResponse({
|
|
1337
|
+
mode: "compact",
|
|
1338
|
+
results: (await kvInstance.list("mem:memories")).filter((m) => {
|
|
1339
|
+
const text = [
|
|
1340
|
+
typeof m["title"] === "string" ? m["title"] : "",
|
|
1341
|
+
typeof m["content"] === "string" ? m["content"] : "",
|
|
1342
|
+
Array.isArray(m["files"]) ? m["files"].join(" ") : "",
|
|
1343
|
+
Array.isArray(m["concepts"]) ? m["concepts"].join(" ") : "",
|
|
1344
|
+
Array.isArray(m["sessionIds"]) ? m["sessionIds"].join(" ") : "",
|
|
1345
|
+
typeof m["id"] === "string" ? m["id"] : ""
|
|
1346
|
+
].join(" ").toLowerCase();
|
|
1347
|
+
return query.split(/\s+/).every((word) => text.includes(word));
|
|
1348
|
+
}).slice(0, limit)
|
|
1349
|
+
}, true);
|
|
1201
1350
|
}
|
|
1202
1351
|
case "memory_sessions": {
|
|
1203
1352
|
const sessions = await kvInstance.list("mem:sessions");
|
|
1204
|
-
const limit =
|
|
1205
|
-
return {
|
|
1206
|
-
type: "text",
|
|
1207
|
-
text: JSON.stringify({ sessions: sessions.slice(0, limit) }, null, 2)
|
|
1208
|
-
}] };
|
|
1353
|
+
const limit = v.limit ?? 20;
|
|
1354
|
+
return textResponse({ sessions: sessions.slice(0, limit) }, true);
|
|
1209
1355
|
}
|
|
1210
1356
|
case "memory_governance_delete": {
|
|
1211
|
-
const ids = normalizeList(args.memoryIds);
|
|
1212
|
-
if (ids.length === 0) throw new Error("memoryIds is required");
|
|
1213
1357
|
let deleted = 0;
|
|
1214
|
-
for (const id of
|
|
1358
|
+
for (const id of v.memoryIds || []) if (await kvInstance.get("mem:memories", id)) {
|
|
1215
1359
|
await kvInstance.delete("mem:memories", id);
|
|
1216
1360
|
deleted++;
|
|
1217
1361
|
}
|
|
1218
1362
|
kvInstance.persist();
|
|
1219
|
-
return {
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
reason: args.reason || "plugin skill request"
|
|
1225
|
-
})
|
|
1226
|
-
}] };
|
|
1227
|
-
}
|
|
1228
|
-
case "memory_export": {
|
|
1229
|
-
const memories = await kvInstance.list("mem:memories");
|
|
1230
|
-
const sessions = await kvInstance.list("mem:sessions");
|
|
1231
|
-
return { content: [{
|
|
1232
|
-
type: "text",
|
|
1233
|
-
text: JSON.stringify({
|
|
1234
|
-
version: VERSION,
|
|
1235
|
-
memories,
|
|
1236
|
-
sessions
|
|
1237
|
-
}, null, 2)
|
|
1238
|
-
}] };
|
|
1363
|
+
return textResponse({
|
|
1364
|
+
deleted,
|
|
1365
|
+
requested: (v.memoryIds || []).length,
|
|
1366
|
+
reason: v.reason
|
|
1367
|
+
});
|
|
1239
1368
|
}
|
|
1369
|
+
case "memory_export": return textResponse({
|
|
1370
|
+
version: VERSION,
|
|
1371
|
+
memories: await kvInstance.list("mem:memories"),
|
|
1372
|
+
sessions: await kvInstance.list("mem:sessions")
|
|
1373
|
+
}, true);
|
|
1240
1374
|
case "memory_audit": {
|
|
1241
1375
|
const entries = await kvInstance.list("mem:audit");
|
|
1242
|
-
const limit =
|
|
1243
|
-
return {
|
|
1244
|
-
type: "text",
|
|
1245
|
-
text: JSON.stringify(entries.slice(0, limit), null, 2)
|
|
1246
|
-
}] };
|
|
1376
|
+
const limit = v.limit ?? 50;
|
|
1377
|
+
return textResponse({ entries: entries.slice(0, limit) }, true);
|
|
1247
1378
|
}
|
|
1248
|
-
default: throw new Error(`Unknown tool: ${
|
|
1379
|
+
default: throw new Error(`Unknown tool: ${v.tool}`);
|
|
1380
|
+
}
|
|
1381
|
+
}
|
|
1382
|
+
async function handleToolCall(toolName, args, kvInstance = kv) {
|
|
1383
|
+
const validated = validate(toolName, args);
|
|
1384
|
+
const handle = await resolveHandle();
|
|
1385
|
+
announceMode(handle);
|
|
1386
|
+
if (handle.mode === "proxy") try {
|
|
1387
|
+
return await handleProxy(validated, handle);
|
|
1388
|
+
} catch (err) {
|
|
1389
|
+
process.stderr.write(`[@agentmemory/mcp] proxy call failed for ${toolName}: ${err instanceof Error ? err.message : String(err)}; invalidating handle and falling back to local KV\n`);
|
|
1390
|
+
invalidateHandle();
|
|
1249
1391
|
}
|
|
1392
|
+
return handleLocal(validated, kvInstance);
|
|
1250
1393
|
}
|
|
1251
1394
|
const transport = createStdioTransport(async (method, params) => {
|
|
1252
1395
|
switch (method) {
|