@agentskit/memory 0.8.3 → 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.
@@ -0,0 +1,48 @@
1
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
2
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
3
+ }) : x)(function(x) {
4
+ if (typeof require !== "undefined") return require.apply(this, arguments);
5
+ throw Error('Dynamic require of "' + x + '" is not supported');
6
+ });
7
+
8
+ // src/personalization.ts
9
+ function createInMemoryPersonalization() {
10
+ const profiles = /* @__PURE__ */ new Map();
11
+ return {
12
+ async get(subjectId) {
13
+ const hit = profiles.get(subjectId);
14
+ return hit ? { ...hit, traits: { ...hit.traits } } : null;
15
+ },
16
+ async set(profile) {
17
+ profiles.set(profile.subjectId, {
18
+ ...profile,
19
+ traits: { ...profile.traits },
20
+ updatedAt: profile.updatedAt || (/* @__PURE__ */ new Date()).toISOString()
21
+ });
22
+ },
23
+ async merge(subjectId, traits) {
24
+ const existing = profiles.get(subjectId);
25
+ const next = {
26
+ subjectId,
27
+ traits: { ...existing?.traits ?? {}, ...traits },
28
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
29
+ };
30
+ profiles.set(subjectId, next);
31
+ return { ...next, traits: { ...next.traits } };
32
+ },
33
+ async delete(subjectId) {
34
+ profiles.delete(subjectId);
35
+ }
36
+ };
37
+ }
38
+ function renderProfileContext(profile) {
39
+ if (!profile || Object.keys(profile.traits).length === 0) return "";
40
+ const lines = Object.entries(profile.traits).filter(([, value]) => value !== void 0 && value !== null && value !== "").map(([key, value]) => `- ${key}: ${typeof value === "string" ? value : JSON.stringify(value)}`);
41
+ if (lines.length === 0) return "";
42
+ return `## User profile
43
+ ${lines.join("\n")}`;
44
+ }
45
+
46
+ export { __require, createInMemoryPersonalization, renderProfileContext };
47
+ //# sourceMappingURL=chunk-G5S2A3MJ.js.map
48
+ //# sourceMappingURL=chunk-G5S2A3MJ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/personalization.ts"],"names":[],"mappings":";;;;;;;;AA0BO,SAAS,6BAAA,GAAsD;AACpE,EAAA,MAAM,QAAA,uBAAe,GAAA,EAAoC;AAEzD,EAAA,OAAO;AAAA,IACL,MAAM,IAAI,SAAA,EAAW;AACnB,MAAA,MAAM,GAAA,GAAM,QAAA,CAAS,GAAA,CAAI,SAAS,CAAA;AAClC,MAAA,OAAO,GAAA,GAAM,EAAE,GAAG,GAAA,EAAK,MAAA,EAAQ,EAAE,GAAG,GAAA,CAAI,MAAA,EAAO,EAAE,GAAI,IAAA;AAAA,IACvD,CAAA;AAAA,IACA,MAAM,IAAI,OAAA,EAAS;AACjB,MAAA,QAAA,CAAS,GAAA,CAAI,QAAQ,SAAA,EAAW;AAAA,QAC9B,GAAG,OAAA;AAAA,QACH,MAAA,EAAQ,EAAE,GAAG,OAAA,CAAQ,MAAA,EAAO;AAAA,QAC5B,WAAW,OAAA,CAAQ,SAAA,IAAA,iBAAa,IAAI,IAAA,IAAO,WAAA;AAAY,OACxD,CAAA;AAAA,IACH,CAAA;AAAA,IACA,MAAM,KAAA,CAAM,SAAA,EAAW,MAAA,EAAQ;AAC7B,MAAA,MAAM,QAAA,GAAW,QAAA,CAAS,GAAA,CAAI,SAAS,CAAA;AACvC,MAAA,MAAM,IAAA,GAA+B;AAAA,QACnC,SAAA;AAAA,QACA,MAAA,EAAQ,EAAE,GAAI,QAAA,EAAU,UAAU,EAAC,EAAI,GAAG,MAAA,EAAO;AAAA,QACjD,SAAA,EAAA,iBAAW,IAAI,IAAA,EAAK,EAAE,WAAA;AAAY,OACpC;AACA,MAAA,QAAA,CAAS,GAAA,CAAI,WAAW,IAAI,CAAA;AAC5B,MAAA,OAAO,EAAE,GAAG,IAAA,EAAM,MAAA,EAAQ,EAAE,GAAG,IAAA,CAAK,QAAO,EAAE;AAAA,IAC/C,CAAA;AAAA,IACA,MAAM,OAAO,SAAA,EAAW;AACtB,MAAA,QAAA,CAAS,OAAO,SAAS,CAAA;AAAA,IAC3B;AAAA,GACF;AACF;AAOO,SAAS,qBAAqB,OAAA,EAAgD;AACnF,EAAA,IAAI,CAAC,WAAW,MAAA,CAAO,IAAA,CAAK,QAAQ,MAAM,CAAA,CAAE,MAAA,KAAW,CAAA,EAAG,OAAO,EAAA;AACjE,EAAA,MAAM,QAAQ,MAAA,CAAO,OAAA,CAAQ,OAAA,CAAQ,MAAM,EACxC,MAAA,CAAO,CAAC,GAAG,KAAK,CAAA,KAAM,KAAA,KAAU,MAAA,IAAa,KAAA,KAAU,QAAQ,KAAA,KAAU,EAAE,CAAA,CAC3E,GAAA,CAAI,CAAC,CAAC,GAAA,EAAK,KAAK,CAAA,KAAM,KAAK,GAAG,CAAA,EAAA,EAAK,OAAO,KAAA,KAAU,WAAW,KAAA,GAAQ,IAAA,CAAK,SAAA,CAAU,KAAK,CAAC,CAAA,CAAE,CAAA;AACjG,EAAA,IAAI,KAAA,CAAM,MAAA,KAAW,CAAA,EAAG,OAAO,EAAA;AAC/B,EAAA,OAAO,CAAA;AAAA,EAAoB,KAAA,CAAM,IAAA,CAAK,IAAI,CAAC,CAAA,CAAA;AAC7C","file":"chunk-G5S2A3MJ.js","sourcesContent":["/**\n * Personalization — a persisted profile per subject (user id,\n * account id, device). The agent reads it on every run to\n * condition responses; the runtime updates it when new facts\n * appear.\n */\n\nexport interface PersonalizationProfile {\n subjectId: string\n /** Human-editable notes, facts, preferences. */\n traits: Record<string, unknown>\n /** ISO timestamp of the latest update. */\n updatedAt: string\n}\n\nexport interface PersonalizationStore {\n get: (subjectId: string) => Promise<PersonalizationProfile | null>\n set: (profile: PersonalizationProfile) => Promise<void>\n merge: (subjectId: string, traits: Record<string, unknown>) => Promise<PersonalizationProfile>\n delete?: (subjectId: string) => Promise<void>\n}\n\n/**\n * In-memory personalization store — tests, single-process demos.\n * Bring your own for production (Postgres, Redis, DynamoDB).\n */\nexport function createInMemoryPersonalization(): PersonalizationStore {\n const profiles = new Map<string, PersonalizationProfile>()\n\n return {\n async get(subjectId) {\n const hit = profiles.get(subjectId)\n return hit ? { ...hit, traits: { ...hit.traits } } : null\n },\n async set(profile) {\n profiles.set(profile.subjectId, {\n ...profile,\n traits: { ...profile.traits },\n updatedAt: profile.updatedAt || new Date().toISOString(),\n })\n },\n async merge(subjectId, traits) {\n const existing = profiles.get(subjectId)\n const next: PersonalizationProfile = {\n subjectId,\n traits: { ...(existing?.traits ?? {}), ...traits },\n updatedAt: new Date().toISOString(),\n }\n profiles.set(subjectId, next)\n return { ...next, traits: { ...next.traits } }\n },\n async delete(subjectId) {\n profiles.delete(subjectId)\n },\n }\n}\n\n/**\n * Render a profile into a system-prompt fragment the runtime can\n * prepend. Kept intentionally short — full profile dumps bloat\n * context and leak unnecessary detail to the model.\n */\nexport function renderProfileContext(profile: PersonalizationProfile | null): string {\n if (!profile || Object.keys(profile.traits).length === 0) return ''\n const lines = Object.entries(profile.traits)\n .filter(([, value]) => value !== undefined && value !== null && value !== '')\n .map(([key, value]) => `- ${key}: ${typeof value === 'string' ? value : JSON.stringify(value)}`)\n if (lines.length === 0) return ''\n return `## User profile\\n${lines.join('\\n')}`\n}\n"]}
package/dist/index.cjs CHANGED
@@ -1,6 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  var core = require('@agentskit/core');
4
+ var security = require('@agentskit/core/security');
4
5
 
5
6
  var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
6
7
  get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
@@ -21,7 +22,11 @@ function fileChatMemory(path) {
21
22
  },
22
23
  async save(messages) {
23
24
  const fs = await import('fs/promises');
24
- await fs.writeFile(path, JSON.stringify(core.serializeMessages(messages), null, 2), "utf8");
25
+ await fs.writeFile(
26
+ path,
27
+ JSON.stringify(core.serializeMessages(messages), null, 2),
28
+ { encoding: "utf8", mode: 384 }
29
+ );
25
30
  },
26
31
  async clear() {
27
32
  try {
@@ -197,7 +202,7 @@ async function createRedisClientAdapter(url) {
197
202
  return await client.keys(pattern);
198
203
  },
199
204
  async disconnect() {
200
- await client.disconnect();
205
+ await client.close();
201
206
  },
202
207
  async call(command, ...args) {
203
208
  return await client.sendCommand([command, ...args.map(String)]);
@@ -425,16 +430,23 @@ function createVectraStore(dirPath) {
425
430
  return {
426
431
  async upsert(docs) {
427
432
  const idx = await getIndex();
428
- for (const doc of docs) {
429
- await idx.insertItem({
430
- vector: doc.vector,
431
- metadata: { _id: doc.id, ...doc.metadata }
432
- });
433
+ await idx.beginUpdate();
434
+ try {
435
+ for (const doc of docs) {
436
+ await idx.insertItem({
437
+ vector: doc.vector,
438
+ metadata: { _id: doc.id, ...doc.metadata }
439
+ });
440
+ }
441
+ await idx.endUpdate();
442
+ } catch (err) {
443
+ idx.cancelUpdate();
444
+ throw err;
433
445
  }
434
446
  },
435
447
  async query(vector, topK) {
436
448
  const idx = await getIndex();
437
- const results = await idx.queryItems(vector, topK);
449
+ const results = await idx.queryItems(vector, "", topK);
438
450
  return results.map((r) => ({
439
451
  id: String(r.item.metadata._id ?? ""),
440
452
  score: r.score,
@@ -1259,6 +1271,102 @@ function createHierarchicalMemory(options) {
1259
1271
  };
1260
1272
  }
1261
1273
 
1274
+ // src/forget.ts
1275
+ function isForgettable(value) {
1276
+ return !!value && typeof value === "object" && "forgetSubject" in value && typeof value.forgetSubject === "function";
1277
+ }
1278
+ async function hash(input) {
1279
+ const encoded = new TextEncoder().encode(input);
1280
+ const digest = await crypto.subtle.digest("SHA-256", encoded);
1281
+ return Array.from(new Uint8Array(digest)).map((b) => b.toString(16).padStart(2, "0")).join("");
1282
+ }
1283
+ async function forgetSubject(memories, subjectId) {
1284
+ const reports = [];
1285
+ for (const memory of memories) {
1286
+ if (!isForgettable(memory)) continue;
1287
+ reports.push(await memory.forgetSubject(subjectId));
1288
+ }
1289
+ const totalDeleted = reports.reduce((sum, r) => sum + r.deletedCount, 0);
1290
+ const evidenceHash = await hash(
1291
+ JSON.stringify({ subjectId, reports: reports.map((r) => ({ b: r.backend, n: r.deletedCount, at: r.at })) })
1292
+ );
1293
+ return { subjectId, reports, totalDeleted, evidenceHash };
1294
+ }
1295
+ function makeForgettable(memory, options) {
1296
+ return Object.assign(memory, {
1297
+ __agentskitBackend: options.backend,
1298
+ forgetSubject: async (subjectId) => {
1299
+ const ids = await options.listIds(subjectId);
1300
+ const failures = [];
1301
+ try {
1302
+ await options.deleteIds(ids);
1303
+ } catch (err) {
1304
+ for (const id of ids) failures.push({ id, reason: err.message });
1305
+ }
1306
+ return {
1307
+ backend: options.backend,
1308
+ deletedCount: ids.length - failures.length,
1309
+ at: (/* @__PURE__ */ new Date()).toISOString(),
1310
+ failures: failures.length ? failures : void 0
1311
+ };
1312
+ }
1313
+ });
1314
+ }
1315
+ async function transform(input, opts) {
1316
+ if (opts.mode === "tokenize") {
1317
+ if (!opts.vault) {
1318
+ throw new core.ConfigError({
1319
+ code: core.ErrorCodes.AK_CONFIG_INVALID,
1320
+ message: 'wrapMemoryWithRedaction: vault is required when mode is "tokenize"'
1321
+ });
1322
+ }
1323
+ if (!opts.allowedRoles) {
1324
+ throw new core.ConfigError({
1325
+ code: core.ErrorCodes.AK_CONFIG_INVALID,
1326
+ message: 'wrapMemoryWithRedaction: allowedRoles is required when mode is "tokenize"'
1327
+ });
1328
+ }
1329
+ const result = await security.tokenize(input, {
1330
+ rules: opts.rules,
1331
+ vault: opts.vault,
1332
+ allowedRoles: opts.allowedRoles,
1333
+ audit: opts.audit
1334
+ });
1335
+ return result.value;
1336
+ }
1337
+ return security.createPIIRedactor({ rules: opts.rules }).redact(input).value;
1338
+ }
1339
+ function wrapChatMemoryWithRedaction(inner, options) {
1340
+ return {
1341
+ load: () => inner.load(),
1342
+ save: async (messages) => {
1343
+ const redacted = await Promise.all(
1344
+ messages.map(async (m) => ({
1345
+ ...m,
1346
+ content: await transform(m.content ?? "", options)
1347
+ }))
1348
+ );
1349
+ await inner.save(redacted);
1350
+ },
1351
+ clear: inner.clear ? () => inner.clear() : void 0
1352
+ };
1353
+ }
1354
+ function wrapVectorMemoryWithRedaction(inner, options) {
1355
+ return {
1356
+ store: async (docs) => {
1357
+ const redacted = await Promise.all(
1358
+ docs.map(async (d) => ({
1359
+ ...d,
1360
+ content: await transform(d.content, options)
1361
+ }))
1362
+ );
1363
+ await inner.store(redacted);
1364
+ },
1365
+ search: (embedding, opts) => inner.search(embedding, opts),
1366
+ delete: inner.delete ? (ids) => inner.delete(ids) : void 0
1367
+ };
1368
+ }
1369
+
1262
1370
  exports.chroma = chroma;
1263
1371
  exports.createEncryptedMemory = createEncryptedMemory;
1264
1372
  exports.createHierarchicalMemory = createHierarchicalMemory;
@@ -1266,6 +1374,8 @@ exports.createInMemoryGraph = createInMemoryGraph;
1266
1374
  exports.createInMemoryPersonalization = createInMemoryPersonalization;
1267
1375
  exports.fileChatMemory = fileChatMemory;
1268
1376
  exports.fileVectorMemory = fileVectorMemory;
1377
+ exports.forgetSubject = forgetSubject;
1378
+ exports.makeForgettable = makeForgettable;
1269
1379
  exports.matchesFilter = matchesFilter;
1270
1380
  exports.milvusVectorStore = milvusVectorStore;
1271
1381
  exports.mongoAtlasVectorStore = mongoAtlasVectorStore;
@@ -1280,5 +1390,7 @@ exports.supabaseVectorStore = supabaseVectorStore;
1280
1390
  exports.tursoChatMemory = tursoChatMemory;
1281
1391
  exports.upstashVector = upstashVector;
1282
1392
  exports.weaviateVectorStore = weaviateVectorStore;
1393
+ exports.wrapChatMemoryWithRedaction = wrapChatMemoryWithRedaction;
1394
+ exports.wrapVectorMemoryWithRedaction = wrapVectorMemoryWithRedaction;
1283
1395
  //# sourceMappingURL=index.cjs.map
1284
1396
  //# sourceMappingURL=index.cjs.map