@memstack/core 0.7.3 → 0.8.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/dist/index.js CHANGED
@@ -724,6 +724,7 @@ var MemoryStore = class {
724
724
 
725
725
  // src/adapters/storage/memory.ts
726
726
  var InMemoryStorageAdapter = class {
727
+ capabilities = { multiProcess: false };
727
728
  memories = /* @__PURE__ */ new Map();
728
729
  async initialize() {
729
730
  }
@@ -819,8 +820,10 @@ var InMemoryStorageAdapter = class {
819
820
  results.sort((a, b) => b.importance - a.importance || b._touchedAt.getTime() - a._touchedAt.getTime());
820
821
  break;
821
822
  }
822
- for (const r of results.slice(0, query.limit ?? 10)) {
823
- r._touchedAt = /* @__PURE__ */ new Date();
823
+ if (query.touch !== false) {
824
+ for (const r of results.slice(0, query.limit ?? 10)) {
825
+ r._touchedAt = /* @__PURE__ */ new Date();
826
+ }
824
827
  }
825
828
  const limit = query.limit ?? 10;
826
829
  return results.slice(0, limit);
@@ -852,6 +855,25 @@ var InMemoryStorageAdapter = class {
852
855
  }
853
856
  };
854
857
 
858
+ // src/enrichment.ts
859
+ var ENRICHMENT_MAX_TOKENS = 1024;
860
+ function extractJson(text) {
861
+ let cleaned = text.trim();
862
+ const fenceMatch = cleaned.match(/```(?:json)?\s*([\s\S]*?)```/);
863
+ if (fenceMatch) cleaned = fenceMatch[1].trim();
864
+ return cleaned;
865
+ }
866
+ function parseTags(text, max = 5) {
867
+ try {
868
+ const parsed = JSON.parse(extractJson(text));
869
+ if (Array.isArray(parsed) && parsed.every((t) => typeof t === "string")) {
870
+ return parsed.map((t) => t.toLowerCase().trim()).slice(0, max);
871
+ }
872
+ } catch {
873
+ }
874
+ return text.split(",").map((t) => t.replace(/[\[\]"]/g, "").trim().toLowerCase()).filter((t) => t.length > 0).slice(0, max);
875
+ }
876
+
855
877
  // src/client.ts
856
878
  var MemStack = class {
857
879
  memory;
@@ -884,7 +906,7 @@ var MemStack = class {
884
906
  const result = await this.config.llm.complete({
885
907
  system: 'Analyze the memory and respond with a JSON object: {"importance": <0.0-1.0>, "tags": [<array of 1-5 lowercase single-word tags>]}. Return ONLY the JSON, nothing else.',
886
908
  user: input.content,
887
- maxTokens: 100,
909
+ maxTokens: ENRICHMENT_MAX_TOKENS,
888
910
  temperature: 0
889
911
  });
890
912
  const parsed = this._parseEnrichmentJson(result.text);
@@ -894,7 +916,7 @@ var MemStack = class {
894
916
  const result = await this.config.llm.complete({
895
917
  system: "Rate the importance of the following memory for an AI agent on a scale of 0.0 to 1.0, where 0.0 is trivial and 1.0 is critical. Return ONLY a single float number, nothing else.",
896
918
  user: input.content,
897
- maxTokens: 10,
919
+ maxTokens: ENRICHMENT_MAX_TOKENS,
898
920
  temperature: 0
899
921
  });
900
922
  const parsed = parseFloat(result.text.trim());
@@ -903,10 +925,10 @@ var MemStack = class {
903
925
  const result = await this.config.llm.complete({
904
926
  system: 'Extract 1-5 concise, lowercase, single-word tags from the following memory. Return ONLY a JSON array of strings, nothing else. Example: ["combat", "goblin", "forest"]',
905
927
  user: input.content,
906
- maxTokens: 80,
928
+ maxTokens: ENRICHMENT_MAX_TOKENS,
907
929
  temperature: 0
908
930
  });
909
- tags = this._parseTagsJson(result.text);
931
+ tags = parseTags(result.text);
910
932
  }
911
933
  } catch (err) {
912
934
  this.config.hooks?.onError?.(
@@ -1024,7 +1046,7 @@ var MemStack = class {
1024
1046
  }
1025
1047
  _parseEnrichmentJson(text) {
1026
1048
  try {
1027
- const json = JSON.parse(this._extractJson(text));
1049
+ const json = JSON.parse(extractJson(text));
1028
1050
  const result = {};
1029
1051
  if (typeof json.importance === "number" && Number.isFinite(json.importance)) {
1030
1052
  result.importance = Math.max(0, Math.min(1, json.importance));
@@ -1037,25 +1059,448 @@ var MemStack = class {
1037
1059
  return {};
1038
1060
  }
1039
1061
  }
1040
- _parseTagsJson(text) {
1041
- try {
1042
- const parsed = JSON.parse(this._extractJson(text));
1043
- if (Array.isArray(parsed) && parsed.every((t) => typeof t === "string")) {
1044
- return parsed.map((t) => t.toLowerCase().trim()).slice(0, 5);
1062
+ };
1063
+
1064
+ // src/retrieval/text.ts
1065
+ var STOPWORDS = /* @__PURE__ */ new Set([
1066
+ "a",
1067
+ "an",
1068
+ "and",
1069
+ "are",
1070
+ "as",
1071
+ "at",
1072
+ "be",
1073
+ "by",
1074
+ "did",
1075
+ "do",
1076
+ "does",
1077
+ "for",
1078
+ "from",
1079
+ "how",
1080
+ "i",
1081
+ "in",
1082
+ "is",
1083
+ "it",
1084
+ "its",
1085
+ "me",
1086
+ "my",
1087
+ "of",
1088
+ "on",
1089
+ "or",
1090
+ "our",
1091
+ "that",
1092
+ "the",
1093
+ "this",
1094
+ "to",
1095
+ "was",
1096
+ "we",
1097
+ "were",
1098
+ "what",
1099
+ "when",
1100
+ "where",
1101
+ "which",
1102
+ "who",
1103
+ "why",
1104
+ "with",
1105
+ "you",
1106
+ "your",
1107
+ // Verbs that frame a question ("what do we use?") without saying what it is about.
1108
+ "can",
1109
+ "could",
1110
+ "has",
1111
+ "have",
1112
+ "should",
1113
+ "use",
1114
+ "used",
1115
+ "uses",
1116
+ "using",
1117
+ "would"
1118
+ ]);
1119
+ function tokenize(text) {
1120
+ return text.toLowerCase().match(/[\p{L}\p{N}]+/gu) ?? [];
1121
+ }
1122
+ function queryTerms(text) {
1123
+ const words = [...new Set(tokenize(text))];
1124
+ const meaningful = words.filter((w) => !STOPWORDS.has(w));
1125
+ return [...new Set((meaningful.length > 0 ? meaningful : words).map(stem))];
1126
+ }
1127
+ function documentTerms(text) {
1128
+ return tokenize(text).map(stem);
1129
+ }
1130
+ var STEP2 = {
1131
+ ational: "ate",
1132
+ tional: "tion",
1133
+ enci: "ence",
1134
+ anci: "ance",
1135
+ izer: "ize",
1136
+ bli: "ble",
1137
+ alli: "al",
1138
+ entli: "ent",
1139
+ eli: "e",
1140
+ ousli: "ous",
1141
+ ization: "ize",
1142
+ ation: "ate",
1143
+ ator: "ate",
1144
+ alism: "al",
1145
+ iveness: "ive",
1146
+ fulness: "ful",
1147
+ ousness: "ous",
1148
+ aliti: "al",
1149
+ iviti: "ive",
1150
+ biliti: "ble",
1151
+ logi: "log"
1152
+ };
1153
+ var STEP3 = {
1154
+ icate: "ic",
1155
+ ative: "",
1156
+ alize: "al",
1157
+ iciti: "ic",
1158
+ ical: "ic",
1159
+ ful: "",
1160
+ ness: ""
1161
+ };
1162
+ var STEP4 = /^(.+?)(al|ance|ence|er|ic|able|ible|ant|ement|ment|ent|ou|ism|ate|iti|ous|ive|ize)$/;
1163
+ var C = "[^aeiou]";
1164
+ var V = "[aeiouy]";
1165
+ var CS = `${C}[^aeiouy]*`;
1166
+ var VS = `${V}[aeiou]*`;
1167
+ var MGR0 = new RegExp(`^(${CS})?${VS}${CS}`);
1168
+ var MEQ1 = new RegExp(`^(${CS})?${VS}${CS}(${VS})?$`);
1169
+ var MGR1 = new RegExp(`^(${CS})?${VS}${CS}${VS}${CS}`);
1170
+ var HAS_VOWEL = new RegExp(`^(${CS})?${V}`);
1171
+ var CVC = new RegExp(`^${CS}${V}[^aeiouwxy]$`);
1172
+ function stem(word) {
1173
+ if (word.length < 3 || !/^[a-z]+$/.test(word)) return word;
1174
+ let w = word;
1175
+ const firstY = w[0] === "y";
1176
+ if (firstY) w = "Y" + w.slice(1);
1177
+ if (/(ss|i)es$/.test(w)) w = w.slice(0, -2);
1178
+ else if (/[^s]s$/.test(w)) w = w.slice(0, -1);
1179
+ let m;
1180
+ if (m = w.match(/^(.+?)eed$/)) {
1181
+ if (MGR0.test(m[1])) w = w.slice(0, -1);
1182
+ } else if (m = w.match(/^(.+?)(ed|ing)$/)) {
1183
+ const base = m[1];
1184
+ if (HAS_VOWEL.test(base)) {
1185
+ w = base;
1186
+ if (/(at|bl|iz)$/.test(w)) w += "e";
1187
+ else if (/([^aeiouylsz])\1$/.test(w)) w = w.slice(0, -1);
1188
+ else if (CVC.test(w)) w += "e";
1189
+ }
1190
+ }
1191
+ if ((m = w.match(/^(.+?)y$/)) && HAS_VOWEL.test(m[1])) w = m[1] + "i";
1192
+ if (m = w.match(/^(.+?)(ational|tional|enci|anci|izer|bli|alli|entli|eli|ousli|ization|ation|ator|alism|iveness|fulness|ousness|aliti|iviti|biliti|logi)$/)) {
1193
+ if (MGR0.test(m[1])) w = m[1] + STEP2[m[2]];
1194
+ }
1195
+ if (m = w.match(/^(.+?)(icate|ative|alize|iciti|ical|ful|ness)$/)) {
1196
+ if (MGR0.test(m[1])) w = m[1] + STEP3[m[2]];
1197
+ }
1198
+ if (m = w.match(STEP4)) {
1199
+ if (MGR1.test(m[1])) w = m[1];
1200
+ } else if (m = w.match(/^(.+?)(s|t)(ion)$/)) {
1201
+ const base = m[1] + m[2];
1202
+ if (MGR1.test(base)) w = base;
1203
+ }
1204
+ if (m = w.match(/^(.+?)e$/)) {
1205
+ const base = m[1];
1206
+ if (MGR1.test(base) || MEQ1.test(base) && !CVC.test(base)) w = base;
1207
+ }
1208
+ if (/ll$/.test(w) && MGR1.test(w)) w = w.slice(0, -1);
1209
+ if (firstY) w = "y" + w.slice(1);
1210
+ return w;
1211
+ }
1212
+
1213
+ // src/retrieval/LexicalRetriever.ts
1214
+ var K1 = 1.2;
1215
+ var B = 0.75;
1216
+ var PREFIX_WEIGHT = 0.5;
1217
+ var MIN_PREFIX_LENGTH = 3;
1218
+ var LexicalRetriever = class {
1219
+ constructor(storage, config = {}) {
1220
+ this.storage = storage;
1221
+ this.candidateLimit = config.candidateLimit ?? 2e3;
1222
+ this.touch = config.touch ?? true;
1223
+ }
1224
+ storage;
1225
+ candidateLimit;
1226
+ touch;
1227
+ async recall(query) {
1228
+ const limit = query.limit ?? 10;
1229
+ const maxChars = query.maxChars ?? 8e3;
1230
+ const terms = queryTerms(query.query ?? "");
1231
+ let ranked = [];
1232
+ let candidates;
1233
+ if (terms.length > 0 && this.storage.search && this.storage.capabilities?.textSearch) {
1234
+ ranked = (await this.storage.search({
1235
+ actorIds: query.actorIds,
1236
+ query: query.query,
1237
+ memoryTypes: query.memoryTypes,
1238
+ limit: this.candidateLimit
1239
+ })).map(({ memory, score }) => ({ memory, score }));
1240
+ } else if (terms.length > 0) {
1241
+ candidates = await this.loadCandidates(query);
1242
+ ranked = rank(candidates, terms);
1243
+ }
1244
+ const fallback = ranked.length === 0;
1245
+ if (fallback) {
1246
+ candidates ??= await this.loadCandidates(query);
1247
+ ranked = [...candidates].sort(byImportanceThenRecency).map((memory) => ({ memory, score: 0 }));
1248
+ }
1249
+ const hits = withinBudget(ranked, limit, maxChars);
1250
+ if (this.touch) await this.touchAll(hits);
1251
+ return { hits, fallback };
1252
+ }
1253
+ async loadCandidates(query) {
1254
+ const byId = /* @__PURE__ */ new Map();
1255
+ for (const actorId of new Set(query.actorIds)) {
1256
+ const memories = await this.storage.retrieve({
1257
+ actorId,
1258
+ memoryTypes: query.memoryTypes,
1259
+ limit: this.candidateLimit,
1260
+ strategy: "important",
1261
+ touch: false
1262
+ });
1263
+ for (const memory of memories) byId.set(memory.id, memory);
1264
+ }
1265
+ return [...byId.values()];
1266
+ }
1267
+ async touchAll(hits) {
1268
+ if (!this.storage.touch) return;
1269
+ await Promise.all(
1270
+ hits.map(
1271
+ ({ memory }) => this.storage.touch(memory.id).catch(() => {
1272
+ })
1273
+ )
1274
+ );
1275
+ }
1276
+ };
1277
+ function rank(memories, terms) {
1278
+ if (memories.length === 0) return [];
1279
+ const candidates = memories.map((memory) => {
1280
+ const tokens = documentTerms(`${memory.content} ${memory.tags.join(" ")}`);
1281
+ const counts = /* @__PURE__ */ new Map();
1282
+ for (const token of tokens) counts.set(token, (counts.get(token) ?? 0) + 1);
1283
+ return { memory, terms: counts, length: tokens.length };
1284
+ });
1285
+ const avgLength = candidates.reduce((sum, c) => sum + c.length, 0) / candidates.length || 1;
1286
+ const n = candidates.length;
1287
+ const frequencies = terms.map(
1288
+ (term) => candidates.map((c) => {
1289
+ let tf = c.terms.get(term) ?? 0;
1290
+ if (term.length >= MIN_PREFIX_LENGTH) {
1291
+ for (const [docTerm, count] of c.terms) {
1292
+ if (docTerm !== term && docTerm.startsWith(term)) tf += count * PREFIX_WEIGHT;
1293
+ }
1045
1294
  }
1046
- } catch {
1295
+ return tf;
1296
+ })
1297
+ );
1298
+ const hits = [];
1299
+ candidates.forEach((c, i) => {
1300
+ let score = 0;
1301
+ frequencies.forEach((perCandidate) => {
1302
+ const tf = perCandidate[i];
1303
+ if (tf === 0) return;
1304
+ const df = perCandidate.filter((f) => f > 0).length;
1305
+ const idf = Math.log(1 + (n - df + 0.5) / (df + 0.5));
1306
+ score += idf * (tf * (K1 + 1) / (tf + K1 * (1 - B + B * c.length / avgLength)));
1307
+ });
1308
+ if (score > 0) hits.push({ memory: c.memory, score });
1309
+ });
1310
+ return hits.sort((a, b) => b.score - a.score || byImportanceThenRecency(a.memory, b.memory));
1311
+ }
1312
+ function byImportanceThenRecency(a, b) {
1313
+ return b.importance - a.importance || b.createdAt.getTime() - a.createdAt.getTime();
1314
+ }
1315
+ function withinBudget(ranked, limit, maxChars) {
1316
+ const hits = [];
1317
+ let chars = 0;
1318
+ for (const hit of ranked) {
1319
+ if (hits.length >= limit) break;
1320
+ const size = hit.memory.content.length;
1321
+ if (hits.length > 0 && chars + size > maxChars) continue;
1322
+ hits.push(hit);
1323
+ chars += size;
1324
+ }
1325
+ return hits;
1326
+ }
1327
+
1328
+ // src/harness/namespaces.ts
1329
+ var GLOBAL_NAMESPACE = "global";
1330
+ function projectNamespace(projectId) {
1331
+ if (!projectId) throw new Error("projectId is required");
1332
+ return `project:${projectId}`;
1333
+ }
1334
+ function sessionNamespace(projectId, sessionId) {
1335
+ if (!projectId || !sessionId) throw new Error("projectId and sessionId are required");
1336
+ return `session:${projectId}:${sessionId}`;
1337
+ }
1338
+ function defaultRecallNamespaces(projectId) {
1339
+ return [projectNamespace(projectId), GLOBAL_NAMESPACE];
1340
+ }
1341
+
1342
+ // src/harness/HarnessMemory.ts
1343
+ var MAX_TAGS = 8;
1344
+ var TAG_PROMPT = 'You tag memories so they can be found later by keyword search. Return 3-5 lowercase, single-word topic tags as a JSON array of strings, and nothing else. Include broader category words a person might search for, not only words already in the text. Example: for "This project uses Hono" return ["framework", "backend", "web", "server", "hono"].';
1345
+ var HarnessMemory = class {
1346
+ storage;
1347
+ llm;
1348
+ retriever;
1349
+ autoTags;
1350
+ tagTimeoutMs;
1351
+ maxContentChars;
1352
+ onError;
1353
+ initialized;
1354
+ constructor(config) {
1355
+ this.storage = config.storage;
1356
+ this.llm = config.llm;
1357
+ this.retriever = new LexicalRetriever(config.storage, { candidateLimit: config.candidateLimit });
1358
+ this.autoTags = config.autoTags ?? true;
1359
+ this.tagTimeoutMs = config.tagTimeoutMs ?? 1e4;
1360
+ this.maxContentChars = config.maxContentChars ?? 8e3;
1361
+ this.onError = config.onError;
1362
+ }
1363
+ async remember(input) {
1364
+ const content = input.content.trim();
1365
+ if (!content) throw validationError("Memory content is empty");
1366
+ if (content.length > this.maxContentChars) {
1367
+ throw validationError(`Memory content is longer than ${this.maxContentChars} characters`, {
1368
+ length: content.length
1369
+ });
1370
+ }
1371
+ if (!input.namespace) throw validationError("Namespace is required");
1372
+ if (input.importance !== void 0 && !(input.importance >= 0 && input.importance <= 1)) {
1373
+ throw validationError("Importance must be between 0 and 1", { importance: input.importance });
1374
+ }
1375
+ await this.ensureInit();
1376
+ const llmTags = this.autoTags ? await this.suggestTags(content) : [];
1377
+ const tags = [...new Set([...input.tags ?? [], ...llmTags].map((t) => t.toLowerCase().trim()).filter(Boolean))];
1378
+ return this.storage.store({
1379
+ actorId: input.namespace,
1380
+ content,
1381
+ memoryType: input.kind ?? "observation",
1382
+ importance: input.importance ?? 0.5,
1383
+ tags: tags.slice(0, MAX_TAGS),
1384
+ metadata: { source: input.source }
1385
+ });
1386
+ }
1387
+ async recall(input) {
1388
+ await this.ensureInit();
1389
+ return this.retriever.recall({
1390
+ actorIds: input.namespaces,
1391
+ query: input.query,
1392
+ memoryTypes: input.kinds,
1393
+ limit: input.limit,
1394
+ maxChars: input.maxChars
1395
+ });
1396
+ }
1397
+ /** The memory with this ID, or null when it does not exist or is outside `namespaces`. */
1398
+ async get(id, namespaces) {
1399
+ await this.ensureInit();
1400
+ const memory = await this.storage.get(id);
1401
+ return memory && namespaces.includes(memory.actorId) ? memory : null;
1402
+ }
1403
+ /** Delete a memory. Memories outside `namespaces` are reported as not found. */
1404
+ async forget(id, namespaces) {
1405
+ const memory = await this.get(id, namespaces);
1406
+ if (!memory) throw notFound("Memory", id);
1407
+ await this.storage.delete(id);
1408
+ }
1409
+ /** Number of memories in each namespace. */
1410
+ async stats(namespaces) {
1411
+ await this.ensureInit();
1412
+ const counts = {};
1413
+ for (const namespace of new Set(namespaces)) {
1414
+ counts[namespace] = await this.storage.count({ actorId: namespace });
1415
+ }
1416
+ return counts;
1417
+ }
1418
+ /**
1419
+ * Moves every memory from one namespace to another, keeping content,
1420
+ * kind, importance, tags, provenance, and creation time. Memories get new
1421
+ * IDs. Used when a project's ID changes, e.g. after its first commit.
1422
+ * Safe to run from two processes at once: a copy whose original was
1423
+ * already moved by the other process is removed again.
1424
+ */
1425
+ async moveNamespace(from, to) {
1426
+ if (!from || !to) throw validationError("Both namespaces are required");
1427
+ if (from === to) return 0;
1428
+ await this.ensureInit();
1429
+ let moved = 0;
1430
+ for (; ; ) {
1431
+ const batch = await this.storage.retrieve({ actorId: from, limit: 500, strategy: "recent", touch: false });
1432
+ if (batch.length === 0) return moved;
1433
+ let progressed = false;
1434
+ for (const memory of batch) {
1435
+ const copy = await this.storage.store({
1436
+ actorId: to,
1437
+ content: memory.content,
1438
+ memoryType: memory.memoryType,
1439
+ importance: memory.importance,
1440
+ emotionalValence: memory.emotionalValence,
1441
+ tags: memory.tags,
1442
+ metadata: memory.metadata,
1443
+ createdAt: memory.createdAt,
1444
+ expiresAt: memory.expiresAt
1445
+ });
1446
+ try {
1447
+ await this.storage.delete(memory.id);
1448
+ moved++;
1449
+ progressed = true;
1450
+ } catch (error) {
1451
+ await this.storage.delete(copy.id);
1452
+ if (!(error instanceof MemStackError && error.code === "NOT_FOUND")) throw error;
1453
+ }
1454
+ }
1455
+ if (!progressed) return moved;
1047
1456
  }
1048
- return text.split(",").map((t) => t.replace(/[\[\]"]/g, "").trim().toLowerCase()).filter((t) => t.length > 0).slice(0, 5);
1049
1457
  }
1050
- /** Strip markdown code fences and extract the JSON payload from LLM output. */
1051
- _extractJson(text) {
1052
- let cleaned = text.trim();
1053
- const fenceMatch = cleaned.match(/```(?:json)?\s*([\s\S]*?)```/);
1054
- if (fenceMatch) cleaned = fenceMatch[1].trim();
1055
- return cleaned;
1458
+ /**
1459
+ * Adopts memories a project stored under IDs it had before, such as
1460
+ * before its first commit. Costs one count per previous ID when there is
1461
+ * nothing to move. Returns the number of memories moved.
1462
+ */
1463
+ async adoptProjects(previousIds, projectId) {
1464
+ const target = projectNamespace(projectId);
1465
+ let moved = 0;
1466
+ for (const id of new Set(previousIds)) {
1467
+ const from = projectNamespace(id);
1468
+ if (from === target) continue;
1469
+ await this.ensureInit();
1470
+ if (await this.storage.count({ actorId: from }) === 0) continue;
1471
+ moved += await this.moveNamespace(from, target);
1472
+ }
1473
+ return moved;
1474
+ }
1475
+ ensureInit() {
1476
+ this.initialized ??= this.storage.initialize().catch((error) => {
1477
+ this.initialized = void 0;
1478
+ throw error;
1479
+ });
1480
+ return this.initialized;
1481
+ }
1482
+ async suggestTags(content) {
1483
+ let timer;
1484
+ try {
1485
+ const timeout = new Promise((_, reject) => {
1486
+ timer = setTimeout(() => reject(new Error(`Tagging timed out after ${this.tagTimeoutMs} ms`)), this.tagTimeoutMs);
1487
+ });
1488
+ const result = await Promise.race([
1489
+ this.llm.complete({ system: TAG_PROMPT, user: content, maxTokens: ENRICHMENT_MAX_TOKENS, temperature: 0 }),
1490
+ timeout
1491
+ ]);
1492
+ if (!result.text.trim()) throw new Error("Tagging returned an empty reply");
1493
+ return parseTags(result.text).filter((t) => /^[\p{L}\p{N}-]+$/u.test(t));
1494
+ } catch (error) {
1495
+ this.onError?.(error instanceof Error ? error : new Error(String(error)), "harness-tagging");
1496
+ return [];
1497
+ } finally {
1498
+ clearTimeout(timer);
1499
+ }
1056
1500
  }
1057
1501
  };
1058
1502
  var DiskStorageAdapter = class {
1503
+ capabilities = { multiProcess: false };
1059
1504
  dir;
1060
1505
  _writeLocks = /* @__PURE__ */ new Map();
1061
1506
  _idIndex = /* @__PURE__ */ new Map();
@@ -1246,26 +1691,28 @@ var DiskStorageAdapter = class {
1246
1691
  );
1247
1692
  break;
1248
1693
  }
1249
- const nowStr = (/* @__PURE__ */ new Date()).toISOString();
1250
- const toTouch = results.slice(0, query.limit ?? 10);
1251
- const touchedActors = /* @__PURE__ */ new Set();
1252
- for (const r of toTouch) {
1253
- r._touchedAt = nowStr;
1254
- touchedActors.add(r.actorId);
1255
- }
1256
- for (const actorId of touchedActors) {
1257
- await this._withWriteLock(actorId, async () => {
1258
- const records = await this._readFile(actorId);
1259
- let changed = false;
1260
- for (const r of records) {
1261
- const touched = toTouch.find((t) => t.id === r.id);
1262
- if (touched) {
1263
- r._touchedAt = nowStr;
1264
- changed = true;
1694
+ if (query.touch !== false) {
1695
+ const nowStr = (/* @__PURE__ */ new Date()).toISOString();
1696
+ const toTouch = results.slice(0, query.limit ?? 10);
1697
+ const touchedActors = /* @__PURE__ */ new Set();
1698
+ for (const r of toTouch) {
1699
+ r._touchedAt = nowStr;
1700
+ touchedActors.add(r.actorId);
1701
+ }
1702
+ for (const actorId of touchedActors) {
1703
+ await this._withWriteLock(actorId, async () => {
1704
+ const records = await this._readFile(actorId);
1705
+ let changed = false;
1706
+ for (const r of records) {
1707
+ const touched = toTouch.find((t) => t.id === r.id);
1708
+ if (touched) {
1709
+ r._touchedAt = nowStr;
1710
+ changed = true;
1711
+ }
1265
1712
  }
1266
- }
1267
- if (changed) await this._writeFile(actorId, records);
1268
- });
1713
+ if (changed) await this._writeFile(actorId, records);
1714
+ });
1715
+ }
1269
1716
  }
1270
1717
  const limit = query.limit ?? 10;
1271
1718
  return results.slice(0, limit).map((r) => this._toExternal(r));
@@ -1416,6 +1863,7 @@ var DiskStorageAdapter = class {
1416
1863
  }
1417
1864
  };
1418
1865
  var MarkdownStorageAdapter = class {
1866
+ capabilities = { multiProcess: false };
1419
1867
  dir;
1420
1868
  oneFilePerActor;
1421
1869
  _cache = null;
@@ -1932,6 +2380,7 @@ var HybridStorageAdapter = class {
1932
2380
 
1933
2381
  // src/adapters/storage/postgres.ts
1934
2382
  var PostgresStorageAdapter = class {
2383
+ capabilities = { multiProcess: true };
1935
2384
  pool;
1936
2385
  table;
1937
2386
  vectorDimensions;
@@ -1967,7 +2416,8 @@ var PostgresStorageAdapter = class {
1967
2416
  const connStr = this._connectionString ?? this._buildConnString();
1968
2417
  try {
1969
2418
  const { default: createPostgres } = await import('postgres');
1970
- const options = {};
2419
+ const options = { onnotice: () => {
2420
+ } };
1971
2421
  if (this._ssl) {
1972
2422
  options.ssl = typeof this._ssl === "object" ? this._ssl : "require";
1973
2423
  }
@@ -2000,35 +2450,50 @@ var PostgresStorageAdapter = class {
2000
2450
  }
2001
2451
  return connStr;
2002
2452
  }
2453
+ // One DO block, so it runs in a single transaction on one connection: the
2454
+ // advisory lock makes processes that start together (Claude Code and Codex)
2455
+ // migrate one at a time instead of racing on CREATE ... IF NOT EXISTS,
2456
+ // which Postgres reports as a duplicate key in pg_type.
2003
2457
  async _runMigration() {
2004
- try {
2005
- await this.pool.query("CREATE EXTENSION IF NOT EXISTS vector");
2006
- } catch {
2007
- }
2008
2458
  await this.pool.query(`
2009
- CREATE TABLE IF NOT EXISTS ${this.table} (
2010
- id TEXT PRIMARY KEY,
2011
- actor_id TEXT NOT NULL,
2012
- memory_type TEXT NOT NULL DEFAULT 'interaction',
2013
- content TEXT NOT NULL,
2014
- importance REAL NOT NULL DEFAULT 0.5,
2015
- emotional_valence REAL NOT NULL DEFAULT 0,
2016
- tags JSONB NOT NULL DEFAULT '[]',
2017
- embedding vector(${this.vectorDimensions}),
2018
- source_id TEXT,
2019
- metadata JSONB NOT NULL DEFAULT '{}',
2020
- expires_at TIMESTAMPTZ,
2021
- created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
2022
- touched_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
2023
- )
2459
+ DO $memstack$
2460
+ BEGIN
2461
+ PERFORM pg_advisory_xact_lock(hashtext('memstack:migrate:${this.table}'));
2462
+ BEGIN
2463
+ CREATE EXTENSION IF NOT EXISTS vector;
2464
+ EXCEPTION WHEN OTHERS THEN
2465
+ NULL; -- pgvector may not be available
2466
+ END;
2467
+ CREATE TABLE IF NOT EXISTS ${this.table} (
2468
+ id TEXT PRIMARY KEY,
2469
+ actor_id TEXT NOT NULL,
2470
+ memory_type TEXT NOT NULL DEFAULT 'interaction',
2471
+ content TEXT NOT NULL,
2472
+ importance REAL NOT NULL DEFAULT 0.5,
2473
+ emotional_valence REAL NOT NULL DEFAULT 0,
2474
+ tags JSONB NOT NULL DEFAULT '[]',
2475
+ embedding vector(${this.vectorDimensions}),
2476
+ source_id TEXT,
2477
+ metadata JSONB NOT NULL DEFAULT '{}',
2478
+ expires_at TIMESTAMPTZ,
2479
+ created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
2480
+ touched_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
2481
+ );
2482
+ BEGIN
2483
+ CREATE INDEX IF NOT EXISTS idx_${this.table}_actor ON ${this.table} (actor_id);
2484
+ CREATE INDEX IF NOT EXISTS idx_${this.table}_created ON ${this.table} (created_at DESC);
2485
+ CREATE INDEX IF NOT EXISTS idx_${this.table}_importance ON ${this.table} (importance DESC);
2486
+ EXCEPTION WHEN OTHERS THEN
2487
+ NULL; -- index creation may fail; non-critical
2488
+ END;
2489
+ BEGIN
2490
+ CREATE INDEX IF NOT EXISTS idx_${this.table}_embedding ON ${this.table} USING hnsw (embedding vector_cosine_ops) WITH (m = 16, ef_construction = 64);
2491
+ EXCEPTION WHEN OTHERS THEN
2492
+ NULL; -- index creation may fail; non-critical
2493
+ END;
2494
+ END
2495
+ $memstack$
2024
2496
  `);
2025
- try {
2026
- await this.pool.query(`CREATE INDEX IF NOT EXISTS idx_${this.table}_actor ON ${this.table} (actor_id)`);
2027
- await this.pool.query(`CREATE INDEX IF NOT EXISTS idx_${this.table}_created ON ${this.table} (created_at DESC)`);
2028
- await this.pool.query(`CREATE INDEX IF NOT EXISTS idx_${this.table}_importance ON ${this.table} (importance DESC)`);
2029
- await this.pool.query(`CREATE INDEX IF NOT EXISTS idx_${this.table}_embedding ON ${this.table} USING hnsw (embedding vector_cosine_ops) WITH (m = 16, ef_construction = 64)`);
2030
- } catch {
2031
- }
2032
2497
  }
2033
2498
  generateId() {
2034
2499
  return `mem_${Date.now().toString(36)}_${crypto.randomUUID().slice(0, 8)}`;
@@ -2163,9 +2628,11 @@ var PostgresStorageAdapter = class {
2163
2628
  const sql = `SELECT * FROM ${this.table} ${where} ORDER BY ${orderBy} LIMIT $${paramIdx}`;
2164
2629
  params.push(limit);
2165
2630
  const { rows } = await this.pool.query(sql, params);
2166
- for (const row of rows.slice(0, limit)) {
2167
- const r = row;
2168
- await this.pool.query(`UPDATE ${this.table} SET touched_at = NOW() WHERE id = $1`, [r.id]);
2631
+ if (query.touch !== false) {
2632
+ for (const row of rows.slice(0, limit)) {
2633
+ const r = row;
2634
+ await this.pool.query(`UPDATE ${this.table} SET touched_at = NOW() WHERE id = $1`, [r.id]);
2635
+ }
2169
2636
  }
2170
2637
  return rows.map((r) => this._rowToMemory(r));
2171
2638
  }
@@ -2229,9 +2696,11 @@ var PostgresStorageAdapter = class {
2229
2696
  params.push(embedding);
2230
2697
  params.push(limit);
2231
2698
  const { rows } = await this.pool.query(sql, params);
2232
- for (const row of rows.slice(0, limit)) {
2233
- const r = row;
2234
- await this.pool.query(`UPDATE ${this.table} SET touched_at = NOW() WHERE id = $1`, [r.id]);
2699
+ if (query.touch !== false) {
2700
+ for (const row of rows.slice(0, limit)) {
2701
+ const r = row;
2702
+ await this.pool.query(`UPDATE ${this.table} SET touched_at = NOW() WHERE id = $1`, [r.id]);
2703
+ }
2235
2704
  }
2236
2705
  return rows.map((r) => this._rowToMemory(r));
2237
2706
  }
@@ -2255,6 +2724,7 @@ var PostgresStorageAdapter = class {
2255
2724
 
2256
2725
  // src/adapters/storage/redis.ts
2257
2726
  var RedisStorageAdapter = class {
2727
+ capabilities = { multiProcess: true };
2258
2728
  redis;
2259
2729
  prefix;
2260
2730
  constructor(config) {
@@ -2392,11 +2862,13 @@ var RedisStorageAdapter = class {
2392
2862
  );
2393
2863
  break;
2394
2864
  }
2395
- const nowStr = (/* @__PURE__ */ new Date()).toISOString();
2396
- const toTouch = results.slice(0, query.limit ?? 10);
2397
- for (const r of toTouch) {
2398
- r._touchedAt = nowStr;
2399
- await this.redis.set(this._memKey(r.id), JSON.stringify(r));
2865
+ if (query.touch !== false) {
2866
+ const nowStr = (/* @__PURE__ */ new Date()).toISOString();
2867
+ const toTouch = results.slice(0, query.limit ?? 10);
2868
+ for (const r of toTouch) {
2869
+ r._touchedAt = nowStr;
2870
+ await this.redis.set(this._memKey(r.id), JSON.stringify(r));
2871
+ }
2400
2872
  }
2401
2873
  const limit = query.limit ?? 10;
2402
2874
  return results.slice(0, limit).map((r) => this._toExternal(r));
@@ -3330,6 +3802,7 @@ var LanceDBStorageAdapter = class {
3330
3802
 
3331
3803
  // src/adapters/storage/mongodb.ts
3332
3804
  var MongoDBStorageAdapter = class {
3805
+ capabilities = { multiProcess: true };
3333
3806
  collection;
3334
3807
  vectorDimensions;
3335
3808
  constructor(config) {
@@ -3378,7 +3851,16 @@ var MongoDBStorageAdapter = class {
3378
3851
  expiresAt: input.expiresAt,
3379
3852
  createdAt: input.createdAt ?? now
3380
3853
  };
3381
- await this.collection.insertOne(this.toDoc(memory));
3854
+ if (input.id) {
3855
+ const { _id, actorId, memoryType, createdAt, ...fields } = this.toDoc(memory);
3856
+ await this.collection.updateOne(
3857
+ { _id },
3858
+ { $set: fields, $setOnInsert: { actorId, memoryType, createdAt } },
3859
+ { upsert: true }
3860
+ );
3861
+ } else {
3862
+ await this.collection.insertOne(this.toDoc(memory));
3863
+ }
3382
3864
  return memory;
3383
3865
  }
3384
3866
  async storeBatch(inputs) {
@@ -3508,6 +3990,33 @@ var MongoDBStorageAdapter = class {
3508
3990
  };
3509
3991
 
3510
3992
  // src/adapters/storage/sqlite.ts
3993
+ var MIGRATIONS_TABLE = "memstack_schema_migrations";
3994
+ var MIGRATIONS = [
3995
+ {
3996
+ version: 1,
3997
+ sql: (t) => `
3998
+ CREATE TABLE IF NOT EXISTS ${t} (
3999
+ id TEXT PRIMARY KEY,
4000
+ actor_id TEXT NOT NULL,
4001
+ memory_type TEXT NOT NULL DEFAULT 'interaction',
4002
+ content TEXT NOT NULL,
4003
+ importance REAL NOT NULL DEFAULT 0.5,
4004
+ emotional_valence REAL NOT NULL DEFAULT 0,
4005
+ tags TEXT NOT NULL DEFAULT '[]',
4006
+ embedding TEXT,
4007
+ source_id TEXT,
4008
+ metadata TEXT NOT NULL DEFAULT '{}',
4009
+ expires_at TEXT,
4010
+ created_at TEXT NOT NULL,
4011
+ touched_at TEXT NOT NULL
4012
+ );
4013
+ CREATE INDEX IF NOT EXISTS idx_${t}_actor ON ${t}(actor_id);
4014
+ CREATE INDEX IF NOT EXISTS idx_${t}_created ON ${t}(created_at DESC);
4015
+ CREATE INDEX IF NOT EXISTS idx_${t}_importance ON ${t}(importance DESC);
4016
+ `
4017
+ }
4018
+ ];
4019
+ MIGRATIONS[MIGRATIONS.length - 1].version;
3511
4020
  function cosineSimilarity(a, b) {
3512
4021
  if (a.length === 0 || b.length === 0) return 0;
3513
4022
  const dims = Math.min(a.length, b.length);
@@ -3523,9 +4032,12 @@ function cosineSimilarity(a, b) {
3523
4032
  return mag === 0 ? 0 : dot / mag;
3524
4033
  }
3525
4034
  var SQLiteStorageAdapter = class {
4035
+ capabilities = { multiProcess: true };
3526
4036
  db;
3527
4037
  table;
3528
4038
  vectorDimensions;
4039
+ busyTimeoutMs;
4040
+ walMode;
3529
4041
  constructor(config) {
3530
4042
  if (!config.db) {
3531
4043
  throw configError("SQLiteStorageAdapter requires a better-sqlite3 database instance");
@@ -3536,33 +4048,67 @@ var SQLiteStorageAdapter = class {
3536
4048
  throw configError(`Invalid table name: "${this.table}". Use only alphanumeric characters and underscores.`);
3537
4049
  }
3538
4050
  this.vectorDimensions = config.vectorDimensions ?? 1536;
4051
+ this.busyTimeoutMs = config.busyTimeoutMs ?? 5e3;
4052
+ if (!Number.isInteger(this.busyTimeoutMs) || this.busyTimeoutMs < 0) {
4053
+ throw configError(`Invalid busyTimeoutMs: ${config.busyTimeoutMs}. Use a non-negative integer.`);
4054
+ }
4055
+ this.walMode = config.walMode ?? true;
3539
4056
  }
3540
4057
  async initialize() {
3541
- this.db.exec(`
3542
- CREATE TABLE IF NOT EXISTS ${this.table} (
3543
- id TEXT PRIMARY KEY,
3544
- actor_id TEXT NOT NULL,
3545
- memory_type TEXT NOT NULL DEFAULT 'interaction',
3546
- content TEXT NOT NULL,
3547
- importance REAL NOT NULL DEFAULT 0.5,
3548
- emotional_valence REAL NOT NULL DEFAULT 0,
3549
- tags TEXT NOT NULL DEFAULT '[]',
3550
- embedding TEXT,
3551
- source_id TEXT,
3552
- metadata TEXT NOT NULL DEFAULT '{}',
3553
- expires_at TEXT,
3554
- created_at TEXT NOT NULL,
3555
- touched_at TEXT NOT NULL
3556
- )
3557
- `);
3558
- this.db.exec(`CREATE INDEX IF NOT EXISTS idx_${this.table}_actor ON ${this.table}(actor_id)`);
3559
- this.db.exec(`CREATE INDEX IF NOT EXISTS idx_${this.table}_created ON ${this.table}(created_at DESC)`);
3560
- this.db.exec(`CREATE INDEX IF NOT EXISTS idx_${this.table}_importance ON ${this.table}(importance DESC)`);
4058
+ this.db.exec(`PRAGMA busy_timeout = ${this.busyTimeoutMs}`);
4059
+ if (this.walMode) this.db.exec("PRAGMA journal_mode = WAL");
4060
+ this.migrate();
4061
+ }
4062
+ /** Schema version applied to this adapter's table, 0 if none. */
4063
+ schemaVersion() {
4064
+ const row = this.db.prepare(
4065
+ `SELECT version FROM ${MIGRATIONS_TABLE} WHERE table_name = ?`
4066
+ ).get(this.table);
4067
+ return row?.version ?? 0;
4068
+ }
4069
+ // Versions are tracked per table rather than with PRAGMA user_version,
4070
+ // so adapters with different table names can share one database file.
4071
+ migrate() {
4072
+ for (const migration of MIGRATIONS) {
4073
+ this.transaction(() => {
4074
+ this.db.exec(
4075
+ `CREATE TABLE IF NOT EXISTS ${MIGRATIONS_TABLE} (table_name TEXT PRIMARY KEY, version INTEGER NOT NULL)`
4076
+ );
4077
+ if (this.schemaVersion() >= migration.version) return;
4078
+ this.db.exec(migration.sql(this.table));
4079
+ this.db.prepare(
4080
+ `INSERT INTO ${MIGRATIONS_TABLE} (table_name, version) VALUES (?, ?)
4081
+ ON CONFLICT(table_name) DO UPDATE SET version = excluded.version`
4082
+ ).run(this.table, migration.version);
4083
+ });
4084
+ }
4085
+ }
4086
+ // BEGIN IMMEDIATE takes the write lock up front, so a concurrent writer
4087
+ // waits on busy_timeout instead of failing when it upgrades a read lock.
4088
+ transaction(fn) {
4089
+ if (this.db.inTransaction) return fn();
4090
+ this.db.exec("BEGIN IMMEDIATE");
4091
+ try {
4092
+ const result = fn();
4093
+ this.db.exec("COMMIT");
4094
+ return result;
4095
+ } catch (error) {
4096
+ if (this.db.inTransaction !== false) {
4097
+ try {
4098
+ this.db.exec("ROLLBACK");
4099
+ } catch {
4100
+ }
4101
+ }
4102
+ throw error;
4103
+ }
3561
4104
  }
3562
4105
  generateId() {
3563
4106
  return `mem_${Date.now().toString(36)}_${crypto.randomUUID().slice(0, 8)}`;
3564
4107
  }
3565
4108
  async store(input) {
4109
+ return this.insert(input);
4110
+ }
4111
+ insert(input) {
3566
4112
  const now = (/* @__PURE__ */ new Date()).toISOString();
3567
4113
  const id = input.id ?? this.generateId();
3568
4114
  this.db.prepare(
@@ -3609,11 +4155,7 @@ var SQLiteStorageAdapter = class {
3609
4155
  };
3610
4156
  }
3611
4157
  async storeBatch(inputs) {
3612
- const results = [];
3613
- for (const input of inputs) {
3614
- results.push(await this.store(input));
3615
- }
3616
- return results;
4158
+ return this.transaction(() => inputs.map((input) => this.insert(input)));
3617
4159
  }
3618
4160
  async get(id) {
3619
4161
  const row = this.db.prepare(
@@ -3659,7 +4201,6 @@ var SQLiteStorageAdapter = class {
3659
4201
  conditions.push("created_at <= ?");
3660
4202
  params.push(query.createdBefore.toISOString());
3661
4203
  }
3662
- const where = `WHERE ${conditions.join(" AND ")}`;
3663
4204
  const hasSemantic = (query.strategy === "semantic" || query.strategy === "hybrid") && embedding && embedding.length > 0;
3664
4205
  let orderBy;
3665
4206
  switch (query.strategy) {
@@ -3680,9 +4221,8 @@ var SQLiteStorageAdapter = class {
3680
4221
  break;
3681
4222
  }
3682
4223
  const limit = query.limit ?? 10;
3683
- const sql = `SELECT * FROM ${this.table} ${where} ORDER BY ${orderBy}`;
3684
- const rows = this.db.prepare(sql).all(...params);
3685
- let results = rows;
4224
+ const sql = `SELECT * FROM ${this.table} WHERE ${conditions.join(" AND ")} ORDER BY ${orderBy}`;
4225
+ let results = this.db.prepare(sql).all(...params);
3686
4226
  if (query.query) {
3687
4227
  const q = query.query.toLowerCase();
3688
4228
  results = results.filter((r) => r.content.toLowerCase().includes(q));
@@ -3702,17 +4242,12 @@ var SQLiteStorageAdapter = class {
3702
4242
  if (query.strategy === "hybrid") {
3703
4243
  scored.sort((a, b) => b.score + b.row.importance - (a.score + a.row.importance));
3704
4244
  }
3705
- const topK = scored.slice(0, limit);
3706
- for (const { row } of topK) {
3707
- this.db.prepare(`UPDATE ${this.table} SET touched_at = ? WHERE id = ?`).run((/* @__PURE__ */ new Date()).toISOString(), row.id);
3708
- }
3709
- return topK.map(({ row }) => this._rowToMemory(row));
4245
+ const topK = scored.slice(0, limit).map(({ row }) => row);
4246
+ this.touchRows(topK, query.touch);
4247
+ return topK.map((row) => this._rowToMemory(row));
3710
4248
  }
3711
- const now = (/* @__PURE__ */ new Date()).toISOString();
3712
4249
  const limited = results.slice(0, limit);
3713
- for (const row of limited) {
3714
- this.db.prepare(`UPDATE ${this.table} SET touched_at = ? WHERE id = ?`).run(now, row.id);
3715
- }
4250
+ this.touchRows(limited, query.touch);
3716
4251
  return limited.map((r) => this._rowToMemory(r));
3717
4252
  }
3718
4253
  async count(filter) {
@@ -3747,6 +4282,14 @@ var SQLiteStorageAdapter = class {
3747
4282
  async close() {
3748
4283
  this.db.close();
3749
4284
  }
4285
+ touchRows(rows, touch) {
4286
+ if (touch === false || rows.length === 0) return;
4287
+ const now = (/* @__PURE__ */ new Date()).toISOString();
4288
+ const stmt = this.db.prepare(`UPDATE ${this.table} SET touched_at = ? WHERE id = ?`);
4289
+ this.transaction(() => {
4290
+ for (const row of rows) stmt.run(now, row.id);
4291
+ });
4292
+ }
3750
4293
  _rowToMemory(row) {
3751
4294
  return {
3752
4295
  id: row.id,
@@ -4252,6 +4795,6 @@ var GroqLLMAdapter = class {
4252
4795
  }
4253
4796
  };
4254
4797
 
4255
- export { AnthropicLLMAdapter, CohereEmbeddingAdapter, DiskStorageAdapter, GroqLLMAdapter, HybridStorageAdapter, InMemoryStorageAdapter, LanceDBStorageAdapter, MarkdownStorageAdapter, MemStack, MemStackError, MongoDBStorageAdapter, Neo4jStorageAdapter, OllamaLLMAdapter, OpenAIEmbeddingAdapter, OpenAILLMAdapter, PostgresStorageAdapter, QdrantStorageAdapter, RedisStorageAdapter, SQLiteStorageAdapter, WeaviateStorageAdapter, configError, notFound, storageError, validationError };
4798
+ export { AnthropicLLMAdapter, CohereEmbeddingAdapter, DiskStorageAdapter, GLOBAL_NAMESPACE, GroqLLMAdapter, HarnessMemory, HybridStorageAdapter, InMemoryStorageAdapter, LanceDBStorageAdapter, LexicalRetriever, MarkdownStorageAdapter, MemStack, MemStackError, MongoDBStorageAdapter, Neo4jStorageAdapter, OllamaLLMAdapter, OpenAIEmbeddingAdapter, OpenAILLMAdapter, PostgresStorageAdapter, QdrantStorageAdapter, RedisStorageAdapter, SQLiteStorageAdapter, WeaviateStorageAdapter, configError, defaultRecallNamespaces, notFound, projectNamespace, sessionNamespace, storageError, validationError };
4256
4799
  //# sourceMappingURL=index.js.map
4257
4800
  //# sourceMappingURL=index.js.map