@theokit/sdk-memory 0.3.3 → 0.4.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/CHANGELOG.md CHANGED
@@ -1,5 +1,28 @@
1
1
  # Changelog — @theokit/sdk-memory
2
2
 
3
+ ## 0.4.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 4aa19d1: Installing this package no longer makes the memory store unreadable.
8
+
9
+ `Memory.runDreamingSweep` in `@theokit/sdk` replaces its own store with this package's whenever this
10
+ package is installed. This package carried a full copy, and the copy stayed on the layout that
11
+ predates the file-per-memory format — so it could not read anything the SDK had written. The sweep
12
+ reported `factsBefore: 0`, a number indistinguishable from an empty store (#430). Nothing threw.
13
+
14
+ The store is now imported from `@theokit/sdk/internal/memory-store` rather than copied, which is why
15
+ the `@theokit/sdk` peer floor rises to `>=4.60.0`: that is the version the sub-path first ships in,
16
+ and importing a path an admitted version does not export is a load-time crash, not a type error.
17
+
18
+ The exported signatures are supersets of what this package exposed before — the added parameters are
19
+ optional — so existing calls are unaffected. What changes is that `appendFactToMarkdown` now writes a
20
+ file per memory with `MEMORY.md` as its index, instead of a bullet under `## Facts`. Bullets written
21
+ by earlier versions are still read.
22
+
23
+ The promise this broke — _"the fallback is not a degraded mode"_ — now has a test. It had none, which
24
+ is why the two copies drifted for two format changes without anything going red.
25
+
3
26
  ## 0.3.3
4
27
 
5
28
  ### Patch Changes
package/dist/index.cjs CHANGED
@@ -4,10 +4,11 @@ var promises = require('fs/promises');
4
4
  var path = require('path');
5
5
  var sdk = require('@theokit/sdk');
6
6
  var persistence = require('@theokit/sdk/persistence');
7
- var pathSafety = require('@theokit/sdk/path-safety');
7
+ var memoryStore = require('@theokit/sdk/internal/memory-store');
8
8
  var crypto = require('crypto');
9
9
  var memoryAdapters = require('@theokit/sdk/internal/memory-adapters');
10
10
  var errors = require('@theokit/sdk/errors');
11
+ var pathSafety = require('@theokit/sdk/path-safety');
11
12
  var fs = require('fs');
12
13
  var module$1 = require('module');
13
14
 
@@ -240,114 +241,20 @@ function createInMemoryMarkdownProvider() {
240
241
  }
241
242
  };
242
243
  }
243
- function redactSecrets(text, opts) {
244
- return sdk.Security.redact(text, opts);
245
- }
246
- function legacyMemoryJsonPath(cwd, config) {
247
- if (config.storePath !== void 0) {
248
- return path.resolve(cwd, config.storePath);
249
- }
250
- const namespace = pathSafety.sanitizeIdentifier(config.namespace ?? "default");
251
- const scope = pathSafety.sanitizeIdentifier(config.scope ?? "agent", { maxLen: 16 });
252
- const userId = pathSafety.sanitizeIdentifier(config.userId ?? "default");
253
- return pathSafety.safePathJoin(cwd, ".theokit", "memory", namespace, `${scope}-${userId}.json`);
254
- }
255
-
256
- // src/internal/store/markdown-store.ts
257
- var MEMORY_MD_HEADER = "# Memory\n\n> Auto-managed by @theokit/sdk. Edit freely \u2014 the SDK reads from here.\n";
258
- var FACTS_HEADING = "## Facts";
259
- function memoryDir(cwd) {
260
- return path.join(cwd, ".theokit", "memory");
261
- }
262
- function memoryMdPath(cwd) {
263
- return path.join(memoryDir(cwd), "MEMORY.md");
264
- }
265
- function notesDir(cwd) {
266
- return path.join(memoryDir(cwd), "notes");
267
- }
268
- async function readFactsFromMarkdown(cwd) {
269
- let raw;
270
- try {
271
- raw = await promises.readFile(memoryMdPath(cwd), "utf8");
272
- } catch {
273
- return [];
274
- }
275
- return parseFactsSection(raw);
276
- }
277
- function appendFactToMarkdown(cwd, fact) {
278
- return persistence.withCwdMutex(memoryDir(cwd), async () => {
279
- const path = memoryMdPath(cwd);
280
- let raw = "";
281
- try {
282
- raw = await promises.readFile(path, "utf8");
283
- } catch {
284
- raw = "";
285
- }
286
- const sanitized = redactSecrets(fact.text);
287
- const next = insertFactBullet(raw, sanitized);
288
- await promises.mkdir(memoryDir(cwd), { recursive: true });
289
- await persistence.replaceFileAtomic(path, next);
290
- });
291
- }
292
244
  async function listNotes(cwd) {
293
245
  let entries = [];
294
246
  try {
295
- entries = await promises.readdir(notesDir(cwd));
247
+ entries = await promises.readdir(memoryStore.notesDir(cwd));
296
248
  } catch {
297
249
  return [];
298
250
  }
299
- return entries.filter((name) => name.endsWith(".md")).map((name) => ({ slug: name.replace(/\.md$/, ""), path: path.join(notesDir(cwd), name) }));
300
- }
301
- function parseFactsSection(raw) {
302
- const idx = raw.indexOf(FACTS_HEADING);
303
- if (idx === -1) return [];
304
- const tail = raw.slice(idx + FACTS_HEADING.length);
305
- const nextHeading = tail.search(/\n#{1,2}\s/);
306
- const block = nextHeading === -1 ? tail : tail.slice(0, nextHeading);
307
- return block.split("\n").map((line) => line.trim()).filter((line) => line.startsWith("- ")).map((line) => ({ text: line.slice(2).trim() }));
308
- }
309
- function insertFactBullet(raw, fact) {
310
- const bullet = `- ${fact}`;
311
- if (raw.length === 0) {
312
- return `${MEMORY_MD_HEADER}
313
- ${FACTS_HEADING}
314
-
315
- ${bullet}
316
- `;
317
- }
318
- const idx = raw.indexOf(FACTS_HEADING);
319
- if (idx === -1) {
320
- const sep = raw.endsWith("\n") ? "" : "\n";
321
- return `${raw}${sep}
322
- ${FACTS_HEADING}
323
-
324
- ${bullet}
325
- `;
326
- }
327
- const after = idx + FACTS_HEADING.length;
328
- const nextHeading = raw.slice(after).search(/\n#{1,2}\s/);
329
- if (nextHeading === -1) {
330
- const trailing = raw.endsWith("\n") ? "" : "\n";
331
- return `${raw}${trailing}${bullet}
332
- `;
333
- }
334
- const insertAt = after + nextHeading;
335
- return `${raw.slice(0, insertAt)}
336
- ${bullet}${raw.slice(insertAt)}`;
337
- }
338
- async function readFacts(cwd, config) {
339
- if (!config.enabled) return [];
340
- return readFactsFromMarkdown(cwd);
341
- }
342
- async function appendFact(cwd, config, fact) {
343
- if (!config.enabled) return;
344
- await appendFactToMarkdown(cwd, fact);
251
+ return entries.filter((name) => name.endsWith(".md")).map((name) => ({ slug: name.replace(/\.md$/, ""), path: path.join(memoryStore.notesDir(cwd), name) }));
345
252
  }
346
253
 
347
254
  // src/internal/store/transcript-store.ts
348
255
  async function persistActiveMemoryTranscript(cwd, transcript) {
349
256
  try {
350
- const dir = path.join(memoryDir(cwd), "transcripts", "active-memory");
257
+ const dir = path.join(memoryStore.memoryDir(cwd), "transcripts", "active-memory");
351
258
  const file = path.join(dir, `${transcript.runId}.json`);
352
259
  await persistence.atomicWriteJson(file, transcript);
353
260
  } catch (cause) {
@@ -951,6 +858,20 @@ var MEMORY_EMBEDDING_ADAPTERS = {
951
858
  jina: jinaMemoryEmbeddingProviderAdapter,
952
859
  gemini: geminiMemoryEmbeddingProviderAdapter
953
860
  };
861
+ function redactSecrets(text, opts) {
862
+ return sdk.Security.redact(text, opts);
863
+ }
864
+ function legacyMemoryJsonPath(cwd, config) {
865
+ if (config.storePath !== void 0) {
866
+ return path.resolve(cwd, config.storePath);
867
+ }
868
+ const namespace = pathSafety.sanitizeIdentifier(config.namespace ?? "default");
869
+ const scope = pathSafety.sanitizeIdentifier(config.scope ?? "agent", { maxLen: 16 });
870
+ const userId = pathSafety.sanitizeIdentifier(config.userId ?? "default");
871
+ return pathSafety.safePathJoin(cwd, ".theokit", "memory", namespace, `${scope}-${userId}.json`);
872
+ }
873
+
874
+ // src/internal/adapter-http-error.ts
954
875
  var RAW_MAX_BYTES = 2048;
955
876
  function parseRetryAfter(headers) {
956
877
  if (headers === void 0) return void 0;
@@ -1039,7 +960,7 @@ function mapOpenAiStatusToCode(status, body) {
1039
960
  function formatMessage(providerId, status, code) {
1040
961
  return `${providerId} API error: ${code} (HTTP ${status})`;
1041
962
  }
1042
- var FACTS_HEADING2 = "## Facts";
963
+ var FACTS_HEADING = "## Facts";
1043
964
  function createCategorizedMemory(options) {
1044
965
  const { root, categories } = options;
1045
966
  validateCategories(categories);
@@ -1113,7 +1034,7 @@ function header(category) {
1113
1034
  category: ${category}
1114
1035
  ---
1115
1036
 
1116
- ${FACTS_HEADING2}
1037
+ ${FACTS_HEADING}
1117
1038
  `;
1118
1039
  }
1119
1040
  async function readFileOrEmpty(path) {
@@ -1137,24 +1058,24 @@ function decodeFact(text) {
1137
1058
  );
1138
1059
  }
1139
1060
  function parseFactBullets(raw) {
1140
- const idx = raw.indexOf(FACTS_HEADING2);
1061
+ const idx = raw.indexOf(FACTS_HEADING);
1141
1062
  if (idx === -1) return [];
1142
- const tail = raw.slice(idx + FACTS_HEADING2.length);
1063
+ const tail = raw.slice(idx + FACTS_HEADING.length);
1143
1064
  const nextHeading = tail.search(/\n#{1,2}\s/);
1144
1065
  const block = nextHeading === -1 ? tail : tail.slice(0, nextHeading);
1145
1066
  return block.split("\n").map((line) => line.trim()).filter((line) => line.startsWith("- ")).map((line) => line.slice(2).trim());
1146
1067
  }
1147
1068
  function appendBullet(raw, text) {
1148
1069
  const bullet = `- ${text}`;
1149
- const idx = raw.indexOf(FACTS_HEADING2);
1070
+ const idx = raw.indexOf(FACTS_HEADING);
1150
1071
  if (idx === -1) {
1151
1072
  const sep = raw.endsWith("\n") ? "" : "\n";
1152
- return `${raw}${sep}${FACTS_HEADING2}
1073
+ return `${raw}${sep}${FACTS_HEADING}
1153
1074
 
1154
1075
  ${bullet}
1155
1076
  `;
1156
1077
  }
1157
- const after = idx + FACTS_HEADING2.length;
1078
+ const after = idx + FACTS_HEADING.length;
1158
1079
  const nextHeading = raw.slice(after).search(/\n#{1,2}\s/);
1159
1080
  if (nextHeading === -1) {
1160
1081
  const trailing = raw.endsWith("\n") ? "" : "\n";
@@ -1166,7 +1087,7 @@ ${bullet}
1166
1087
  ${bullet}${raw.slice(insertAt)}`;
1167
1088
  }
1168
1089
  function diaryPath(cwd) {
1169
- return path.join(memoryDir(cwd), "dream-diary.md");
1090
+ return path.join(memoryStore.memoryDir(cwd), "dream-diary.md");
1170
1091
  }
1171
1092
  function renderDiaryEntry(entry) {
1172
1093
  const stamp = new Date(entry.timestampMs).toISOString();
@@ -1311,7 +1232,7 @@ async function runInner(options) {
1311
1232
  const now = options.now ?? Date.now;
1312
1233
  const timestampMs = now();
1313
1234
  try {
1314
- const facts = await readFactsFromMarkdown(options.cwd);
1235
+ const facts = await memoryStore.readFactsFromMarkdown(options.cwd);
1315
1236
  if (facts.length === 0) {
1316
1237
  return emptyResult("skipped");
1317
1238
  }
@@ -1345,10 +1266,10 @@ async function runInner(options) {
1345
1266
  }
1346
1267
  async function writeConsolidatedNotes(cwd, clusters, timestampMs) {
1347
1268
  if (clusters.length === 0) return 0;
1348
- const notesDir2 = path.join(memoryDir(cwd), "notes");
1349
- await promises.mkdir(notesDir2, { recursive: true });
1269
+ const notesDir3 = path.join(memoryStore.memoryDir(cwd), "notes");
1270
+ await promises.mkdir(notesDir3, { recursive: true });
1350
1271
  const isoSlug = new Date(timestampMs).toISOString().replace(/[^\dT]/g, "-");
1351
- const file = path.join(notesDir2, `dreamed-${isoSlug}.md`);
1272
+ const file = path.join(notesDir3, `dreamed-${isoSlug}.md`);
1352
1273
  const body = deepPhase(clusters, timestampMs);
1353
1274
  await persistence.replaceFileAtomic(file, body);
1354
1275
  return 1;
@@ -1498,7 +1419,7 @@ function findWordBoundarySplit(text, maxChars) {
1498
1419
  }
1499
1420
  var MAX_TURN_CHARS = 2e3;
1500
1421
  function sessionsDir(cwd) {
1501
- return path.join(memoryDir(cwd), "sessions");
1422
+ return path.join(memoryStore.memoryDir(cwd), "sessions");
1502
1423
  }
1503
1424
  function sessionSummaryPath(cwd, runId) {
1504
1425
  return path.join(sessionsDir(cwd), `${sanitizeRunId2(runId)}.md`);
@@ -1545,7 +1466,7 @@ async function discoverSessionFiles(cwd) {
1545
1466
  } catch {
1546
1467
  return [];
1547
1468
  }
1548
- const root = memoryDir(cwd);
1469
+ const root = memoryStore.memoryDir(cwd);
1549
1470
  return entries.filter((entry) => entry.endsWith(".md")).map((entry) => {
1550
1471
  const absolutePath = path.join(sessionsDir(cwd), entry);
1551
1472
  return {
@@ -1559,7 +1480,7 @@ function relativeToRoot(root, absolutePath) {
1559
1480
  return absolutePath;
1560
1481
  }
1561
1482
  function wikiDir(cwd) {
1562
- return path.join(memoryDir(cwd), "wiki");
1483
+ return path.join(memoryStore.memoryDir(cwd), "wiki");
1563
1484
  }
1564
1485
  async function discoverWikiFiles(cwd) {
1565
1486
  let entries;
@@ -1568,7 +1489,7 @@ async function discoverWikiFiles(cwd) {
1568
1489
  } catch {
1569
1490
  return [];
1570
1491
  }
1571
- const root = memoryDir(cwd);
1492
+ const root = memoryStore.memoryDir(cwd);
1572
1493
  return entries.filter((entry) => entry.endsWith(".md")).map((entry) => ({
1573
1494
  absolutePath: path.join(wikiDir(cwd), entry),
1574
1495
  relPath: path.join("wiki", entry)
@@ -2146,22 +2067,22 @@ function blendScores(hit, vectorScore, weights) {
2146
2067
  };
2147
2068
  }
2148
2069
  async function collectMarkdownFiles(cwd) {
2149
- const root = memoryDir(cwd);
2070
+ const root = memoryStore.memoryDir(cwd);
2150
2071
  const results = [];
2151
2072
  try {
2152
- await promises.stat(memoryMdPath(cwd));
2073
+ await promises.stat(memoryStore.memoryMdPath(cwd));
2153
2074
  results.push({
2154
- absolutePath: memoryMdPath(cwd),
2155
- relPath: path.relative(root, memoryMdPath(cwd)),
2075
+ absolutePath: memoryStore.memoryMdPath(cwd),
2076
+ relPath: path.relative(root, memoryStore.memoryMdPath(cwd)),
2156
2077
  source: "memory"
2157
2078
  });
2158
2079
  } catch {
2159
2080
  }
2160
2081
  try {
2161
- const entries = await promises.readdir(notesDir(cwd));
2082
+ const entries = await promises.readdir(memoryStore.notesDir(cwd));
2162
2083
  for (const entry of entries) {
2163
2084
  if (!entry.endsWith(".md")) continue;
2164
- const abs = path.join(notesDir(cwd), entry);
2085
+ const abs = path.join(memoryStore.notesDir(cwd), entry);
2165
2086
  results.push({ absolutePath: abs, relPath: path.relative(root, abs), source: "memory" });
2166
2087
  }
2167
2088
  } catch {
@@ -2349,7 +2270,7 @@ async function readLegacyFacts(jsonPath) {
2349
2270
  }
2350
2271
  async function writeMigratedFacts(cwd, jsonPath, facts) {
2351
2272
  try {
2352
- for (const fact of facts) await appendFactToMarkdown(cwd, fact);
2273
+ for (const fact of facts) await memoryStore.appendFactToMarkdown(cwd, fact);
2353
2274
  await promises.unlink(jsonPath).catch(() => void 0);
2354
2275
  process.stderr.write(
2355
2276
  `[theokit-sdk] migrated ${facts.length} fact(s) from ${jsonPath} to MEMORY.md
@@ -2372,7 +2293,7 @@ async function migrateLegacyJson(cwd, config) {
2372
2293
  if (!await fileExists(jsonPath)) {
2373
2294
  return { migrated: false, factCount: 0, reason: "no-legacy-json" };
2374
2295
  }
2375
- if (await fileExists(memoryMdPath(cwd))) {
2296
+ if (await fileExists(memoryStore.memoryMdPath(cwd))) {
2376
2297
  process.stderr.write(
2377
2298
  `[theokit-sdk] memory migration skipped: both MEMORY.md and legacy JSON exist at ${jsonPath}; leaving both intact
2378
2299
  `
@@ -2458,7 +2379,7 @@ function createMemorySearchTool(opts) {
2458
2379
  };
2459
2380
  }
2460
2381
  function createMemoryGetTool(opts) {
2461
- const memoryRoot = path.resolve(memoryDir(opts.cwd));
2382
+ const memoryRoot = path.resolve(memoryStore.memoryDir(opts.cwd));
2462
2383
  return {
2463
2384
  name: "memory_get",
2464
2385
  description: GET_DESCRIPTION,
@@ -2527,6 +2448,42 @@ function isPathInside(root, candidate) {
2527
2448
  return candidate === root || candidate.startsWith(normalizedRoot);
2528
2449
  }
2529
2450
 
2451
+ Object.defineProperty(exports, "appendFact", {
2452
+ enumerable: true,
2453
+ get: function () { return memoryStore.appendFact; }
2454
+ });
2455
+ Object.defineProperty(exports, "appendFactToMarkdown", {
2456
+ enumerable: true,
2457
+ get: function () { return memoryStore.appendFactToMarkdown; }
2458
+ });
2459
+ Object.defineProperty(exports, "claudeProjectMemoryDir", {
2460
+ enumerable: true,
2461
+ get: function () { return memoryStore.claudeProjectMemoryDir; }
2462
+ });
2463
+ Object.defineProperty(exports, "memoryDir", {
2464
+ enumerable: true,
2465
+ get: function () { return memoryStore.memoryDir; }
2466
+ });
2467
+ Object.defineProperty(exports, "memoryMdPath", {
2468
+ enumerable: true,
2469
+ get: function () { return memoryStore.memoryMdPath; }
2470
+ });
2471
+ Object.defineProperty(exports, "memoryWriteDir", {
2472
+ enumerable: true,
2473
+ get: function () { return memoryStore.memoryWriteDir; }
2474
+ });
2475
+ Object.defineProperty(exports, "notesDir", {
2476
+ enumerable: true,
2477
+ get: function () { return memoryStore.notesDir; }
2478
+ });
2479
+ Object.defineProperty(exports, "readFacts", {
2480
+ enumerable: true,
2481
+ get: function () { return memoryStore.readFacts; }
2482
+ });
2483
+ Object.defineProperty(exports, "readFactsFromMarkdown", {
2484
+ enumerable: true,
2485
+ get: function () { return memoryStore.readFactsFromMarkdown; }
2486
+ });
2530
2487
  Object.defineProperty(exports, "createOpenAiCompatibleRuntime", {
2531
2488
  enumerable: true,
2532
2489
  get: function () { return memoryAdapters.createOpenAiCompatibleRuntime; }
@@ -2555,8 +2512,6 @@ exports.PRAGMA_STATEMENTS = PRAGMA_STATEMENTS;
2555
2512
  exports.SCHEMA_STATEMENTS = SCHEMA_STATEMENTS;
2556
2513
  exports.VALID_BACKENDS = VALID_BACKENDS;
2557
2514
  exports.appendDiaryEntry = appendDiaryEntry;
2558
- exports.appendFact = appendFact;
2559
- exports.appendFactToMarkdown = appendFactToMarkdown;
2560
2515
  exports.assertValidBackend = assertValidBackend;
2561
2516
  exports.azureOpenAiMemoryEmbeddingProviderAdapter = azureOpenAiMemoryEmbeddingProviderAdapter;
2562
2517
  exports.buildErrorMetadata = buildErrorMetadata;
@@ -2587,12 +2542,9 @@ exports.lightPhase = lightPhase;
2587
2542
  exports.listNotes = listNotes;
2588
2543
  exports.loadSqliteVecExtension = loadSqliteVecExtension;
2589
2544
  exports.mapOpenAICompatibleError = mapOpenAICompatibleError;
2590
- exports.memoryDir = memoryDir;
2591
- exports.memoryMdPath = memoryMdPath;
2592
2545
  exports.migrateLegacyJson = migrateLegacyJson;
2593
2546
  exports.migrateSqliteToLance = migrateSqliteToLance;
2594
2547
  exports.mistralMemoryEmbeddingProviderAdapter = mistralMemoryEmbeddingProviderAdapter;
2595
- exports.notesDir = notesDir;
2596
2548
  exports.ollamaMemoryEmbeddingProviderAdapter = ollamaMemoryEmbeddingProviderAdapter;
2597
2549
  exports.openAiMemoryEmbeddingProviderAdapter = openAiMemoryEmbeddingProviderAdapter;
2598
2550
  exports.openLanceIndex = openLanceIndex;
@@ -2603,8 +2555,6 @@ exports.parseRetryAfter = parseRetryAfter;
2603
2555
  exports.parseSearchOptions = parseSearchOptions;
2604
2556
  exports.persistActiveMemoryTranscript = persistActiveMemoryTranscript;
2605
2557
  exports.readEmbeddingIdentity = readEmbeddingIdentity;
2606
- exports.readFacts = readFacts;
2607
- exports.readFactsFromMarkdown = readFactsFromMarkdown;
2608
2558
  exports.readMemoryFileBounded = readMemoryFileBounded;
2609
2559
  exports.redactSecrets = redactSecrets;
2610
2560
  exports.remPhase = remPhase;