@agentskit/memory 0.8.1 → 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 {
@@ -49,7 +54,11 @@ async function openDatabase(path) {
49
54
  const Database = mod.default ?? mod;
50
55
  return new Database(path);
51
56
  } catch {
52
- throw new Error("Install better-sqlite3 to use sqliteChatMemory: npm install better-sqlite3");
57
+ throw new core.MemoryError({
58
+ code: core.ErrorCodes.AK_MEMORY_PEER_MISSING,
59
+ message: "Install better-sqlite3 to use sqliteChatMemory: npm install better-sqlite3",
60
+ hint: 'sqliteChatMemory uses the optional peer "better-sqlite3".'
61
+ });
53
62
  }
54
63
  }
55
64
  function sqliteChatMemory(config) {
@@ -100,7 +109,11 @@ async function loadSdk() {
100
109
  moduleId
101
110
  );
102
111
  } catch {
103
- throw new Error("Install @libsql/client to use tursoChatMemory: npm install @libsql/client");
112
+ throw new core.MemoryError({
113
+ code: core.ErrorCodes.AK_MEMORY_PEER_MISSING,
114
+ message: "Install @libsql/client to use tursoChatMemory: npm install @libsql/client",
115
+ hint: 'tursoChatMemory uses the optional peer "@libsql/client".'
116
+ });
104
117
  }
105
118
  })();
106
119
  }
@@ -161,14 +174,16 @@ function tursoChatMemory(config) {
161
174
  }
162
175
  };
163
176
  }
164
-
165
- // src/redis-client.ts
166
177
  async function createRedisClientAdapter(url) {
167
178
  let redis;
168
179
  try {
169
180
  redis = await import('redis');
170
181
  } catch {
171
- throw new Error("Install redis to use Redis memory backends: npm install redis");
182
+ throw new core.MemoryError({
183
+ code: core.ErrorCodes.AK_MEMORY_PEER_MISSING,
184
+ message: "Install redis to use Redis memory backends: npm install redis",
185
+ hint: 'redisChatMemory and redisVectorMemory use the optional peer "redis".'
186
+ });
172
187
  }
173
188
  const client = redis.createClient({ url });
174
189
  await client.connect();
@@ -187,7 +202,7 @@ async function createRedisClientAdapter(url) {
187
202
  return await client.keys(pattern);
188
203
  },
189
204
  async disconnect() {
190
- await client.disconnect();
205
+ await client.close();
191
206
  },
192
207
  async call(command, ...args) {
193
208
  return await client.sendCommand([command, ...args.map(String)]);
@@ -394,9 +409,11 @@ function requireVectra() {
394
409
  try {
395
410
  return __require("vectra");
396
411
  } catch {
397
- throw new Error(
398
- "Install vectra to use fileVectorMemory: npm install vectra"
399
- );
412
+ throw new core.MemoryError({
413
+ code: core.ErrorCodes.AK_MEMORY_PEER_MISSING,
414
+ message: "Install vectra to use fileVectorMemory: npm install vectra",
415
+ hint: 'fileVectorMemory uses the optional peer "vectra" for the on-disk index.'
416
+ });
400
417
  }
401
418
  }
402
419
  function createVectraStore(dirPath) {
@@ -413,16 +430,23 @@ function createVectraStore(dirPath) {
413
430
  return {
414
431
  async upsert(docs) {
415
432
  const idx = await getIndex();
416
- for (const doc of docs) {
417
- await idx.insertItem({
418
- vector: doc.vector,
419
- metadata: { _id: doc.id, ...doc.metadata }
420
- });
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;
421
445
  }
422
446
  },
423
447
  async query(vector, topK) {
424
448
  const idx = await getIndex();
425
- const results = await idx.queryItems(vector, topK);
449
+ const results = await idx.queryItems(vector, "", topK);
426
450
  return results.map((r) => ({
427
451
  id: String(r.item.metadata._id ?? ""),
428
452
  score: r.score,
@@ -634,8 +658,6 @@ function pgvector(config) {
634
658
  }
635
659
  };
636
660
  }
637
-
638
- // src/vector/pinecone.ts
639
661
  async function call(config, path, body) {
640
662
  const fetchImpl = config.fetch ?? globalThis.fetch;
641
663
  const response = await fetchImpl(`${config.indexUrl}${path}`, {
@@ -647,7 +669,13 @@ async function call(config, path, body) {
647
669
  body: JSON.stringify(body)
648
670
  });
649
671
  const text = await response.text();
650
- if (!response.ok) throw new Error(`pinecone ${response.status}: ${text.slice(0, 200)}`);
672
+ if (!response.ok) {
673
+ throw new core.MemoryError({
674
+ code: core.ErrorCodes.AK_MEMORY_REMOTE_HTTP,
675
+ message: `pinecone ${response.status}: ${text.slice(0, 200)}`,
676
+ hint: `URL ${config.indexUrl}${path}. Check api-key + index URL/namespace.`
677
+ });
678
+ }
651
679
  return text.length > 0 ? JSON.parse(text) : {};
652
680
  }
653
681
  function pinecone(config) {
@@ -687,8 +715,6 @@ function pinecone(config) {
687
715
  }
688
716
  };
689
717
  }
690
-
691
- // src/vector/qdrant.ts
692
718
  async function call2(config, method, path, body) {
693
719
  const fetchImpl = config.fetch ?? globalThis.fetch;
694
720
  const response = await fetchImpl(`${config.url}${path}`, {
@@ -700,7 +726,13 @@ async function call2(config, method, path, body) {
700
726
  body: body === void 0 ? void 0 : JSON.stringify(body)
701
727
  });
702
728
  const text = await response.text();
703
- if (!response.ok) throw new Error(`qdrant ${response.status}: ${text.slice(0, 200)}`);
729
+ if (!response.ok) {
730
+ throw new core.MemoryError({
731
+ code: core.ErrorCodes.AK_MEMORY_REMOTE_HTTP,
732
+ message: `qdrant ${response.status}: ${text.slice(0, 200)}`,
733
+ hint: `URL ${config.url}${path}. Check api-key + collection "${config.collection}".`
734
+ });
735
+ }
704
736
  return text.length > 0 ? JSON.parse(text) : {};
705
737
  }
706
738
  function qdrant(config) {
@@ -739,8 +771,6 @@ function qdrant(config) {
739
771
  }
740
772
  };
741
773
  }
742
-
743
- // src/vector/chroma.ts
744
774
  async function call3(config, method, path, body) {
745
775
  const fetchImpl = config.fetch ?? globalThis.fetch;
746
776
  const response = await fetchImpl(`${config.url}${path}`, {
@@ -749,7 +779,13 @@ async function call3(config, method, path, body) {
749
779
  body: body === void 0 ? void 0 : JSON.stringify(body)
750
780
  });
751
781
  const text = await response.text();
752
- if (!response.ok) throw new Error(`chroma ${response.status}: ${text.slice(0, 200)}`);
782
+ if (!response.ok) {
783
+ throw new core.MemoryError({
784
+ code: core.ErrorCodes.AK_MEMORY_REMOTE_HTTP,
785
+ message: `chroma ${response.status}: ${text.slice(0, 200)}`,
786
+ hint: `URL ${config.url}${path}. Check Chroma server health + collection name.`
787
+ });
788
+ }
753
789
  return text.length > 0 ? JSON.parse(text) : {};
754
790
  }
755
791
  function chroma(config) {
@@ -788,8 +824,6 @@ function chroma(config) {
788
824
  }
789
825
  };
790
826
  }
791
-
792
- // src/vector/upstash.ts
793
827
  async function call4(config, path, body) {
794
828
  const fetchImpl = config.fetch ?? globalThis.fetch;
795
829
  const response = await fetchImpl(`${config.url}${path}`, {
@@ -801,7 +835,13 @@ async function call4(config, path, body) {
801
835
  body: JSON.stringify(body)
802
836
  });
803
837
  const text = await response.text();
804
- if (!response.ok) throw new Error(`upstash-vector ${response.status}: ${text.slice(0, 200)}`);
838
+ if (!response.ok) {
839
+ throw new core.MemoryError({
840
+ code: core.ErrorCodes.AK_MEMORY_REMOTE_HTTP,
841
+ message: `upstash-vector ${response.status}: ${text.slice(0, 200)}`,
842
+ hint: `URL ${config.url}${path}. Check token + index URL.`
843
+ });
844
+ }
805
845
  return text.length > 0 ? JSON.parse(text) : {};
806
846
  }
807
847
  function upstashVector(config) {
@@ -836,8 +876,6 @@ function upstashVector(config) {
836
876
  }
837
877
  };
838
878
  }
839
-
840
- // src/vector/supabase.ts
841
879
  var cachedSdk2 = null;
842
880
  async function loadSdk2() {
843
881
  if (!cachedSdk2) {
@@ -849,9 +887,11 @@ async function loadSdk2() {
849
887
  moduleId
850
888
  );
851
889
  } catch {
852
- throw new Error(
853
- "Install @supabase/supabase-js to use supabaseVectorStore: npm install @supabase/supabase-js"
854
- );
890
+ throw new core.MemoryError({
891
+ code: core.ErrorCodes.AK_MEMORY_PEER_MISSING,
892
+ message: "Install @supabase/supabase-js to use supabaseVectorStore: npm install @supabase/supabase-js",
893
+ hint: 'supabaseVectorStore uses the optional peer "@supabase/supabase-js".'
894
+ });
855
895
  }
856
896
  })();
857
897
  }
@@ -861,7 +901,13 @@ function buildRunner(client) {
861
901
  return {
862
902
  async query(sql, params) {
863
903
  const result = await client.rpc("agentskit_execute_sql", { sql, params });
864
- if (result.error) throw new Error(`supabase: ${result.error.message}`);
904
+ if (result.error) {
905
+ throw new core.MemoryError({
906
+ code: core.ErrorCodes.AK_MEMORY_REMOTE_HTTP,
907
+ message: `supabase: ${result.error.message}`,
908
+ hint: "Check the agentskit_execute_sql RPC + service role key permissions."
909
+ });
910
+ }
865
911
  return { rows: result.data ?? [] };
866
912
  }
867
913
  };
@@ -905,8 +951,6 @@ function supabaseVectorStore(config) {
905
951
  }
906
952
  };
907
953
  }
908
-
909
- // src/vector/weaviate.ts
910
954
  async function call5(config, method, path, body) {
911
955
  const fetchImpl = config.fetch ?? globalThis.fetch;
912
956
  const response = await fetchImpl(`${config.url}${path}`, {
@@ -918,7 +962,13 @@ async function call5(config, method, path, body) {
918
962
  body: body === void 0 ? void 0 : JSON.stringify(body)
919
963
  });
920
964
  const text = await response.text();
921
- if (!response.ok) throw new Error(`weaviate ${response.status}: ${text.slice(0, 200)}`);
965
+ if (!response.ok) {
966
+ throw new core.MemoryError({
967
+ code: core.ErrorCodes.AK_MEMORY_REMOTE_HTTP,
968
+ message: `weaviate ${response.status}: ${text.slice(0, 200)}`,
969
+ hint: `URL ${config.url}${path}. Check API key + class name "${config.className}".`
970
+ });
971
+ }
922
972
  return text.length > 0 ? JSON.parse(text) : {};
923
973
  }
924
974
  function weaviateVectorStore(config) {
@@ -963,8 +1013,6 @@ function weaviateVectorStore(config) {
963
1013
  }
964
1014
  };
965
1015
  }
966
-
967
- // src/vector/milvus.ts
968
1016
  async function call6(config, path, body) {
969
1017
  const fetchImpl = config.fetch ?? globalThis.fetch;
970
1018
  const response = await fetchImpl(`${config.url}${path}`, {
@@ -976,7 +1024,13 @@ async function call6(config, path, body) {
976
1024
  body: JSON.stringify(body)
977
1025
  });
978
1026
  const text = await response.text();
979
- if (!response.ok) throw new Error(`milvus ${response.status}: ${text.slice(0, 200)}`);
1027
+ if (!response.ok) {
1028
+ throw new core.MemoryError({
1029
+ code: core.ErrorCodes.AK_MEMORY_REMOTE_HTTP,
1030
+ message: `milvus ${response.status}: ${text.slice(0, 200)}`,
1031
+ hint: `URL ${config.url}${path}. Check token + collection "${config.collection}".`
1032
+ });
1033
+ }
980
1034
  return text.length > 0 ? JSON.parse(text) : {};
981
1035
  }
982
1036
  function milvusVectorStore(config) {
@@ -1066,8 +1120,6 @@ function mongoAtlasVectorStore(config) {
1066
1120
  }
1067
1121
  };
1068
1122
  }
1069
-
1070
- // src/encrypted.ts
1071
1123
  function toBase64(bytes) {
1072
1124
  if (typeof Buffer !== "undefined") return Buffer.from(bytes).toString("base64");
1073
1125
  let binary = "";
@@ -1085,14 +1137,24 @@ async function resolveKey(subtle, material) {
1085
1137
  if ("type" in material && material.type === "secret") return material;
1086
1138
  const raw = material;
1087
1139
  if (raw.byteLength !== 32) {
1088
- throw new Error(`createEncryptedMemory: key must be 32 bytes (got ${raw.byteLength})`);
1140
+ throw new core.ConfigError({
1141
+ code: core.ErrorCodes.AK_CONFIG_INVALID,
1142
+ message: `createEncryptedMemory: key must be 32 bytes (got ${raw.byteLength})`,
1143
+ hint: "Generate a 32-byte key, e.g. crypto.getRandomValues(new Uint8Array(32))."
1144
+ });
1089
1145
  }
1090
1146
  return subtle.importKey("raw", raw, { name: "AES-GCM" }, false, ["encrypt", "decrypt"]);
1091
1147
  }
1092
1148
  async function createEncryptedMemory(options) {
1093
1149
  const subtle = options.subtle ?? globalThis.crypto?.subtle;
1094
1150
  const random = options.getRandomValues ?? ((v) => globalThis.crypto.getRandomValues(v));
1095
- if (!subtle) throw new Error("createEncryptedMemory: SubtleCrypto not available");
1151
+ if (!subtle) {
1152
+ throw new core.MemoryError({
1153
+ code: core.ErrorCodes.AK_MEMORY_LOAD_FAILED,
1154
+ message: "createEncryptedMemory: SubtleCrypto not available",
1155
+ hint: "Run on Node \u2265 20 / a modern browser, or pass options.subtle explicitly."
1156
+ });
1157
+ }
1096
1158
  const key = await resolveKey(subtle, options.key);
1097
1159
  const aad = options.aad;
1098
1160
  const encrypt = async (plain) => {
@@ -1209,6 +1271,102 @@ function createHierarchicalMemory(options) {
1209
1271
  };
1210
1272
  }
1211
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
+
1212
1370
  exports.chroma = chroma;
1213
1371
  exports.createEncryptedMemory = createEncryptedMemory;
1214
1372
  exports.createHierarchicalMemory = createHierarchicalMemory;
@@ -1216,6 +1374,8 @@ exports.createInMemoryGraph = createInMemoryGraph;
1216
1374
  exports.createInMemoryPersonalization = createInMemoryPersonalization;
1217
1375
  exports.fileChatMemory = fileChatMemory;
1218
1376
  exports.fileVectorMemory = fileVectorMemory;
1377
+ exports.forgetSubject = forgetSubject;
1378
+ exports.makeForgettable = makeForgettable;
1219
1379
  exports.matchesFilter = matchesFilter;
1220
1380
  exports.milvusVectorStore = milvusVectorStore;
1221
1381
  exports.mongoAtlasVectorStore = mongoAtlasVectorStore;
@@ -1230,5 +1390,7 @@ exports.supabaseVectorStore = supabaseVectorStore;
1230
1390
  exports.tursoChatMemory = tursoChatMemory;
1231
1391
  exports.upstashVector = upstashVector;
1232
1392
  exports.weaviateVectorStore = weaviateVectorStore;
1393
+ exports.wrapChatMemoryWithRedaction = wrapChatMemoryWithRedaction;
1394
+ exports.wrapVectorMemoryWithRedaction = wrapVectorMemoryWithRedaction;
1233
1395
  //# sourceMappingURL=index.cjs.map
1234
1396
  //# sourceMappingURL=index.cjs.map