@agentskit/memory 0.8.3 → 0.10.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,9 @@
1
1
  'use strict';
2
2
 
3
3
  var core = require('@agentskit/core');
4
+ var security = require('@agentskit/core/security');
5
+ var promises = require('fs/promises');
6
+ var path = require('path');
4
7
 
5
8
  var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
6
9
  get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
@@ -21,7 +24,11 @@ function fileChatMemory(path) {
21
24
  },
22
25
  async save(messages) {
23
26
  const fs = await import('fs/promises');
24
- await fs.writeFile(path, JSON.stringify(core.serializeMessages(messages), null, 2), "utf8");
27
+ await fs.writeFile(
28
+ path,
29
+ JSON.stringify(core.serializeMessages(messages), null, 2),
30
+ { encoding: "utf8", mode: 384 }
31
+ );
25
32
  },
26
33
  async clear() {
27
34
  try {
@@ -197,7 +204,7 @@ async function createRedisClientAdapter(url) {
197
204
  return await client.keys(pattern);
198
205
  },
199
206
  async disconnect() {
200
- await client.disconnect();
207
+ await client.close();
201
208
  },
202
209
  async call(command, ...args) {
203
210
  return await client.sendCommand([command, ...args.map(String)]);
@@ -425,16 +432,23 @@ function createVectraStore(dirPath) {
425
432
  return {
426
433
  async upsert(docs) {
427
434
  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
- });
435
+ await idx.beginUpdate();
436
+ try {
437
+ for (const doc of docs) {
438
+ await idx.insertItem({
439
+ vector: doc.vector,
440
+ metadata: { _id: doc.id, ...doc.metadata }
441
+ });
442
+ }
443
+ await idx.endUpdate();
444
+ } catch (err) {
445
+ idx.cancelUpdate();
446
+ throw err;
433
447
  }
434
448
  },
435
449
  async query(vector, topK) {
436
450
  const idx = await getIndex();
437
- const results = await idx.queryItems(vector, topK);
451
+ const results = await idx.queryItems(vector, "", topK);
438
452
  return results.map((r) => ({
439
453
  id: String(r.item.metadata._id ?? ""),
440
454
  score: r.score,
@@ -1259,13 +1273,550 @@ function createHierarchicalMemory(options) {
1259
1273
  };
1260
1274
  }
1261
1275
 
1276
+ // src/forget.ts
1277
+ function isForgettable(value) {
1278
+ return !!value && typeof value === "object" && "forgetSubject" in value && typeof value.forgetSubject === "function";
1279
+ }
1280
+ async function hash(input) {
1281
+ const encoded = new TextEncoder().encode(input);
1282
+ const digest = await crypto.subtle.digest("SHA-256", encoded);
1283
+ return Array.from(new Uint8Array(digest)).map((b) => b.toString(16).padStart(2, "0")).join("");
1284
+ }
1285
+ async function forgetSubject(memories, subjectId) {
1286
+ const reports = [];
1287
+ for (const memory of memories) {
1288
+ if (!isForgettable(memory)) continue;
1289
+ reports.push(await memory.forgetSubject(subjectId));
1290
+ }
1291
+ const totalDeleted = reports.reduce((sum, r) => sum + r.deletedCount, 0);
1292
+ const evidenceHash = await hash(
1293
+ JSON.stringify({ subjectId, reports: reports.map((r) => ({ b: r.backend, n: r.deletedCount, at: r.at })) })
1294
+ );
1295
+ return { subjectId, reports, totalDeleted, evidenceHash };
1296
+ }
1297
+ function makeForgettable(memory, options) {
1298
+ return Object.assign(memory, {
1299
+ __agentskitBackend: options.backend,
1300
+ forgetSubject: async (subjectId) => {
1301
+ const ids = await options.listIds(subjectId);
1302
+ const failures = [];
1303
+ try {
1304
+ await options.deleteIds(ids);
1305
+ } catch (err) {
1306
+ for (const id of ids) failures.push({ id, reason: err.message });
1307
+ }
1308
+ return {
1309
+ backend: options.backend,
1310
+ deletedCount: ids.length - failures.length,
1311
+ at: (/* @__PURE__ */ new Date()).toISOString(),
1312
+ failures: failures.length ? failures : void 0
1313
+ };
1314
+ }
1315
+ });
1316
+ }
1317
+ async function transform(input, opts) {
1318
+ if (opts.mode === "tokenize") {
1319
+ if (!opts.vault) {
1320
+ throw new core.ConfigError({
1321
+ code: core.ErrorCodes.AK_CONFIG_INVALID,
1322
+ message: 'wrapMemoryWithRedaction: vault is required when mode is "tokenize"'
1323
+ });
1324
+ }
1325
+ if (!opts.allowedRoles) {
1326
+ throw new core.ConfigError({
1327
+ code: core.ErrorCodes.AK_CONFIG_INVALID,
1328
+ message: 'wrapMemoryWithRedaction: allowedRoles is required when mode is "tokenize"'
1329
+ });
1330
+ }
1331
+ const result = await security.tokenize(input, {
1332
+ rules: opts.rules,
1333
+ vault: opts.vault,
1334
+ allowedRoles: opts.allowedRoles,
1335
+ audit: opts.audit
1336
+ });
1337
+ return result.value;
1338
+ }
1339
+ return security.createPIIRedactor({ rules: opts.rules }).redact(input).value;
1340
+ }
1341
+ function wrapChatMemoryWithRedaction(inner, options) {
1342
+ return {
1343
+ load: () => inner.load(),
1344
+ save: async (messages) => {
1345
+ const redacted = await Promise.all(
1346
+ messages.map(async (m) => ({
1347
+ ...m,
1348
+ content: await transform(m.content ?? "", options)
1349
+ }))
1350
+ );
1351
+ await inner.save(redacted);
1352
+ },
1353
+ clear: inner.clear ? () => inner.clear() : void 0
1354
+ };
1355
+ }
1356
+ function wrapVectorMemoryWithRedaction(inner, options) {
1357
+ return {
1358
+ store: async (docs) => {
1359
+ const redacted = await Promise.all(
1360
+ docs.map(async (d) => ({
1361
+ ...d,
1362
+ content: await transform(d.content, options)
1363
+ }))
1364
+ );
1365
+ await inner.store(redacted);
1366
+ },
1367
+ search: (embedding, opts) => inner.search(embedding, opts),
1368
+ delete: inner.delete ? (ids) => inner.delete(ids) : void 0
1369
+ };
1370
+ }
1371
+
1372
+ // src/kv-store-types.ts
1373
+ var isExpired = (entry, ttlSeconds, now) => {
1374
+ if (ttlSeconds === void 0) return false;
1375
+ return now - entry.insertedAt > ttlSeconds * 1e3;
1376
+ };
1377
+ var enforceMaxMessages = (map, maxMessages) => {
1378
+ if (maxMessages === void 0) return;
1379
+ while (map.size > maxMessages) {
1380
+ const oldest = map.keys().next().value;
1381
+ if (oldest === void 0) break;
1382
+ map.delete(oldest);
1383
+ }
1384
+ };
1385
+
1386
+ // src/kv-store-basic.ts
1387
+ var createInMemoryStore = (config) => {
1388
+ const store = /* @__PURE__ */ new Map();
1389
+ const now = () => Date.now();
1390
+ return {
1391
+ id: "in-memory",
1392
+ async get(key) {
1393
+ const entry = store.get(key);
1394
+ if (!entry) return void 0;
1395
+ if (isExpired(entry, config.ttlSeconds, now())) {
1396
+ store.delete(key);
1397
+ return void 0;
1398
+ }
1399
+ return entry.value;
1400
+ },
1401
+ async set(key, value) {
1402
+ store.set(key, { value, insertedAt: now() });
1403
+ enforceMaxMessages(store, config.maxMessages);
1404
+ }
1405
+ };
1406
+ };
1407
+ var createFileStore = (config) => {
1408
+ const path$1 = config.path;
1409
+ let cache;
1410
+ const load = async () => {
1411
+ if (cache) return cache;
1412
+ try {
1413
+ const parsed = JSON.parse(await promises.readFile(path$1, "utf8"));
1414
+ cache = new Map(Object.entries(parsed));
1415
+ } catch (err) {
1416
+ if (err.code === "ENOENT") cache = /* @__PURE__ */ new Map();
1417
+ else throw err;
1418
+ }
1419
+ return cache;
1420
+ };
1421
+ const persist = async (map) => {
1422
+ await promises.mkdir(path.dirname(path$1), { recursive: true });
1423
+ await promises.writeFile(path$1, JSON.stringify(Object.fromEntries(map), null, 2), { encoding: "utf8", mode: 384 });
1424
+ };
1425
+ return {
1426
+ id: `file:${path$1}`,
1427
+ async get(key) {
1428
+ const map = await load();
1429
+ const entry = map.get(key);
1430
+ if (!entry) return void 0;
1431
+ if (isExpired(entry, config.ttlSeconds, Date.now())) {
1432
+ map.delete(key);
1433
+ await persist(map);
1434
+ return void 0;
1435
+ }
1436
+ return entry.value;
1437
+ },
1438
+ async set(key, value) {
1439
+ const map = await load();
1440
+ map.set(key, { value, insertedAt: Date.now() });
1441
+ enforceMaxMessages(map, config.maxMessages);
1442
+ await persist(map);
1443
+ }
1444
+ };
1445
+ };
1446
+ var resolveLocalStorage = () => {
1447
+ const maybe = globalThis.localStorage;
1448
+ return maybe && typeof maybe.getItem === "function" && typeof maybe.setItem === "function" ? maybe : void 0;
1449
+ };
1450
+ var defaultLocalStoragePath = () => `${process.cwd()}/.agentskit/memory-localstorage.json`;
1451
+ var createLocalStorageStore = ({
1452
+ config,
1453
+ storage = resolveLocalStorage(),
1454
+ filePath = defaultLocalStoragePath()
1455
+ }) => {
1456
+ const key = config.key;
1457
+ let cache;
1458
+ const mapFromJson = (raw) => raw ? new Map(Object.entries(JSON.parse(raw))) : /* @__PURE__ */ new Map();
1459
+ const loadFromFile = async () => {
1460
+ if (cache) return cache;
1461
+ try {
1462
+ cache = mapFromJson(await promises.readFile(filePath, "utf8"));
1463
+ } catch (err) {
1464
+ if (err.code === "ENOENT") cache = /* @__PURE__ */ new Map();
1465
+ else throw err;
1466
+ }
1467
+ return cache;
1468
+ };
1469
+ const load = async () => storage ? mapFromJson(storage.getItem(key)) : loadFromFile();
1470
+ const persist = async (map) => {
1471
+ const raw = JSON.stringify(Object.fromEntries(map), null, 2);
1472
+ if (storage) {
1473
+ storage.setItem(key, raw);
1474
+ return;
1475
+ }
1476
+ await promises.mkdir(path.dirname(filePath), { recursive: true });
1477
+ await promises.writeFile(filePath, raw, { encoding: "utf8", mode: 384 });
1478
+ };
1479
+ return {
1480
+ id: storage ? `localstorage:${key}` : `localstorage-file:${filePath}:${key}`,
1481
+ async get(itemKey) {
1482
+ const map = await load();
1483
+ const entry = map.get(itemKey);
1484
+ if (!entry) return void 0;
1485
+ if (isExpired(entry, config.ttlSeconds, Date.now())) {
1486
+ map.delete(itemKey);
1487
+ await persist(map);
1488
+ return void 0;
1489
+ }
1490
+ return entry.value;
1491
+ },
1492
+ async set(itemKey, value) {
1493
+ const map = await load();
1494
+ map.set(itemKey, { value, insertedAt: Date.now() });
1495
+ enforceMaxMessages(map, config.maxMessages);
1496
+ await persist(map);
1497
+ }
1498
+ };
1499
+ };
1500
+
1501
+ // src/kv-store-sqlite.ts
1502
+ var createSqliteStore = ({ config, open }) => {
1503
+ const db = open(config.path);
1504
+ db.exec(
1505
+ `CREATE TABLE IF NOT EXISTS memory (
1506
+ key TEXT PRIMARY KEY,
1507
+ value TEXT NOT NULL,
1508
+ inserted_at INTEGER NOT NULL
1509
+ )`
1510
+ );
1511
+ const getStmt = db.prepare("SELECT value, inserted_at FROM memory WHERE key = ?");
1512
+ const setStmt = db.prepare(
1513
+ "INSERT INTO memory(key, value, inserted_at) VALUES(?, ?, ?) ON CONFLICT(key) DO UPDATE SET value=excluded.value, inserted_at=excluded.inserted_at"
1514
+ );
1515
+ const delStmt = db.prepare("DELETE FROM memory WHERE key = ?");
1516
+ const oldestStmt = db.prepare("SELECT key FROM memory ORDER BY inserted_at ASC LIMIT 1");
1517
+ const countStmt = db.prepare("SELECT COUNT(*) as n FROM memory");
1518
+ const enforce = () => {
1519
+ if (config.maxMessages === void 0) return;
1520
+ const countResult = countStmt.get();
1521
+ let count = countResult ? countResult.n : 0;
1522
+ while (count > config.maxMessages) {
1523
+ const oldest = oldestStmt.get();
1524
+ if (!oldest) break;
1525
+ delStmt.run(oldest.key);
1526
+ count -= 1;
1527
+ }
1528
+ };
1529
+ return {
1530
+ id: `sqlite:${config.path}`,
1531
+ async get(key) {
1532
+ const row = getStmt.get(key);
1533
+ if (!row) return void 0;
1534
+ if (isExpired({ insertedAt: row.inserted_at }, config.ttlSeconds, Date.now())) {
1535
+ delStmt.run(key);
1536
+ return void 0;
1537
+ }
1538
+ return JSON.parse(row.value);
1539
+ },
1540
+ async set(key, value) {
1541
+ setStmt.run(key, JSON.stringify(value), Date.now());
1542
+ enforce();
1543
+ }
1544
+ };
1545
+ };
1546
+ var tryDefaultSqliteOpener = async () => {
1547
+ try {
1548
+ const moduleId = "better-sqlite3";
1549
+ const mod = await import(
1550
+ /* @vite-ignore */
1551
+ moduleId
1552
+ );
1553
+ const Ctor = mod.default;
1554
+ if (typeof Ctor !== "function") return void 0;
1555
+ return (path) => new Ctor(path);
1556
+ } catch {
1557
+ return void 0;
1558
+ }
1559
+ };
1560
+ var createRedisStore = ({ config, client }) => {
1561
+ const prefix = config.prefix;
1562
+ const namespaced = (key) => `${prefix}${key}`;
1563
+ const wrap = async (op, fn) => {
1564
+ try {
1565
+ return await fn();
1566
+ } catch (cause) {
1567
+ throw new core.MemoryError({
1568
+ code: "AK_MEMORY_REDIS_CONNECTION_FAILED",
1569
+ message: `createRedisStore.${op}: redis command failed \u2014 ${cause instanceof Error ? cause.message : String(cause)}`,
1570
+ cause: cause instanceof Error ? cause : void 0
1571
+ });
1572
+ }
1573
+ };
1574
+ const enforce = async () => {
1575
+ if (config.maxMessages === void 0) return;
1576
+ const keys = await wrap("enforce", () => Promise.resolve(client.keys(`${prefix}*`)));
1577
+ if (keys.length <= config.maxMessages) return;
1578
+ const envelopes = [];
1579
+ for (const fullKey of keys) {
1580
+ const raw = await wrap("enforce", () => Promise.resolve(client.get(fullKey)));
1581
+ if (raw === null) continue;
1582
+ envelopes.push({ key: fullKey, insertedAt: JSON.parse(raw).insertedAt });
1583
+ }
1584
+ envelopes.sort((a, b) => a.insertedAt - b.insertedAt);
1585
+ let excess = envelopes.length - config.maxMessages;
1586
+ for (const entry of envelopes) {
1587
+ if (excess <= 0) break;
1588
+ await wrap("enforce", () => Promise.resolve(client.del(entry.key)));
1589
+ excess -= 1;
1590
+ }
1591
+ };
1592
+ return {
1593
+ id: `redis:${prefix}`,
1594
+ async get(key) {
1595
+ const raw = await wrap("get", () => Promise.resolve(client.get(namespaced(key))));
1596
+ if (raw === null) return void 0;
1597
+ const envelope = JSON.parse(raw);
1598
+ if (isExpired({ value: envelope.value, insertedAt: envelope.insertedAt }, config.ttlSeconds, Date.now())) {
1599
+ await wrap("get", () => Promise.resolve(client.del(namespaced(key))));
1600
+ return void 0;
1601
+ }
1602
+ return envelope.value;
1603
+ },
1604
+ async set(key, value) {
1605
+ const payload = JSON.stringify({ value, insertedAt: Date.now() });
1606
+ const options = config.ttlSeconds === void 0 ? void 0 : { EX: config.ttlSeconds };
1607
+ await wrap("set", () => Promise.resolve(client.set(namespaced(key), payload, options)));
1608
+ await enforce();
1609
+ }
1610
+ };
1611
+ };
1612
+ var adaptIoredis = (io) => ({
1613
+ get: (key) => io.get(key),
1614
+ set: (key, value, options) => options?.EX === void 0 ? io.set(key, value) : io.set(key, value, "EX", options.EX),
1615
+ del: (key) => io.del(key),
1616
+ keys: (pattern) => io.keys(pattern)
1617
+ });
1618
+ var tryDefaultRedisClient = async (url) => {
1619
+ try {
1620
+ const moduleId = "redis";
1621
+ const mod = await import(
1622
+ /* @vite-ignore */
1623
+ moduleId
1624
+ );
1625
+ const createClient = mod.createClient;
1626
+ if (typeof createClient !== "function") return void 0;
1627
+ const client = createClient({ url });
1628
+ try {
1629
+ await client.connect();
1630
+ } catch (cause) {
1631
+ throw new core.MemoryError({
1632
+ code: "AK_MEMORY_REDIS_CONNECTION_FAILED",
1633
+ message: `tryDefaultRedisClient: redis connect() failed \u2014 ${cause instanceof Error ? cause.message : String(cause)}`,
1634
+ cause: cause instanceof Error ? cause : void 0
1635
+ });
1636
+ }
1637
+ return client;
1638
+ } catch (err) {
1639
+ if (err instanceof core.MemoryError) throw err;
1640
+ return void 0;
1641
+ }
1642
+ };
1643
+ var createVectorStore = ({
1644
+ config,
1645
+ vectorStore,
1646
+ embedder
1647
+ }) => {
1648
+ const collection = config.collection;
1649
+ const embedOne = async (text) => {
1650
+ const [vec] = await embedder.embed([text]);
1651
+ if (vec === void 0) {
1652
+ throw new core.MemoryError({
1653
+ code: "AK_MEMORY_VECTOR_EMBEDDER_REQUIRED",
1654
+ message: "createVectorStore: embedder returned no vector for the input text."
1655
+ });
1656
+ }
1657
+ return vec;
1658
+ };
1659
+ return {
1660
+ id: `vector:${config.provider}:${collection}`,
1661
+ async get(key) {
1662
+ const vec = await embedOne(key);
1663
+ const hits = await vectorStore.query(vec, 1, { __collection: collection, __key: key });
1664
+ const hit = hits[0];
1665
+ if (hit === void 0) return void 0;
1666
+ if (hit.metadata["__key"] !== key) return void 0;
1667
+ const insertedAt = hit.metadata["__insertedAt"];
1668
+ if (typeof insertedAt === "number" && isExpired({ insertedAt }, config.ttlSeconds, Date.now())) {
1669
+ return void 0;
1670
+ }
1671
+ return hit.metadata["__value"];
1672
+ },
1673
+ async set(key, value) {
1674
+ const vec = await embedOne(key);
1675
+ await vectorStore.upsert([
1676
+ {
1677
+ chunkId: `${collection}:${key}`,
1678
+ vec,
1679
+ metadata: { __collection: collection, __key: key, __value: value, __insertedAt: Date.now() }
1680
+ }
1681
+ ]);
1682
+ },
1683
+ async recall(query, k = 5) {
1684
+ const vec = await embedOne(query);
1685
+ const hits = await vectorStore.query(vec, k, { __collection: collection });
1686
+ const now = Date.now();
1687
+ const results = [];
1688
+ for (const hit of hits) {
1689
+ const insertedAt = hit.metadata["__insertedAt"];
1690
+ if (typeof insertedAt === "number" && isExpired({ insertedAt }, config.ttlSeconds, now)) {
1691
+ continue;
1692
+ }
1693
+ results.push(hit.metadata["__value"]);
1694
+ }
1695
+ return results;
1696
+ }
1697
+ };
1698
+ };
1699
+ var MemoryBackendNotImplementedError = class extends Error {
1700
+ constructor(backend) {
1701
+ super(
1702
+ `Memory backend "${backend}" is not implemented. Supported: "in-memory", "file", "sqlite", "localstorage", "redis", "vector".`
1703
+ );
1704
+ this.code = "MEMORY_BACKEND_NOT_IMPLEMENTED";
1705
+ this.backend = backend;
1706
+ }
1707
+ };
1708
+ var MEMORY_BACKEND_SUPPORT = {
1709
+ "in-memory": "supported",
1710
+ file: "supported",
1711
+ sqlite: "supported",
1712
+ redis: "supported",
1713
+ vector: "supported",
1714
+ localstorage: "supported"
1715
+ };
1716
+ var isMemoryBackendSupported = (backend) => MEMORY_BACKEND_SUPPORT[backend] === "supported";
1717
+ var createKvMemoryFromConfig = ({
1718
+ config,
1719
+ sqlite,
1720
+ localStorageFilePath,
1721
+ redis,
1722
+ vectorStore,
1723
+ embedder
1724
+ }) => {
1725
+ if (config.backend === "in-memory") return createInMemoryStore(config);
1726
+ if (config.backend === "file") return createFileStore(config);
1727
+ if (config.backend === "localstorage") {
1728
+ return createLocalStorageStore({
1729
+ config,
1730
+ ...localStorageFilePath ? { filePath: localStorageFilePath } : {}
1731
+ });
1732
+ }
1733
+ if (config.backend === "sqlite") {
1734
+ if (!sqlite) {
1735
+ throw new core.MemoryError({
1736
+ code: "AK_MEMORY_SQLITE_OPENER_REQUIRED",
1737
+ message: "createKvMemoryFromConfig: sqlite backend requires an `open` function (better-sqlite3), or call createKvMemoryFromConfigAuto which lazy-imports it."
1738
+ });
1739
+ }
1740
+ return createSqliteStore({ config, open: sqlite });
1741
+ }
1742
+ if (config.backend === "redis") {
1743
+ if (!redis) {
1744
+ throw new core.MemoryError({
1745
+ code: "AK_MEMORY_REDIS_CLIENT_REQUIRED",
1746
+ message: "createKvMemoryFromConfig: redis backend requires a `redis` client, or call createKvMemoryFromConfigAuto which lazy-imports it."
1747
+ });
1748
+ }
1749
+ return createRedisStore({ config, client: redis });
1750
+ }
1751
+ if (config.backend === "vector") {
1752
+ if (!vectorStore) {
1753
+ throw new core.MemoryError({
1754
+ code: "AK_MEMORY_VECTOR_STORE_REQUIRED",
1755
+ message: "createKvMemoryFromConfig: vector backend requires a `vectorStore`."
1756
+ });
1757
+ }
1758
+ if (!embedder) {
1759
+ throw new core.MemoryError({
1760
+ code: "AK_MEMORY_VECTOR_EMBEDDER_REQUIRED",
1761
+ message: "createKvMemoryFromConfig: vector backend requires an `embedder`."
1762
+ });
1763
+ }
1764
+ return createVectorStore({ config, vectorStore, embedder });
1765
+ }
1766
+ const exhausted = config;
1767
+ throw new MemoryBackendNotImplementedError(exhausted.backend);
1768
+ };
1769
+ var createKvMemoryFromConfigAuto = async (config) => {
1770
+ if (config.backend === "sqlite") {
1771
+ const sqlite = await tryDefaultSqliteOpener();
1772
+ if (!sqlite) {
1773
+ throw new core.MemoryError({
1774
+ code: "AK_MEMORY_PEER_MISSING",
1775
+ message: "createKvMemoryFromConfigAuto: sqlite backend needs `better-sqlite3` (pnpm add better-sqlite3)."
1776
+ });
1777
+ }
1778
+ return createKvMemoryFromConfig({ config, sqlite });
1779
+ }
1780
+ if (config.backend === "redis") {
1781
+ const redis = await tryDefaultRedisClient(config.url);
1782
+ if (!redis) {
1783
+ throw new core.MemoryError({
1784
+ code: "AK_MEMORY_PEER_MISSING",
1785
+ message: "createKvMemoryFromConfigAuto: redis backend needs `redis` (pnpm add redis)."
1786
+ });
1787
+ }
1788
+ return createKvMemoryFromConfig({ config, redis });
1789
+ }
1790
+ if (config.backend === "vector") {
1791
+ throw new core.MemoryError({
1792
+ code: "AK_MEMORY_VECTOR_STORE_REQUIRED",
1793
+ message: "createKvMemoryFromConfigAuto: vector backend requires an injected vectorStore + embedder."
1794
+ });
1795
+ }
1796
+ return createKvMemoryFromConfig({ config });
1797
+ };
1798
+
1799
+ exports.MEMORY_BACKEND_SUPPORT = MEMORY_BACKEND_SUPPORT;
1800
+ exports.MemoryBackendNotImplementedError = MemoryBackendNotImplementedError;
1801
+ exports.adaptIoredis = adaptIoredis;
1262
1802
  exports.chroma = chroma;
1263
1803
  exports.createEncryptedMemory = createEncryptedMemory;
1804
+ exports.createFileStore = createFileStore;
1264
1805
  exports.createHierarchicalMemory = createHierarchicalMemory;
1265
1806
  exports.createInMemoryGraph = createInMemoryGraph;
1266
1807
  exports.createInMemoryPersonalization = createInMemoryPersonalization;
1808
+ exports.createInMemoryStore = createInMemoryStore;
1809
+ exports.createKvMemoryFromConfig = createKvMemoryFromConfig;
1810
+ exports.createKvMemoryFromConfigAuto = createKvMemoryFromConfigAuto;
1811
+ exports.createLocalStorageStore = createLocalStorageStore;
1812
+ exports.createRedisStore = createRedisStore;
1813
+ exports.createSqliteStore = createSqliteStore;
1814
+ exports.createVectorStore = createVectorStore;
1267
1815
  exports.fileChatMemory = fileChatMemory;
1268
1816
  exports.fileVectorMemory = fileVectorMemory;
1817
+ exports.forgetSubject = forgetSubject;
1818
+ exports.isMemoryBackendSupported = isMemoryBackendSupported;
1819
+ exports.makeForgettable = makeForgettable;
1269
1820
  exports.matchesFilter = matchesFilter;
1270
1821
  exports.milvusVectorStore = milvusVectorStore;
1271
1822
  exports.mongoAtlasVectorStore = mongoAtlasVectorStore;
@@ -1277,8 +1828,12 @@ exports.redisVectorMemory = redisVectorMemory;
1277
1828
  exports.renderProfileContext = renderProfileContext;
1278
1829
  exports.sqliteChatMemory = sqliteChatMemory;
1279
1830
  exports.supabaseVectorStore = supabaseVectorStore;
1831
+ exports.tryDefaultRedisClient = tryDefaultRedisClient;
1832
+ exports.tryDefaultSqliteOpener = tryDefaultSqliteOpener;
1280
1833
  exports.tursoChatMemory = tursoChatMemory;
1281
1834
  exports.upstashVector = upstashVector;
1282
1835
  exports.weaviateVectorStore = weaviateVectorStore;
1836
+ exports.wrapChatMemoryWithRedaction = wrapChatMemoryWithRedaction;
1837
+ exports.wrapVectorMemoryWithRedaction = wrapVectorMemoryWithRedaction;
1283
1838
  //# sourceMappingURL=index.cjs.map
1284
1839
  //# sourceMappingURL=index.cjs.map