@anuma/sdk 6.33.2 → 6.35.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.
@@ -1389,6 +1389,9 @@ __export(index_exports, {
1389
1389
  LoggerProvider: () => LoggerProvider,
1390
1390
  MAX_HOPS: () => MAX_HOPS,
1391
1391
  MEDIUM_TTL_MS: () => MEDIUM_TTL_MS,
1392
+ MEMORY_KINDS: () => MEMORY_KINDS,
1393
+ MEMORY_LEVELS: () => MEMORY_LEVELS,
1394
+ MemoryLevelError: () => MemoryLevelError,
1392
1395
  NEVER_TTL_MS: () => NEVER_TTL_MS,
1393
1396
  NODE_BUDGET: () => NODE_BUDGET,
1394
1397
  NOTION_OAUTH_CONFIG: () => NOTION_OAUTH_CONFIG,
@@ -1399,6 +1402,7 @@ __export(index_exports, {
1399
1402
  QueueManager: () => QueueManager,
1400
1403
  RECALL_MAX_LIMIT: () => RECALL_MAX_LIMIT,
1401
1404
  RECALL_TOOL_NAME: () => RECALL_TOOL_NAME,
1405
+ RemoteMemoryError: () => RemoteMemoryError,
1402
1406
  RerankerUnavailableError: () => RerankerUnavailableError,
1403
1407
  SDK_SCHEMA_VERSION: () => SDK_SCHEMA_VERSION,
1404
1408
  SHORT_TTL_MS: () => SHORT_TTL_MS,
@@ -1462,6 +1466,8 @@ __export(index_exports, {
1462
1466
  createNotionTools: () => createNotionTools,
1463
1467
  createPlatformCursorStore: () => createPlatformCursorStore,
1464
1468
  createRecallTool: () => createRecallTool,
1469
+ createRemoteMemoryPersistence: () => createRemoteMemoryPersistence,
1470
+ createRemoteMemoryPipeline: () => createRemoteMemoryPipeline,
1465
1471
  createStockPricePreProcessor: () => createStockPricePreProcessor,
1466
1472
  createStreamingDeAnonymizer: () => createStreamingDeAnonymizer,
1467
1473
  createVaultEmbeddingCache: () => createVaultEmbeddingCache,
@@ -4177,13 +4183,13 @@ async function searchChunksOp(ctx, queryVector, options) {
4177
4183
  const storedById = new Map(
4178
4184
  await Promise.all(
4179
4185
  Array.from(uniqueMessages, async ([id, m]) => {
4180
- const stored = await messageRawToStored(
4186
+ const stored2 = await messageRawToStored(
4181
4187
  m,
4182
4188
  ctx.walletAddress,
4183
4189
  ctx.signMessage,
4184
4190
  ctx.embeddedWalletSigner
4185
4191
  );
4186
- return [id, stored];
4192
+ return [id, stored2];
4187
4193
  })
4188
4194
  )
4189
4195
  );
@@ -4201,18 +4207,18 @@ async function searchChunksOp(ctx, queryVector, options) {
4201
4207
  })
4202
4208
  );
4203
4209
  return topK.map(({ message, similarity, chunkTextSource }) => {
4204
- const stored = { ...storedById.get(message.id) };
4210
+ const stored2 = { ...storedById.get(message.id) };
4205
4211
  let chunkText2;
4206
4212
  if (chunkTextSource.kind === "chunk") {
4207
- chunkText2 = resolveChunkText(stored.content, chunkTextSource.chunk, chunkTextSource.siblings);
4213
+ chunkText2 = resolveChunkText(stored2.content, chunkTextSource.chunk, chunkTextSource.siblings);
4208
4214
  } else if (chunkTextSource.kind === "chunk-cached") {
4209
4215
  const state = chunkStateByMsgId.get(message.id);
4210
4216
  const chunk = state && state.version === chunkTextSource.version ? state.chunks[chunkTextSource.chunkIndex] : void 0;
4211
- chunkText2 = resolveChunkText(stored.content, chunk, state?.chunks);
4217
+ chunkText2 = resolveChunkText(stored2.content, chunk, state?.chunks);
4212
4218
  } else {
4213
- chunkText2 = stored.content;
4219
+ chunkText2 = stored2.content;
4214
4220
  }
4215
- return { chunkText: chunkText2, message: stored, similarity };
4221
+ return { chunkText: chunkText2, message: stored2, similarity };
4216
4222
  });
4217
4223
  }
4218
4224
  function makeSyntheticStoredMessage(opts) {
@@ -5336,7 +5342,7 @@ async function embedOne(text12, options, outer) {
5336
5342
  }
5337
5343
  var DEFAULT_EMBEDDING_BATCH_SIZE = 100;
5338
5344
  var DEFAULT_EMBEDDING_BATCH_CONCURRENCY = 3;
5339
- async function generateEmbeddingsBatch(texts, headers, baseUrl, model, onUsage, maskInput, timeoutMs) {
5345
+ async function generateEmbeddingsBatch(texts, headers, baseUrl, model, onUsage, maskInput, timeoutMs, outer) {
5340
5346
  const response = await withEmbeddingRetry(
5341
5347
  () => withDeadline(
5342
5348
  (signal) => postApiV1Embeddings({
@@ -5346,8 +5352,10 @@ async function generateEmbeddingsBatch(texts, headers, baseUrl, model, onUsage,
5346
5352
  ...signal && { signal }
5347
5353
  }),
5348
5354
  timeoutMs,
5349
- "embedding batch request"
5350
- )
5355
+ "embedding batch request",
5356
+ outer
5357
+ ),
5358
+ outer
5351
5359
  );
5352
5360
  if (response.error) {
5353
5361
  throw embeddingErrorFrom(response);
@@ -5365,6 +5373,11 @@ async function generateEmbeddingsBatch(texts, headers, baseUrl, model, onUsage,
5365
5373
  }
5366
5374
  async function generateEmbeddings(texts, options) {
5367
5375
  if (texts.length === 0) return [];
5376
+ const total = options.totalTimeoutMs;
5377
+ if (total === void 0) return embedMany(texts, options, void 0);
5378
+ return withDeadline((signal) => embedMany(texts, options, signal), total, "embedding batch");
5379
+ }
5380
+ async function embedMany(texts, options, outer) {
5368
5381
  const { baseUrl = BASE_URL, model, batchSize, cache } = options;
5369
5382
  const timeoutMs = options.timeoutMs ?? DEFAULT_EMBEDDING_REQUEST_TIMEOUT_MS;
5370
5383
  const chunkSize = batchSize ?? DEFAULT_EMBEDDING_BATCH_SIZE;
@@ -5385,7 +5398,8 @@ async function generateEmbeddings(texts, options) {
5385
5398
  if (uncachedTexts.length === 0) {
5386
5399
  return results;
5387
5400
  }
5388
- const headers = await resolveAuthHeaders(options);
5401
+ const headers = await resolveAuthHeaders(options, outer);
5402
+ if (outer?.aborted) throw outer.reason;
5389
5403
  const embeddingModel = model ?? DEFAULT_API_EMBEDDING_MODEL;
5390
5404
  let newEmbeddings;
5391
5405
  if (uncachedTexts.length <= chunkSize) {
@@ -5396,7 +5410,8 @@ async function generateEmbeddings(texts, options) {
5396
5410
  embeddingModel,
5397
5411
  options.onUsage,
5398
5412
  options.maskInput,
5399
- timeoutMs
5413
+ timeoutMs,
5414
+ outer
5400
5415
  );
5401
5416
  } else {
5402
5417
  const chunks = [];
@@ -5407,6 +5422,7 @@ async function generateEmbeddings(texts, options) {
5407
5422
  let nextIndex = 0;
5408
5423
  const worker = async () => {
5409
5424
  while (nextIndex < chunks.length) {
5425
+ if (outer?.aborted) throw outer.reason;
5410
5426
  const idx = nextIndex++;
5411
5427
  allEmbeddings[idx] = await generateEmbeddingsBatch(
5412
5428
  chunks[idx],
@@ -5415,7 +5431,8 @@ async function generateEmbeddings(texts, options) {
5415
5431
  embeddingModel,
5416
5432
  options.onUsage,
5417
5433
  options.maskInput,
5418
- timeoutMs
5434
+ timeoutMs,
5435
+ outer
5419
5436
  );
5420
5437
  }
5421
5438
  };
@@ -5426,6 +5443,7 @@ async function generateEmbeddings(texts, options) {
5426
5443
  await Promise.all(workers);
5427
5444
  newEmbeddings = allEmbeddings.flat();
5428
5445
  }
5446
+ if (outer?.aborted) throw outer.reason;
5429
5447
  for (let i = 0; i < uncachedIndices.length; i++) {
5430
5448
  const f32Embedding = Float32Array.from(newEmbeddings[i]);
5431
5449
  results[uncachedIndices[i]] = Array.from(f32Embedding);
@@ -10514,15 +10532,15 @@ function createSummaryContext(database) {
10514
10532
  summariesCollection: database.get("conversation_summaries")
10515
10533
  };
10516
10534
  }
10517
- function modelToStored(record) {
10535
+ function modelToStored(record2) {
10518
10536
  return {
10519
- uniqueId: record.id,
10520
- conversationId: record.conversationId,
10521
- summary: record.summary,
10522
- summarizedUpTo: record.summarizedUpTo,
10523
- tokenCount: record.tokenCount,
10524
- createdAt: record.createdAt,
10525
- updatedAt: record.updatedAt
10537
+ uniqueId: record2.id,
10538
+ conversationId: record2.conversationId,
10539
+ summary: record2.summary,
10540
+ summarizedUpTo: record2.summarizedUpTo,
10541
+ tokenCount: record2.tokenCount,
10542
+ createdAt: record2.createdAt,
10543
+ updatedAt: record2.updatedAt
10526
10544
  };
10527
10545
  }
10528
10546
  async function getConversationSummaryOp(ctx, conversationId) {
@@ -10531,17 +10549,17 @@ async function getConversationSummaryOp(ctx, conversationId) {
10531
10549
  return modelToStored(results[0]);
10532
10550
  }
10533
10551
  async function upsertConversationSummaryOp(ctx, conversationId, summary, summarizedUpTo, tokenCount) {
10534
- let record;
10552
+ let record2;
10535
10553
  await ctx.database.write(async () => {
10536
10554
  const existing = await ctx.summariesCollection.query(import_watermelondb5.Q.where("conversation_id", conversationId)).fetch();
10537
10555
  if (existing.length > 0) {
10538
- record = await existing[0].update((rec) => {
10556
+ record2 = await existing[0].update((rec) => {
10539
10557
  rec.summary = summary;
10540
10558
  rec.summarizedUpTo = summarizedUpTo;
10541
10559
  rec.tokenCount = tokenCount;
10542
10560
  });
10543
10561
  } else {
10544
- record = await ctx.summariesCollection.create((rec) => {
10562
+ record2 = await ctx.summariesCollection.create((rec) => {
10545
10563
  rec.conversationId = conversationId;
10546
10564
  rec.summary = summary;
10547
10565
  rec.summarizedUpTo = summarizedUpTo;
@@ -10549,13 +10567,13 @@ async function upsertConversationSummaryOp(ctx, conversationId, summary, summari
10549
10567
  });
10550
10568
  }
10551
10569
  });
10552
- return modelToStored(record);
10570
+ return modelToStored(record2);
10553
10571
  }
10554
10572
  async function deleteConversationSummaryOp(ctx, conversationId) {
10555
10573
  await ctx.database.write(async () => {
10556
10574
  const existing = await ctx.summariesCollection.query(import_watermelondb5.Q.where("conversation_id", conversationId)).fetch();
10557
- for (const record of existing) {
10558
- await record.destroyPermanently();
10575
+ for (const record2 of existing) {
10576
+ await record2.destroyPermanently();
10559
10577
  }
10560
10578
  });
10561
10579
  }
@@ -10803,6 +10821,15 @@ __decorateClass([
10803
10821
  __decorateClass([
10804
10822
  (0, import_decorators6.text)("scope")
10805
10823
  ], VaultMemory.prototype, "scope", 2);
10824
+ __decorateClass([
10825
+ (0, import_decorators6.field)("kind")
10826
+ ], VaultMemory.prototype, "kind", 2);
10827
+ __decorateClass([
10828
+ (0, import_decorators6.field)("kind_value")
10829
+ ], VaultMemory.prototype, "kindValue", 2);
10830
+ __decorateClass([
10831
+ (0, import_decorators6.field)("level")
10832
+ ], VaultMemory.prototype, "level", 2);
10806
10833
  __decorateClass([
10807
10834
  (0, import_decorators6.field)("folder_id")
10808
10835
  ], VaultMemory.prototype, "folderId", 2);
@@ -11028,7 +11055,7 @@ __decorateClass([
11028
11055
  ], VaultFolder.prototype, "context", 2);
11029
11056
 
11030
11057
  // src/lib/db/schema.ts
11031
- var SDK_SCHEMA_VERSION = 47;
11058
+ var SDK_SCHEMA_VERSION = 48;
11032
11059
  var sdkSchema = (0, import_watermelondb17.appSchema)({
11033
11060
  version: SDK_SCHEMA_VERSION,
11034
11061
  tables: [
@@ -11123,6 +11150,9 @@ var sdkSchema = (0, import_watermelondb17.appSchema)({
11123
11150
  columns: [
11124
11151
  { name: "content", type: "string" },
11125
11152
  { name: "scope", type: "string", isIndexed: true },
11153
+ { name: "kind", type: "string", isOptional: true, isIndexed: true },
11154
+ { name: "kind_value", type: "string", isOptional: true },
11155
+ { name: "level", type: "string", isOptional: true, isIndexed: true },
11126
11156
  { name: "folder_id", type: "string", isOptional: true, isIndexed: true },
11127
11157
  { name: "created_at", type: "number", isIndexed: true },
11128
11158
  { name: "updated_at", type: "number", isIndexed: true },
@@ -11799,6 +11829,22 @@ var sdkMigrations = (0, import_migrations2.schemaMigrations)({
11799
11829
  ]
11800
11830
  })
11801
11831
  ]
11832
+ },
11833
+ {
11834
+ toVersion: 48,
11835
+ steps: [
11836
+ (0, import_migrations2.addColumns)({
11837
+ table: "memory_vault",
11838
+ columns: [
11839
+ { name: "kind", type: "string", isOptional: true, isIndexed: true },
11840
+ { name: "kind_value", type: "string", isOptional: true },
11841
+ { name: "level", type: "string", isOptional: true, isIndexed: true }
11842
+ ]
11843
+ }),
11844
+ (0, import_migrations2.unsafeExecuteSql)(
11845
+ "UPDATE memory_vault SET level = CASE WHEN scope IN ('shared', 'public') THEN 'matching' ELSE 'private' END WHERE level IS NULL;"
11846
+ )
11847
+ ]
11802
11848
  }
11803
11849
  ]
11804
11850
  });
@@ -12056,25 +12102,25 @@ async function upsertEntitiesInWrite(ctx, entities) {
12056
12102
  const kindBackfills = existing.filter((e) => {
12057
12103
  const incoming = kindByName.get(e.canonicalName);
12058
12104
  return incoming !== void 0 && (e.kind === null || e.kind === void 0 || e.kind === "");
12059
- }).map((record) => ({ record, kind: kindByName.get(record.canonicalName) }));
12105
+ }).map((record2) => ({ record: record2, kind: kindByName.get(record2.canonicalName) }));
12060
12106
  const missing = unique.filter((n) => !existingNames.has(n));
12061
12107
  const created = missing.map(
12062
- (name) => ctx.entityCollection.prepareCreate((record) => {
12063
- record._setRaw("canonical_name", name);
12108
+ (name) => ctx.entityCollection.prepareCreate((record2) => {
12109
+ record2._setRaw("canonical_name", name);
12064
12110
  const kind = kindByName.get(name);
12065
- if (kind !== void 0) record._setRaw("kind", kind);
12111
+ if (kind !== void 0) record2._setRaw("kind", kind);
12066
12112
  })
12067
12113
  );
12068
12114
  for (const e of existing) out.set(e.canonicalName, entityToStored(e));
12069
- for (const record of created) out.set(record.canonicalName, entityToStored(record));
12070
- for (const { record, kind } of kindBackfills) {
12071
- out.set(record.canonicalName, { ...entityToStored(record), kind });
12115
+ for (const record2 of created) out.set(record2.canonicalName, entityToStored(record2));
12116
+ for (const { record: record2, kind } of kindBackfills) {
12117
+ out.set(record2.canonicalName, { ...entityToStored(record2), kind });
12072
12118
  }
12073
12119
  return { entities: out, operations: created, kindBackfills };
12074
12120
  }
12075
12121
  function prepareKindBackfills(backfills) {
12076
12122
  return backfills.map(
12077
- ({ record, kind }) => record.prepareUpdate((r) => {
12123
+ ({ record: record2, kind }) => record2.prepareUpdate((r) => {
12078
12124
  r._setRaw("kind", kind);
12079
12125
  })
12080
12126
  );
@@ -12105,10 +12151,10 @@ function displayNamesOf(entities) {
12105
12151
  }
12106
12152
  return out;
12107
12153
  }
12108
- function topicsEqual(stored, computed) {
12109
- if (stored === null || stored.length !== computed.length) return false;
12154
+ function topicsEqual(stored2, computed) {
12155
+ if (stored2 === null || stored2.length !== computed.length) return false;
12110
12156
  const key = (t) => JSON.stringify([t.name, t.kind ?? null, t.source]);
12111
- const storedKeys = stored.map(key).sort();
12157
+ const storedKeys = stored2.map(key).sort();
12112
12158
  const computedKeys = computed.map(key).sort();
12113
12159
  return storedKeys.every((k, i) => k === computedKeys[i]);
12114
12160
  }
@@ -12174,10 +12220,10 @@ async function linkMemoryEntitiesOp(ctx, memoryId, entityInputs, options) {
12174
12220
  return;
12175
12221
  }
12176
12222
  const linkOps = toCreate.map(
12177
- (e) => ctx.memoryEntityCollection.prepareCreate((record) => {
12178
- record._setRaw("memory_id", memoryId);
12179
- record._setRaw("entity_id", e.uniqueId);
12180
- if (userId !== void 0) record._setRaw("user_id", userId);
12223
+ (e) => ctx.memoryEntityCollection.prepareCreate((record2) => {
12224
+ record2._setRaw("memory_id", memoryId);
12225
+ record2._setRaw("entity_id", e.uniqueId);
12226
+ if (userId !== void 0) record2._setRaw("user_id", userId);
12181
12227
  })
12182
12228
  );
12183
12229
  await ctx.database.batch(
@@ -12245,10 +12291,10 @@ async function replaceMemoryEntities(ctx, memoryId, entityInputs, options) {
12245
12291
  ...entityOps,
12246
12292
  ...prepareKindBackfills(kindBackfills),
12247
12293
  ...toCreate.map(
12248
- (e) => ctx.memoryEntityCollection.prepareCreate((record) => {
12249
- record._setRaw("memory_id", memoryId);
12250
- record._setRaw("entity_id", e.uniqueId);
12251
- if (userId !== void 0) record._setRaw("user_id", userId);
12294
+ (e) => ctx.memoryEntityCollection.prepareCreate((record2) => {
12295
+ record2._setRaw("memory_id", memoryId);
12296
+ record2._setRaw("entity_id", e.uniqueId);
12297
+ if (userId !== void 0) record2._setRaw("user_id", userId);
12252
12298
  })
12253
12299
  ),
12254
12300
  ...toDestroy.map((l) => l.prepareDestroyPermanently()),
@@ -12366,13 +12412,54 @@ async function decryptVaultMemoryFields(memory, address, signMessage, embeddedWa
12366
12412
  }
12367
12413
  }
12368
12414
  const decryptedContent = await decryptField(memory.content, address);
12415
+ const decryptedKindValue = typeof memory.kindValue === "string" ? await decryptField(memory.kindValue, address) : memory.kindValue;
12369
12416
  return {
12370
12417
  ...memory,
12371
- content: decryptedContent
12418
+ content: decryptedContent,
12419
+ ...decryptedKindValue !== void 0 && { kindValue: decryptedKindValue }
12372
12420
  };
12373
12421
  }
12374
12422
 
12375
12423
  // src/lib/db/memoryVault/types.ts
12424
+ var MEMORY_KINDS = [
12425
+ "display_name",
12426
+ "birth_date",
12427
+ "bio",
12428
+ "occupation",
12429
+ "interest",
12430
+ "gender",
12431
+ "height_cm",
12432
+ "looking_for",
12433
+ "politics",
12434
+ "religion",
12435
+ "ethnicity",
12436
+ "smoking",
12437
+ "drinking",
12438
+ "exercise",
12439
+ "sexuality",
12440
+ "prompt"
12441
+ ];
12442
+ var MEMORY_LEVELS = ["private", "matching", "profile"];
12443
+ var MemoryLevelError = class extends Error {
12444
+ constructor(message) {
12445
+ super(message);
12446
+ this.name = "MemoryLevelError";
12447
+ }
12448
+ };
12449
+ var PUBLISHED_SCOPES = /* @__PURE__ */ new Set(["shared", "public"]);
12450
+ function levelFromScope(scope) {
12451
+ return typeof scope === "string" && PUBLISHED_SCOPES.has(scope) ? "matching" : "private";
12452
+ }
12453
+ function scopeForLevel(level) {
12454
+ return level === "private" ? "private" : "shared";
12455
+ }
12456
+ function resolveMemoryLevel(level, scope) {
12457
+ return typeof level === "string" && MEMORY_LEVELS.includes(level) ? level : levelFromScope(scope);
12458
+ }
12459
+ function levelForScopeChange(current, nextScope) {
12460
+ const implied = levelFromScope(nextScope);
12461
+ return implied === "matching" && resolveMemoryLevel(current.level, current.scope) === "profile" ? "profile" : implied;
12462
+ }
12376
12463
  function parseMedia(value) {
12377
12464
  if (typeof value !== "string" || value === "") return null;
12378
12465
  try {
@@ -12402,8 +12489,58 @@ function visibilityConditions(requested) {
12402
12489
  if (excluded.length === 0) return [];
12403
12490
  return [import_watermelondb20.Q.or(import_watermelondb20.Q.where("visibility", null), import_watermelondb20.Q.where("visibility", import_watermelondb20.Q.notIn(excluded)))];
12404
12491
  }
12405
- function isOwnedByCtxUser(ctx, record) {
12406
- return ctx.userId === void 0 || record.userId === ctx.userId;
12492
+ function isKinded(record2) {
12493
+ return record2.kind !== null && record2.kind !== void 0;
12494
+ }
12495
+ function assertValidKindLevel(kind, level) {
12496
+ const hasKind = kind !== null && kind !== void 0;
12497
+ if (hasKind && !MEMORY_KINDS.includes(kind)) {
12498
+ throw new MemoryLevelError(`Unknown memory kind: ${kind}`);
12499
+ }
12500
+ if (level !== void 0 && !MEMORY_LEVELS.includes(level)) {
12501
+ throw new MemoryLevelError(`Unknown memory level: ${level}`);
12502
+ }
12503
+ if (level === "profile" && !hasKind) {
12504
+ throw new MemoryLevelError("Only a memory with a kind can be at level 'profile'");
12505
+ }
12506
+ }
12507
+ function resolveCreateLevel(opts) {
12508
+ if (opts.level !== void 0) return { level: opts.level, scope: scopeForLevel(opts.level) };
12509
+ if (opts.scope !== void 0) return { level: levelFromScope(opts.scope), scope: opts.scope };
12510
+ return { level: "private", scope: "private" };
12511
+ }
12512
+ async function encryptKindValue(ctx, value) {
12513
+ if (typeof value !== "string" || !ctx.walletAddress || !ctx.signMessage) return value;
12514
+ return encryptVaultMemoryContent(
12515
+ value,
12516
+ ctx.walletAddress,
12517
+ ctx.signMessage,
12518
+ ctx.embeddedWalletSigner
12519
+ );
12520
+ }
12521
+ function levelConditions(requested) {
12522
+ if (!requested?.length) return [];
12523
+ const published = ["shared", "public"];
12524
+ const wantsMatching = requested.includes("matching");
12525
+ const wantsPrivate = requested.includes("private");
12526
+ const unresolved = import_watermelondb20.Q.or(import_watermelondb20.Q.where("level", null), import_watermelondb20.Q.where("level", import_watermelondb20.Q.notIn([...MEMORY_LEVELS])));
12527
+ const byLevel = import_watermelondb20.Q.where("level", import_watermelondb20.Q.oneOf([...requested]));
12528
+ if (wantsMatching && wantsPrivate) return [import_watermelondb20.Q.or(byLevel, unresolved)];
12529
+ if (wantsMatching) {
12530
+ return [import_watermelondb20.Q.or(byLevel, import_watermelondb20.Q.and(unresolved, import_watermelondb20.Q.where("scope", import_watermelondb20.Q.oneOf(published))))];
12531
+ }
12532
+ if (wantsPrivate) {
12533
+ return [
12534
+ import_watermelondb20.Q.or(
12535
+ byLevel,
12536
+ import_watermelondb20.Q.and(unresolved, import_watermelondb20.Q.or(import_watermelondb20.Q.where("scope", null), import_watermelondb20.Q.where("scope", import_watermelondb20.Q.notIn(published))))
12537
+ )
12538
+ ];
12539
+ }
12540
+ return [byLevel];
12541
+ }
12542
+ function isOwnedByCtxUser(ctx, record2) {
12543
+ return ctx.userId === void 0 || record2.userId === ctx.userId;
12407
12544
  }
12408
12545
  function baseVaultConditions(ctx, options) {
12409
12546
  return [
@@ -12445,6 +12582,9 @@ function vaultMemoryToStoredRaw(memory) {
12445
12582
  uniqueId: memory.id,
12446
12583
  content: memory.content,
12447
12584
  scope: memory.scope,
12585
+ kind: memory.kind ?? null,
12586
+ kindValue: memory.kindValue ?? null,
12587
+ level: resolveMemoryLevel(memory.level, memory.scope),
12448
12588
  folderId: memory.folderId ?? null,
12449
12589
  userId: memory.userId ?? null,
12450
12590
  embedding: memory.embedding ?? null,
@@ -12483,42 +12623,48 @@ async function vaultMemoryToStored(memory, walletAddress, signMessage, embeddedW
12483
12623
  }
12484
12624
  return raw;
12485
12625
  }
12486
- function populateNewVaultMemory(record, ctx, opts, encryptedContent) {
12487
- record._setRaw("content", encryptedContent);
12488
- record._setRaw("scope", opts.scope ?? "private");
12489
- record._setRaw("folder_id", opts.folderId ?? null);
12490
- record._setRaw("user_id", ctx.userId ?? null);
12491
- record._setRaw("is_deleted", false);
12626
+ function populateNewVaultMemory(record2, ctx, opts, encryptedContent, encryptedKindValue) {
12627
+ const { level, scope } = resolveCreateLevel(opts);
12628
+ record2._setRaw("content", encryptedContent);
12629
+ record2._setRaw("scope", scope);
12630
+ record2._setRaw("level", level);
12631
+ record2._setRaw("kind", opts.kind ?? null);
12632
+ record2._setRaw("kind_value", encryptedKindValue ?? null);
12633
+ record2._setRaw("folder_id", opts.folderId ?? null);
12634
+ record2._setRaw("user_id", ctx.userId ?? null);
12635
+ record2._setRaw("is_deleted", false);
12492
12636
  if (opts.embedding !== void 0) {
12493
- record._setRaw("embedding", opts.embedding);
12494
- record._setRaw("embedding_model", opts.embeddingModel ?? null);
12637
+ record2._setRaw("embedding", opts.embedding);
12638
+ record2._setRaw("embedding_model", opts.embeddingModel ?? null);
12495
12639
  }
12496
12640
  if (opts.sourceChunkIds !== void 0) {
12497
- record._setRaw("source_chunk_ids", JSON.stringify(opts.sourceChunkIds));
12641
+ record2._setRaw("source_chunk_ids", JSON.stringify(opts.sourceChunkIds));
12498
12642
  }
12499
- record._setRaw("proof_count", opts.proofCount ?? 1);
12500
- record._setRaw("source", opts.source ?? "manual");
12643
+ record2._setRaw("proof_count", opts.proofCount ?? 1);
12644
+ record2._setRaw("source", opts.source ?? "manual");
12501
12645
  if (opts.eventTime) {
12502
- record._setRaw("event_time_start", opts.eventTime.start ?? null);
12503
- record._setRaw("event_time_end", opts.eventTime.end ?? null);
12504
- record._setRaw("event_time_kind", opts.eventTime.kind ?? null);
12646
+ record2._setRaw("event_time_start", opts.eventTime.start ?? null);
12647
+ record2._setRaw("event_time_end", opts.eventTime.end ?? null);
12648
+ record2._setRaw("event_time_kind", opts.eventTime.kind ?? null);
12505
12649
  }
12506
12650
  if (opts.factType !== void 0) {
12507
- record._setRaw("fact_type", opts.factType);
12651
+ record2._setRaw("fact_type", opts.factType);
12508
12652
  }
12509
12653
  if (opts.trustTier !== void 0) {
12510
- record._setRaw("trust_tier", normalizeTrustTier(opts.trustTier));
12654
+ record2._setRaw("trust_tier", normalizeTrustTier(opts.trustTier));
12511
12655
  }
12512
- record._setRaw("visibility", opts.visibility ?? "private");
12513
- record._setRaw(
12656
+ record2._setRaw("visibility", opts.visibility ?? "private");
12657
+ record2._setRaw(
12514
12658
  "published_at",
12515
12659
  opts.visibility && opts.visibility !== "private" ? opts.publishedAt ?? Date.now() : null
12516
12660
  );
12517
12661
  if (opts.geohash !== void 0) {
12518
- record._setRaw("geohash", opts.geohash);
12662
+ record2._setRaw("geohash", opts.geohash);
12519
12663
  }
12520
12664
  }
12521
12665
  async function createVaultMemoryOp(ctx, opts) {
12666
+ assertValidKindLevel(opts.kind, resolveCreateLevel(opts).level);
12667
+ const encryptedKindValue = await encryptKindValue(ctx, opts.kindValue);
12522
12668
  const encryptedContent = ctx.walletAddress && ctx.signMessage ? await encryptVaultMemoryContent(
12523
12669
  opts.content,
12524
12670
  ctx.walletAddress,
@@ -12529,13 +12675,15 @@ async function createVaultMemoryOp(ctx, opts) {
12529
12675
  if (ctx.canWrite && !await ctx.canWrite())
12530
12676
  throw new Error("Memory source is no longer eligible");
12531
12677
  return ctx.vaultMemoryCollection.create(
12532
- (record) => populateNewVaultMemory(record, ctx, opts, encryptedContent)
12678
+ (record2) => populateNewVaultMemory(record2, ctx, opts, encryptedContent, encryptedKindValue)
12533
12679
  );
12534
12680
  });
12535
12681
  return vaultMemoryToStored(created, ctx.walletAddress, ctx.signMessage, ctx.embeddedWalletSigner);
12536
12682
  }
12537
12683
  async function createSupersedingMemoryOp(ctx, opts, targetId) {
12538
12684
  if (!targetId) return { created: null, retired: false };
12685
+ assertValidKindLevel(opts.kind, resolveCreateLevel(opts).level);
12686
+ const encryptedKindValue = await encryptKindValue(ctx, opts.kindValue);
12539
12687
  const encryptedContent = ctx.walletAddress && ctx.signMessage ? await encryptVaultMemoryContent(
12540
12688
  opts.content,
12541
12689
  ctx.walletAddress,
@@ -12552,9 +12700,10 @@ async function createSupersedingMemoryOp(ctx, opts, targetId) {
12552
12700
  } catch {
12553
12701
  return;
12554
12702
  }
12555
- if (target.isDeleted || target.supersededBy || !isOwnedByCtxUser(ctx, target)) return;
12703
+ if (target.isDeleted || target.supersededBy || isKinded(target) || !isOwnedByCtxUser(ctx, target))
12704
+ return;
12556
12705
  createdRecord = await ctx.vaultMemoryCollection.create(
12557
- (record) => populateNewVaultMemory(record, ctx, opts, encryptedContent)
12706
+ (record2) => populateNewVaultMemory(record2, ctx, opts, encryptedContent, encryptedKindValue)
12558
12707
  );
12559
12708
  await target.update((r) => {
12560
12709
  r._setRaw("superseded_by", createdRecord.id);
@@ -12618,6 +12767,10 @@ async function getMemoriesByEventTimeOp(ctx, windowStart, windowEnd) {
12618
12767
  }
12619
12768
  async function createVaultMemoriesBatchOp(ctx, optionsArray) {
12620
12769
  if (optionsArray.length === 0) return [];
12770
+ for (const opts of optionsArray) assertValidKindLevel(opts.kind, resolveCreateLevel(opts).level);
12771
+ const encryptedKindValues = await Promise.all(
12772
+ optionsArray.map((opts) => encryptKindValue(ctx, opts.kindValue))
12773
+ );
12621
12774
  const encryptedContents = await Promise.all(
12622
12775
  optionsArray.map(async (opts) => {
12623
12776
  if (ctx.walletAddress && ctx.signMessage) {
@@ -12636,7 +12789,7 @@ async function createVaultMemoriesBatchOp(ctx, optionsArray) {
12636
12789
  throw new Error("Memory source is no longer eligible");
12637
12790
  const prepared = optionsArray.map(
12638
12791
  (opts, i) => ctx.vaultMemoryCollection.prepareCreate(
12639
- (record) => populateNewVaultMemory(record, ctx, opts, encryptedContents[i])
12792
+ (record2) => populateNewVaultMemory(record2, ctx, opts, encryptedContents[i], encryptedKindValues[i])
12640
12793
  )
12641
12794
  );
12642
12795
  await ctx.database.batch(...prepared);
@@ -12644,16 +12797,16 @@ async function createVaultMemoriesBatchOp(ctx, optionsArray) {
12644
12797
  });
12645
12798
  return Promise.all(
12646
12799
  created.map(
12647
- (record) => vaultMemoryToStored(record, ctx.walletAddress, ctx.signMessage, ctx.embeddedWalletSigner)
12800
+ (record2) => vaultMemoryToStored(record2, ctx.walletAddress, ctx.signMessage, ctx.embeddedWalletSigner)
12648
12801
  )
12649
12802
  );
12650
12803
  }
12651
12804
  async function getVaultMemoryOp(ctx, id) {
12652
12805
  try {
12653
- const record = await ctx.vaultMemoryCollection.find(id);
12654
- if (record.isDeleted || !isOwnedByCtxUser(ctx, record)) return null;
12806
+ const record2 = await ctx.vaultMemoryCollection.find(id);
12807
+ if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2)) return null;
12655
12808
  return vaultMemoryToStored(
12656
- record,
12809
+ record2,
12657
12810
  ctx.walletAddress,
12658
12811
  ctx.signMessage,
12659
12812
  ctx.embeddedWalletSigner
@@ -12679,6 +12832,9 @@ function vaultMemoryRawToStoredRaw(raw) {
12679
12832
  uniqueId: raw.id,
12680
12833
  content: raw.content ?? "",
12681
12834
  scope: raw.scope ?? "",
12835
+ kind: raw.kind ?? null,
12836
+ kindValue: raw.kind_value ?? null,
12837
+ level: resolveMemoryLevel(raw.level, raw.scope),
12682
12838
  folderId: raw.folder_id ?? null,
12683
12839
  userId: raw.user_id ?? null,
12684
12840
  embedding: raw.embedding ?? null,
@@ -12711,17 +12867,19 @@ function vaultMemoryRawToStoredRaw(raw) {
12711
12867
  };
12712
12868
  }
12713
12869
  async function vaultMemoryRawToStored(raw, walletAddress, signMessage, embeddedWalletSigner) {
12714
- const stored = vaultMemoryRawToStoredRaw(raw);
12870
+ const stored2 = vaultMemoryRawToStoredRaw(raw);
12715
12871
  if (walletAddress) {
12716
- return decryptVaultMemoryFields(stored, walletAddress, signMessage, embeddedWalletSigner);
12872
+ return decryptVaultMemoryFields(stored2, walletAddress, signMessage, embeddedWalletSigner);
12717
12873
  }
12718
- return stored;
12874
+ return stored2;
12719
12875
  }
12720
12876
  async function getAllVaultMemoriesOp(ctx, options) {
12721
12877
  const conditions = [
12722
12878
  ...baseVaultConditions(ctx, options),
12723
12879
  ...options?.scopes?.length ? [import_watermelondb20.Q.where("scope", import_watermelondb20.Q.oneOf(options.scopes))] : [],
12724
12880
  ...visibilityConditions(options?.visibility),
12881
+ ...levelConditions(options?.levels),
12882
+ ...options?.kinds?.length ? [import_watermelondb20.Q.where("kind", import_watermelondb20.Q.oneOf(options.kinds))] : [],
12725
12883
  ...options?.folderId !== void 0 ? [import_watermelondb20.Q.where("folder_id", options.folderId)] : [],
12726
12884
  ...options?.factTypes?.length ? [import_watermelondb20.Q.where("fact_type", import_watermelondb20.Q.oneOf(options.factTypes))] : [],
12727
12885
  import_watermelondb20.Q.sortBy(options?.since ? "updated_at" : "created_at", import_watermelondb20.Q.desc),
@@ -12867,13 +13025,13 @@ async function getVaultMemoriesByIdsOp(ctx, ids, options) {
12867
13025
  async function getAllVaultMemoryContentsOp(ctx, options) {
12868
13026
  const results = await ctx.vaultMemoryCollection.query(...baseVaultConditions(ctx, options)).unsafeFetchRaw();
12869
13027
  return mapInBatches(results, async (raw) => {
12870
- const stored = await vaultMemoryRawToStored(
13028
+ const stored2 = await vaultMemoryRawToStored(
12871
13029
  raw,
12872
13030
  ctx.walletAddress,
12873
13031
  ctx.signMessage,
12874
13032
  ctx.embeddedWalletSigner
12875
13033
  );
12876
- return stored.content;
13034
+ return stored2.content;
12877
13035
  });
12878
13036
  }
12879
13037
  async function countActiveVaultMemoriesOp(ctx) {
@@ -12888,6 +13046,14 @@ async function updateVaultMemoryOp(ctx, id, opts) {
12888
13046
  try {
12889
13047
  const probe = await ctx.vaultMemoryCollection.find(id);
12890
13048
  if (probe.isDeleted || probe.supersededBy || !isOwnedByCtxUser(ctx, probe)) return null;
13049
+ if (opts.freeFormOnly && isKinded(probe)) return null;
13050
+ const levelAfter = (current) => {
13051
+ if (opts.level !== void 0) return opts.level;
13052
+ if (opts.scope === void 0) return resolveMemoryLevel(current.level, current.scope);
13053
+ return levelForScopeChange(current, opts.scope);
13054
+ };
13055
+ assertValidKindLevel(opts.kind !== void 0 ? opts.kind : probe.kind, levelAfter(probe));
13056
+ const encryptedKindValue = await encryptKindValue(ctx, opts.kindValue);
12891
13057
  const encryptedContent = ctx.walletAddress && ctx.signMessage ? await encryptVaultMemoryContent(
12892
13058
  opts.content,
12893
13059
  ctx.walletAddress,
@@ -12895,30 +13061,43 @@ async function updateVaultMemoryOp(ctx, id, opts) {
12895
13061
  ctx.embeddedWalletSigner
12896
13062
  ) : opts.content;
12897
13063
  let stale = false;
12898
- const record = probe;
12899
- const originalUpdatedAt = record.updatedAt.getTime();
13064
+ const record2 = probe;
13065
+ const originalUpdatedAt = record2.updatedAt.getTime();
12900
13066
  await ctx.database.write(async () => {
12901
13067
  if (ctx.canWrite && !await ctx.canWrite())
12902
13068
  throw new Error("Memory source is no longer eligible");
12903
- if (record.isDeleted || record.supersededBy || !isOwnedByCtxUser(ctx, record)) {
13069
+ if (record2.isDeleted || record2.supersededBy || !isOwnedByCtxUser(ctx, record2) || opts.freeFormOnly && isKinded(record2)) {
12904
13070
  stale = true;
12905
13071
  return;
12906
13072
  }
13073
+ const nextKind = opts.kind !== void 0 ? opts.kind : record2.kind;
13074
+ const nextLevel = levelAfter(record2);
13075
+ assertValidKindLevel(nextKind, nextLevel);
12907
13076
  let observedSources = [];
12908
13077
  let replayedObservation = false;
12909
13078
  if (opts.observationSourceIds?.length) {
12910
13079
  try {
12911
- const parsed = JSON.parse(record.sourceChunkIds ?? "[]");
13080
+ const parsed = JSON.parse(record2.sourceChunkIds ?? "[]");
12912
13081
  if (Array.isArray(parsed))
12913
13082
  observedSources = parsed.filter((id2) => typeof id2 === "string");
12914
13083
  } catch {
12915
13084
  }
12916
13085
  replayedObservation = opts.observationSourceIds.every((id2) => observedSources.includes(id2));
12917
13086
  }
12918
- await record.update((r) => {
13087
+ await record2.update((r) => {
12919
13088
  r._setRaw("content", encryptedContent);
12920
- if (opts.scope !== void 0) {
13089
+ if (opts.level !== void 0) {
13090
+ r._setRaw("level", nextLevel);
13091
+ r._setRaw("scope", scopeForLevel(nextLevel));
13092
+ } else if (opts.scope !== void 0) {
12921
13093
  r._setRaw("scope", opts.scope);
13094
+ r._setRaw("level", nextLevel);
13095
+ }
13096
+ if (opts.kind !== void 0) {
13097
+ r._setRaw("kind", opts.kind);
13098
+ }
13099
+ if (encryptedKindValue !== void 0) {
13100
+ r._setRaw("kind_value", encryptedKindValue);
12922
13101
  }
12923
13102
  if (opts.folderId !== void 0) {
12924
13103
  r._setRaw("folder_id", opts.folderId);
@@ -12972,12 +13151,13 @@ async function updateVaultMemoryOp(ctx, id, opts) {
12972
13151
  });
12973
13152
  if (stale) return null;
12974
13153
  return vaultMemoryToStored(
12975
- record,
13154
+ record2,
12976
13155
  ctx.walletAddress,
12977
13156
  ctx.signMessage,
12978
13157
  ctx.embeddedWalletSigner
12979
13158
  );
12980
- } catch {
13159
+ } catch (err) {
13160
+ if (err instanceof MemoryLevelError) throw err;
12981
13161
  return null;
12982
13162
  }
12983
13163
  }
@@ -12986,21 +13166,21 @@ async function setMemoryEntitiesOp(ctx, memoryId, entities) {
12986
13166
  if (!entityCtx) {
12987
13167
  throw new Error("setMemoryEntitiesOp requires ctx.entityCtx (entity collections)");
12988
13168
  }
12989
- let record;
13169
+ let record2;
12990
13170
  try {
12991
- record = await ctx.vaultMemoryCollection.find(memoryId);
13171
+ record2 = await ctx.vaultMemoryCollection.find(memoryId);
12992
13172
  } catch {
12993
13173
  return null;
12994
13174
  }
12995
- if (record.isDeleted || !isOwnedByCtxUser(ctx, record)) return null;
13175
+ if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2)) return null;
12996
13176
  let stale = false;
12997
- const originalUpdatedAt = record.updatedAt.getTime();
13177
+ const originalUpdatedAt = record2.updatedAt.getTime();
12998
13178
  await ctx.database.write(async (writer) => {
12999
- if (record.isDeleted || !isOwnedByCtxUser(ctx, record)) {
13179
+ if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2)) {
13000
13180
  stale = true;
13001
13181
  return;
13002
13182
  }
13003
- await record.update((r) => {
13183
+ await record2.update((r) => {
13004
13184
  r._setRaw("topics_user_managed", true);
13005
13185
  r._setRaw("updated_at", originalUpdatedAt);
13006
13186
  });
@@ -13024,25 +13204,25 @@ async function setMemoryEntitiesOp(ctx, memoryId, entities) {
13024
13204
  );
13025
13205
  });
13026
13206
  if (stale) return null;
13027
- return vaultMemoryToStored(record, ctx.walletAddress, ctx.signMessage, ctx.embeddedWalletSigner);
13207
+ return vaultMemoryToStored(record2, ctx.walletAddress, ctx.signMessage, ctx.embeddedWalletSigner);
13028
13208
  }
13029
13209
  async function clearMemoryTopicsOverrideOp(ctx, memoryId, options) {
13030
- let record;
13210
+ let record2;
13031
13211
  try {
13032
- record = await ctx.vaultMemoryCollection.find(memoryId);
13212
+ record2 = await ctx.vaultMemoryCollection.find(memoryId);
13033
13213
  } catch {
13034
13214
  return false;
13035
13215
  }
13036
- if (record.isDeleted || !isOwnedByCtxUser(ctx, record)) return false;
13037
- const originalUpdatedAt = record.updatedAt.getTime();
13216
+ if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2)) return false;
13217
+ const originalUpdatedAt = record2.updatedAt.getTime();
13038
13218
  let cleared = false;
13039
13219
  await ctx.database.write(async () => {
13040
- if (options?.unlessTopicsRecorded && parseTopics(record.topics) !== null) return;
13220
+ if (options?.unlessTopicsRecorded && parseTopics(record2.topics) !== null) return;
13041
13221
  cleared = true;
13042
- await record.update((r) => {
13222
+ await record2.update((r) => {
13043
13223
  r._setRaw("topics_user_managed", false);
13044
13224
  r._setRaw("topics_extracted_version", null);
13045
- if (record.topicsExtractedAt === null) {
13225
+ if (record2.topicsExtractedAt === null) {
13046
13226
  r._setRaw("topics_extracted_at", originalUpdatedAt);
13047
13227
  }
13048
13228
  r._setRaw("updated_at", originalUpdatedAt);
@@ -13051,22 +13231,22 @@ async function clearMemoryTopicsOverrideOp(ctx, memoryId, options) {
13051
13231
  return cleared;
13052
13232
  }
13053
13233
  async function setMemoryVisibilityOp(ctx, id, opts) {
13054
- let record;
13234
+ let record2;
13055
13235
  try {
13056
- record = await ctx.vaultMemoryCollection.find(id);
13236
+ record2 = await ctx.vaultMemoryCollection.find(id);
13057
13237
  } catch {
13058
13238
  return null;
13059
13239
  }
13060
- if (record.isDeleted || !isOwnedByCtxUser(ctx, record)) return null;
13240
+ if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2)) return null;
13061
13241
  let stale = false;
13062
13242
  await ctx.database.write(async () => {
13063
- if (record.isDeleted || !isOwnedByCtxUser(ctx, record)) {
13243
+ if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2)) {
13064
13244
  stale = true;
13065
13245
  return;
13066
13246
  }
13067
- const currentUpdatedAt = record.updatedAt.getTime();
13068
- const currentPublishedAt = record.publishedAt ?? null;
13069
- await record.update((r) => {
13247
+ const currentUpdatedAt = record2.updatedAt.getTime();
13248
+ const currentPublishedAt = record2.publishedAt ?? null;
13249
+ await record2.update((r) => {
13070
13250
  r._setRaw("visibility", opts.visibility);
13071
13251
  if (opts.visibility === "private") {
13072
13252
  r._setRaw("published_at", null);
@@ -13080,19 +13260,19 @@ async function setMemoryVisibilityOp(ctx, id, opts) {
13080
13260
  });
13081
13261
  });
13082
13262
  if (stale) return null;
13083
- return vaultMemoryToStored(record, ctx.walletAddress, ctx.signMessage, ctx.embeddedWalletSigner);
13263
+ return vaultMemoryToStored(record2, ctx.walletAddress, ctx.signMessage, ctx.embeddedWalletSigner);
13084
13264
  }
13085
13265
  async function deleteVaultMemoryOp(ctx, id) {
13086
13266
  try {
13087
- const record = await ctx.vaultMemoryCollection.find(id);
13088
- if (record.isDeleted || !isOwnedByCtxUser(ctx, record)) return false;
13267
+ const record2 = await ctx.vaultMemoryCollection.find(id);
13268
+ if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2)) return false;
13089
13269
  let stale = false;
13090
13270
  await ctx.database.write(async () => {
13091
- if (record.isDeleted || !isOwnedByCtxUser(ctx, record)) {
13271
+ if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2)) {
13092
13272
  stale = true;
13093
13273
  return;
13094
13274
  }
13095
- await record.update((r) => {
13275
+ await record2.update((r) => {
13096
13276
  r._setRaw("is_deleted", true);
13097
13277
  });
13098
13278
  });
@@ -13111,8 +13291,9 @@ async function deleteVaultMemoryOp(ctx, id) {
13111
13291
  async function supersedeVaultMemoryOp(ctx, id, supersededById) {
13112
13292
  if (id === supersededById) return false;
13113
13293
  try {
13114
- const record = await ctx.vaultMemoryCollection.find(id);
13115
- if (record.isDeleted || record.supersededBy || !isOwnedByCtxUser(ctx, record)) return false;
13294
+ const record2 = await ctx.vaultMemoryCollection.find(id);
13295
+ if (record2.isDeleted || record2.supersededBy || !isOwnedByCtxUser(ctx, record2)) return false;
13296
+ if (isKinded(record2)) return false;
13116
13297
  let successor;
13117
13298
  try {
13118
13299
  successor = await ctx.vaultMemoryCollection.find(supersededById);
@@ -13126,7 +13307,7 @@ async function supersedeVaultMemoryOp(ctx, id, supersededById) {
13126
13307
  await ctx.database.write(async () => {
13127
13308
  if (ctx.canWrite && !await ctx.canWrite())
13128
13309
  throw new Error("Memory source is no longer eligible");
13129
- if (record.isDeleted || record.supersededBy || !isOwnedByCtxUser(ctx, record)) {
13310
+ if (record2.isDeleted || record2.supersededBy || !isOwnedByCtxUser(ctx, record2)) {
13130
13311
  stale = true;
13131
13312
  return;
13132
13313
  }
@@ -13134,7 +13315,7 @@ async function supersedeVaultMemoryOp(ctx, id, supersededById) {
13134
13315
  stale = true;
13135
13316
  return;
13136
13317
  }
13137
- await record.update((r) => {
13318
+ await record2.update((r) => {
13138
13319
  r._setRaw("superseded_by", supersededById);
13139
13320
  r._setRaw("superseded_at", Date.now());
13140
13321
  });
@@ -13153,7 +13334,7 @@ async function getUnfiledVaultMemoriesOp(ctx) {
13153
13334
  const results = await ctx.vaultMemoryCollection.query(...conditions).fetch();
13154
13335
  return mapInBatches(
13155
13336
  results,
13156
- (record) => vaultMemoryToStored(record, ctx.walletAddress, ctx.signMessage, ctx.embeddedWalletSigner)
13337
+ (record2) => vaultMemoryToStored(record2, ctx.walletAddress, ctx.signMessage, ctx.embeddedWalletSigner)
13157
13338
  );
13158
13339
  }
13159
13340
  var TOPICS_EXTRACTION_VERSION = 3;
@@ -13295,17 +13476,17 @@ async function stampTopicsExtractedAtOp(ctx, memoryIds, extractedAt, version = T
13295
13476
  }
13296
13477
  }
13297
13478
  const eligible = records.filter(
13298
- (record) => !record.isDeleted && isOwnedByCtxUser(ctx, record) && !record.topicsUserManaged
13479
+ (record2) => !record2.isDeleted && isOwnedByCtxUser(ctx, record2) && !record2.topicsUserManaged
13299
13480
  );
13300
- const prepared = eligible.map((record) => {
13301
- const originalUpdatedAt = record.updatedAt.getTime();
13302
- return record.prepareUpdate((r) => {
13481
+ const prepared = eligible.map((record2) => {
13482
+ const originalUpdatedAt = record2.updatedAt.getTime();
13483
+ return record2.prepareUpdate((r) => {
13303
13484
  r._setRaw("topics_extracted_at", extractedAt);
13304
13485
  r._setRaw("topics_extracted_version", version);
13305
13486
  r._setRaw("updated_at", originalUpdatedAt);
13306
13487
  });
13307
13488
  });
13308
- for (const record of eligible) stamped.push(record.id);
13489
+ for (const record2 of eligible) stamped.push(record2.id);
13309
13490
  if (prepared.length > 0) await ctx.database.batch(...prepared);
13310
13491
  });
13311
13492
  }
@@ -13320,14 +13501,14 @@ async function relinkMemoryTopicsOp(ctx, memoryIds) {
13320
13501
  for (const id of Array.from(new Set(memoryIds))) {
13321
13502
  try {
13322
13503
  await ctx.database.write(async (writer) => {
13323
- let record;
13504
+ let record2;
13324
13505
  try {
13325
- record = await ctx.vaultMemoryCollection.find(id);
13506
+ record2 = await ctx.vaultMemoryCollection.find(id);
13326
13507
  } catch {
13327
13508
  return;
13328
13509
  }
13329
- if (record.isDeleted || !isOwnedByCtxUser(ctx, record)) return;
13330
- const topics = parseTopics(record.topics);
13510
+ if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2)) return;
13511
+ const topics = parseTopics(record2.topics);
13331
13512
  if (topics === null) return;
13332
13513
  await writer.callWriter(() => relinkMemoryEntitiesFromTopicsOp(entityCtx, id, topics));
13333
13514
  relinked.push(id);
@@ -13352,20 +13533,20 @@ async function backfillMemoryTopicsOp(ctx, memoryIds) {
13352
13533
  await ctx.database.write(async () => {
13353
13534
  const writes = [];
13354
13535
  for (const id of chunkIds) {
13355
- let record;
13536
+ let record2;
13356
13537
  try {
13357
- record = await ctx.vaultMemoryCollection.find(id);
13538
+ record2 = await ctx.vaultMemoryCollection.find(id);
13358
13539
  } catch {
13359
13540
  continue;
13360
13541
  }
13361
- if (record.isDeleted || !isOwnedByCtxUser(ctx, record)) continue;
13362
- if (parseTopics(record.topics) !== null) continue;
13542
+ if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2)) continue;
13543
+ if (parseTopics(record2.topics) !== null) continue;
13363
13544
  const links = await entityCtx.memoryEntityCollection.query(import_watermelondb20.Q.where("memory_id", id)).unsafeFetchRaw();
13364
13545
  const entityIds = links.map((l) => String(l.entity_id));
13365
13546
  if (entityIds.length === 0) continue;
13366
13547
  const entities = await entityCtx.entityCollection.query(import_watermelondb20.Q.where("id", import_watermelondb20.Q.oneOf(entityIds))).fetch();
13367
13548
  if (entities.length === 0) continue;
13368
- const source = record.topicsUserManaged ? "user" : "auto";
13549
+ const source = record2.topicsUserManaged ? "user" : "auto";
13369
13550
  const write = await resolveMemoryTopicsWrite(entityCtx, id, entities, [], source);
13370
13551
  if (write) writes.push(write);
13371
13552
  }
@@ -13383,7 +13564,7 @@ async function deleteAllVaultMemoriesForUserOp(ctx, userId) {
13383
13564
  if (records.length === 0) return 0;
13384
13565
  await ctx.database.write(async () => {
13385
13566
  const prepared = records.map(
13386
- (record) => record.prepareUpdate((r) => {
13567
+ (record2) => record2.prepareUpdate((r) => {
13387
13568
  r._setRaw("is_deleted", true);
13388
13569
  })
13389
13570
  );
@@ -13413,7 +13594,10 @@ function assertVaultScopeForSweep(ctx) {
13413
13594
  }
13414
13595
  async function getDecayCandidatesRawOp(ctx) {
13415
13596
  assertVaultScopeForSweep(ctx);
13416
- const results = await ctx.vaultMemoryCollection.query(...baseVaultConditions(ctx, { includeArchived: true, includeQuarantined: true })).unsafeFetchRaw();
13597
+ const results = await ctx.vaultMemoryCollection.query(
13598
+ ...baseVaultConditions(ctx, { includeArchived: true, includeQuarantined: true }),
13599
+ import_watermelondb20.Q.where("kind", null)
13600
+ ).unsafeFetchRaw();
13417
13601
  return results.map((raw) => ({
13418
13602
  uniqueId: raw.id,
13419
13603
  factType: raw.fact_type ?? null,
@@ -13428,20 +13612,20 @@ async function getDecayCandidatesRawOp(ctx) {
13428
13612
  }
13429
13613
  async function archiveVaultMemoryOp(ctx, id, opts) {
13430
13614
  try {
13431
- const record = await ctx.vaultMemoryCollection.find(id);
13432
- if (record.isDeleted || !isOwnedByCtxUser(ctx, record)) return false;
13615
+ const record2 = await ctx.vaultMemoryCollection.find(id);
13616
+ if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2)) return false;
13433
13617
  let stale = false;
13434
13618
  const archivedAtValue = opts?.now ?? Date.now();
13435
13619
  await ctx.database.write(async () => {
13436
- if (record.isDeleted || !isOwnedByCtxUser(ctx, record) || record.archivedAt !== null) {
13620
+ if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2) || record2.archivedAt !== null) {
13437
13621
  stale = true;
13438
13622
  return;
13439
13623
  }
13440
- if (opts?.expectedUpdatedAt !== void 0 && record.updatedAt.getTime() !== opts.expectedUpdatedAt || opts?.expectedLastObservedAt !== void 0 && (record.lastObservedAt ?? null) !== opts.expectedLastObservedAt) {
13624
+ if (opts?.expectedUpdatedAt !== void 0 && record2.updatedAt.getTime() !== opts.expectedUpdatedAt || opts?.expectedLastObservedAt !== void 0 && (record2.lastObservedAt ?? null) !== opts.expectedLastObservedAt) {
13441
13625
  stale = true;
13442
13626
  return;
13443
13627
  }
13444
- await record.update((r) => {
13628
+ await record2.update((r) => {
13445
13629
  r._setRaw("archived_at", archivedAtValue);
13446
13630
  });
13447
13631
  });
@@ -13452,15 +13636,15 @@ async function archiveVaultMemoryOp(ctx, id, opts) {
13452
13636
  }
13453
13637
  async function restoreVaultMemoryOp(ctx, id) {
13454
13638
  try {
13455
- const record = await ctx.vaultMemoryCollection.find(id);
13456
- if (record.isDeleted || !isOwnedByCtxUser(ctx, record)) return false;
13639
+ const record2 = await ctx.vaultMemoryCollection.find(id);
13640
+ if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2)) return false;
13457
13641
  let stale = false;
13458
13642
  await ctx.database.write(async () => {
13459
- if (record.isDeleted || !isOwnedByCtxUser(ctx, record)) {
13643
+ if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2)) {
13460
13644
  stale = true;
13461
13645
  return;
13462
13646
  }
13463
- await record.update((r) => {
13647
+ await record2.update((r) => {
13464
13648
  r._setRaw("archived_at", null);
13465
13649
  });
13466
13650
  });
@@ -13471,17 +13655,17 @@ async function restoreVaultMemoryOp(ctx, id) {
13471
13655
  }
13472
13656
  async function hardDeleteDecayedOp(ctx, id, opts) {
13473
13657
  try {
13474
- const record = await ctx.vaultMemoryCollection.find(id);
13475
- if (record.isDeleted || !isOwnedByCtxUser(ctx, record)) return false;
13658
+ const record2 = await ctx.vaultMemoryCollection.find(id);
13659
+ if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2)) return false;
13476
13660
  const now = opts.now ?? Date.now();
13477
13661
  let stale = false;
13478
13662
  await ctx.database.write(async () => {
13479
- const archivedAt = record.archivedAt;
13480
- if (record.isDeleted || !isOwnedByCtxUser(ctx, record) || archivedAt === null || now - archivedAt <= opts.hardDeleteWindowMs) {
13663
+ const archivedAt = record2.archivedAt;
13664
+ if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2) || archivedAt === null || now - archivedAt <= opts.hardDeleteWindowMs) {
13481
13665
  stale = true;
13482
13666
  return;
13483
13667
  }
13484
- await record.update((r) => {
13668
+ await record2.update((r) => {
13485
13669
  r._setRaw("is_deleted", true);
13486
13670
  });
13487
13671
  });
@@ -13499,14 +13683,14 @@ async function hardDeleteDecayedOp(ctx, id, opts) {
13499
13683
  }
13500
13684
  async function updateVaultMemoryEmbeddingOp(ctx, id, embedding, embeddingModel, expected) {
13501
13685
  try {
13502
- const record = await ctx.vaultMemoryCollection.find(id);
13503
- if (record.isDeleted || !isOwnedByCtxUser(ctx, record)) return false;
13504
- const readUpdatedAt = record.updatedAt.getTime();
13505
- const readStoredContent = record._getRaw("content");
13686
+ const record2 = await ctx.vaultMemoryCollection.find(id);
13687
+ if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2)) return false;
13688
+ const readUpdatedAt = record2.updatedAt.getTime();
13689
+ const readStoredContent = record2._getRaw("content");
13506
13690
  if (expected?.updatedAt !== void 0 && expected.updatedAt !== readUpdatedAt) return false;
13507
13691
  if (expected?.content !== void 0) {
13508
13692
  const current = await vaultMemoryToStored(
13509
- record,
13693
+ record2,
13510
13694
  ctx.walletAddress,
13511
13695
  ctx.signMessage,
13512
13696
  ctx.embeddedWalletSigner
@@ -13515,11 +13699,11 @@ async function updateVaultMemoryEmbeddingOp(ctx, id, embedding, embeddingModel,
13515
13699
  }
13516
13700
  let written = false;
13517
13701
  await ctx.database.write(async () => {
13518
- if (record.isDeleted || !isOwnedByCtxUser(ctx, record)) return;
13519
- const originalUpdatedAt = record.updatedAt.getTime();
13520
- if (originalUpdatedAt !== readUpdatedAt || record._getRaw("content") !== readStoredContent)
13702
+ if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2)) return;
13703
+ const originalUpdatedAt = record2.updatedAt.getTime();
13704
+ if (originalUpdatedAt !== readUpdatedAt || record2._getRaw("content") !== readStoredContent)
13521
13705
  return;
13522
- await record.update((r) => {
13706
+ await record2.update((r) => {
13523
13707
  r._setRaw("embedding", embedding);
13524
13708
  r._setRaw("embedding_model", embeddingModel);
13525
13709
  r._setRaw("updated_at", originalUpdatedAt);
@@ -13534,8 +13718,8 @@ async function updateVaultMemoryEmbeddingOp(ctx, id, embedding, embeddingModel,
13534
13718
  function normalizeForDedupe(content) {
13535
13719
  return content.normalize("NFKC").trim().replace(/\s+/g, " ").toLowerCase();
13536
13720
  }
13537
- async function findQuarantinedDuplicateOp(ctx, content, sourceIds, where) {
13538
- const wanted = [...new Set(sourceIds)].sort().join("\0");
13721
+ async function findQuarantinedDuplicateOp(ctx, content, sourceIds2, where) {
13722
+ const wanted = [...new Set(sourceIds2)].sort().join("\0");
13539
13723
  const target = normalizeForDedupe(content);
13540
13724
  const rows = await ctx.vaultMemoryCollection.query(
13541
13725
  import_watermelondb20.Q.where("trust_tier", "quarantined"),
@@ -13554,13 +13738,13 @@ async function findQuarantinedDuplicateOp(ctx, content, sourceIds, where) {
13554
13738
  if (!Array.isArray(ids)) continue;
13555
13739
  const key = [...new Set(ids.filter((id) => typeof id === "string"))].sort().join("\0");
13556
13740
  if (key !== wanted) continue;
13557
- const stored = await vaultMemoryRawToStored(
13741
+ const stored2 = await vaultMemoryRawToStored(
13558
13742
  raw,
13559
13743
  ctx.walletAddress,
13560
13744
  ctx.signMessage,
13561
13745
  ctx.embeddedWalletSigner
13562
13746
  );
13563
- if (normalizeForDedupe(stored.content) === target) return stored.uniqueId;
13747
+ if (normalizeForDedupe(stored2.content) === target) return stored2.uniqueId;
13564
13748
  }
13565
13749
  return null;
13566
13750
  }
@@ -13670,25 +13854,26 @@ async function ingestPublishedPhotoMemoriesOp(ctx, rows) {
13670
13854
  inserted = writable.length;
13671
13855
  if (writable.length === 0) return;
13672
13856
  const prepared = writable.map(
13673
- ({ row, content }) => ctx.vaultMemoryCollection.prepareCreate((record) => {
13674
- record._raw.id = row.memoryId;
13675
- record._setRaw("content", content);
13676
- record._setRaw("scope", "shared");
13677
- record._setRaw("folder_id", null);
13678
- record._setRaw("user_id", ctx.userId ?? null);
13679
- record._setRaw("is_deleted", false);
13680
- record._setRaw("proof_count", 1);
13681
- record._setRaw("source", SOURCE_PHOTO);
13682
- record._setRaw(
13857
+ ({ row, content }) => ctx.vaultMemoryCollection.prepareCreate((record2) => {
13858
+ record2._raw.id = row.memoryId;
13859
+ record2._setRaw("content", content);
13860
+ record2._setRaw("scope", "shared");
13861
+ record2._setRaw("level", "matching");
13862
+ record2._setRaw("folder_id", null);
13863
+ record2._setRaw("user_id", ctx.userId ?? null);
13864
+ record2._setRaw("is_deleted", false);
13865
+ record2._setRaw("proof_count", 1);
13866
+ record2._setRaw("source", SOURCE_PHOTO);
13867
+ record2._setRaw(
13683
13868
  "media",
13684
13869
  row.media && row.media.length > 0 ? JSON.stringify(row.media) : null
13685
13870
  );
13686
- record._setRaw("visibility", "public");
13687
- record._setRaw("published_at", now);
13871
+ record2._setRaw("visibility", "public");
13872
+ record2._setRaw("published_at", now);
13688
13873
  if (row.eventTime) {
13689
- record._setRaw("event_time_start", row.eventTime.start ?? null);
13690
- record._setRaw("event_time_end", row.eventTime.end ?? null);
13691
- record._setRaw("event_time_kind", row.eventTime.kind ?? null);
13874
+ record2._setRaw("event_time_start", row.eventTime.start ?? null);
13875
+ record2._setRaw("event_time_end", row.eventTime.end ?? null);
13876
+ record2._setRaw("event_time_kind", row.eventTime.kind ?? null);
13692
13877
  }
13693
13878
  })
13694
13879
  );
@@ -14053,11 +14238,11 @@ function folderToStored(folder) {
14053
14238
  }
14054
14239
  async function createVaultFolderOp(ctx, opts) {
14055
14240
  const created = await ctx.database.write(async () => {
14056
- return ctx.vaultFolderCollection.create((record) => {
14057
- record._setRaw("name", opts.name);
14058
- record._setRaw("scope", opts.scope ?? "private");
14059
- record._setRaw("is_system", opts.isSystem ?? false);
14060
- record._setRaw("is_deleted", false);
14241
+ return ctx.vaultFolderCollection.create((record2) => {
14242
+ record2._setRaw("name", opts.name);
14243
+ record2._setRaw("scope", opts.scope ?? "private");
14244
+ record2._setRaw("is_system", opts.isSystem ?? false);
14245
+ record2._setRaw("is_deleted", false);
14061
14246
  });
14062
14247
  });
14063
14248
  return folderToStored(created);
@@ -14068,14 +14253,14 @@ async function getAllVaultFoldersOp(ctx) {
14068
14253
  }
14069
14254
  async function updateVaultFolderOp(ctx, id, opts) {
14070
14255
  try {
14071
- const record = await ctx.vaultFolderCollection.find(id);
14072
- if (record.isDeleted) return null;
14073
- const scopeChanged = opts.scope !== void 0 && opts.scope !== record.scope;
14256
+ const record2 = await ctx.vaultFolderCollection.find(id);
14257
+ if (record2.isDeleted) return null;
14258
+ const scopeChanged = opts.scope !== void 0 && opts.scope !== record2.scope;
14074
14259
  const updated = await ctx.database.write(async () => {
14075
14260
  const memories = scopeChanged ? await ctx.vaultMemoryCollection.query(import_watermelondb21.Q.where("folder_id", id), import_watermelondb21.Q.where("is_deleted", false)).fetch() : [];
14076
14261
  const updates = [];
14077
14262
  updates.push(
14078
- record.prepareUpdate((r) => {
14263
+ record2.prepareUpdate((r) => {
14079
14264
  if (opts.name !== void 0) r._setRaw("name", opts.name);
14080
14265
  if (opts.scope !== void 0) r._setRaw("scope", opts.scope);
14081
14266
  })
@@ -14083,6 +14268,7 @@ async function updateVaultFolderOp(ctx, id, opts) {
14083
14268
  for (const memory of memories) {
14084
14269
  updates.push(
14085
14270
  memory.prepareUpdate((r) => {
14271
+ r._setRaw("level", levelForScopeChange(r, opts.scope));
14086
14272
  r._setRaw("scope", opts.scope);
14087
14273
  })
14088
14274
  );
@@ -14097,17 +14283,18 @@ async function updateVaultFolderOp(ctx, id, opts) {
14097
14283
  }
14098
14284
  async function deleteVaultFolderOp(ctx, id) {
14099
14285
  try {
14100
- const record = await ctx.vaultFolderCollection.find(id);
14101
- if (record.isDeleted) return false;
14286
+ const record2 = await ctx.vaultFolderCollection.find(id);
14287
+ if (record2.isDeleted) return false;
14102
14288
  await ctx.database.write(async () => {
14103
14289
  const memories = await ctx.vaultMemoryCollection.query(import_watermelondb21.Q.where("folder_id", id), import_watermelondb21.Q.where("is_deleted", false)).fetch();
14104
14290
  const preparedMemories = memories.map(
14105
14291
  (memory) => memory.prepareUpdate((r) => {
14106
14292
  r._setRaw("folder_id", null);
14293
+ r._setRaw("level", levelForScopeChange(r, "private"));
14107
14294
  r._setRaw("scope", "private");
14108
14295
  })
14109
14296
  );
14110
- const preparedFolder = record.prepareUpdate((r) => {
14297
+ const preparedFolder = record2.prepareUpdate((r) => {
14111
14298
  r._setRaw("is_deleted", true);
14112
14299
  });
14113
14300
  await ctx.database.batch(...preparedMemories, preparedFolder);
@@ -14140,6 +14327,7 @@ async function moveMemoriesToFolderOp(ctx, memoryIds, folderId) {
14140
14327
  const prepared = memories.map(
14141
14328
  (memory) => memory.prepareUpdate((r) => {
14142
14329
  r._setRaw("folder_id", folderId);
14330
+ r._setRaw("level", levelForScopeChange(r, targetScope));
14143
14331
  r._setRaw("scope", targetScope);
14144
14332
  })
14145
14333
  );
@@ -14153,11 +14341,11 @@ async function moveMemoriesToFolderOp(ctx, memoryIds, folderId) {
14153
14341
  }
14154
14342
  async function updateVaultFolderContextOp(ctx, id, context) {
14155
14343
  try {
14156
- const record = await ctx.vaultFolderCollection.find(id);
14157
- if (record.isDeleted) return null;
14344
+ const record2 = await ctx.vaultFolderCollection.find(id);
14345
+ if (record2.isDeleted) return null;
14158
14346
  const updated = await ctx.database.write(async () => {
14159
14347
  await ctx.database.batch(
14160
- record.prepareUpdate((r) => {
14348
+ record2.prepareUpdate((r) => {
14161
14349
  r._setRaw("context", context);
14162
14350
  })
14163
14351
  );
@@ -16235,7 +16423,7 @@ async function rankPreparedVaultCandidates(query, prepared, embeddingOptions, se
16235
16423
  if (useFusion && !embeddingsUnavailable && facetQueries) {
16236
16424
  let subEmbeddings;
16237
16425
  try {
16238
- subEmbeddings = await generateEmbeddings(facetQueries, embeddingOptions);
16426
+ subEmbeddings = prepared.facetEmbeddings ?? await generateEmbeddings(facetQueries, embeddingOptions);
16239
16427
  } catch (err) {
16240
16428
  getLogger().warn(
16241
16429
  "memoryVault: sub-query embedding failed \u2014 falling back to single-query ranking: " + (err instanceof Error ? err.message : String(err))
@@ -16421,6 +16609,35 @@ var DEFAULT_SCOPE = "private";
16421
16609
  var DEFAULT_CONSOLIDATE_THRESHOLD = 0.55;
16422
16610
  var DEFAULT_CONSOLIDATE_TOP_K = 20;
16423
16611
  async function retain(content, ctx, options = {}) {
16612
+ return retainWithPersistence(
16613
+ content,
16614
+ {
16615
+ embeddingOptions: ctx.embeddingOptions,
16616
+ vaultCache: ctx.vaultCache,
16617
+ persistence: {
16618
+ prepare: (query, searchOptions) => prepareVaultCandidates(
16619
+ query,
16620
+ ctx.vaultCtx,
16621
+ ctx.embeddingOptions,
16622
+ ctx.vaultCache,
16623
+ searchOptions
16624
+ ),
16625
+ get: (id) => getVaultMemoryOp(ctx.vaultCtx, id),
16626
+ tombstones: (_embedding, _model, scope, folderId) => getAllVaultMemoriesOp(ctx.vaultCtx, {
16627
+ includeDeleted: true,
16628
+ scopes: [scope],
16629
+ ...folderId !== void 0 && { folderId }
16630
+ }),
16631
+ create: (input) => createVaultMemoryOp(ctx.vaultCtx, input),
16632
+ update: (id, patch) => updateVaultMemoryOp(ctx.vaultCtx, id, patch),
16633
+ supersede: (id, successor) => supersedeVaultMemoryOp(ctx.vaultCtx, id, successor),
16634
+ createSuperseding: (input, target) => createSupersedingMemoryOp(ctx.vaultCtx, input, target)
16635
+ }
16636
+ },
16637
+ options
16638
+ );
16639
+ }
16640
+ async function retainWithPersistence(content, ctx, options = {}) {
16424
16641
  const trimmed = content.trim();
16425
16642
  if (trimmed.length === 0) {
16426
16643
  throw new Error("retain: content cannot be empty");
@@ -16433,19 +16650,14 @@ async function retain(content, ctx, options = {}) {
16433
16650
  let supersedeContent;
16434
16651
  let prepared;
16435
16652
  if (enableAutoMerge) {
16436
- prepared = await prepareVaultCandidates(
16437
- trimmed,
16438
- ctx.vaultCtx,
16439
- ctx.embeddingOptions,
16440
- ctx.vaultCache,
16441
- {
16442
- limit: Math.max(options.consolidateTopK ?? DEFAULT_CONSOLIDATE_TOP_K, 1),
16443
- useFusion: false,
16444
- scopes: [resolvedScope],
16445
- includeArchived: true,
16446
- ...options.folderId !== void 0 && { folderId: options.folderId }
16447
- }
16448
- );
16653
+ prepared = await ctx.persistence.prepare(trimmed, {
16654
+ limit: Math.max(options.consolidateTopK ?? DEFAULT_CONSOLIDATE_TOP_K, 1),
16655
+ useFusion: false,
16656
+ scopes: [resolvedScope],
16657
+ includeArchived: true,
16658
+ ...options.folderId !== void 0 && { folderId: options.folderId }
16659
+ });
16660
+ prepared = withoutKindedRows(prepared);
16449
16661
  if (prepared.embeddingFailure || prepared.embeddingsUnavailable) {
16450
16662
  throw new Error(
16451
16663
  "retain: embeddings unavailable \u2014 refusing to auto-merge against an inert cosine lane, which would create a duplicate instead of merging into the existing memory. Retry when embeddings recover, or pass enableAutoMerge: false to force a create."
@@ -16476,7 +16688,7 @@ async function retain(content, ctx, options = {}) {
16476
16688
  );
16477
16689
  if (matches.length > 0) {
16478
16690
  const targetId = matches[0].uniqueId;
16479
- const existing = await getVaultMemoryOp(ctx.vaultCtx, targetId);
16691
+ const existing = await ctx.persistence.get(targetId);
16480
16692
  if (existing && !existing.supersededBy) {
16481
16693
  const mergedSourceIds = unionStrings(
16482
16694
  existing.sourceChunkIds ?? [],
@@ -16485,8 +16697,9 @@ async function retain(content, ctx, options = {}) {
16485
16697
  const eventTimeUpdate = pickEventTimeUpdate(existing, options.eventTime);
16486
16698
  const factTypeUpdate = pickFactTypeUpdate(existing, options.factType);
16487
16699
  const resurrect = resurrectFields(existing);
16488
- const updated = await updateVaultMemoryOp(ctx.vaultCtx, targetId, {
16700
+ const updated = await ctx.persistence.update(targetId, {
16489
16701
  content: existing.content,
16702
+ freeFormOnly: true,
16490
16703
  proofCountIncrement: 1,
16491
16704
  observationSourceIds: options.sourceChunkIds,
16492
16705
  sourceChunkIds: mergedSourceIds,
@@ -16512,7 +16725,8 @@ async function retain(content, ctx, options = {}) {
16512
16725
  }
16513
16726
  const contentToWrite = supersedeContent ?? trimmed;
16514
16727
  const reusableQueryEmbedding = supersedeContent === void 0 && prepared && prepared.queryEmbedding.length > 0 ? prepared.queryEmbedding : void 0;
16515
- const embedding = reusableQueryEmbedding ?? await generateEmbedding(contentToWrite, ctx.embeddingOptions);
16728
+ const generatedEmbedding = reusableQueryEmbedding ?? await generateEmbedding(contentToWrite, ctx.embeddingOptions);
16729
+ const embedding = ctx.normalizeEmbedding?.(generatedEmbedding) ?? generatedEmbedding;
16516
16730
  const embeddingModel = ctx.embeddingOptions.model ?? DEFAULT_API_EMBEDDING_MODEL;
16517
16731
  if (options.respectTombstones) {
16518
16732
  const tombstone = await findTombstoneMatch(embedding, embeddingModel, resolvedScope, ctx, {
@@ -16552,8 +16766,7 @@ async function retain(content, ctx, options = {}) {
16552
16766
  };
16553
16767
  if (supersedeTargetIds.length > 0) {
16554
16768
  const [primaryTargetId, ...restTargetIds] = supersedeTargetIds;
16555
- const { created: created2, retired } = await createSupersedingMemoryOp(
16556
- ctx.vaultCtx,
16769
+ const { created: created2, retired } = await ctx.persistence.createSuperseding(
16557
16770
  createOpts,
16558
16771
  primaryTargetId
16559
16772
  );
@@ -16569,11 +16782,11 @@ async function retain(content, ctx, options = {}) {
16569
16782
  for (const staleId of restTargetIds) {
16570
16783
  let ok = false;
16571
16784
  try {
16572
- ok = await supersedeVaultMemoryOp(ctx.vaultCtx, staleId, created2.uniqueId) === true;
16785
+ ok = await ctx.persistence.supersede(staleId, created2.uniqueId) === true;
16573
16786
  } catch {
16574
16787
  }
16575
16788
  if (ok) continue;
16576
- const stillLive = await getVaultMemoryOp(ctx.vaultCtx, staleId).catch(() => null);
16789
+ const stillLive = await (ctx.persistence.getFresh ? ctx.persistence.getFresh(staleId) : ctx.persistence.get(staleId)).catch(() => null);
16577
16790
  if (stillLive && !stillLive.supersededBy) liveLeftovers.push(staleId);
16578
16791
  }
16579
16792
  if (liveLeftovers.length > 0) {
@@ -16600,7 +16813,7 @@ async function retain(content, ctx, options = {}) {
16600
16813
  `supersede: primary target ${primaryTargetId} retired or deleted inside the atomic write`
16601
16814
  );
16602
16815
  }
16603
- const created = await createVaultMemoryOp(ctx.vaultCtx, createOpts);
16816
+ const created = await ctx.persistence.create(createOpts);
16604
16817
  cacheRowVector(
16605
16818
  ctx.vaultCache,
16606
16819
  created.uniqueId,
@@ -16615,15 +16828,22 @@ async function retain(content, ctx, options = {}) {
16615
16828
  ...consolidationDecidedCreate && { consolidation: "create" }
16616
16829
  };
16617
16830
  }
16831
+ function withoutKindedRows(prepared) {
16832
+ const kinded = new Set(
16833
+ prepared.memories.filter((m) => m.kind !== null && m.kind !== void 0).map((m) => m.uniqueId)
16834
+ );
16835
+ if (kinded.size === 0) return prepared;
16836
+ return {
16837
+ ...prepared,
16838
+ memories: prepared.memories.filter((m) => !kinded.has(m.uniqueId)),
16839
+ embeddedItems: prepared.embeddedItems.filter((item) => !kinded.has(item.id))
16840
+ };
16841
+ }
16618
16842
  function unionStrings(a, b) {
16619
16843
  return [.../* @__PURE__ */ new Set([...a, ...b])];
16620
16844
  }
16621
16845
  async function findTombstoneMatch(embedding, embeddingModel, scope, ctx, opts) {
16622
- const rows = await getAllVaultMemoriesOp(ctx.vaultCtx, {
16623
- includeDeleted: true,
16624
- scopes: [scope],
16625
- ...opts.folderId !== void 0 && { folderId: opts.folderId }
16626
- });
16846
+ const rows = await ctx.persistence.tombstones(embedding, embeddingModel, scope, opts.folderId);
16627
16847
  let bestId = null;
16628
16848
  let bestSim = opts.threshold;
16629
16849
  for (const row of rows) {
@@ -16690,7 +16910,7 @@ async function tryConsolidate(trimmed, ctx, options, prepared) {
16690
16910
  if (requestedIds.length === 0) return null;
16691
16911
  const valid = [];
16692
16912
  for (const id of requestedIds) {
16693
- const existing = await getVaultMemoryOp(ctx.vaultCtx, id);
16913
+ const existing = await ctx.persistence.get(id);
16694
16914
  if (existing && !existing.supersededBy) valid.push(id);
16695
16915
  }
16696
16916
  if (valid.length === 0) {
@@ -16702,7 +16922,7 @@ async function tryConsolidate(trimmed, ctx, options, prepared) {
16702
16922
  return { supersede: valid, content: decision.content };
16703
16923
  }
16704
16924
  if (decision.action === "noop" && decision.targetId) {
16705
- const existing = await getVaultMemoryOp(ctx.vaultCtx, decision.targetId);
16925
+ const existing = await ctx.persistence.get(decision.targetId);
16706
16926
  if (!existing || existing.supersededBy) {
16707
16927
  return abandonToRace(
16708
16928
  options,
@@ -16716,8 +16936,9 @@ async function tryConsolidate(trimmed, ctx, options, prepared) {
16716
16936
  const eventTimeUpdate = pickEventTimeUpdate(existing, options.eventTime);
16717
16937
  const factTypeUpdate = pickFactTypeUpdate(existing, options.factType);
16718
16938
  const resurrect = resurrectFields(existing);
16719
- const updated = await updateVaultMemoryOp(ctx.vaultCtx, decision.targetId, {
16939
+ const updated = await ctx.persistence.update(decision.targetId, {
16720
16940
  content: existing.content,
16941
+ freeFormOnly: true,
16721
16942
  proofCountIncrement: 1,
16722
16943
  observationSourceIds: options.sourceChunkIds,
16723
16944
  sourceChunkIds: mergedSourceIds,
@@ -16744,7 +16965,7 @@ async function tryConsolidate(trimmed, ctx, options, prepared) {
16744
16965
  };
16745
16966
  }
16746
16967
  if (decision.action === "update" && decision.targetId && decision.content) {
16747
- const existing = await getVaultMemoryOp(ctx.vaultCtx, decision.targetId);
16968
+ const existing = await ctx.persistence.get(decision.targetId);
16748
16969
  if (!existing || existing.supersededBy) {
16749
16970
  return abandonToRace(
16750
16971
  options,
@@ -16755,13 +16976,15 @@ async function tryConsolidate(trimmed, ctx, options, prepared) {
16755
16976
  existing.sourceChunkIds ?? [],
16756
16977
  options.sourceChunkIds ?? []
16757
16978
  );
16758
- const newEmbedding = await generateEmbedding(decision.content, ctx.embeddingOptions);
16979
+ const generatedEmbedding = await generateEmbedding(decision.content, ctx.embeddingOptions);
16980
+ const newEmbedding = ctx.normalizeEmbedding?.(generatedEmbedding) ?? generatedEmbedding;
16759
16981
  const consolidatedModel = ctx.embeddingOptions.model ?? DEFAULT_API_EMBEDDING_MODEL;
16760
16982
  const eventTimeUpdate = pickEventTimeUpdate(existing, options.eventTime);
16761
16983
  const factTypeUpdate = pickFactTypeUpdate(existing, options.factType);
16762
16984
  const resurrect = resurrectFields(existing);
16763
- const updated = await updateVaultMemoryOp(ctx.vaultCtx, decision.targetId, {
16985
+ const updated = await ctx.persistence.update(decision.targetId, {
16764
16986
  content: decision.content,
16987
+ freeFormOnly: true,
16765
16988
  proofCountIncrement: 1,
16766
16989
  observationSourceIds: options.sourceChunkIds,
16767
16990
  sourceChunkIds: mergedSourceIds,
@@ -16804,8 +17027,8 @@ async function tryConsolidate(trimmed, ctx, options, prepared) {
16804
17027
  return null;
16805
17028
  }
16806
17029
  async function assertMergeTargetGoneOrThrow(ctx, targetId) {
16807
- const stillExists = await getVaultMemoryOp(ctx.vaultCtx, targetId);
16808
- if (stillExists) {
17030
+ const stillExists = await (ctx.persistence.getFresh ? ctx.persistence.getFresh(targetId) : ctx.persistence.get(targetId));
17031
+ if (stillExists && (stillExists.kind === null || stillExists.kind === void 0)) {
16809
17032
  throw new Error(`retain: merge into memory ${targetId} failed to persist`);
16810
17033
  }
16811
17034
  }
@@ -17321,9 +17544,9 @@ function createAutoExtractor(options) {
17321
17544
  const persistCursor = (conversationId, messages, advancedToId, contiguous) => {
17322
17545
  if (!cursorStore || conversationId === void 0 || !contiguous) return;
17323
17546
  try {
17324
- const stored = cursorStore.get(conversationId);
17325
- if (stored && stored !== advancedToId) {
17326
- const storedIdx = messages.findIndex((m) => m.id === stored);
17547
+ const stored2 = cursorStore.get(conversationId);
17548
+ if (stored2 && stored2 !== advancedToId) {
17549
+ const storedIdx = messages.findIndex((m) => m.id === stored2);
17327
17550
  const newIdx = messages.findIndex((m) => m.id === advancedToId);
17328
17551
  if (storedIdx !== -1 && newIdx !== -1 && storedIdx >= newIdx) return;
17329
17552
  }
@@ -18303,7 +18526,7 @@ async function recall(query, ctx, options = {}) {
18303
18526
  if (graphLaneFailed) degraded.push("graph-lane-failed");
18304
18527
  if (temporalLaneFailed) degraded.push("temporal-lane-failed");
18305
18528
  if (chunksScopeRestricted) degraded.push("chunks-scope-restricted");
18306
- const laneRan = types.includes("fact") && !!ctx.vaultCtx && !!ctx.vaultCache || types.includes("chunk") && !!ctx.storageCtx || chunksScopeRestricted && !!ctx.storageCtx;
18529
+ const laneRan = types.includes("fact") && (!!ctx.factSource || !!ctx.vaultCtx && !!ctx.vaultCache) || types.includes("chunk") && !!ctx.storageCtx || chunksScopeRestricted && !!ctx.storageCtx;
18307
18530
  const scores = admitted.map((m) => m.score);
18308
18531
  const minScoreApplied = factResults.length > 0 ? factFloor : chunkResults.length > 0 ? chunkFloor : factFloor >= 0 ? factFloor : chunkFloor;
18309
18532
  const diagnostics = {
@@ -18345,7 +18568,7 @@ async function recall(query, ctx, options = {}) {
18345
18568
  return { memories: [], usedBudget, reranked: false, candidateCount: 0 };
18346
18569
  }
18347
18570
  const needsChunkEmbedding = types.includes("chunk") && ctx.storageCtx;
18348
- const wantsTemporal = types.includes("fact") && ctx.vaultCtx;
18571
+ const wantsTemporal = types.includes("fact") && (ctx.factSource || ctx.vaultCtx);
18349
18572
  const graphRefiner = flags.traverse && options.graphRefine && options.decomposeOptions ? createLlmNeighborRefiner(options.decomposeOptions) : void 0;
18350
18573
  const queryEmbedTotalTimeoutMs = options.queryEmbedTotalTimeoutMs ?? DEFAULT_QUERY_EMBED_TOTAL_TIMEOUT_MS;
18351
18574
  const prepStart = nowMs2();
@@ -18375,7 +18598,7 @@ async function recall(query, ctx, options = {}) {
18375
18598
  safeLane(
18376
18599
  "graph",
18377
18600
  () => graphLaneFailed = true,
18378
- () => buildGraphLaneRanking(query, ctx, flags.traverse, {
18601
+ () => ctx.factSource ? ctx.factSource.graphRanking(query, flags.traverse, options) : buildGraphLaneRanking(query, ctx, flags.traverse, {
18379
18602
  ...options.maxHops !== void 0 && { maxHops: options.maxHops },
18380
18603
  ...options.entityFanout !== void 0 && { entityFanout: options.entityFanout },
18381
18604
  ...options.nodeBudget !== void 0 && { nodeBudget: options.nodeBudget },
@@ -18386,13 +18609,13 @@ async function recall(query, ctx, options = {}) {
18386
18609
  wantsTemporal ? safeLane(
18387
18610
  "temporal",
18388
18611
  () => temporalLaneFailed = true,
18389
- () => buildTemporalLaneRanking(query, ctx.vaultCtx, options.now)
18612
+ () => ctx.factSource ? ctx.factSource.temporalRanking(query, options.now) : buildTemporalLaneRanking(query, ctx.vaultCtx, options.now)
18390
18613
  ) : Promise.resolve([])
18391
18614
  ]);
18392
18615
  prepMs = nowMs2() - prepStart;
18393
18616
  graphLaneCount = entityRanking.length;
18394
18617
  temporalLaneCount = temporalRanking.length;
18395
- if (types.includes("fact") && ctx.vaultCtx && ctx.vaultCache) {
18618
+ if (types.includes("fact") && (ctx.factSource || ctx.vaultCtx && ctx.vaultCache)) {
18396
18619
  const factStart = nowMs2();
18397
18620
  const vaultMinScore = options.minScore ?? DEFAULT_FACT_MIN_SCORE;
18398
18621
  factFloor = vaultMinScore;
@@ -18408,50 +18631,50 @@ async function recall(query, ctx, options = {}) {
18408
18631
  rankedOnCosine: factRankedOnCosine,
18409
18632
  decryptLast: factDecryptLast,
18410
18633
  rowsDecrypted: factRowsDecrypted
18411
- } = await searchVaultMemoriesWithSize(
18412
- query,
18634
+ } = await (ctx.factSource?.search.bind(ctx.factSource) ?? ((searchQuery, searchOptions) => searchVaultMemoriesWithSize(
18635
+ searchQuery,
18413
18636
  ctx.vaultCtx,
18414
18637
  ctx.embeddingOptions,
18415
18638
  ctx.vaultCache,
18416
- {
18417
- limit: types.includes("chunk") ? Math.max(limit * 2, 16) : limit,
18418
- minSimilarity: vaultMinScore,
18419
- useFusion: true,
18420
- rerank: flags.rerank,
18421
- ...options.rerankTopN !== void 0 && { rerankTopN: options.rerankTopN },
18422
- ...options.ceWeight !== void 0 && { ceWeight: options.ceWeight },
18423
- ...options.rerankLoadTimeoutMs !== void 0 && {
18424
- rerankLoadTimeoutMs: options.rerankLoadTimeoutMs
18425
- },
18426
- ...options.recencyAlpha !== void 0 && { recencyAlpha: options.recencyAlpha },
18427
- ...options.recency && { recency: options.recency },
18428
- ...options.mmr !== void 0 && { mmr: options.mmr },
18429
- ...options.supersessionBoost !== void 0 && {
18430
- supersessionBoost: options.supersessionBoost
18431
- },
18432
- ...options.supersessionWindow !== void 0 && {
18433
- supersessionWindow: options.supersessionWindow
18434
- },
18435
- ...options.proofCountAlpha !== void 0 && {
18436
- proofCountAlpha: options.proofCountAlpha
18437
- },
18438
- ...options.bm25AdmissionDivisor !== void 0 && {
18439
- bm25AdmissionDivisor: options.bm25AdmissionDivisor
18440
- },
18441
- ...options.rrfK !== void 0 && { rrfK: options.rrfK },
18442
- ...options.decryptLast !== void 0 && { decryptLast: options.decryptLast },
18443
- ...subQueries && { subQueries },
18444
- ...options.scopes && { scopes: options.scopes },
18445
- ...options.folderId !== void 0 && { folderId: options.folderId },
18446
- ...options.factTypes?.length && { factTypes: options.factTypes },
18447
- ...options.memoryIds !== void 0 && { memoryIds: options.memoryIds },
18448
- ...options.factTypeWeights && { factTypeWeights: options.factTypeWeights },
18449
- ...entityRanking.length > 0 && { entityRanking },
18450
- ...temporalRanking.length > 0 && { temporalRanking },
18451
- ...needsChunkEmbedding && { queryEmbedding: queryEmbedding ?? [] },
18452
- queryEmbedTotalTimeoutMs
18453
- }
18454
- );
18639
+ searchOptions
18640
+ )))(query, {
18641
+ limit: types.includes("chunk") ? Math.max(limit * 2, 16) : limit,
18642
+ minSimilarity: vaultMinScore,
18643
+ useFusion: true,
18644
+ rerank: flags.rerank,
18645
+ ...options.rerankTopN !== void 0 && { rerankTopN: options.rerankTopN },
18646
+ ...options.ceWeight !== void 0 && { ceWeight: options.ceWeight },
18647
+ ...options.rerankLoadTimeoutMs !== void 0 && {
18648
+ rerankLoadTimeoutMs: options.rerankLoadTimeoutMs
18649
+ },
18650
+ ...options.recencyAlpha !== void 0 && { recencyAlpha: options.recencyAlpha },
18651
+ ...options.recency && { recency: options.recency },
18652
+ ...options.mmr !== void 0 && { mmr: options.mmr },
18653
+ ...options.supersessionBoost !== void 0 && {
18654
+ supersessionBoost: options.supersessionBoost
18655
+ },
18656
+ ...options.supersessionWindow !== void 0 && {
18657
+ supersessionWindow: options.supersessionWindow
18658
+ },
18659
+ ...options.proofCountAlpha !== void 0 && {
18660
+ proofCountAlpha: options.proofCountAlpha
18661
+ },
18662
+ ...options.bm25AdmissionDivisor !== void 0 && {
18663
+ bm25AdmissionDivisor: options.bm25AdmissionDivisor
18664
+ },
18665
+ ...options.rrfK !== void 0 && { rrfK: options.rrfK },
18666
+ ...options.decryptLast !== void 0 && { decryptLast: options.decryptLast },
18667
+ ...subQueries && { subQueries },
18668
+ ...options.scopes && { scopes: options.scopes },
18669
+ ...options.folderId !== void 0 && { folderId: options.folderId },
18670
+ ...options.factTypes?.length && { factTypes: options.factTypes },
18671
+ ...options.memoryIds !== void 0 && { memoryIds: options.memoryIds },
18672
+ ...options.factTypeWeights && { factTypeWeights: options.factTypeWeights },
18673
+ ...entityRanking.length > 0 && { entityRanking },
18674
+ ...temporalRanking.length > 0 && { temporalRanking },
18675
+ ...needsChunkEmbedding && { queryEmbedding: queryEmbedding ?? [] },
18676
+ queryEmbedTotalTimeoutMs
18677
+ });
18455
18678
  factResults.push(
18456
18679
  ...dedupeBy(
18457
18680
  results,
@@ -19264,26 +19487,26 @@ async function extractAndLinkEntitiesForMemoriesOp(ctx, memoryIds, options) {
19264
19487
  };
19265
19488
  const inputs = [];
19266
19489
  for (const id of new Set(memoryIds)) {
19267
- let record;
19490
+ let record2;
19268
19491
  try {
19269
- record = await ctx.vaultMemoryCollection.find(id);
19492
+ record2 = await ctx.vaultMemoryCollection.find(id);
19270
19493
  } catch (err) {
19271
19494
  log.warn("[memory/topics] vault lookup failed for extraction", err);
19272
19495
  skip(id, "not-found");
19273
19496
  continue;
19274
19497
  }
19275
- if (record.isDeleted || ctx.userId !== void 0 && record.userId !== ctx.userId || record.topicsUserManaged) {
19498
+ if (record2.isDeleted || ctx.userId !== void 0 && record2.userId !== ctx.userId || record2.topicsUserManaged) {
19276
19499
  skip(id, "excluded");
19277
19500
  continue;
19278
19501
  }
19279
19502
  try {
19280
- const stored = await vaultMemoryToStored(
19281
- record,
19503
+ const stored2 = await vaultMemoryToStored(
19504
+ record2,
19282
19505
  ctx.walletAddress,
19283
19506
  ctx.signMessage,
19284
19507
  ctx.embeddedWalletSigner
19285
19508
  );
19286
- inputs.push({ id, content: stored.content });
19509
+ inputs.push({ id, content: stored2.content });
19287
19510
  } catch (err) {
19288
19511
  log.warn("[memory/topics] failed to load memory for extraction", err);
19289
19512
  skip(id, "unreadable");
@@ -19468,6 +19691,781 @@ function createLocalMemoryStore(options) {
19468
19691
  };
19469
19692
  }
19470
19693
 
19694
+ // src/lib/memory/store/remotePersistence.ts
19695
+ var RemoteMemoryError = class extends Error {
19696
+ constructor(message, status, code) {
19697
+ super(message);
19698
+ this.status = status;
19699
+ this.code = code;
19700
+ this.name = "RemoteMemoryError";
19701
+ }
19702
+ };
19703
+ var ciphertextPattern = /^enc:v\d+:[0-9a-f]+$/i;
19704
+ var memoryFields = {
19705
+ memory_id: true,
19706
+ content: true,
19707
+ scope: true,
19708
+ created_at: true,
19709
+ updated_at: true,
19710
+ is_deleted: true,
19711
+ embedding: true,
19712
+ embedding_model: true,
19713
+ kind: true,
19714
+ kind_value: true,
19715
+ level: true,
19716
+ folder_id: true,
19717
+ source_chunk_ids: true,
19718
+ proof_count: true,
19719
+ source: true,
19720
+ event_time_start: true,
19721
+ event_time_end: true,
19722
+ event_time_kind: true,
19723
+ topics_user_managed: true,
19724
+ topics: true,
19725
+ topics_updated_at: true,
19726
+ media: true,
19727
+ topics_extracted_at: true,
19728
+ topics_extracted_version: true,
19729
+ superseded_by: true,
19730
+ superseded_at: true,
19731
+ last_observed_at: true,
19732
+ fact_type: true,
19733
+ archived_at: true,
19734
+ trust_tier: true,
19735
+ visibility: true,
19736
+ twin_opt_in: true,
19737
+ published_at: true,
19738
+ geohash: true
19739
+ };
19740
+ var candidateListLimits = [
19741
+ ["scopes", 20],
19742
+ ["fact_types", 20],
19743
+ ["memory_ids", 1e3],
19744
+ ["force_ids", 100]
19745
+ ];
19746
+ function record(value) {
19747
+ return typeof value === "object" && value !== null && !Array.isArray(value);
19748
+ }
19749
+ function memoryRecord(value) {
19750
+ if (!record(value) || !record(value.memory) || typeof value.memory.memory_id !== "string" || typeof value.memory.content !== "string" || typeof value.memory.scope !== "string" || typeof value.memory.created_at !== "number" || typeof value.memory.updated_at !== "number" || typeof value.memory.is_deleted !== "boolean" || !Number.isSafeInteger(value.version) || value.version < 1 || typeof value.server_updated_at !== "string" || value.score !== void 0 && (typeof value.score !== "number" || !Number.isFinite(value.score))) {
19751
+ throw new Error("Invalid nearby private-memory response");
19752
+ }
19753
+ return value;
19754
+ }
19755
+ async function createRemoteMemoryPersistence(options) {
19756
+ const base = new URL(options.baseUrl);
19757
+ if (!/^https?:$/.test(base.protocol) || base.username || base.password || base.search || base.hash) {
19758
+ throw new Error(
19759
+ "baseUrl must be an HTTP(S) origin or base path without credentials, query or fragment"
19760
+ );
19761
+ }
19762
+ if (!options.keyId || options.keyId.length > 256)
19763
+ throw new Error("A canonical keyId is required");
19764
+ const timeoutMs = options.timeoutMs ?? 3e4;
19765
+ if (!Number.isFinite(timeoutMs) || timeoutMs <= 0)
19766
+ throw new Error("timeoutMs must be a positive number");
19767
+ const root = base.href.replace(/\/$/, "") + "/api/private-memories";
19768
+ const fetcher = options.fetch ?? globalThis.fetch;
19769
+ const request = async (path, init = {}, signal) => {
19770
+ const controller = new AbortController();
19771
+ let timedOut = false;
19772
+ const timer = setTimeout(() => {
19773
+ timedOut = true;
19774
+ controller.abort();
19775
+ }, timeoutMs);
19776
+ const forwardAbort = () => controller.abort(signal?.reason);
19777
+ if (signal?.aborted) forwardAbort();
19778
+ else signal?.addEventListener("abort", forwardAbort, { once: true });
19779
+ let rejectAborted;
19780
+ const aborted = new Promise((_, reject) => {
19781
+ rejectAborted = () => reject(
19782
+ controller.signal.reason instanceof Error ? controller.signal.reason : new Error("Nearby request aborted")
19783
+ );
19784
+ if (controller.signal.aborted) rejectAborted();
19785
+ else controller.signal.addEventListener("abort", rejectAborted, { once: true });
19786
+ });
19787
+ aborted.catch(() => void 0);
19788
+ try {
19789
+ const token = await Promise.race([options.getToken(), aborted]);
19790
+ if (controller.signal.aborted) await aborted;
19791
+ if (!token) throw new RemoteMemoryError("Authentication required", 401);
19792
+ const response = await fetcher(root + path, {
19793
+ ...init,
19794
+ headers: {
19795
+ Authorization: `Bearer ${token}`,
19796
+ ...init.body ? { "Content-Type": "application/json" } : {}
19797
+ },
19798
+ redirect: "error",
19799
+ signal: controller.signal
19800
+ });
19801
+ if (!response.ok) {
19802
+ const body = await response.json().catch(() => null);
19803
+ throw new RemoteMemoryError(
19804
+ record(body) && typeof body.detail === "string" ? body.detail : `Nearby request failed (${response.status})`,
19805
+ response.status,
19806
+ record(body) && typeof body.code === "string" ? body.code : void 0
19807
+ );
19808
+ }
19809
+ return await response.json();
19810
+ } catch (error) {
19811
+ if (timedOut) throw new RemoteMemoryError("Nearby request timed out", 408, "timeout");
19812
+ throw error;
19813
+ } finally {
19814
+ clearTimeout(timer);
19815
+ signal?.removeEventListener("abort", forwardAbort);
19816
+ if (rejectAborted) controller.signal.removeEventListener("abort", rejectAborted);
19817
+ }
19818
+ };
19819
+ const account = await request("/account", {}, options.signal);
19820
+ if (!record(account) || account.state !== "active") {
19821
+ throw new RemoteMemoryError(
19822
+ "Complete and verify migration before using remote memories",
19823
+ 409,
19824
+ "memory_not_active"
19825
+ );
19826
+ }
19827
+ if (account.key_id !== options.keyId) {
19828
+ throw new RemoteMemoryError(
19829
+ "The canonical memory key does not match this account",
19830
+ 409,
19831
+ "key_mismatch"
19832
+ );
19833
+ }
19834
+ const snapshots = /* @__PURE__ */ new WeakMap();
19835
+ const decode = async (value) => {
19836
+ const item = memoryRecord(value);
19837
+ const decrypt = async (ciphertext) => {
19838
+ if (!ciphertextPattern.test(ciphertext))
19839
+ throw new Error("Nearby returned unencrypted memory content");
19840
+ const plaintext = await options.decrypt(ciphertext);
19841
+ if (plaintext === ciphertext) throw new Error("Memory decryption failed");
19842
+ return plaintext;
19843
+ };
19844
+ const decoded = {
19845
+ ...item,
19846
+ memory: {
19847
+ ...item.memory,
19848
+ content: await decrypt(item.memory.content),
19849
+ ...item.memory.kind_value !== void 0 && {
19850
+ kind_value: await decrypt(item.memory.kind_value)
19851
+ }
19852
+ }
19853
+ };
19854
+ return remember(decoded, item);
19855
+ };
19856
+ const remember = (decoded, item) => {
19857
+ snapshots.set(decoded, {
19858
+ id: item.memory.memory_id,
19859
+ version: item.version,
19860
+ content: decoded.memory.content,
19861
+ kindValue: decoded.memory.kind_value,
19862
+ encryptedContent: item.memory.content,
19863
+ encryptedKindValue: item.memory.kind_value
19864
+ });
19865
+ return decoded;
19866
+ };
19867
+ const decodeAll = async (values) => {
19868
+ const records = values.map(memoryRecord);
19869
+ const settled = await Promise.allSettled(records.map(decode));
19870
+ const items = [];
19871
+ const failed = [];
19872
+ settled.forEach((result, i) => {
19873
+ if (result.status === "fulfilled") items.push(result.value);
19874
+ else
19875
+ failed.push({
19876
+ memory_id: records[i].memory.memory_id,
19877
+ version: records[i].version,
19878
+ error: result.reason instanceof Error ? result.reason : new Error(String(result.reason))
19879
+ });
19880
+ });
19881
+ return { items, failed };
19882
+ };
19883
+ const decodeCommitted = async (value, write) => {
19884
+ const item = memoryRecord(value);
19885
+ if (item.memory.memory_id !== write.body.memory.memory_id || item.memory.content !== write.body.memory.content || item.memory.kind_value !== write.body.memory.kind_value)
19886
+ return decode(item);
19887
+ return remember(
19888
+ {
19889
+ ...item,
19890
+ memory: {
19891
+ ...item.memory,
19892
+ content: write.content,
19893
+ ...write.kindValue !== void 0 && { kind_value: write.kindValue }
19894
+ }
19895
+ },
19896
+ item
19897
+ );
19898
+ };
19899
+ const encryptField2 = async (plaintext) => {
19900
+ const ciphertext = await options.encrypt(plaintext);
19901
+ if (ciphertext === plaintext || !ciphertextPattern.test(ciphertext))
19902
+ throw new Error("Field encryption must return SDK ciphertext; refusing to upload plaintext");
19903
+ return ciphertext;
19904
+ };
19905
+ const memoryPath = (id) => {
19906
+ if (!id || id.length > 128) throw new Error("memory_id must be 1\u2013128 characters");
19907
+ return "/memories/" + encodeURIComponent(id);
19908
+ };
19909
+ const prepareWrite = async (memory, expectedVersion, signal) => {
19910
+ const unknown = Object.keys(memory).filter(
19911
+ (key) => !Object.prototype.hasOwnProperty.call(memoryFields, key)
19912
+ );
19913
+ if (unknown.length) {
19914
+ throw new RemoteMemoryError(
19915
+ `Unknown private-memory fields (${unknown.join(", ")}); refusing to forward them`,
19916
+ 400,
19917
+ "unknown_field"
19918
+ );
19919
+ }
19920
+ memory = { ...memory, ...memory.embedding && { embedding: [...memory.embedding] } };
19921
+ const path = memoryPath(memory.memory_id);
19922
+ const snapshot = typeof expectedVersion === "number" ? void 0 : snapshots.get(expectedVersion);
19923
+ if (typeof expectedVersion !== "number" && (!snapshot || snapshot.id !== memory.memory_id || snapshot.version !== expectedVersion.version))
19924
+ throw new Error(
19925
+ "Expected snapshot must be an unmodified version from this persistence instance"
19926
+ );
19927
+ expectedVersion = typeof expectedVersion === "number" ? expectedVersion : snapshot.version;
19928
+ if (!Number.isSafeInteger(expectedVersion) || expectedVersion < 0)
19929
+ throw new Error("expectedVersion must be a nonnegative integer");
19930
+ const conflict = () => new RemoteMemoryError("The memory changed since it was read", 409, "version_conflict");
19931
+ let existing;
19932
+ if (expectedVersion !== 0 && !snapshot) {
19933
+ try {
19934
+ existing = memoryRecord(await request(path, {}, signal));
19935
+ } catch (error) {
19936
+ if (error instanceof RemoteMemoryError && error.status === 404) throw conflict();
19937
+ throw error;
19938
+ }
19939
+ }
19940
+ if (existing && existing.version !== expectedVersion) throw conflict();
19941
+ const decoded = existing ? await decode(existing).catch(() => void 0) : void 0;
19942
+ const content = (snapshot?.content ?? decoded?.memory.content) === memory.content ? snapshot?.encryptedContent ?? existing.memory.content : await encryptField2(memory.content);
19943
+ const kindValue = memory.kind_value === void 0 ? void 0 : (snapshot?.kindValue ?? decoded?.memory.kind_value) === memory.kind_value ? snapshot?.encryptedKindValue ?? existing.memory.kind_value : await encryptField2(memory.kind_value);
19944
+ return {
19945
+ body: {
19946
+ expected_version: expectedVersion,
19947
+ memory: { ...memory, content, ...kindValue !== void 0 && { kind_value: kindValue } }
19948
+ },
19949
+ content: memory.content,
19950
+ kindValue: memory.kind_value
19951
+ };
19952
+ };
19953
+ const fetchCandidates = async (embedding, candidateOptions, withCounts) => {
19954
+ const limit = candidateOptions.limit ?? 100;
19955
+ if (!Number.isInteger(limit) || limit < 1 || limit > 100)
19956
+ throw new Error("Candidate limit must be 1\u2013100");
19957
+ for (const [key, max] of candidateListLimits) {
19958
+ const values = candidateOptions[key];
19959
+ if (values && values.length > max)
19960
+ throw new Error(`Candidate ${key} accepts at most ${max} entries (got ${values.length})`);
19961
+ }
19962
+ const result = await request(
19963
+ "/candidates",
19964
+ {
19965
+ method: "POST",
19966
+ body: JSON.stringify({
19967
+ embedding,
19968
+ limit,
19969
+ force_ids: candidateOptions.force_ids ?? [],
19970
+ ...withCounts && { with_counts: true },
19971
+ ...Object.fromEntries(
19972
+ [
19973
+ "scopes",
19974
+ "memory_ids",
19975
+ "embedding_model",
19976
+ "strict_model",
19977
+ "include_deleted",
19978
+ "deleted_only"
19979
+ ].filter(
19980
+ (key) => candidateOptions[key] !== void 0
19981
+ ).map((key) => [key, candidateOptions[key]])
19982
+ ),
19983
+ ...candidateOptions.fact_types !== void 0 && {
19984
+ fact_types: candidateOptions.fact_types
19985
+ },
19986
+ ...candidateOptions.include_archived !== void 0 && {
19987
+ include_archived: candidateOptions.include_archived
19988
+ },
19989
+ ...candidateOptions.include_quarantined !== void 0 && {
19990
+ include_quarantined: candidateOptions.include_quarantined
19991
+ },
19992
+ ...candidateOptions.include_superseded !== void 0 && {
19993
+ include_superseded: candidateOptions.include_superseded
19994
+ }
19995
+ })
19996
+ },
19997
+ candidateOptions.signal
19998
+ );
19999
+ if (!record(result) || !Array.isArray(result.items))
20000
+ throw new Error("Invalid nearby candidate response");
20001
+ return result;
20002
+ };
20003
+ const candidateSet = async (embedding, candidateOptions = {}) => {
20004
+ const result = await fetchCandidates(embedding, candidateOptions, true);
20005
+ if (!Number.isSafeInteger(result.total_count) || result.total_count < 0 || !Number.isSafeInteger(result.unavailable_count) || result.unavailable_count < 0)
20006
+ throw new Error("Invalid nearby candidate response");
20007
+ return {
20008
+ ...await decodeAll(result.items),
20009
+ total_count: result.total_count,
20010
+ unavailable_count: result.unavailable_count
20011
+ };
20012
+ };
20013
+ return {
20014
+ get: async (id, signal) => {
20015
+ try {
20016
+ return await decode(await request(memoryPath(id), {}, signal));
20017
+ } catch (error) {
20018
+ if (error instanceof RemoteMemoryError && error.status === 404) return null;
20019
+ throw error;
20020
+ }
20021
+ },
20022
+ list: async (listOptions = {}) => {
20023
+ const { signal, ...query } = listOptions;
20024
+ if (query.limit !== void 0 && (!Number.isInteger(query.limit) || query.limit < 1 || query.limit > 200)) {
20025
+ throw new Error("Page limit must be 1\u2013200");
20026
+ }
20027
+ const params = new URLSearchParams();
20028
+ for (const key of [
20029
+ "cursor",
20030
+ "limit",
20031
+ "include_deleted",
20032
+ "include_archived",
20033
+ "include_quarantined",
20034
+ "include_superseded",
20035
+ "include_embeddings"
20036
+ ]) {
20037
+ if (query[key] !== void 0) params.set(key, String(query[key]));
20038
+ }
20039
+ const page = await request("/memories?" + params.toString(), {}, signal);
20040
+ if (!record(page) || !Array.isArray(page.items) || page.next_cursor !== void 0 && typeof page.next_cursor !== "string") {
20041
+ throw new Error("Invalid nearby private-memory page");
20042
+ }
20043
+ return {
20044
+ ...await decodeAll(page.items),
20045
+ ...page.next_cursor !== void 0 && { next_cursor: page.next_cursor }
20046
+ };
20047
+ },
20048
+ put: async (memory, expectedVersion, signal) => {
20049
+ const write = await prepareWrite(memory, expectedVersion, signal);
20050
+ return decodeCommitted(
20051
+ await request(
20052
+ memoryPath(write.body.memory.memory_id),
20053
+ {
20054
+ method: "PUT",
20055
+ body: JSON.stringify({ key_id: options.keyId, ...write.body })
20056
+ },
20057
+ signal
20058
+ ),
20059
+ write
20060
+ );
20061
+ },
20062
+ putMany: async (writes, signal) => {
20063
+ if (writes.length < 1 || writes.length > 50 || new Set(writes.map((w) => w.memory.memory_id)).size !== writes.length)
20064
+ throw new Error("Batch must contain 1\u201350 distinct memory ids");
20065
+ const prepared = await Promise.all(
20066
+ writes.map((w) => prepareWrite(w.memory, w.expectedVersion, signal))
20067
+ );
20068
+ const result = await request(
20069
+ "/memories/batch",
20070
+ {
20071
+ method: "POST",
20072
+ body: JSON.stringify({ key_id: options.keyId, writes: prepared.map((w) => w.body) })
20073
+ },
20074
+ signal
20075
+ );
20076
+ if (!record(result) || !Array.isArray(result.items) || result.items.length !== prepared.length)
20077
+ throw new Error("Invalid nearby batch response");
20078
+ return Promise.all(result.items.map((item, i) => decodeCommitted(item, prepared[i])));
20079
+ },
20080
+ candidateSet,
20081
+ candidates: async (embedding, candidateOptions = {}) => decodeAll((await fetchCandidates(embedding, candidateOptions, false)).items)
20082
+ };
20083
+ }
20084
+
20085
+ // src/lib/memory/store/remotePipeline.ts
20086
+ var import_uuid4 = require("uuid");
20087
+ init_logger();
20088
+ function storedVector(vector) {
20089
+ if (!Array.isArray(vector) || vector.length !== 1536 && vector.length !== 4096 || vector.some((v) => !Number.isFinite(v)))
20090
+ throw new Error("Remote memories require a finite 1536/4096-dimensional vector");
20091
+ const out = vector.slice(0, 1536);
20092
+ const norm = Math.sqrt(out.reduce((sum, v) => sum + v * v, 0));
20093
+ if (!norm) throw new Error("Remote query/content vector has no direction after MRL truncation");
20094
+ return out.map((v) => v / norm);
20095
+ }
20096
+ function sourceIds(value) {
20097
+ if (!value) return [];
20098
+ try {
20099
+ const parsed = JSON.parse(value);
20100
+ return Array.isArray(parsed) ? parsed.filter((id) => typeof id === "string") : [];
20101
+ } catch {
20102
+ return [];
20103
+ }
20104
+ }
20105
+ function isMemoryLevel(value) {
20106
+ return MEMORY_LEVELS.includes(value);
20107
+ }
20108
+ function stored(row) {
20109
+ return {
20110
+ uniqueId: row.memory_id,
20111
+ content: row.content,
20112
+ scope: row.scope,
20113
+ folderId: row.folder_id ?? null,
20114
+ userId: null,
20115
+ kind: row.kind ?? null,
20116
+ kindValue: row.kind_value ?? null,
20117
+ ...isMemoryLevel(row.level) && { level: row.level },
20118
+ embedding: row.embedding ? JSON.stringify(row.embedding) : null,
20119
+ embeddingModel: row.embedding_model ?? null,
20120
+ sourceChunkIds: row.source_chunk_ids === void 0 ? null : sourceIds(row.source_chunk_ids),
20121
+ proofCount: row.proof_count ?? null,
20122
+ source: row.source ?? null,
20123
+ media: parseMedia(row.media),
20124
+ eventTimeStart: row.event_time_start ?? null,
20125
+ eventTimeEnd: row.event_time_end ?? null,
20126
+ eventTimeKind: row.event_time_kind ?? null,
20127
+ topicsUserManaged: row.topics_user_managed ?? false,
20128
+ topics: parseTopics(row.topics),
20129
+ topicsUpdatedAt: row.topics_updated_at ?? null,
20130
+ topicsExtractedAt: row.topics_extracted_at ?? null,
20131
+ topicsExtractedVersion: row.topics_extracted_version ?? null,
20132
+ supersededBy: row.superseded_by ?? null,
20133
+ supersededAt: row.superseded_at ?? null,
20134
+ lastObservedAt: row.last_observed_at ?? null,
20135
+ factType: row.fact_type ?? null,
20136
+ archivedAt: row.archived_at ?? null,
20137
+ trustTier: row.trust_tier ?? null,
20138
+ visibility: row.visibility === "public" ? "public" : "private",
20139
+ twinOptIn: row.twin_opt_in ?? false,
20140
+ publishedAt: row.published_at ?? null,
20141
+ geohash: row.geohash ?? null,
20142
+ createdAt: new Date(row.created_at),
20143
+ updatedAt: new Date(row.updated_at),
20144
+ isDeleted: row.is_deleted
20145
+ };
20146
+ }
20147
+ function createRemoteMemoryPipeline(options) {
20148
+ const { persistence, embeddingOptions } = options;
20149
+ const model = embeddingOptions.model ?? DEFAULT_API_EMBEDDING_MODEL;
20150
+ const operation = (mode) => {
20151
+ const rejectUndecryptable = (failed) => {
20152
+ if (!failed.length) return;
20153
+ if (mode === "retain")
20154
+ throw new Error(
20155
+ `Remote memories could not decrypt ${failed.length} candidate row(s); refusing to retain until they are repaired`
20156
+ );
20157
+ getLogger().warn(
20158
+ `[memory/remote] Skipping ${failed.length} undecryptable candidate row(s)`,
20159
+ failed.map((failure) => failure.memory_id)
20160
+ );
20161
+ };
20162
+ const snapshots = /* @__PURE__ */ new Map();
20163
+ const remember = (items) => {
20164
+ items.forEach((item) => snapshots.set(item.memory.memory_id, item));
20165
+ return items.map((item) => stored(item.memory));
20166
+ };
20167
+ const get = async (id) => {
20168
+ const snapshot = snapshots.get(id) ?? await persistence.get(id);
20169
+ if (!snapshot || snapshot.memory.is_deleted || snapshot.memory.superseded_by) return null;
20170
+ snapshots.set(id, snapshot);
20171
+ return stored(snapshot.memory);
20172
+ };
20173
+ const prepare = async (query, search = {}) => {
20174
+ if (search.folderId !== void 0)
20175
+ throw new Error("Remote memories do not support folder filters");
20176
+ const facets = normalizeSubQueries(search.subQueries);
20177
+ const facetQueries = facets.length >= 2 ? facets : [];
20178
+ const start = Date.now();
20179
+ const budgetMs = search.queryEmbedTotalTimeoutMs ?? 8e3;
20180
+ const embed = (texts) => generateEmbeddings(texts, {
20181
+ ...embeddingOptions,
20182
+ totalTimeoutMs: budgetMs
20183
+ });
20184
+ const embedFacets = async () => {
20185
+ if (!facetQueries.length) return [];
20186
+ try {
20187
+ const vectors2 = await embed(facetQueries);
20188
+ if (vectors2.length !== facetQueries.length)
20189
+ throw new Error("Incomplete facet embeddings");
20190
+ return vectors2.map(storedVector);
20191
+ } catch (error) {
20192
+ getLogger().warn(
20193
+ "[memory/remote] Facet embeddings unavailable; using primary query",
20194
+ error
20195
+ );
20196
+ return [];
20197
+ }
20198
+ };
20199
+ const [primary, facetEmbeddings] = await Promise.all([
20200
+ search.queryEmbedding ?? embed([query]).then((vectors2) => vectors2[0]),
20201
+ embedFacets()
20202
+ ]);
20203
+ const queryEmbedding = storedVector(primary);
20204
+ const queryEmbedMs = Date.now() - start;
20205
+ const graph = search.entityRanking ?? [];
20206
+ const temporal = search.temporalRanking ?? [];
20207
+ const forced = /* @__PURE__ */ new Set();
20208
+ for (let i = 0; i < Math.max(graph.length, temporal.length) && forced.size < 100; i++) {
20209
+ if (graph[i] !== void 0) forced.add(graph[i]);
20210
+ if (forced.size < 100 && temporal[i] !== void 0) forced.add(temporal[i]);
20211
+ }
20212
+ const forceIds = [...forced];
20213
+ const windowOptions = (i, signal) => ({
20214
+ limit: Math.min(100, Math.max((search.limit ?? 8) * 3, 30)),
20215
+ force_ids: i === 0 ? forceIds : [],
20216
+ ...search.scopes && { scopes: search.scopes },
20217
+ ...search.factTypes && { fact_types: search.factTypes },
20218
+ ...search.memoryIds !== void 0 && { memory_ids: search.memoryIds },
20219
+ include_archived: search.includeArchived,
20220
+ embedding_model: model,
20221
+ ...signal && { signal }
20222
+ });
20223
+ const vectors = [queryEmbedding, ...facetEmbeddings];
20224
+ let windows;
20225
+ if (mode === "retain") {
20226
+ windows = await Promise.all(
20227
+ vectors.map((embedding, i) => persistence.candidateSet(embedding, windowOptions(i)))
20228
+ );
20229
+ } else {
20230
+ const deadline = new AbortController();
20231
+ const timer = setTimeout(
20232
+ () => deadline.abort(
20233
+ new RemoteMemoryError("Remote recall exceeded its query budget", 408, "timeout")
20234
+ ),
20235
+ Math.max(0, start + budgetMs - Date.now())
20236
+ );
20237
+ try {
20238
+ windows = await Promise.all(
20239
+ vectors.map(
20240
+ (embedding, i) => persistence.candidates(embedding, windowOptions(i, deadline.signal))
20241
+ )
20242
+ );
20243
+ } finally {
20244
+ clearTimeout(timer);
20245
+ }
20246
+ }
20247
+ rejectUndecryptable([
20248
+ ...new Map(
20249
+ windows.flatMap((window2) => window2.failed).map((failure) => [failure.memory_id, failure])
20250
+ ).values()
20251
+ ]);
20252
+ const items = [
20253
+ ...new Map(
20254
+ windows.flatMap((window2) => window2.items).map((item) => [item.memory.memory_id, item])
20255
+ ).values()
20256
+ ];
20257
+ const memories = remember(items);
20258
+ return {
20259
+ memories,
20260
+ embeddedItems: memories.map((memory) => ({
20261
+ id: memory.uniqueId,
20262
+ content: memory.content,
20263
+ embedding: JSON.parse(memory.embedding ?? "[]"),
20264
+ createdAt: memory.createdAt,
20265
+ updatedAt: memory.updatedAt,
20266
+ proofCount: memory.proofCount,
20267
+ lastObservedAt: memory.lastObservedAt,
20268
+ eventTimeStart: memory.eventTimeStart,
20269
+ eventTimeEnd: memory.eventTimeEnd,
20270
+ eventTimeKind: memory.eventTimeKind === "point" || memory.eventTimeKind === "range" || memory.eventTimeKind === "ongoing" ? memory.eventTimeKind : null,
20271
+ factType: memory.factType,
20272
+ sourceChunkIds: memory.sourceChunkIds
20273
+ })),
20274
+ queryEmbedding,
20275
+ facetEmbeddings,
20276
+ vaultSize: Math.max(windows[0].total_count ?? 0, items.length),
20277
+ embeddingFailure: windows.some((window2) => (window2.unavailable_count ?? 0) > 0),
20278
+ embeddingsUnavailable: (windows[0].total_count ?? items.length) > 0 && !memories.some((memory) => memory.embedding),
20279
+ decryptLast: true,
20280
+ rowsDecrypted: items.length,
20281
+ queryEmbedMs,
20282
+ rowsEmbedded: 0
20283
+ };
20284
+ };
20285
+ const createRow = (input) => {
20286
+ if (input.folderId !== void 0 && input.folderId !== null)
20287
+ throw new Error("Remote memories do not support folders");
20288
+ const now = Date.now();
20289
+ return {
20290
+ memory_id: (0, import_uuid4.v7)(),
20291
+ content: input.content,
20292
+ scope: input.scope ?? "private",
20293
+ created_at: now,
20294
+ updated_at: now,
20295
+ is_deleted: false,
20296
+ ...input.embedding !== void 0 && {
20297
+ embedding: storedVector(JSON.parse(input.embedding)),
20298
+ embedding_model: input.embeddingModel
20299
+ },
20300
+ source_chunk_ids: JSON.stringify(input.sourceChunkIds ?? []),
20301
+ proof_count: input.proofCount ?? 1,
20302
+ source: input.source ?? "manual",
20303
+ ...input.eventTime && {
20304
+ event_time_start: input.eventTime.start ?? void 0,
20305
+ event_time_end: input.eventTime.end ?? void 0,
20306
+ event_time_kind: input.eventTime.kind ?? void 0
20307
+ },
20308
+ fact_type: input.factType,
20309
+ trust_tier: normalizeTrustTier(input.trustTier) ?? void 0,
20310
+ geohash: input.geohash,
20311
+ visibility: "private",
20312
+ twin_opt_in: false
20313
+ };
20314
+ };
20315
+ const write = async (memory, snapshot) => remember([await persistence.put(memory, snapshot)])[0];
20316
+ const port = {
20317
+ prepare,
20318
+ get,
20319
+ getFresh: async (id) => {
20320
+ const current = await persistence.get(id);
20321
+ return current && !current.memory.is_deleted && !current.memory.superseded_by ? stored(current.memory) : null;
20322
+ },
20323
+ tombstones: async (embedding, embeddingModel, scope, folderId) => {
20324
+ if (folderId !== void 0) throw new Error("Remote memories do not support folders");
20325
+ const window2 = await persistence.candidateSet(storedVector(embedding), {
20326
+ limit: 1,
20327
+ scopes: [scope],
20328
+ embedding_model: embeddingModel,
20329
+ strict_model: true,
20330
+ include_deleted: true,
20331
+ deleted_only: true
20332
+ });
20333
+ rejectUndecryptable(window2.failed);
20334
+ return remember(window2.items);
20335
+ },
20336
+ create: (input) => write(createRow(input), 0),
20337
+ update: async (id, patch) => {
20338
+ const existing = await get(id);
20339
+ if (!existing || patch.freeFormOnly && existing.kind !== null && existing.kind !== void 0)
20340
+ return null;
20341
+ const snapshot = snapshots.get(id);
20342
+ const memory = {
20343
+ ...snapshot.memory,
20344
+ content: patch.content,
20345
+ updated_at: patch.preserveUpdatedAt ? snapshot.memory.updated_at : Date.now()
20346
+ };
20347
+ if (patch.scope !== void 0) memory.scope = patch.scope;
20348
+ if (patch.embedding === void 0 && patch.content !== snapshot.memory.content) {
20349
+ delete memory.embedding;
20350
+ delete memory.embedding_model;
20351
+ }
20352
+ if (patch.embedding !== void 0) {
20353
+ memory.embedding = patch.embedding === null ? [] : storedVector(JSON.parse(patch.embedding));
20354
+ memory.embedding_model = patch.embeddingModel ?? void 0;
20355
+ }
20356
+ const observed = sourceIds(memory.source_chunk_ids);
20357
+ const replay = !!patch.observationSourceIds?.length && patch.observationSourceIds.every((id2) => observed.includes(id2));
20358
+ if (patch.sourceChunkIds !== void 0)
20359
+ memory.source_chunk_ids = JSON.stringify(
20360
+ patch.observationSourceIds?.length ? [.../* @__PURE__ */ new Set([...observed, ...patch.sourceChunkIds])] : patch.sourceChunkIds
20361
+ );
20362
+ if (!replay) {
20363
+ if (patch.proofCountIncrement !== void 0)
20364
+ memory.proof_count = (memory.proof_count ?? 1) + patch.proofCountIncrement;
20365
+ else if (patch.proofCount !== void 0) memory.proof_count = patch.proofCount;
20366
+ if (patch.lastObservedAt !== void 0) memory.last_observed_at = patch.lastObservedAt;
20367
+ }
20368
+ if (patch.source !== void 0) memory.source = patch.source;
20369
+ if (patch.factType !== void 0) memory.fact_type = patch.factType;
20370
+ if (patch.trustTier !== void 0)
20371
+ memory.trust_tier = normalizeTrustTier(patch.trustTier) ?? void 0;
20372
+ if (patch.topicsUserManaged !== void 0)
20373
+ memory.topics_user_managed = patch.topicsUserManaged;
20374
+ if (patch.eventTime !== void 0) {
20375
+ memory.event_time_start = patch.eventTime.start ?? void 0;
20376
+ memory.event_time_end = patch.eventTime.end ?? void 0;
20377
+ memory.event_time_kind = patch.eventTime.kind ?? void 0;
20378
+ }
20379
+ if (patch.restore) memory.archived_at = void 0;
20380
+ return write(memory, snapshot);
20381
+ },
20382
+ supersede: async (id, successor) => {
20383
+ const [target, newer] = await Promise.all([get(id), get(successor)]);
20384
+ if (!target || !newer || id === successor) return false;
20385
+ const old = snapshots.get(id);
20386
+ const next = snapshots.get(successor);
20387
+ remember(
20388
+ await persistence.putMany([
20389
+ {
20390
+ memory: { ...old.memory, superseded_by: successor, superseded_at: Date.now() },
20391
+ expectedVersion: old
20392
+ },
20393
+ { memory: next.memory, expectedVersion: next }
20394
+ ])
20395
+ );
20396
+ return true;
20397
+ },
20398
+ createSuperseding: async (input, targetId) => {
20399
+ const target = await get(targetId);
20400
+ if (!target) return { created: null, retired: false };
20401
+ const snapshot = snapshots.get(targetId);
20402
+ const successor = createRow(input);
20403
+ const rows = remember(
20404
+ await persistence.putMany([
20405
+ { memory: successor, expectedVersion: 0 },
20406
+ {
20407
+ memory: {
20408
+ ...snapshot.memory,
20409
+ superseded_by: successor.memory_id,
20410
+ superseded_at: Date.now()
20411
+ },
20412
+ expectedVersion: snapshot
20413
+ }
20414
+ ])
20415
+ );
20416
+ return { created: rows[0], retired: true };
20417
+ }
20418
+ };
20419
+ return { prepare, port };
20420
+ };
20421
+ return {
20422
+ recall: async (query, recallOptions = {}) => {
20423
+ const { prepare } = operation("recall");
20424
+ return recall(
20425
+ query,
20426
+ {
20427
+ embeddingOptions,
20428
+ factSource: {
20429
+ graphRanking: options.graphRanking,
20430
+ temporalRanking: options.temporalRanking,
20431
+ search: async (text12, searchOptions) => {
20432
+ const prepared = await prepare(text12, searchOptions);
20433
+ const ranked = await rankPreparedVaultCandidates(
20434
+ text12,
20435
+ prepared,
20436
+ embeddingOptions,
20437
+ searchOptions
20438
+ );
20439
+ return {
20440
+ ...ranked,
20441
+ rankedOnCosine: prepared.memories.length > 0 && !prepared.embeddingsUnavailable,
20442
+ decryptLast: true,
20443
+ rowsDecrypted: prepared.rowsDecrypted,
20444
+ queryEmbedMs: prepared.queryEmbedMs,
20445
+ rowsEmbedded: 0
20446
+ };
20447
+ }
20448
+ }
20449
+ },
20450
+ { ...recallOptions, types: ["fact"] }
20451
+ );
20452
+ },
20453
+ retain: async (content, retainOptions) => {
20454
+ const { port } = operation("retain");
20455
+ return retainWithPersistence(
20456
+ content,
20457
+ {
20458
+ persistence: port,
20459
+ embeddingOptions,
20460
+ vaultCache: /* @__PURE__ */ new Map(),
20461
+ normalizeEmbedding: storedVector
20462
+ },
20463
+ retainOptions
20464
+ );
20465
+ }
20466
+ };
20467
+ }
20468
+
19471
20469
  // src/lib/memory/synthesizeProfile.ts
19472
20470
  init_internalFlowMarker();
19473
20471
  init_logger();
@@ -22893,7 +23891,7 @@ function useChat(options) {
22893
23891
 
22894
23892
  // src/expo/useChatStorage.ts
22895
23893
  var import_react5 = require("react");
22896
- var import_uuid5 = require("uuid");
23894
+ var import_uuid6 = require("uuid");
22897
23895
  init_clientConfig();
22898
23896
 
22899
23897
  // src/lib/chat/assembleMessages.ts
@@ -23556,9 +24554,9 @@ async function decryptMediaFields(media, address, signMessage, embeddedWalletSig
23556
24554
  }
23557
24555
 
23558
24556
  // src/lib/db/media/types.ts
23559
- var import_uuid4 = require("uuid");
24557
+ var import_uuid5 = require("uuid");
23560
24558
  function generateMediaId() {
23561
- return `media_${(0, import_uuid4.v7)()}`;
24559
+ return `media_${(0, import_uuid5.v7)()}`;
23562
24560
  }
23563
24561
 
23564
24562
  // src/lib/db/media/operations.ts
@@ -23769,10 +24767,10 @@ function extractImageModelFromToolEvents(toolCallEvents) {
23769
24767
  }
23770
24768
  return void 0;
23771
24769
  }
23772
- function storedToLlmapiMessage(stored) {
23773
- const content = [{ type: "text", text: stored.content }];
23774
- if (stored.role !== "assistant" && stored.files?.length) {
23775
- for (const file of stored.files) {
24770
+ function storedToLlmapiMessage(stored2) {
24771
+ const content = [{ type: "text", text: stored2.content }];
24772
+ if (stored2.role !== "assistant" && stored2.files?.length) {
24773
+ for (const file of stored2.files) {
23776
24774
  if (isSendableImageURL(file.url)) {
23777
24775
  content.push({
23778
24776
  type: "image_url",
@@ -23782,11 +24780,11 @@ function storedToLlmapiMessage(stored) {
23782
24780
  }
23783
24781
  }
23784
24782
  const messages = [];
23785
- if (stored.role === "assistant" && stored.toolCallEvents?.length) {
24783
+ if (stored2.role === "assistant" && stored2.toolCallEvents?.length) {
23786
24784
  messages.push({
23787
- role: stored.role,
24785
+ role: stored2.role,
23788
24786
  content: void 0,
23789
- tool_calls: stored.toolCallEvents.map((event) => ({
24787
+ tool_calls: stored2.toolCallEvents.map((event) => ({
23790
24788
  id: event.id,
23791
24789
  type: "function",
23792
24790
  function: {
@@ -23795,7 +24793,7 @@ function storedToLlmapiMessage(stored) {
23795
24793
  }
23796
24794
  }))
23797
24795
  });
23798
- for (const event of stored.toolCallEvents) {
24796
+ for (const event of stored2.toolCallEvents) {
23799
24797
  if (event.id && event.output !== void 0 && event.output !== null) {
23800
24798
  messages.push({
23801
24799
  role: "tool",
@@ -23804,14 +24802,14 @@ function storedToLlmapiMessage(stored) {
23804
24802
  });
23805
24803
  }
23806
24804
  }
23807
- const postToolText = stored.content.replace(/!\[[^\]]*\]\(https?:\/\/[a-z0-9]+\.r2\.cloudflarestorage\.com\/[^)]+\)/g, "").replace(/https?:\/\/[a-z0-9]+\.r2\.cloudflarestorage\.com\/[^\s)]+/g, "").replace(/!\[[^\]]*\]\(https?:\/\/[^)\s]+\/api\/v1\/media\/[^/)\s]+\/[^)]+\)/g, "").replace(/https?:\/\/[^\s)]+\/api\/v1\/media\/[^/\s)]+\/[^\s)]+/g, "").replace(/\n{3,}/g, "\n\n").trim();
24805
+ const postToolText = stored2.content.replace(/!\[[^\]]*\]\(https?:\/\/[a-z0-9]+\.r2\.cloudflarestorage\.com\/[^)]+\)/g, "").replace(/https?:\/\/[a-z0-9]+\.r2\.cloudflarestorage\.com\/[^\s)]+/g, "").replace(/!\[[^\]]*\]\(https?:\/\/[^)\s]+\/api\/v1\/media\/[^/)\s]+\/[^)]+\)/g, "").replace(/https?:\/\/[^\s)]+\/api\/v1\/media\/[^/\s)]+\/[^\s)]+/g, "").replace(/\n{3,}/g, "\n\n").trim();
23808
24806
  messages.push({
23809
- role: stored.role,
24807
+ role: stored2.role,
23810
24808
  content: [{ type: "text", text: postToolText }]
23811
24809
  });
23812
24810
  } else {
23813
24811
  messages.push({
23814
- role: stored.role,
24812
+ role: stored2.role,
23815
24813
  content
23816
24814
  });
23817
24815
  }
@@ -24518,7 +25516,7 @@ function useChatStorage(options) {
24518
25516
  };
24519
25517
  };
24520
25518
  pendingResumeRef.current = null;
24521
- const effectiveAssistantUniqueId = assistantUniqueId ?? (resumable ? `msg_${(0, import_uuid5.v7)()}` : void 0);
25519
+ const effectiveAssistantUniqueId = assistantUniqueId ?? (resumable ? `msg_${(0, import_uuid6.v7)()}` : void 0);
24522
25520
  const embedToolText = (text12, mask, masked, token) => {
24523
25521
  const opts = {
24524
25522
  getToken: token,
@@ -25036,7 +26034,7 @@ function useChatStorage(options) {
25036
26034
  const detachedResult = result;
25037
26035
  if (detachedResult.detached) {
25038
26036
  recordToolSetTurn(database, convId, matchedToolSets);
25039
- const rowId = effectiveAssistantUniqueId ?? `msg_${(0, import_uuid5.v7)()}`;
26037
+ const rowId = effectiveAssistantUniqueId ?? `msg_${(0, import_uuid6.v7)()}`;
25040
26038
  pendingResumeRef.current = {
25041
26039
  handle: detachedResult.resume ?? null,
25042
26040
  convId,
@@ -25546,6 +26544,9 @@ function useChatStorage(options) {
25546
26544
  LoggerProvider,
25547
26545
  MAX_HOPS,
25548
26546
  MEDIUM_TTL_MS,
26547
+ MEMORY_KINDS,
26548
+ MEMORY_LEVELS,
26549
+ MemoryLevelError,
25549
26550
  NEVER_TTL_MS,
25550
26551
  NODE_BUDGET,
25551
26552
  NOTION_OAUTH_CONFIG,
@@ -25556,6 +26557,7 @@ function useChatStorage(options) {
25556
26557
  QueueManager,
25557
26558
  RECALL_MAX_LIMIT,
25558
26559
  RECALL_TOOL_NAME,
26560
+ RemoteMemoryError,
25559
26561
  RerankerUnavailableError,
25560
26562
  SDK_SCHEMA_VERSION,
25561
26563
  SHORT_TTL_MS,
@@ -25619,6 +26621,8 @@ function useChatStorage(options) {
25619
26621
  createNotionTools,
25620
26622
  createPlatformCursorStore,
25621
26623
  createRecallTool,
26624
+ createRemoteMemoryPersistence,
26625
+ createRemoteMemoryPipeline,
25622
26626
  createStockPricePreProcessor,
25623
26627
  createStreamingDeAnonymizer,
25624
26628
  createVaultEmbeddingCache,