@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.
@@ -2622,13 +2622,13 @@ async function searchChunksOp(ctx, queryVector, options) {
2622
2622
  const storedById = new Map(
2623
2623
  await Promise.all(
2624
2624
  Array.from(uniqueMessages, async ([id, m]) => {
2625
- const stored = await messageRawToStored(
2625
+ const stored2 = await messageRawToStored(
2626
2626
  m,
2627
2627
  ctx.walletAddress,
2628
2628
  ctx.signMessage,
2629
2629
  ctx.embeddedWalletSigner
2630
2630
  );
2631
- return [id, stored];
2631
+ return [id, stored2];
2632
2632
  })
2633
2633
  )
2634
2634
  );
@@ -2646,18 +2646,18 @@ async function searchChunksOp(ctx, queryVector, options) {
2646
2646
  })
2647
2647
  );
2648
2648
  return topK.map(({ message, similarity, chunkTextSource }) => {
2649
- const stored = { ...storedById.get(message.id) };
2649
+ const stored2 = { ...storedById.get(message.id) };
2650
2650
  let chunkText2;
2651
2651
  if (chunkTextSource.kind === "chunk") {
2652
- chunkText2 = resolveChunkText(stored.content, chunkTextSource.chunk, chunkTextSource.siblings);
2652
+ chunkText2 = resolveChunkText(stored2.content, chunkTextSource.chunk, chunkTextSource.siblings);
2653
2653
  } else if (chunkTextSource.kind === "chunk-cached") {
2654
2654
  const state = chunkStateByMsgId.get(message.id);
2655
2655
  const chunk = state && state.version === chunkTextSource.version ? state.chunks[chunkTextSource.chunkIndex] : void 0;
2656
- chunkText2 = resolveChunkText(stored.content, chunk, state?.chunks);
2656
+ chunkText2 = resolveChunkText(stored2.content, chunk, state?.chunks);
2657
2657
  } else {
2658
- chunkText2 = stored.content;
2658
+ chunkText2 = stored2.content;
2659
2659
  }
2660
- return { chunkText: chunkText2, message: stored, similarity };
2660
+ return { chunkText: chunkText2, message: stored2, similarity };
2661
2661
  });
2662
2662
  }
2663
2663
  function makeSyntheticStoredMessage(opts) {
@@ -3776,7 +3776,7 @@ async function embedOne(text12, options, outer) {
3776
3776
  }
3777
3777
  var DEFAULT_EMBEDDING_BATCH_SIZE = 100;
3778
3778
  var DEFAULT_EMBEDDING_BATCH_CONCURRENCY = 3;
3779
- async function generateEmbeddingsBatch(texts, headers, baseUrl, model, onUsage, maskInput, timeoutMs) {
3779
+ async function generateEmbeddingsBatch(texts, headers, baseUrl, model, onUsage, maskInput, timeoutMs, outer) {
3780
3780
  const response = await withEmbeddingRetry(
3781
3781
  () => withDeadline(
3782
3782
  (signal) => postApiV1Embeddings({
@@ -3786,8 +3786,10 @@ async function generateEmbeddingsBatch(texts, headers, baseUrl, model, onUsage,
3786
3786
  ...signal && { signal }
3787
3787
  }),
3788
3788
  timeoutMs,
3789
- "embedding batch request"
3790
- )
3789
+ "embedding batch request",
3790
+ outer
3791
+ ),
3792
+ outer
3791
3793
  );
3792
3794
  if (response.error) {
3793
3795
  throw embeddingErrorFrom(response);
@@ -3805,6 +3807,11 @@ async function generateEmbeddingsBatch(texts, headers, baseUrl, model, onUsage,
3805
3807
  }
3806
3808
  async function generateEmbeddings(texts, options) {
3807
3809
  if (texts.length === 0) return [];
3810
+ const total = options.totalTimeoutMs;
3811
+ if (total === void 0) return embedMany(texts, options, void 0);
3812
+ return withDeadline((signal) => embedMany(texts, options, signal), total, "embedding batch");
3813
+ }
3814
+ async function embedMany(texts, options, outer) {
3808
3815
  const { baseUrl = BASE_URL, model, batchSize, cache } = options;
3809
3816
  const timeoutMs = options.timeoutMs ?? DEFAULT_EMBEDDING_REQUEST_TIMEOUT_MS;
3810
3817
  const chunkSize = batchSize ?? DEFAULT_EMBEDDING_BATCH_SIZE;
@@ -3825,7 +3832,8 @@ async function generateEmbeddings(texts, options) {
3825
3832
  if (uncachedTexts.length === 0) {
3826
3833
  return results;
3827
3834
  }
3828
- const headers = await resolveAuthHeaders(options);
3835
+ const headers = await resolveAuthHeaders(options, outer);
3836
+ if (outer?.aborted) throw outer.reason;
3829
3837
  const embeddingModel = model ?? DEFAULT_API_EMBEDDING_MODEL;
3830
3838
  let newEmbeddings;
3831
3839
  if (uncachedTexts.length <= chunkSize) {
@@ -3836,7 +3844,8 @@ async function generateEmbeddings(texts, options) {
3836
3844
  embeddingModel,
3837
3845
  options.onUsage,
3838
3846
  options.maskInput,
3839
- timeoutMs
3847
+ timeoutMs,
3848
+ outer
3840
3849
  );
3841
3850
  } else {
3842
3851
  const chunks = [];
@@ -3847,6 +3856,7 @@ async function generateEmbeddings(texts, options) {
3847
3856
  let nextIndex = 0;
3848
3857
  const worker = async () => {
3849
3858
  while (nextIndex < chunks.length) {
3859
+ if (outer?.aborted) throw outer.reason;
3850
3860
  const idx = nextIndex++;
3851
3861
  allEmbeddings[idx] = await generateEmbeddingsBatch(
3852
3862
  chunks[idx],
@@ -3855,7 +3865,8 @@ async function generateEmbeddings(texts, options) {
3855
3865
  embeddingModel,
3856
3866
  options.onUsage,
3857
3867
  options.maskInput,
3858
- timeoutMs
3868
+ timeoutMs,
3869
+ outer
3859
3870
  );
3860
3871
  }
3861
3872
  };
@@ -3866,6 +3877,7 @@ async function generateEmbeddings(texts, options) {
3866
3877
  await Promise.all(workers);
3867
3878
  newEmbeddings = allEmbeddings.flat();
3868
3879
  }
3880
+ if (outer?.aborted) throw outer.reason;
3869
3881
  for (let i = 0; i < uncachedIndices.length; i++) {
3870
3882
  const f32Embedding = Float32Array.from(newEmbeddings[i]);
3871
3883
  results[uncachedIndices[i]] = Array.from(f32Embedding);
@@ -8940,15 +8952,15 @@ function createSummaryContext(database) {
8940
8952
  summariesCollection: database.get("conversation_summaries")
8941
8953
  };
8942
8954
  }
8943
- function modelToStored(record) {
8955
+ function modelToStored(record2) {
8944
8956
  return {
8945
- uniqueId: record.id,
8946
- conversationId: record.conversationId,
8947
- summary: record.summary,
8948
- summarizedUpTo: record.summarizedUpTo,
8949
- tokenCount: record.tokenCount,
8950
- createdAt: record.createdAt,
8951
- updatedAt: record.updatedAt
8957
+ uniqueId: record2.id,
8958
+ conversationId: record2.conversationId,
8959
+ summary: record2.summary,
8960
+ summarizedUpTo: record2.summarizedUpTo,
8961
+ tokenCount: record2.tokenCount,
8962
+ createdAt: record2.createdAt,
8963
+ updatedAt: record2.updatedAt
8952
8964
  };
8953
8965
  }
8954
8966
  async function getConversationSummaryOp(ctx, conversationId) {
@@ -8957,17 +8969,17 @@ async function getConversationSummaryOp(ctx, conversationId) {
8957
8969
  return modelToStored(results[0]);
8958
8970
  }
8959
8971
  async function upsertConversationSummaryOp(ctx, conversationId, summary, summarizedUpTo, tokenCount) {
8960
- let record;
8972
+ let record2;
8961
8973
  await ctx.database.write(async () => {
8962
8974
  const existing = await ctx.summariesCollection.query(Q2.where("conversation_id", conversationId)).fetch();
8963
8975
  if (existing.length > 0) {
8964
- record = await existing[0].update((rec) => {
8976
+ record2 = await existing[0].update((rec) => {
8965
8977
  rec.summary = summary;
8966
8978
  rec.summarizedUpTo = summarizedUpTo;
8967
8979
  rec.tokenCount = tokenCount;
8968
8980
  });
8969
8981
  } else {
8970
- record = await ctx.summariesCollection.create((rec) => {
8982
+ record2 = await ctx.summariesCollection.create((rec) => {
8971
8983
  rec.conversationId = conversationId;
8972
8984
  rec.summary = summary;
8973
8985
  rec.summarizedUpTo = summarizedUpTo;
@@ -8975,13 +8987,13 @@ async function upsertConversationSummaryOp(ctx, conversationId, summary, summari
8975
8987
  });
8976
8988
  }
8977
8989
  });
8978
- return modelToStored(record);
8990
+ return modelToStored(record2);
8979
8991
  }
8980
8992
  async function deleteConversationSummaryOp(ctx, conversationId) {
8981
8993
  await ctx.database.write(async () => {
8982
8994
  const existing = await ctx.summariesCollection.query(Q2.where("conversation_id", conversationId)).fetch();
8983
- for (const record of existing) {
8984
- await record.destroyPermanently();
8995
+ for (const record2 of existing) {
8996
+ await record2.destroyPermanently();
8985
8997
  }
8986
8998
  });
8987
8999
  }
@@ -9234,6 +9246,15 @@ __decorateClass([
9234
9246
  __decorateClass([
9235
9247
  text6("scope")
9236
9248
  ], VaultMemory.prototype, "scope", 2);
9249
+ __decorateClass([
9250
+ field5("kind")
9251
+ ], VaultMemory.prototype, "kind", 2);
9252
+ __decorateClass([
9253
+ field5("kind_value")
9254
+ ], VaultMemory.prototype, "kindValue", 2);
9255
+ __decorateClass([
9256
+ field5("level")
9257
+ ], VaultMemory.prototype, "level", 2);
9237
9258
  __decorateClass([
9238
9259
  field5("folder_id")
9239
9260
  ], VaultMemory.prototype, "folderId", 2);
@@ -9459,7 +9480,7 @@ __decorateClass([
9459
9480
  ], VaultFolder.prototype, "context", 2);
9460
9481
 
9461
9482
  // src/lib/db/schema.ts
9462
- var SDK_SCHEMA_VERSION = 47;
9483
+ var SDK_SCHEMA_VERSION = 48;
9463
9484
  var sdkSchema = appSchema2({
9464
9485
  version: SDK_SCHEMA_VERSION,
9465
9486
  tables: [
@@ -9554,6 +9575,9 @@ var sdkSchema = appSchema2({
9554
9575
  columns: [
9555
9576
  { name: "content", type: "string" },
9556
9577
  { name: "scope", type: "string", isIndexed: true },
9578
+ { name: "kind", type: "string", isOptional: true, isIndexed: true },
9579
+ { name: "kind_value", type: "string", isOptional: true },
9580
+ { name: "level", type: "string", isOptional: true, isIndexed: true },
9557
9581
  { name: "folder_id", type: "string", isOptional: true, isIndexed: true },
9558
9582
  { name: "created_at", type: "number", isIndexed: true },
9559
9583
  { name: "updated_at", type: "number", isIndexed: true },
@@ -10230,6 +10254,22 @@ var sdkMigrations = schemaMigrations2({
10230
10254
  ]
10231
10255
  })
10232
10256
  ]
10257
+ },
10258
+ {
10259
+ toVersion: 48,
10260
+ steps: [
10261
+ addColumns2({
10262
+ table: "memory_vault",
10263
+ columns: [
10264
+ { name: "kind", type: "string", isOptional: true, isIndexed: true },
10265
+ { name: "kind_value", type: "string", isOptional: true },
10266
+ { name: "level", type: "string", isOptional: true, isIndexed: true }
10267
+ ]
10268
+ }),
10269
+ unsafeExecuteSql(
10270
+ "UPDATE memory_vault SET level = CASE WHEN scope IN ('shared', 'public') THEN 'matching' ELSE 'private' END WHERE level IS NULL;"
10271
+ )
10272
+ ]
10233
10273
  }
10234
10274
  ]
10235
10275
  });
@@ -10486,25 +10526,25 @@ async function upsertEntitiesInWrite(ctx, entities) {
10486
10526
  const kindBackfills = existing.filter((e) => {
10487
10527
  const incoming = kindByName.get(e.canonicalName);
10488
10528
  return incoming !== void 0 && (e.kind === null || e.kind === void 0 || e.kind === "");
10489
- }).map((record) => ({ record, kind: kindByName.get(record.canonicalName) }));
10529
+ }).map((record2) => ({ record: record2, kind: kindByName.get(record2.canonicalName) }));
10490
10530
  const missing = unique.filter((n) => !existingNames.has(n));
10491
10531
  const created = missing.map(
10492
- (name) => ctx.entityCollection.prepareCreate((record) => {
10493
- record._setRaw("canonical_name", name);
10532
+ (name) => ctx.entityCollection.prepareCreate((record2) => {
10533
+ record2._setRaw("canonical_name", name);
10494
10534
  const kind = kindByName.get(name);
10495
- if (kind !== void 0) record._setRaw("kind", kind);
10535
+ if (kind !== void 0) record2._setRaw("kind", kind);
10496
10536
  })
10497
10537
  );
10498
10538
  for (const e of existing) out.set(e.canonicalName, entityToStored(e));
10499
- for (const record of created) out.set(record.canonicalName, entityToStored(record));
10500
- for (const { record, kind } of kindBackfills) {
10501
- out.set(record.canonicalName, { ...entityToStored(record), kind });
10539
+ for (const record2 of created) out.set(record2.canonicalName, entityToStored(record2));
10540
+ for (const { record: record2, kind } of kindBackfills) {
10541
+ out.set(record2.canonicalName, { ...entityToStored(record2), kind });
10502
10542
  }
10503
10543
  return { entities: out, operations: created, kindBackfills };
10504
10544
  }
10505
10545
  function prepareKindBackfills(backfills) {
10506
10546
  return backfills.map(
10507
- ({ record, kind }) => record.prepareUpdate((r) => {
10547
+ ({ record: record2, kind }) => record2.prepareUpdate((r) => {
10508
10548
  r._setRaw("kind", kind);
10509
10549
  })
10510
10550
  );
@@ -10535,10 +10575,10 @@ function displayNamesOf(entities) {
10535
10575
  }
10536
10576
  return out;
10537
10577
  }
10538
- function topicsEqual(stored, computed) {
10539
- if (stored === null || stored.length !== computed.length) return false;
10578
+ function topicsEqual(stored2, computed) {
10579
+ if (stored2 === null || stored2.length !== computed.length) return false;
10540
10580
  const key = (t) => JSON.stringify([t.name, t.kind ?? null, t.source]);
10541
- const storedKeys = stored.map(key).sort();
10581
+ const storedKeys = stored2.map(key).sort();
10542
10582
  const computedKeys = computed.map(key).sort();
10543
10583
  return storedKeys.every((k, i) => k === computedKeys[i]);
10544
10584
  }
@@ -10604,10 +10644,10 @@ async function linkMemoryEntitiesOp(ctx, memoryId, entityInputs, options) {
10604
10644
  return;
10605
10645
  }
10606
10646
  const linkOps = toCreate.map(
10607
- (e) => ctx.memoryEntityCollection.prepareCreate((record) => {
10608
- record._setRaw("memory_id", memoryId);
10609
- record._setRaw("entity_id", e.uniqueId);
10610
- if (userId !== void 0) record._setRaw("user_id", userId);
10647
+ (e) => ctx.memoryEntityCollection.prepareCreate((record2) => {
10648
+ record2._setRaw("memory_id", memoryId);
10649
+ record2._setRaw("entity_id", e.uniqueId);
10650
+ if (userId !== void 0) record2._setRaw("user_id", userId);
10611
10651
  })
10612
10652
  );
10613
10653
  await ctx.database.batch(
@@ -10675,10 +10715,10 @@ async function replaceMemoryEntities(ctx, memoryId, entityInputs, options) {
10675
10715
  ...entityOps,
10676
10716
  ...prepareKindBackfills(kindBackfills),
10677
10717
  ...toCreate.map(
10678
- (e) => ctx.memoryEntityCollection.prepareCreate((record) => {
10679
- record._setRaw("memory_id", memoryId);
10680
- record._setRaw("entity_id", e.uniqueId);
10681
- if (userId !== void 0) record._setRaw("user_id", userId);
10718
+ (e) => ctx.memoryEntityCollection.prepareCreate((record2) => {
10719
+ record2._setRaw("memory_id", memoryId);
10720
+ record2._setRaw("entity_id", e.uniqueId);
10721
+ if (userId !== void 0) record2._setRaw("user_id", userId);
10682
10722
  })
10683
10723
  ),
10684
10724
  ...toDestroy.map((l) => l.prepareDestroyPermanently()),
@@ -10795,13 +10835,54 @@ async function decryptVaultMemoryFields(memory, address, signMessage, embeddedWa
10795
10835
  }
10796
10836
  }
10797
10837
  const decryptedContent = await decryptField(memory.content, address);
10838
+ const decryptedKindValue = typeof memory.kindValue === "string" ? await decryptField(memory.kindValue, address) : memory.kindValue;
10798
10839
  return {
10799
10840
  ...memory,
10800
- content: decryptedContent
10841
+ content: decryptedContent,
10842
+ ...decryptedKindValue !== void 0 && { kindValue: decryptedKindValue }
10801
10843
  };
10802
10844
  }
10803
10845
 
10804
10846
  // src/lib/db/memoryVault/types.ts
10847
+ var MEMORY_KINDS = [
10848
+ "display_name",
10849
+ "birth_date",
10850
+ "bio",
10851
+ "occupation",
10852
+ "interest",
10853
+ "gender",
10854
+ "height_cm",
10855
+ "looking_for",
10856
+ "politics",
10857
+ "religion",
10858
+ "ethnicity",
10859
+ "smoking",
10860
+ "drinking",
10861
+ "exercise",
10862
+ "sexuality",
10863
+ "prompt"
10864
+ ];
10865
+ var MEMORY_LEVELS = ["private", "matching", "profile"];
10866
+ var MemoryLevelError = class extends Error {
10867
+ constructor(message) {
10868
+ super(message);
10869
+ this.name = "MemoryLevelError";
10870
+ }
10871
+ };
10872
+ var PUBLISHED_SCOPES = /* @__PURE__ */ new Set(["shared", "public"]);
10873
+ function levelFromScope(scope) {
10874
+ return typeof scope === "string" && PUBLISHED_SCOPES.has(scope) ? "matching" : "private";
10875
+ }
10876
+ function scopeForLevel(level) {
10877
+ return level === "private" ? "private" : "shared";
10878
+ }
10879
+ function resolveMemoryLevel(level, scope) {
10880
+ return typeof level === "string" && MEMORY_LEVELS.includes(level) ? level : levelFromScope(scope);
10881
+ }
10882
+ function levelForScopeChange(current, nextScope) {
10883
+ const implied = levelFromScope(nextScope);
10884
+ return implied === "matching" && resolveMemoryLevel(current.level, current.scope) === "profile" ? "profile" : implied;
10885
+ }
10805
10886
  function parseMedia(value) {
10806
10887
  if (typeof value !== "string" || value === "") return null;
10807
10888
  try {
@@ -10831,8 +10912,58 @@ function visibilityConditions(requested) {
10831
10912
  if (excluded.length === 0) return [];
10832
10913
  return [Q5.or(Q5.where("visibility", null), Q5.where("visibility", Q5.notIn(excluded)))];
10833
10914
  }
10834
- function isOwnedByCtxUser(ctx, record) {
10835
- return ctx.userId === void 0 || record.userId === ctx.userId;
10915
+ function isKinded(record2) {
10916
+ return record2.kind !== null && record2.kind !== void 0;
10917
+ }
10918
+ function assertValidKindLevel(kind, level) {
10919
+ const hasKind = kind !== null && kind !== void 0;
10920
+ if (hasKind && !MEMORY_KINDS.includes(kind)) {
10921
+ throw new MemoryLevelError(`Unknown memory kind: ${kind}`);
10922
+ }
10923
+ if (level !== void 0 && !MEMORY_LEVELS.includes(level)) {
10924
+ throw new MemoryLevelError(`Unknown memory level: ${level}`);
10925
+ }
10926
+ if (level === "profile" && !hasKind) {
10927
+ throw new MemoryLevelError("Only a memory with a kind can be at level 'profile'");
10928
+ }
10929
+ }
10930
+ function resolveCreateLevel(opts) {
10931
+ if (opts.level !== void 0) return { level: opts.level, scope: scopeForLevel(opts.level) };
10932
+ if (opts.scope !== void 0) return { level: levelFromScope(opts.scope), scope: opts.scope };
10933
+ return { level: "private", scope: "private" };
10934
+ }
10935
+ async function encryptKindValue(ctx, value) {
10936
+ if (typeof value !== "string" || !ctx.walletAddress || !ctx.signMessage) return value;
10937
+ return encryptVaultMemoryContent(
10938
+ value,
10939
+ ctx.walletAddress,
10940
+ ctx.signMessage,
10941
+ ctx.embeddedWalletSigner
10942
+ );
10943
+ }
10944
+ function levelConditions(requested) {
10945
+ if (!requested?.length) return [];
10946
+ const published = ["shared", "public"];
10947
+ const wantsMatching = requested.includes("matching");
10948
+ const wantsPrivate = requested.includes("private");
10949
+ const unresolved = Q5.or(Q5.where("level", null), Q5.where("level", Q5.notIn([...MEMORY_LEVELS])));
10950
+ const byLevel = Q5.where("level", Q5.oneOf([...requested]));
10951
+ if (wantsMatching && wantsPrivate) return [Q5.or(byLevel, unresolved)];
10952
+ if (wantsMatching) {
10953
+ return [Q5.or(byLevel, Q5.and(unresolved, Q5.where("scope", Q5.oneOf(published))))];
10954
+ }
10955
+ if (wantsPrivate) {
10956
+ return [
10957
+ Q5.or(
10958
+ byLevel,
10959
+ Q5.and(unresolved, Q5.or(Q5.where("scope", null), Q5.where("scope", Q5.notIn(published))))
10960
+ )
10961
+ ];
10962
+ }
10963
+ return [byLevel];
10964
+ }
10965
+ function isOwnedByCtxUser(ctx, record2) {
10966
+ return ctx.userId === void 0 || record2.userId === ctx.userId;
10836
10967
  }
10837
10968
  function baseVaultConditions(ctx, options) {
10838
10969
  return [
@@ -10874,6 +11005,9 @@ function vaultMemoryToStoredRaw(memory) {
10874
11005
  uniqueId: memory.id,
10875
11006
  content: memory.content,
10876
11007
  scope: memory.scope,
11008
+ kind: memory.kind ?? null,
11009
+ kindValue: memory.kindValue ?? null,
11010
+ level: resolveMemoryLevel(memory.level, memory.scope),
10877
11011
  folderId: memory.folderId ?? null,
10878
11012
  userId: memory.userId ?? null,
10879
11013
  embedding: memory.embedding ?? null,
@@ -10912,42 +11046,48 @@ async function vaultMemoryToStored(memory, walletAddress, signMessage, embeddedW
10912
11046
  }
10913
11047
  return raw;
10914
11048
  }
10915
- function populateNewVaultMemory(record, ctx, opts, encryptedContent) {
10916
- record._setRaw("content", encryptedContent);
10917
- record._setRaw("scope", opts.scope ?? "private");
10918
- record._setRaw("folder_id", opts.folderId ?? null);
10919
- record._setRaw("user_id", ctx.userId ?? null);
10920
- record._setRaw("is_deleted", false);
11049
+ function populateNewVaultMemory(record2, ctx, opts, encryptedContent, encryptedKindValue) {
11050
+ const { level, scope } = resolveCreateLevel(opts);
11051
+ record2._setRaw("content", encryptedContent);
11052
+ record2._setRaw("scope", scope);
11053
+ record2._setRaw("level", level);
11054
+ record2._setRaw("kind", opts.kind ?? null);
11055
+ record2._setRaw("kind_value", encryptedKindValue ?? null);
11056
+ record2._setRaw("folder_id", opts.folderId ?? null);
11057
+ record2._setRaw("user_id", ctx.userId ?? null);
11058
+ record2._setRaw("is_deleted", false);
10921
11059
  if (opts.embedding !== void 0) {
10922
- record._setRaw("embedding", opts.embedding);
10923
- record._setRaw("embedding_model", opts.embeddingModel ?? null);
11060
+ record2._setRaw("embedding", opts.embedding);
11061
+ record2._setRaw("embedding_model", opts.embeddingModel ?? null);
10924
11062
  }
10925
11063
  if (opts.sourceChunkIds !== void 0) {
10926
- record._setRaw("source_chunk_ids", JSON.stringify(opts.sourceChunkIds));
11064
+ record2._setRaw("source_chunk_ids", JSON.stringify(opts.sourceChunkIds));
10927
11065
  }
10928
- record._setRaw("proof_count", opts.proofCount ?? 1);
10929
- record._setRaw("source", opts.source ?? "manual");
11066
+ record2._setRaw("proof_count", opts.proofCount ?? 1);
11067
+ record2._setRaw("source", opts.source ?? "manual");
10930
11068
  if (opts.eventTime) {
10931
- record._setRaw("event_time_start", opts.eventTime.start ?? null);
10932
- record._setRaw("event_time_end", opts.eventTime.end ?? null);
10933
- record._setRaw("event_time_kind", opts.eventTime.kind ?? null);
11069
+ record2._setRaw("event_time_start", opts.eventTime.start ?? null);
11070
+ record2._setRaw("event_time_end", opts.eventTime.end ?? null);
11071
+ record2._setRaw("event_time_kind", opts.eventTime.kind ?? null);
10934
11072
  }
10935
11073
  if (opts.factType !== void 0) {
10936
- record._setRaw("fact_type", opts.factType);
11074
+ record2._setRaw("fact_type", opts.factType);
10937
11075
  }
10938
11076
  if (opts.trustTier !== void 0) {
10939
- record._setRaw("trust_tier", normalizeTrustTier(opts.trustTier));
11077
+ record2._setRaw("trust_tier", normalizeTrustTier(opts.trustTier));
10940
11078
  }
10941
- record._setRaw("visibility", opts.visibility ?? "private");
10942
- record._setRaw(
11079
+ record2._setRaw("visibility", opts.visibility ?? "private");
11080
+ record2._setRaw(
10943
11081
  "published_at",
10944
11082
  opts.visibility && opts.visibility !== "private" ? opts.publishedAt ?? Date.now() : null
10945
11083
  );
10946
11084
  if (opts.geohash !== void 0) {
10947
- record._setRaw("geohash", opts.geohash);
11085
+ record2._setRaw("geohash", opts.geohash);
10948
11086
  }
10949
11087
  }
10950
11088
  async function createVaultMemoryOp(ctx, opts) {
11089
+ assertValidKindLevel(opts.kind, resolveCreateLevel(opts).level);
11090
+ const encryptedKindValue = await encryptKindValue(ctx, opts.kindValue);
10951
11091
  const encryptedContent = ctx.walletAddress && ctx.signMessage ? await encryptVaultMemoryContent(
10952
11092
  opts.content,
10953
11093
  ctx.walletAddress,
@@ -10958,13 +11098,15 @@ async function createVaultMemoryOp(ctx, opts) {
10958
11098
  if (ctx.canWrite && !await ctx.canWrite())
10959
11099
  throw new Error("Memory source is no longer eligible");
10960
11100
  return ctx.vaultMemoryCollection.create(
10961
- (record) => populateNewVaultMemory(record, ctx, opts, encryptedContent)
11101
+ (record2) => populateNewVaultMemory(record2, ctx, opts, encryptedContent, encryptedKindValue)
10962
11102
  );
10963
11103
  });
10964
11104
  return vaultMemoryToStored(created, ctx.walletAddress, ctx.signMessage, ctx.embeddedWalletSigner);
10965
11105
  }
10966
11106
  async function createSupersedingMemoryOp(ctx, opts, targetId) {
10967
11107
  if (!targetId) return { created: null, retired: false };
11108
+ assertValidKindLevel(opts.kind, resolveCreateLevel(opts).level);
11109
+ const encryptedKindValue = await encryptKindValue(ctx, opts.kindValue);
10968
11110
  const encryptedContent = ctx.walletAddress && ctx.signMessage ? await encryptVaultMemoryContent(
10969
11111
  opts.content,
10970
11112
  ctx.walletAddress,
@@ -10981,9 +11123,10 @@ async function createSupersedingMemoryOp(ctx, opts, targetId) {
10981
11123
  } catch {
10982
11124
  return;
10983
11125
  }
10984
- if (target.isDeleted || target.supersededBy || !isOwnedByCtxUser(ctx, target)) return;
11126
+ if (target.isDeleted || target.supersededBy || isKinded(target) || !isOwnedByCtxUser(ctx, target))
11127
+ return;
10985
11128
  createdRecord = await ctx.vaultMemoryCollection.create(
10986
- (record) => populateNewVaultMemory(record, ctx, opts, encryptedContent)
11129
+ (record2) => populateNewVaultMemory(record2, ctx, opts, encryptedContent, encryptedKindValue)
10987
11130
  );
10988
11131
  await target.update((r) => {
10989
11132
  r._setRaw("superseded_by", createdRecord.id);
@@ -11047,6 +11190,10 @@ async function getMemoriesByEventTimeOp(ctx, windowStart, windowEnd) {
11047
11190
  }
11048
11191
  async function createVaultMemoriesBatchOp(ctx, optionsArray) {
11049
11192
  if (optionsArray.length === 0) return [];
11193
+ for (const opts of optionsArray) assertValidKindLevel(opts.kind, resolveCreateLevel(opts).level);
11194
+ const encryptedKindValues = await Promise.all(
11195
+ optionsArray.map((opts) => encryptKindValue(ctx, opts.kindValue))
11196
+ );
11050
11197
  const encryptedContents = await Promise.all(
11051
11198
  optionsArray.map(async (opts) => {
11052
11199
  if (ctx.walletAddress && ctx.signMessage) {
@@ -11065,7 +11212,7 @@ async function createVaultMemoriesBatchOp(ctx, optionsArray) {
11065
11212
  throw new Error("Memory source is no longer eligible");
11066
11213
  const prepared = optionsArray.map(
11067
11214
  (opts, i) => ctx.vaultMemoryCollection.prepareCreate(
11068
- (record) => populateNewVaultMemory(record, ctx, opts, encryptedContents[i])
11215
+ (record2) => populateNewVaultMemory(record2, ctx, opts, encryptedContents[i], encryptedKindValues[i])
11069
11216
  )
11070
11217
  );
11071
11218
  await ctx.database.batch(...prepared);
@@ -11073,16 +11220,16 @@ async function createVaultMemoriesBatchOp(ctx, optionsArray) {
11073
11220
  });
11074
11221
  return Promise.all(
11075
11222
  created.map(
11076
- (record) => vaultMemoryToStored(record, ctx.walletAddress, ctx.signMessage, ctx.embeddedWalletSigner)
11223
+ (record2) => vaultMemoryToStored(record2, ctx.walletAddress, ctx.signMessage, ctx.embeddedWalletSigner)
11077
11224
  )
11078
11225
  );
11079
11226
  }
11080
11227
  async function getVaultMemoryOp(ctx, id) {
11081
11228
  try {
11082
- const record = await ctx.vaultMemoryCollection.find(id);
11083
- if (record.isDeleted || !isOwnedByCtxUser(ctx, record)) return null;
11229
+ const record2 = await ctx.vaultMemoryCollection.find(id);
11230
+ if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2)) return null;
11084
11231
  return vaultMemoryToStored(
11085
- record,
11232
+ record2,
11086
11233
  ctx.walletAddress,
11087
11234
  ctx.signMessage,
11088
11235
  ctx.embeddedWalletSigner
@@ -11108,6 +11255,9 @@ function vaultMemoryRawToStoredRaw(raw) {
11108
11255
  uniqueId: raw.id,
11109
11256
  content: raw.content ?? "",
11110
11257
  scope: raw.scope ?? "",
11258
+ kind: raw.kind ?? null,
11259
+ kindValue: raw.kind_value ?? null,
11260
+ level: resolveMemoryLevel(raw.level, raw.scope),
11111
11261
  folderId: raw.folder_id ?? null,
11112
11262
  userId: raw.user_id ?? null,
11113
11263
  embedding: raw.embedding ?? null,
@@ -11140,17 +11290,19 @@ function vaultMemoryRawToStoredRaw(raw) {
11140
11290
  };
11141
11291
  }
11142
11292
  async function vaultMemoryRawToStored(raw, walletAddress, signMessage, embeddedWalletSigner) {
11143
- const stored = vaultMemoryRawToStoredRaw(raw);
11293
+ const stored2 = vaultMemoryRawToStoredRaw(raw);
11144
11294
  if (walletAddress) {
11145
- return decryptVaultMemoryFields(stored, walletAddress, signMessage, embeddedWalletSigner);
11295
+ return decryptVaultMemoryFields(stored2, walletAddress, signMessage, embeddedWalletSigner);
11146
11296
  }
11147
- return stored;
11297
+ return stored2;
11148
11298
  }
11149
11299
  async function getAllVaultMemoriesOp(ctx, options) {
11150
11300
  const conditions = [
11151
11301
  ...baseVaultConditions(ctx, options),
11152
11302
  ...options?.scopes?.length ? [Q5.where("scope", Q5.oneOf(options.scopes))] : [],
11153
11303
  ...visibilityConditions(options?.visibility),
11304
+ ...levelConditions(options?.levels),
11305
+ ...options?.kinds?.length ? [Q5.where("kind", Q5.oneOf(options.kinds))] : [],
11154
11306
  ...options?.folderId !== void 0 ? [Q5.where("folder_id", options.folderId)] : [],
11155
11307
  ...options?.factTypes?.length ? [Q5.where("fact_type", Q5.oneOf(options.factTypes))] : [],
11156
11308
  Q5.sortBy(options?.since ? "updated_at" : "created_at", Q5.desc),
@@ -11296,13 +11448,13 @@ async function getVaultMemoriesByIdsOp(ctx, ids, options) {
11296
11448
  async function getAllVaultMemoryContentsOp(ctx, options) {
11297
11449
  const results = await ctx.vaultMemoryCollection.query(...baseVaultConditions(ctx, options)).unsafeFetchRaw();
11298
11450
  return mapInBatches(results, async (raw) => {
11299
- const stored = await vaultMemoryRawToStored(
11451
+ const stored2 = await vaultMemoryRawToStored(
11300
11452
  raw,
11301
11453
  ctx.walletAddress,
11302
11454
  ctx.signMessage,
11303
11455
  ctx.embeddedWalletSigner
11304
11456
  );
11305
- return stored.content;
11457
+ return stored2.content;
11306
11458
  });
11307
11459
  }
11308
11460
  async function countActiveVaultMemoriesOp(ctx) {
@@ -11317,6 +11469,14 @@ async function updateVaultMemoryOp(ctx, id, opts) {
11317
11469
  try {
11318
11470
  const probe = await ctx.vaultMemoryCollection.find(id);
11319
11471
  if (probe.isDeleted || probe.supersededBy || !isOwnedByCtxUser(ctx, probe)) return null;
11472
+ if (opts.freeFormOnly && isKinded(probe)) return null;
11473
+ const levelAfter = (current) => {
11474
+ if (opts.level !== void 0) return opts.level;
11475
+ if (opts.scope === void 0) return resolveMemoryLevel(current.level, current.scope);
11476
+ return levelForScopeChange(current, opts.scope);
11477
+ };
11478
+ assertValidKindLevel(opts.kind !== void 0 ? opts.kind : probe.kind, levelAfter(probe));
11479
+ const encryptedKindValue = await encryptKindValue(ctx, opts.kindValue);
11320
11480
  const encryptedContent = ctx.walletAddress && ctx.signMessage ? await encryptVaultMemoryContent(
11321
11481
  opts.content,
11322
11482
  ctx.walletAddress,
@@ -11324,30 +11484,43 @@ async function updateVaultMemoryOp(ctx, id, opts) {
11324
11484
  ctx.embeddedWalletSigner
11325
11485
  ) : opts.content;
11326
11486
  let stale = false;
11327
- const record = probe;
11328
- const originalUpdatedAt = record.updatedAt.getTime();
11487
+ const record2 = probe;
11488
+ const originalUpdatedAt = record2.updatedAt.getTime();
11329
11489
  await ctx.database.write(async () => {
11330
11490
  if (ctx.canWrite && !await ctx.canWrite())
11331
11491
  throw new Error("Memory source is no longer eligible");
11332
- if (record.isDeleted || record.supersededBy || !isOwnedByCtxUser(ctx, record)) {
11492
+ if (record2.isDeleted || record2.supersededBy || !isOwnedByCtxUser(ctx, record2) || opts.freeFormOnly && isKinded(record2)) {
11333
11493
  stale = true;
11334
11494
  return;
11335
11495
  }
11496
+ const nextKind = opts.kind !== void 0 ? opts.kind : record2.kind;
11497
+ const nextLevel = levelAfter(record2);
11498
+ assertValidKindLevel(nextKind, nextLevel);
11336
11499
  let observedSources = [];
11337
11500
  let replayedObservation = false;
11338
11501
  if (opts.observationSourceIds?.length) {
11339
11502
  try {
11340
- const parsed = JSON.parse(record.sourceChunkIds ?? "[]");
11503
+ const parsed = JSON.parse(record2.sourceChunkIds ?? "[]");
11341
11504
  if (Array.isArray(parsed))
11342
11505
  observedSources = parsed.filter((id2) => typeof id2 === "string");
11343
11506
  } catch {
11344
11507
  }
11345
11508
  replayedObservation = opts.observationSourceIds.every((id2) => observedSources.includes(id2));
11346
11509
  }
11347
- await record.update((r) => {
11510
+ await record2.update((r) => {
11348
11511
  r._setRaw("content", encryptedContent);
11349
- if (opts.scope !== void 0) {
11512
+ if (opts.level !== void 0) {
11513
+ r._setRaw("level", nextLevel);
11514
+ r._setRaw("scope", scopeForLevel(nextLevel));
11515
+ } else if (opts.scope !== void 0) {
11350
11516
  r._setRaw("scope", opts.scope);
11517
+ r._setRaw("level", nextLevel);
11518
+ }
11519
+ if (opts.kind !== void 0) {
11520
+ r._setRaw("kind", opts.kind);
11521
+ }
11522
+ if (encryptedKindValue !== void 0) {
11523
+ r._setRaw("kind_value", encryptedKindValue);
11351
11524
  }
11352
11525
  if (opts.folderId !== void 0) {
11353
11526
  r._setRaw("folder_id", opts.folderId);
@@ -11401,12 +11574,13 @@ async function updateVaultMemoryOp(ctx, id, opts) {
11401
11574
  });
11402
11575
  if (stale) return null;
11403
11576
  return vaultMemoryToStored(
11404
- record,
11577
+ record2,
11405
11578
  ctx.walletAddress,
11406
11579
  ctx.signMessage,
11407
11580
  ctx.embeddedWalletSigner
11408
11581
  );
11409
- } catch {
11582
+ } catch (err) {
11583
+ if (err instanceof MemoryLevelError) throw err;
11410
11584
  return null;
11411
11585
  }
11412
11586
  }
@@ -11415,21 +11589,21 @@ async function setMemoryEntitiesOp(ctx, memoryId, entities) {
11415
11589
  if (!entityCtx) {
11416
11590
  throw new Error("setMemoryEntitiesOp requires ctx.entityCtx (entity collections)");
11417
11591
  }
11418
- let record;
11592
+ let record2;
11419
11593
  try {
11420
- record = await ctx.vaultMemoryCollection.find(memoryId);
11594
+ record2 = await ctx.vaultMemoryCollection.find(memoryId);
11421
11595
  } catch {
11422
11596
  return null;
11423
11597
  }
11424
- if (record.isDeleted || !isOwnedByCtxUser(ctx, record)) return null;
11598
+ if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2)) return null;
11425
11599
  let stale = false;
11426
- const originalUpdatedAt = record.updatedAt.getTime();
11600
+ const originalUpdatedAt = record2.updatedAt.getTime();
11427
11601
  await ctx.database.write(async (writer) => {
11428
- if (record.isDeleted || !isOwnedByCtxUser(ctx, record)) {
11602
+ if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2)) {
11429
11603
  stale = true;
11430
11604
  return;
11431
11605
  }
11432
- await record.update((r) => {
11606
+ await record2.update((r) => {
11433
11607
  r._setRaw("topics_user_managed", true);
11434
11608
  r._setRaw("updated_at", originalUpdatedAt);
11435
11609
  });
@@ -11453,25 +11627,25 @@ async function setMemoryEntitiesOp(ctx, memoryId, entities) {
11453
11627
  );
11454
11628
  });
11455
11629
  if (stale) return null;
11456
- return vaultMemoryToStored(record, ctx.walletAddress, ctx.signMessage, ctx.embeddedWalletSigner);
11630
+ return vaultMemoryToStored(record2, ctx.walletAddress, ctx.signMessage, ctx.embeddedWalletSigner);
11457
11631
  }
11458
11632
  async function clearMemoryTopicsOverrideOp(ctx, memoryId, options) {
11459
- let record;
11633
+ let record2;
11460
11634
  try {
11461
- record = await ctx.vaultMemoryCollection.find(memoryId);
11635
+ record2 = await ctx.vaultMemoryCollection.find(memoryId);
11462
11636
  } catch {
11463
11637
  return false;
11464
11638
  }
11465
- if (record.isDeleted || !isOwnedByCtxUser(ctx, record)) return false;
11466
- const originalUpdatedAt = record.updatedAt.getTime();
11639
+ if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2)) return false;
11640
+ const originalUpdatedAt = record2.updatedAt.getTime();
11467
11641
  let cleared = false;
11468
11642
  await ctx.database.write(async () => {
11469
- if (options?.unlessTopicsRecorded && parseTopics(record.topics) !== null) return;
11643
+ if (options?.unlessTopicsRecorded && parseTopics(record2.topics) !== null) return;
11470
11644
  cleared = true;
11471
- await record.update((r) => {
11645
+ await record2.update((r) => {
11472
11646
  r._setRaw("topics_user_managed", false);
11473
11647
  r._setRaw("topics_extracted_version", null);
11474
- if (record.topicsExtractedAt === null) {
11648
+ if (record2.topicsExtractedAt === null) {
11475
11649
  r._setRaw("topics_extracted_at", originalUpdatedAt);
11476
11650
  }
11477
11651
  r._setRaw("updated_at", originalUpdatedAt);
@@ -11480,22 +11654,22 @@ async function clearMemoryTopicsOverrideOp(ctx, memoryId, options) {
11480
11654
  return cleared;
11481
11655
  }
11482
11656
  async function setMemoryVisibilityOp(ctx, id, opts) {
11483
- let record;
11657
+ let record2;
11484
11658
  try {
11485
- record = await ctx.vaultMemoryCollection.find(id);
11659
+ record2 = await ctx.vaultMemoryCollection.find(id);
11486
11660
  } catch {
11487
11661
  return null;
11488
11662
  }
11489
- if (record.isDeleted || !isOwnedByCtxUser(ctx, record)) return null;
11663
+ if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2)) return null;
11490
11664
  let stale = false;
11491
11665
  await ctx.database.write(async () => {
11492
- if (record.isDeleted || !isOwnedByCtxUser(ctx, record)) {
11666
+ if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2)) {
11493
11667
  stale = true;
11494
11668
  return;
11495
11669
  }
11496
- const currentUpdatedAt = record.updatedAt.getTime();
11497
- const currentPublishedAt = record.publishedAt ?? null;
11498
- await record.update((r) => {
11670
+ const currentUpdatedAt = record2.updatedAt.getTime();
11671
+ const currentPublishedAt = record2.publishedAt ?? null;
11672
+ await record2.update((r) => {
11499
11673
  r._setRaw("visibility", opts.visibility);
11500
11674
  if (opts.visibility === "private") {
11501
11675
  r._setRaw("published_at", null);
@@ -11509,19 +11683,19 @@ async function setMemoryVisibilityOp(ctx, id, opts) {
11509
11683
  });
11510
11684
  });
11511
11685
  if (stale) return null;
11512
- return vaultMemoryToStored(record, ctx.walletAddress, ctx.signMessage, ctx.embeddedWalletSigner);
11686
+ return vaultMemoryToStored(record2, ctx.walletAddress, ctx.signMessage, ctx.embeddedWalletSigner);
11513
11687
  }
11514
11688
  async function deleteVaultMemoryOp(ctx, id) {
11515
11689
  try {
11516
- const record = await ctx.vaultMemoryCollection.find(id);
11517
- if (record.isDeleted || !isOwnedByCtxUser(ctx, record)) return false;
11690
+ const record2 = await ctx.vaultMemoryCollection.find(id);
11691
+ if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2)) return false;
11518
11692
  let stale = false;
11519
11693
  await ctx.database.write(async () => {
11520
- if (record.isDeleted || !isOwnedByCtxUser(ctx, record)) {
11694
+ if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2)) {
11521
11695
  stale = true;
11522
11696
  return;
11523
11697
  }
11524
- await record.update((r) => {
11698
+ await record2.update((r) => {
11525
11699
  r._setRaw("is_deleted", true);
11526
11700
  });
11527
11701
  });
@@ -11540,8 +11714,9 @@ async function deleteVaultMemoryOp(ctx, id) {
11540
11714
  async function supersedeVaultMemoryOp(ctx, id, supersededById) {
11541
11715
  if (id === supersededById) return false;
11542
11716
  try {
11543
- const record = await ctx.vaultMemoryCollection.find(id);
11544
- if (record.isDeleted || record.supersededBy || !isOwnedByCtxUser(ctx, record)) return false;
11717
+ const record2 = await ctx.vaultMemoryCollection.find(id);
11718
+ if (record2.isDeleted || record2.supersededBy || !isOwnedByCtxUser(ctx, record2)) return false;
11719
+ if (isKinded(record2)) return false;
11545
11720
  let successor;
11546
11721
  try {
11547
11722
  successor = await ctx.vaultMemoryCollection.find(supersededById);
@@ -11555,7 +11730,7 @@ async function supersedeVaultMemoryOp(ctx, id, supersededById) {
11555
11730
  await ctx.database.write(async () => {
11556
11731
  if (ctx.canWrite && !await ctx.canWrite())
11557
11732
  throw new Error("Memory source is no longer eligible");
11558
- if (record.isDeleted || record.supersededBy || !isOwnedByCtxUser(ctx, record)) {
11733
+ if (record2.isDeleted || record2.supersededBy || !isOwnedByCtxUser(ctx, record2)) {
11559
11734
  stale = true;
11560
11735
  return;
11561
11736
  }
@@ -11563,7 +11738,7 @@ async function supersedeVaultMemoryOp(ctx, id, supersededById) {
11563
11738
  stale = true;
11564
11739
  return;
11565
11740
  }
11566
- await record.update((r) => {
11741
+ await record2.update((r) => {
11567
11742
  r._setRaw("superseded_by", supersededById);
11568
11743
  r._setRaw("superseded_at", Date.now());
11569
11744
  });
@@ -11582,7 +11757,7 @@ async function getUnfiledVaultMemoriesOp(ctx) {
11582
11757
  const results = await ctx.vaultMemoryCollection.query(...conditions).fetch();
11583
11758
  return mapInBatches(
11584
11759
  results,
11585
- (record) => vaultMemoryToStored(record, ctx.walletAddress, ctx.signMessage, ctx.embeddedWalletSigner)
11760
+ (record2) => vaultMemoryToStored(record2, ctx.walletAddress, ctx.signMessage, ctx.embeddedWalletSigner)
11586
11761
  );
11587
11762
  }
11588
11763
  var TOPICS_EXTRACTION_VERSION = 3;
@@ -11724,17 +11899,17 @@ async function stampTopicsExtractedAtOp(ctx, memoryIds, extractedAt, version = T
11724
11899
  }
11725
11900
  }
11726
11901
  const eligible = records.filter(
11727
- (record) => !record.isDeleted && isOwnedByCtxUser(ctx, record) && !record.topicsUserManaged
11902
+ (record2) => !record2.isDeleted && isOwnedByCtxUser(ctx, record2) && !record2.topicsUserManaged
11728
11903
  );
11729
- const prepared = eligible.map((record) => {
11730
- const originalUpdatedAt = record.updatedAt.getTime();
11731
- return record.prepareUpdate((r) => {
11904
+ const prepared = eligible.map((record2) => {
11905
+ const originalUpdatedAt = record2.updatedAt.getTime();
11906
+ return record2.prepareUpdate((r) => {
11732
11907
  r._setRaw("topics_extracted_at", extractedAt);
11733
11908
  r._setRaw("topics_extracted_version", version);
11734
11909
  r._setRaw("updated_at", originalUpdatedAt);
11735
11910
  });
11736
11911
  });
11737
- for (const record of eligible) stamped.push(record.id);
11912
+ for (const record2 of eligible) stamped.push(record2.id);
11738
11913
  if (prepared.length > 0) await ctx.database.batch(...prepared);
11739
11914
  });
11740
11915
  }
@@ -11749,14 +11924,14 @@ async function relinkMemoryTopicsOp(ctx, memoryIds) {
11749
11924
  for (const id of Array.from(new Set(memoryIds))) {
11750
11925
  try {
11751
11926
  await ctx.database.write(async (writer) => {
11752
- let record;
11927
+ let record2;
11753
11928
  try {
11754
- record = await ctx.vaultMemoryCollection.find(id);
11929
+ record2 = await ctx.vaultMemoryCollection.find(id);
11755
11930
  } catch {
11756
11931
  return;
11757
11932
  }
11758
- if (record.isDeleted || !isOwnedByCtxUser(ctx, record)) return;
11759
- const topics = parseTopics(record.topics);
11933
+ if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2)) return;
11934
+ const topics = parseTopics(record2.topics);
11760
11935
  if (topics === null) return;
11761
11936
  await writer.callWriter(() => relinkMemoryEntitiesFromTopicsOp(entityCtx, id, topics));
11762
11937
  relinked.push(id);
@@ -11781,20 +11956,20 @@ async function backfillMemoryTopicsOp(ctx, memoryIds) {
11781
11956
  await ctx.database.write(async () => {
11782
11957
  const writes = [];
11783
11958
  for (const id of chunkIds) {
11784
- let record;
11959
+ let record2;
11785
11960
  try {
11786
- record = await ctx.vaultMemoryCollection.find(id);
11961
+ record2 = await ctx.vaultMemoryCollection.find(id);
11787
11962
  } catch {
11788
11963
  continue;
11789
11964
  }
11790
- if (record.isDeleted || !isOwnedByCtxUser(ctx, record)) continue;
11791
- if (parseTopics(record.topics) !== null) continue;
11965
+ if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2)) continue;
11966
+ if (parseTopics(record2.topics) !== null) continue;
11792
11967
  const links = await entityCtx.memoryEntityCollection.query(Q5.where("memory_id", id)).unsafeFetchRaw();
11793
11968
  const entityIds = links.map((l) => String(l.entity_id));
11794
11969
  if (entityIds.length === 0) continue;
11795
11970
  const entities = await entityCtx.entityCollection.query(Q5.where("id", Q5.oneOf(entityIds))).fetch();
11796
11971
  if (entities.length === 0) continue;
11797
- const source = record.topicsUserManaged ? "user" : "auto";
11972
+ const source = record2.topicsUserManaged ? "user" : "auto";
11798
11973
  const write = await resolveMemoryTopicsWrite(entityCtx, id, entities, [], source);
11799
11974
  if (write) writes.push(write);
11800
11975
  }
@@ -11812,7 +11987,7 @@ async function deleteAllVaultMemoriesForUserOp(ctx, userId) {
11812
11987
  if (records.length === 0) return 0;
11813
11988
  await ctx.database.write(async () => {
11814
11989
  const prepared = records.map(
11815
- (record) => record.prepareUpdate((r) => {
11990
+ (record2) => record2.prepareUpdate((r) => {
11816
11991
  r._setRaw("is_deleted", true);
11817
11992
  })
11818
11993
  );
@@ -11842,7 +12017,10 @@ function assertVaultScopeForSweep(ctx) {
11842
12017
  }
11843
12018
  async function getDecayCandidatesRawOp(ctx) {
11844
12019
  assertVaultScopeForSweep(ctx);
11845
- const results = await ctx.vaultMemoryCollection.query(...baseVaultConditions(ctx, { includeArchived: true, includeQuarantined: true })).unsafeFetchRaw();
12020
+ const results = await ctx.vaultMemoryCollection.query(
12021
+ ...baseVaultConditions(ctx, { includeArchived: true, includeQuarantined: true }),
12022
+ Q5.where("kind", null)
12023
+ ).unsafeFetchRaw();
11846
12024
  return results.map((raw) => ({
11847
12025
  uniqueId: raw.id,
11848
12026
  factType: raw.fact_type ?? null,
@@ -11857,20 +12035,20 @@ async function getDecayCandidatesRawOp(ctx) {
11857
12035
  }
11858
12036
  async function archiveVaultMemoryOp(ctx, id, opts) {
11859
12037
  try {
11860
- const record = await ctx.vaultMemoryCollection.find(id);
11861
- if (record.isDeleted || !isOwnedByCtxUser(ctx, record)) return false;
12038
+ const record2 = await ctx.vaultMemoryCollection.find(id);
12039
+ if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2)) return false;
11862
12040
  let stale = false;
11863
12041
  const archivedAtValue = opts?.now ?? Date.now();
11864
12042
  await ctx.database.write(async () => {
11865
- if (record.isDeleted || !isOwnedByCtxUser(ctx, record) || record.archivedAt !== null) {
12043
+ if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2) || record2.archivedAt !== null) {
11866
12044
  stale = true;
11867
12045
  return;
11868
12046
  }
11869
- if (opts?.expectedUpdatedAt !== void 0 && record.updatedAt.getTime() !== opts.expectedUpdatedAt || opts?.expectedLastObservedAt !== void 0 && (record.lastObservedAt ?? null) !== opts.expectedLastObservedAt) {
12047
+ if (opts?.expectedUpdatedAt !== void 0 && record2.updatedAt.getTime() !== opts.expectedUpdatedAt || opts?.expectedLastObservedAt !== void 0 && (record2.lastObservedAt ?? null) !== opts.expectedLastObservedAt) {
11870
12048
  stale = true;
11871
12049
  return;
11872
12050
  }
11873
- await record.update((r) => {
12051
+ await record2.update((r) => {
11874
12052
  r._setRaw("archived_at", archivedAtValue);
11875
12053
  });
11876
12054
  });
@@ -11881,15 +12059,15 @@ async function archiveVaultMemoryOp(ctx, id, opts) {
11881
12059
  }
11882
12060
  async function restoreVaultMemoryOp(ctx, id) {
11883
12061
  try {
11884
- const record = await ctx.vaultMemoryCollection.find(id);
11885
- if (record.isDeleted || !isOwnedByCtxUser(ctx, record)) return false;
12062
+ const record2 = await ctx.vaultMemoryCollection.find(id);
12063
+ if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2)) return false;
11886
12064
  let stale = false;
11887
12065
  await ctx.database.write(async () => {
11888
- if (record.isDeleted || !isOwnedByCtxUser(ctx, record)) {
12066
+ if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2)) {
11889
12067
  stale = true;
11890
12068
  return;
11891
12069
  }
11892
- await record.update((r) => {
12070
+ await record2.update((r) => {
11893
12071
  r._setRaw("archived_at", null);
11894
12072
  });
11895
12073
  });
@@ -11900,17 +12078,17 @@ async function restoreVaultMemoryOp(ctx, id) {
11900
12078
  }
11901
12079
  async function hardDeleteDecayedOp(ctx, id, opts) {
11902
12080
  try {
11903
- const record = await ctx.vaultMemoryCollection.find(id);
11904
- if (record.isDeleted || !isOwnedByCtxUser(ctx, record)) return false;
12081
+ const record2 = await ctx.vaultMemoryCollection.find(id);
12082
+ if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2)) return false;
11905
12083
  const now = opts.now ?? Date.now();
11906
12084
  let stale = false;
11907
12085
  await ctx.database.write(async () => {
11908
- const archivedAt = record.archivedAt;
11909
- if (record.isDeleted || !isOwnedByCtxUser(ctx, record) || archivedAt === null || now - archivedAt <= opts.hardDeleteWindowMs) {
12086
+ const archivedAt = record2.archivedAt;
12087
+ if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2) || archivedAt === null || now - archivedAt <= opts.hardDeleteWindowMs) {
11910
12088
  stale = true;
11911
12089
  return;
11912
12090
  }
11913
- await record.update((r) => {
12091
+ await record2.update((r) => {
11914
12092
  r._setRaw("is_deleted", true);
11915
12093
  });
11916
12094
  });
@@ -11928,14 +12106,14 @@ async function hardDeleteDecayedOp(ctx, id, opts) {
11928
12106
  }
11929
12107
  async function updateVaultMemoryEmbeddingOp(ctx, id, embedding, embeddingModel, expected) {
11930
12108
  try {
11931
- const record = await ctx.vaultMemoryCollection.find(id);
11932
- if (record.isDeleted || !isOwnedByCtxUser(ctx, record)) return false;
11933
- const readUpdatedAt = record.updatedAt.getTime();
11934
- const readStoredContent = record._getRaw("content");
12109
+ const record2 = await ctx.vaultMemoryCollection.find(id);
12110
+ if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2)) return false;
12111
+ const readUpdatedAt = record2.updatedAt.getTime();
12112
+ const readStoredContent = record2._getRaw("content");
11935
12113
  if (expected?.updatedAt !== void 0 && expected.updatedAt !== readUpdatedAt) return false;
11936
12114
  if (expected?.content !== void 0) {
11937
12115
  const current = await vaultMemoryToStored(
11938
- record,
12116
+ record2,
11939
12117
  ctx.walletAddress,
11940
12118
  ctx.signMessage,
11941
12119
  ctx.embeddedWalletSigner
@@ -11944,11 +12122,11 @@ async function updateVaultMemoryEmbeddingOp(ctx, id, embedding, embeddingModel,
11944
12122
  }
11945
12123
  let written = false;
11946
12124
  await ctx.database.write(async () => {
11947
- if (record.isDeleted || !isOwnedByCtxUser(ctx, record)) return;
11948
- const originalUpdatedAt = record.updatedAt.getTime();
11949
- if (originalUpdatedAt !== readUpdatedAt || record._getRaw("content") !== readStoredContent)
12125
+ if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2)) return;
12126
+ const originalUpdatedAt = record2.updatedAt.getTime();
12127
+ if (originalUpdatedAt !== readUpdatedAt || record2._getRaw("content") !== readStoredContent)
11950
12128
  return;
11951
- await record.update((r) => {
12129
+ await record2.update((r) => {
11952
12130
  r._setRaw("embedding", embedding);
11953
12131
  r._setRaw("embedding_model", embeddingModel);
11954
12132
  r._setRaw("updated_at", originalUpdatedAt);
@@ -11963,8 +12141,8 @@ async function updateVaultMemoryEmbeddingOp(ctx, id, embedding, embeddingModel,
11963
12141
  function normalizeForDedupe(content) {
11964
12142
  return content.normalize("NFKC").trim().replace(/\s+/g, " ").toLowerCase();
11965
12143
  }
11966
- async function findQuarantinedDuplicateOp(ctx, content, sourceIds, where) {
11967
- const wanted = [...new Set(sourceIds)].sort().join("\0");
12144
+ async function findQuarantinedDuplicateOp(ctx, content, sourceIds2, where) {
12145
+ const wanted = [...new Set(sourceIds2)].sort().join("\0");
11968
12146
  const target = normalizeForDedupe(content);
11969
12147
  const rows = await ctx.vaultMemoryCollection.query(
11970
12148
  Q5.where("trust_tier", "quarantined"),
@@ -11983,13 +12161,13 @@ async function findQuarantinedDuplicateOp(ctx, content, sourceIds, where) {
11983
12161
  if (!Array.isArray(ids)) continue;
11984
12162
  const key = [...new Set(ids.filter((id) => typeof id === "string"))].sort().join("\0");
11985
12163
  if (key !== wanted) continue;
11986
- const stored = await vaultMemoryRawToStored(
12164
+ const stored2 = await vaultMemoryRawToStored(
11987
12165
  raw,
11988
12166
  ctx.walletAddress,
11989
12167
  ctx.signMessage,
11990
12168
  ctx.embeddedWalletSigner
11991
12169
  );
11992
- if (normalizeForDedupe(stored.content) === target) return stored.uniqueId;
12170
+ if (normalizeForDedupe(stored2.content) === target) return stored2.uniqueId;
11993
12171
  }
11994
12172
  return null;
11995
12173
  }
@@ -12098,25 +12276,26 @@ async function ingestPublishedPhotoMemoriesOp(ctx, rows) {
12098
12276
  inserted = writable.length;
12099
12277
  if (writable.length === 0) return;
12100
12278
  const prepared = writable.map(
12101
- ({ row, content }) => ctx.vaultMemoryCollection.prepareCreate((record) => {
12102
- record._raw.id = row.memoryId;
12103
- record._setRaw("content", content);
12104
- record._setRaw("scope", "shared");
12105
- record._setRaw("folder_id", null);
12106
- record._setRaw("user_id", ctx.userId ?? null);
12107
- record._setRaw("is_deleted", false);
12108
- record._setRaw("proof_count", 1);
12109
- record._setRaw("source", SOURCE_PHOTO);
12110
- record._setRaw(
12279
+ ({ row, content }) => ctx.vaultMemoryCollection.prepareCreate((record2) => {
12280
+ record2._raw.id = row.memoryId;
12281
+ record2._setRaw("content", content);
12282
+ record2._setRaw("scope", "shared");
12283
+ record2._setRaw("level", "matching");
12284
+ record2._setRaw("folder_id", null);
12285
+ record2._setRaw("user_id", ctx.userId ?? null);
12286
+ record2._setRaw("is_deleted", false);
12287
+ record2._setRaw("proof_count", 1);
12288
+ record2._setRaw("source", SOURCE_PHOTO);
12289
+ record2._setRaw(
12111
12290
  "media",
12112
12291
  row.media && row.media.length > 0 ? JSON.stringify(row.media) : null
12113
12292
  );
12114
- record._setRaw("visibility", "public");
12115
- record._setRaw("published_at", now);
12293
+ record2._setRaw("visibility", "public");
12294
+ record2._setRaw("published_at", now);
12116
12295
  if (row.eventTime) {
12117
- record._setRaw("event_time_start", row.eventTime.start ?? null);
12118
- record._setRaw("event_time_end", row.eventTime.end ?? null);
12119
- record._setRaw("event_time_kind", row.eventTime.kind ?? null);
12296
+ record2._setRaw("event_time_start", row.eventTime.start ?? null);
12297
+ record2._setRaw("event_time_end", row.eventTime.end ?? null);
12298
+ record2._setRaw("event_time_kind", row.eventTime.kind ?? null);
12120
12299
  }
12121
12300
  })
12122
12301
  );
@@ -12480,11 +12659,11 @@ function folderToStored(folder) {
12480
12659
  }
12481
12660
  async function createVaultFolderOp(ctx, opts) {
12482
12661
  const created = await ctx.database.write(async () => {
12483
- return ctx.vaultFolderCollection.create((record) => {
12484
- record._setRaw("name", opts.name);
12485
- record._setRaw("scope", opts.scope ?? "private");
12486
- record._setRaw("is_system", opts.isSystem ?? false);
12487
- record._setRaw("is_deleted", false);
12662
+ return ctx.vaultFolderCollection.create((record2) => {
12663
+ record2._setRaw("name", opts.name);
12664
+ record2._setRaw("scope", opts.scope ?? "private");
12665
+ record2._setRaw("is_system", opts.isSystem ?? false);
12666
+ record2._setRaw("is_deleted", false);
12488
12667
  });
12489
12668
  });
12490
12669
  return folderToStored(created);
@@ -12495,14 +12674,14 @@ async function getAllVaultFoldersOp(ctx) {
12495
12674
  }
12496
12675
  async function updateVaultFolderOp(ctx, id, opts) {
12497
12676
  try {
12498
- const record = await ctx.vaultFolderCollection.find(id);
12499
- if (record.isDeleted) return null;
12500
- const scopeChanged = opts.scope !== void 0 && opts.scope !== record.scope;
12677
+ const record2 = await ctx.vaultFolderCollection.find(id);
12678
+ if (record2.isDeleted) return null;
12679
+ const scopeChanged = opts.scope !== void 0 && opts.scope !== record2.scope;
12501
12680
  const updated = await ctx.database.write(async () => {
12502
12681
  const memories = scopeChanged ? await ctx.vaultMemoryCollection.query(Q6.where("folder_id", id), Q6.where("is_deleted", false)).fetch() : [];
12503
12682
  const updates = [];
12504
12683
  updates.push(
12505
- record.prepareUpdate((r) => {
12684
+ record2.prepareUpdate((r) => {
12506
12685
  if (opts.name !== void 0) r._setRaw("name", opts.name);
12507
12686
  if (opts.scope !== void 0) r._setRaw("scope", opts.scope);
12508
12687
  })
@@ -12510,6 +12689,7 @@ async function updateVaultFolderOp(ctx, id, opts) {
12510
12689
  for (const memory of memories) {
12511
12690
  updates.push(
12512
12691
  memory.prepareUpdate((r) => {
12692
+ r._setRaw("level", levelForScopeChange(r, opts.scope));
12513
12693
  r._setRaw("scope", opts.scope);
12514
12694
  })
12515
12695
  );
@@ -12524,17 +12704,18 @@ async function updateVaultFolderOp(ctx, id, opts) {
12524
12704
  }
12525
12705
  async function deleteVaultFolderOp(ctx, id) {
12526
12706
  try {
12527
- const record = await ctx.vaultFolderCollection.find(id);
12528
- if (record.isDeleted) return false;
12707
+ const record2 = await ctx.vaultFolderCollection.find(id);
12708
+ if (record2.isDeleted) return false;
12529
12709
  await ctx.database.write(async () => {
12530
12710
  const memories = await ctx.vaultMemoryCollection.query(Q6.where("folder_id", id), Q6.where("is_deleted", false)).fetch();
12531
12711
  const preparedMemories = memories.map(
12532
12712
  (memory) => memory.prepareUpdate((r) => {
12533
12713
  r._setRaw("folder_id", null);
12714
+ r._setRaw("level", levelForScopeChange(r, "private"));
12534
12715
  r._setRaw("scope", "private");
12535
12716
  })
12536
12717
  );
12537
- const preparedFolder = record.prepareUpdate((r) => {
12718
+ const preparedFolder = record2.prepareUpdate((r) => {
12538
12719
  r._setRaw("is_deleted", true);
12539
12720
  });
12540
12721
  await ctx.database.batch(...preparedMemories, preparedFolder);
@@ -12567,6 +12748,7 @@ async function moveMemoriesToFolderOp(ctx, memoryIds, folderId) {
12567
12748
  const prepared = memories.map(
12568
12749
  (memory) => memory.prepareUpdate((r) => {
12569
12750
  r._setRaw("folder_id", folderId);
12751
+ r._setRaw("level", levelForScopeChange(r, targetScope));
12570
12752
  r._setRaw("scope", targetScope);
12571
12753
  })
12572
12754
  );
@@ -12580,11 +12762,11 @@ async function moveMemoriesToFolderOp(ctx, memoryIds, folderId) {
12580
12762
  }
12581
12763
  async function updateVaultFolderContextOp(ctx, id, context) {
12582
12764
  try {
12583
- const record = await ctx.vaultFolderCollection.find(id);
12584
- if (record.isDeleted) return null;
12765
+ const record2 = await ctx.vaultFolderCollection.find(id);
12766
+ if (record2.isDeleted) return null;
12585
12767
  const updated = await ctx.database.write(async () => {
12586
12768
  await ctx.database.batch(
12587
- record.prepareUpdate((r) => {
12769
+ record2.prepareUpdate((r) => {
12588
12770
  r._setRaw("context", context);
12589
12771
  })
12590
12772
  );
@@ -14641,7 +14823,7 @@ async function rankPreparedVaultCandidates(query, prepared, embeddingOptions, se
14641
14823
  if (useFusion && !embeddingsUnavailable && facetQueries) {
14642
14824
  let subEmbeddings;
14643
14825
  try {
14644
- subEmbeddings = await generateEmbeddings(facetQueries, embeddingOptions);
14826
+ subEmbeddings = prepared.facetEmbeddings ?? await generateEmbeddings(facetQueries, embeddingOptions);
14645
14827
  } catch (err) {
14646
14828
  getLogger().warn(
14647
14829
  "memoryVault: sub-query embedding failed \u2014 falling back to single-query ranking: " + (err instanceof Error ? err.message : String(err))
@@ -14826,6 +15008,35 @@ var DEFAULT_SCOPE = "private";
14826
15008
  var DEFAULT_CONSOLIDATE_THRESHOLD = 0.55;
14827
15009
  var DEFAULT_CONSOLIDATE_TOP_K = 20;
14828
15010
  async function retain(content, ctx, options = {}) {
15011
+ return retainWithPersistence(
15012
+ content,
15013
+ {
15014
+ embeddingOptions: ctx.embeddingOptions,
15015
+ vaultCache: ctx.vaultCache,
15016
+ persistence: {
15017
+ prepare: (query, searchOptions) => prepareVaultCandidates(
15018
+ query,
15019
+ ctx.vaultCtx,
15020
+ ctx.embeddingOptions,
15021
+ ctx.vaultCache,
15022
+ searchOptions
15023
+ ),
15024
+ get: (id) => getVaultMemoryOp(ctx.vaultCtx, id),
15025
+ tombstones: (_embedding, _model, scope, folderId) => getAllVaultMemoriesOp(ctx.vaultCtx, {
15026
+ includeDeleted: true,
15027
+ scopes: [scope],
15028
+ ...folderId !== void 0 && { folderId }
15029
+ }),
15030
+ create: (input) => createVaultMemoryOp(ctx.vaultCtx, input),
15031
+ update: (id, patch) => updateVaultMemoryOp(ctx.vaultCtx, id, patch),
15032
+ supersede: (id, successor) => supersedeVaultMemoryOp(ctx.vaultCtx, id, successor),
15033
+ createSuperseding: (input, target) => createSupersedingMemoryOp(ctx.vaultCtx, input, target)
15034
+ }
15035
+ },
15036
+ options
15037
+ );
15038
+ }
15039
+ async function retainWithPersistence(content, ctx, options = {}) {
14829
15040
  const trimmed = content.trim();
14830
15041
  if (trimmed.length === 0) {
14831
15042
  throw new Error("retain: content cannot be empty");
@@ -14838,19 +15049,14 @@ async function retain(content, ctx, options = {}) {
14838
15049
  let supersedeContent;
14839
15050
  let prepared;
14840
15051
  if (enableAutoMerge) {
14841
- prepared = await prepareVaultCandidates(
14842
- trimmed,
14843
- ctx.vaultCtx,
14844
- ctx.embeddingOptions,
14845
- ctx.vaultCache,
14846
- {
14847
- limit: Math.max(options.consolidateTopK ?? DEFAULT_CONSOLIDATE_TOP_K, 1),
14848
- useFusion: false,
14849
- scopes: [resolvedScope],
14850
- includeArchived: true,
14851
- ...options.folderId !== void 0 && { folderId: options.folderId }
14852
- }
14853
- );
15052
+ prepared = await ctx.persistence.prepare(trimmed, {
15053
+ limit: Math.max(options.consolidateTopK ?? DEFAULT_CONSOLIDATE_TOP_K, 1),
15054
+ useFusion: false,
15055
+ scopes: [resolvedScope],
15056
+ includeArchived: true,
15057
+ ...options.folderId !== void 0 && { folderId: options.folderId }
15058
+ });
15059
+ prepared = withoutKindedRows(prepared);
14854
15060
  if (prepared.embeddingFailure || prepared.embeddingsUnavailable) {
14855
15061
  throw new Error(
14856
15062
  "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."
@@ -14881,7 +15087,7 @@ async function retain(content, ctx, options = {}) {
14881
15087
  );
14882
15088
  if (matches.length > 0) {
14883
15089
  const targetId = matches[0].uniqueId;
14884
- const existing = await getVaultMemoryOp(ctx.vaultCtx, targetId);
15090
+ const existing = await ctx.persistence.get(targetId);
14885
15091
  if (existing && !existing.supersededBy) {
14886
15092
  const mergedSourceIds = unionStrings(
14887
15093
  existing.sourceChunkIds ?? [],
@@ -14890,8 +15096,9 @@ async function retain(content, ctx, options = {}) {
14890
15096
  const eventTimeUpdate = pickEventTimeUpdate(existing, options.eventTime);
14891
15097
  const factTypeUpdate = pickFactTypeUpdate(existing, options.factType);
14892
15098
  const resurrect = resurrectFields(existing);
14893
- const updated = await updateVaultMemoryOp(ctx.vaultCtx, targetId, {
15099
+ const updated = await ctx.persistence.update(targetId, {
14894
15100
  content: existing.content,
15101
+ freeFormOnly: true,
14895
15102
  proofCountIncrement: 1,
14896
15103
  observationSourceIds: options.sourceChunkIds,
14897
15104
  sourceChunkIds: mergedSourceIds,
@@ -14917,7 +15124,8 @@ async function retain(content, ctx, options = {}) {
14917
15124
  }
14918
15125
  const contentToWrite = supersedeContent ?? trimmed;
14919
15126
  const reusableQueryEmbedding = supersedeContent === void 0 && prepared && prepared.queryEmbedding.length > 0 ? prepared.queryEmbedding : void 0;
14920
- const embedding = reusableQueryEmbedding ?? await generateEmbedding(contentToWrite, ctx.embeddingOptions);
15127
+ const generatedEmbedding = reusableQueryEmbedding ?? await generateEmbedding(contentToWrite, ctx.embeddingOptions);
15128
+ const embedding = ctx.normalizeEmbedding?.(generatedEmbedding) ?? generatedEmbedding;
14921
15129
  const embeddingModel = ctx.embeddingOptions.model ?? DEFAULT_API_EMBEDDING_MODEL;
14922
15130
  if (options.respectTombstones) {
14923
15131
  const tombstone = await findTombstoneMatch(embedding, embeddingModel, resolvedScope, ctx, {
@@ -14957,8 +15165,7 @@ async function retain(content, ctx, options = {}) {
14957
15165
  };
14958
15166
  if (supersedeTargetIds.length > 0) {
14959
15167
  const [primaryTargetId, ...restTargetIds] = supersedeTargetIds;
14960
- const { created: created2, retired } = await createSupersedingMemoryOp(
14961
- ctx.vaultCtx,
15168
+ const { created: created2, retired } = await ctx.persistence.createSuperseding(
14962
15169
  createOpts,
14963
15170
  primaryTargetId
14964
15171
  );
@@ -14974,11 +15181,11 @@ async function retain(content, ctx, options = {}) {
14974
15181
  for (const staleId of restTargetIds) {
14975
15182
  let ok = false;
14976
15183
  try {
14977
- ok = await supersedeVaultMemoryOp(ctx.vaultCtx, staleId, created2.uniqueId) === true;
15184
+ ok = await ctx.persistence.supersede(staleId, created2.uniqueId) === true;
14978
15185
  } catch {
14979
15186
  }
14980
15187
  if (ok) continue;
14981
- const stillLive = await getVaultMemoryOp(ctx.vaultCtx, staleId).catch(() => null);
15188
+ const stillLive = await (ctx.persistence.getFresh ? ctx.persistence.getFresh(staleId) : ctx.persistence.get(staleId)).catch(() => null);
14982
15189
  if (stillLive && !stillLive.supersededBy) liveLeftovers.push(staleId);
14983
15190
  }
14984
15191
  if (liveLeftovers.length > 0) {
@@ -15005,7 +15212,7 @@ async function retain(content, ctx, options = {}) {
15005
15212
  `supersede: primary target ${primaryTargetId} retired or deleted inside the atomic write`
15006
15213
  );
15007
15214
  }
15008
- const created = await createVaultMemoryOp(ctx.vaultCtx, createOpts);
15215
+ const created = await ctx.persistence.create(createOpts);
15009
15216
  cacheRowVector(
15010
15217
  ctx.vaultCache,
15011
15218
  created.uniqueId,
@@ -15020,15 +15227,22 @@ async function retain(content, ctx, options = {}) {
15020
15227
  ...consolidationDecidedCreate && { consolidation: "create" }
15021
15228
  };
15022
15229
  }
15230
+ function withoutKindedRows(prepared) {
15231
+ const kinded = new Set(
15232
+ prepared.memories.filter((m) => m.kind !== null && m.kind !== void 0).map((m) => m.uniqueId)
15233
+ );
15234
+ if (kinded.size === 0) return prepared;
15235
+ return {
15236
+ ...prepared,
15237
+ memories: prepared.memories.filter((m) => !kinded.has(m.uniqueId)),
15238
+ embeddedItems: prepared.embeddedItems.filter((item) => !kinded.has(item.id))
15239
+ };
15240
+ }
15023
15241
  function unionStrings(a, b) {
15024
15242
  return [.../* @__PURE__ */ new Set([...a, ...b])];
15025
15243
  }
15026
15244
  async function findTombstoneMatch(embedding, embeddingModel, scope, ctx, opts) {
15027
- const rows = await getAllVaultMemoriesOp(ctx.vaultCtx, {
15028
- includeDeleted: true,
15029
- scopes: [scope],
15030
- ...opts.folderId !== void 0 && { folderId: opts.folderId }
15031
- });
15245
+ const rows = await ctx.persistence.tombstones(embedding, embeddingModel, scope, opts.folderId);
15032
15246
  let bestId = null;
15033
15247
  let bestSim = opts.threshold;
15034
15248
  for (const row of rows) {
@@ -15095,7 +15309,7 @@ async function tryConsolidate(trimmed, ctx, options, prepared) {
15095
15309
  if (requestedIds.length === 0) return null;
15096
15310
  const valid = [];
15097
15311
  for (const id of requestedIds) {
15098
- const existing = await getVaultMemoryOp(ctx.vaultCtx, id);
15312
+ const existing = await ctx.persistence.get(id);
15099
15313
  if (existing && !existing.supersededBy) valid.push(id);
15100
15314
  }
15101
15315
  if (valid.length === 0) {
@@ -15107,7 +15321,7 @@ async function tryConsolidate(trimmed, ctx, options, prepared) {
15107
15321
  return { supersede: valid, content: decision.content };
15108
15322
  }
15109
15323
  if (decision.action === "noop" && decision.targetId) {
15110
- const existing = await getVaultMemoryOp(ctx.vaultCtx, decision.targetId);
15324
+ const existing = await ctx.persistence.get(decision.targetId);
15111
15325
  if (!existing || existing.supersededBy) {
15112
15326
  return abandonToRace(
15113
15327
  options,
@@ -15121,8 +15335,9 @@ async function tryConsolidate(trimmed, ctx, options, prepared) {
15121
15335
  const eventTimeUpdate = pickEventTimeUpdate(existing, options.eventTime);
15122
15336
  const factTypeUpdate = pickFactTypeUpdate(existing, options.factType);
15123
15337
  const resurrect = resurrectFields(existing);
15124
- const updated = await updateVaultMemoryOp(ctx.vaultCtx, decision.targetId, {
15338
+ const updated = await ctx.persistence.update(decision.targetId, {
15125
15339
  content: existing.content,
15340
+ freeFormOnly: true,
15126
15341
  proofCountIncrement: 1,
15127
15342
  observationSourceIds: options.sourceChunkIds,
15128
15343
  sourceChunkIds: mergedSourceIds,
@@ -15149,7 +15364,7 @@ async function tryConsolidate(trimmed, ctx, options, prepared) {
15149
15364
  };
15150
15365
  }
15151
15366
  if (decision.action === "update" && decision.targetId && decision.content) {
15152
- const existing = await getVaultMemoryOp(ctx.vaultCtx, decision.targetId);
15367
+ const existing = await ctx.persistence.get(decision.targetId);
15153
15368
  if (!existing || existing.supersededBy) {
15154
15369
  return abandonToRace(
15155
15370
  options,
@@ -15160,13 +15375,15 @@ async function tryConsolidate(trimmed, ctx, options, prepared) {
15160
15375
  existing.sourceChunkIds ?? [],
15161
15376
  options.sourceChunkIds ?? []
15162
15377
  );
15163
- const newEmbedding = await generateEmbedding(decision.content, ctx.embeddingOptions);
15378
+ const generatedEmbedding = await generateEmbedding(decision.content, ctx.embeddingOptions);
15379
+ const newEmbedding = ctx.normalizeEmbedding?.(generatedEmbedding) ?? generatedEmbedding;
15164
15380
  const consolidatedModel = ctx.embeddingOptions.model ?? DEFAULT_API_EMBEDDING_MODEL;
15165
15381
  const eventTimeUpdate = pickEventTimeUpdate(existing, options.eventTime);
15166
15382
  const factTypeUpdate = pickFactTypeUpdate(existing, options.factType);
15167
15383
  const resurrect = resurrectFields(existing);
15168
- const updated = await updateVaultMemoryOp(ctx.vaultCtx, decision.targetId, {
15384
+ const updated = await ctx.persistence.update(decision.targetId, {
15169
15385
  content: decision.content,
15386
+ freeFormOnly: true,
15170
15387
  proofCountIncrement: 1,
15171
15388
  observationSourceIds: options.sourceChunkIds,
15172
15389
  sourceChunkIds: mergedSourceIds,
@@ -15209,8 +15426,8 @@ async function tryConsolidate(trimmed, ctx, options, prepared) {
15209
15426
  return null;
15210
15427
  }
15211
15428
  async function assertMergeTargetGoneOrThrow(ctx, targetId) {
15212
- const stillExists = await getVaultMemoryOp(ctx.vaultCtx, targetId);
15213
- if (stillExists) {
15429
+ const stillExists = await (ctx.persistence.getFresh ? ctx.persistence.getFresh(targetId) : ctx.persistence.get(targetId));
15430
+ if (stillExists && (stillExists.kind === null || stillExists.kind === void 0)) {
15214
15431
  throw new Error(`retain: merge into memory ${targetId} failed to persist`);
15215
15432
  }
15216
15433
  }
@@ -15724,9 +15941,9 @@ function createAutoExtractor(options) {
15724
15941
  const persistCursor = (conversationId, messages, advancedToId, contiguous) => {
15725
15942
  if (!cursorStore || conversationId === void 0 || !contiguous) return;
15726
15943
  try {
15727
- const stored = cursorStore.get(conversationId);
15728
- if (stored && stored !== advancedToId) {
15729
- const storedIdx = messages.findIndex((m) => m.id === stored);
15944
+ const stored2 = cursorStore.get(conversationId);
15945
+ if (stored2 && stored2 !== advancedToId) {
15946
+ const storedIdx = messages.findIndex((m) => m.id === stored2);
15730
15947
  const newIdx = messages.findIndex((m) => m.id === advancedToId);
15731
15948
  if (storedIdx !== -1 && newIdx !== -1 && storedIdx >= newIdx) return;
15732
15949
  }
@@ -16695,7 +16912,7 @@ async function recall(query, ctx, options = {}) {
16695
16912
  if (graphLaneFailed) degraded.push("graph-lane-failed");
16696
16913
  if (temporalLaneFailed) degraded.push("temporal-lane-failed");
16697
16914
  if (chunksScopeRestricted) degraded.push("chunks-scope-restricted");
16698
- const laneRan = types.includes("fact") && !!ctx.vaultCtx && !!ctx.vaultCache || types.includes("chunk") && !!ctx.storageCtx || chunksScopeRestricted && !!ctx.storageCtx;
16915
+ const laneRan = types.includes("fact") && (!!ctx.factSource || !!ctx.vaultCtx && !!ctx.vaultCache) || types.includes("chunk") && !!ctx.storageCtx || chunksScopeRestricted && !!ctx.storageCtx;
16699
16916
  const scores = admitted.map((m) => m.score);
16700
16917
  const minScoreApplied = factResults.length > 0 ? factFloor : chunkResults.length > 0 ? chunkFloor : factFloor >= 0 ? factFloor : chunkFloor;
16701
16918
  const diagnostics = {
@@ -16737,7 +16954,7 @@ async function recall(query, ctx, options = {}) {
16737
16954
  return { memories: [], usedBudget, reranked: false, candidateCount: 0 };
16738
16955
  }
16739
16956
  const needsChunkEmbedding = types.includes("chunk") && ctx.storageCtx;
16740
- const wantsTemporal = types.includes("fact") && ctx.vaultCtx;
16957
+ const wantsTemporal = types.includes("fact") && (ctx.factSource || ctx.vaultCtx);
16741
16958
  const graphRefiner = flags.traverse && options.graphRefine && options.decomposeOptions ? createLlmNeighborRefiner(options.decomposeOptions) : void 0;
16742
16959
  const queryEmbedTotalTimeoutMs = options.queryEmbedTotalTimeoutMs ?? DEFAULT_QUERY_EMBED_TOTAL_TIMEOUT_MS;
16743
16960
  const prepStart = nowMs2();
@@ -16767,7 +16984,7 @@ async function recall(query, ctx, options = {}) {
16767
16984
  safeLane(
16768
16985
  "graph",
16769
16986
  () => graphLaneFailed = true,
16770
- () => buildGraphLaneRanking(query, ctx, flags.traverse, {
16987
+ () => ctx.factSource ? ctx.factSource.graphRanking(query, flags.traverse, options) : buildGraphLaneRanking(query, ctx, flags.traverse, {
16771
16988
  ...options.maxHops !== void 0 && { maxHops: options.maxHops },
16772
16989
  ...options.entityFanout !== void 0 && { entityFanout: options.entityFanout },
16773
16990
  ...options.nodeBudget !== void 0 && { nodeBudget: options.nodeBudget },
@@ -16778,13 +16995,13 @@ async function recall(query, ctx, options = {}) {
16778
16995
  wantsTemporal ? safeLane(
16779
16996
  "temporal",
16780
16997
  () => temporalLaneFailed = true,
16781
- () => buildTemporalLaneRanking(query, ctx.vaultCtx, options.now)
16998
+ () => ctx.factSource ? ctx.factSource.temporalRanking(query, options.now) : buildTemporalLaneRanking(query, ctx.vaultCtx, options.now)
16782
16999
  ) : Promise.resolve([])
16783
17000
  ]);
16784
17001
  prepMs = nowMs2() - prepStart;
16785
17002
  graphLaneCount = entityRanking.length;
16786
17003
  temporalLaneCount = temporalRanking.length;
16787
- if (types.includes("fact") && ctx.vaultCtx && ctx.vaultCache) {
17004
+ if (types.includes("fact") && (ctx.factSource || ctx.vaultCtx && ctx.vaultCache)) {
16788
17005
  const factStart = nowMs2();
16789
17006
  const vaultMinScore = options.minScore ?? DEFAULT_FACT_MIN_SCORE;
16790
17007
  factFloor = vaultMinScore;
@@ -16800,50 +17017,50 @@ async function recall(query, ctx, options = {}) {
16800
17017
  rankedOnCosine: factRankedOnCosine,
16801
17018
  decryptLast: factDecryptLast,
16802
17019
  rowsDecrypted: factRowsDecrypted
16803
- } = await searchVaultMemoriesWithSize(
16804
- query,
17020
+ } = await (ctx.factSource?.search.bind(ctx.factSource) ?? ((searchQuery, searchOptions) => searchVaultMemoriesWithSize(
17021
+ searchQuery,
16805
17022
  ctx.vaultCtx,
16806
17023
  ctx.embeddingOptions,
16807
17024
  ctx.vaultCache,
16808
- {
16809
- limit: types.includes("chunk") ? Math.max(limit * 2, 16) : limit,
16810
- minSimilarity: vaultMinScore,
16811
- useFusion: true,
16812
- rerank: flags.rerank,
16813
- ...options.rerankTopN !== void 0 && { rerankTopN: options.rerankTopN },
16814
- ...options.ceWeight !== void 0 && { ceWeight: options.ceWeight },
16815
- ...options.rerankLoadTimeoutMs !== void 0 && {
16816
- rerankLoadTimeoutMs: options.rerankLoadTimeoutMs
16817
- },
16818
- ...options.recencyAlpha !== void 0 && { recencyAlpha: options.recencyAlpha },
16819
- ...options.recency && { recency: options.recency },
16820
- ...options.mmr !== void 0 && { mmr: options.mmr },
16821
- ...options.supersessionBoost !== void 0 && {
16822
- supersessionBoost: options.supersessionBoost
16823
- },
16824
- ...options.supersessionWindow !== void 0 && {
16825
- supersessionWindow: options.supersessionWindow
16826
- },
16827
- ...options.proofCountAlpha !== void 0 && {
16828
- proofCountAlpha: options.proofCountAlpha
16829
- },
16830
- ...options.bm25AdmissionDivisor !== void 0 && {
16831
- bm25AdmissionDivisor: options.bm25AdmissionDivisor
16832
- },
16833
- ...options.rrfK !== void 0 && { rrfK: options.rrfK },
16834
- ...options.decryptLast !== void 0 && { decryptLast: options.decryptLast },
16835
- ...subQueries && { subQueries },
16836
- ...options.scopes && { scopes: options.scopes },
16837
- ...options.folderId !== void 0 && { folderId: options.folderId },
16838
- ...options.factTypes?.length && { factTypes: options.factTypes },
16839
- ...options.memoryIds !== void 0 && { memoryIds: options.memoryIds },
16840
- ...options.factTypeWeights && { factTypeWeights: options.factTypeWeights },
16841
- ...entityRanking.length > 0 && { entityRanking },
16842
- ...temporalRanking.length > 0 && { temporalRanking },
16843
- ...needsChunkEmbedding && { queryEmbedding: queryEmbedding ?? [] },
16844
- queryEmbedTotalTimeoutMs
16845
- }
16846
- );
17025
+ searchOptions
17026
+ )))(query, {
17027
+ limit: types.includes("chunk") ? Math.max(limit * 2, 16) : limit,
17028
+ minSimilarity: vaultMinScore,
17029
+ useFusion: true,
17030
+ rerank: flags.rerank,
17031
+ ...options.rerankTopN !== void 0 && { rerankTopN: options.rerankTopN },
17032
+ ...options.ceWeight !== void 0 && { ceWeight: options.ceWeight },
17033
+ ...options.rerankLoadTimeoutMs !== void 0 && {
17034
+ rerankLoadTimeoutMs: options.rerankLoadTimeoutMs
17035
+ },
17036
+ ...options.recencyAlpha !== void 0 && { recencyAlpha: options.recencyAlpha },
17037
+ ...options.recency && { recency: options.recency },
17038
+ ...options.mmr !== void 0 && { mmr: options.mmr },
17039
+ ...options.supersessionBoost !== void 0 && {
17040
+ supersessionBoost: options.supersessionBoost
17041
+ },
17042
+ ...options.supersessionWindow !== void 0 && {
17043
+ supersessionWindow: options.supersessionWindow
17044
+ },
17045
+ ...options.proofCountAlpha !== void 0 && {
17046
+ proofCountAlpha: options.proofCountAlpha
17047
+ },
17048
+ ...options.bm25AdmissionDivisor !== void 0 && {
17049
+ bm25AdmissionDivisor: options.bm25AdmissionDivisor
17050
+ },
17051
+ ...options.rrfK !== void 0 && { rrfK: options.rrfK },
17052
+ ...options.decryptLast !== void 0 && { decryptLast: options.decryptLast },
17053
+ ...subQueries && { subQueries },
17054
+ ...options.scopes && { scopes: options.scopes },
17055
+ ...options.folderId !== void 0 && { folderId: options.folderId },
17056
+ ...options.factTypes?.length && { factTypes: options.factTypes },
17057
+ ...options.memoryIds !== void 0 && { memoryIds: options.memoryIds },
17058
+ ...options.factTypeWeights && { factTypeWeights: options.factTypeWeights },
17059
+ ...entityRanking.length > 0 && { entityRanking },
17060
+ ...temporalRanking.length > 0 && { temporalRanking },
17061
+ ...needsChunkEmbedding && { queryEmbedding: queryEmbedding ?? [] },
17062
+ queryEmbedTotalTimeoutMs
17063
+ });
16847
17064
  factResults.push(
16848
17065
  ...dedupeBy(
16849
17066
  results,
@@ -17648,26 +17865,26 @@ async function extractAndLinkEntitiesForMemoriesOp(ctx, memoryIds, options) {
17648
17865
  };
17649
17866
  const inputs = [];
17650
17867
  for (const id of new Set(memoryIds)) {
17651
- let record;
17868
+ let record2;
17652
17869
  try {
17653
- record = await ctx.vaultMemoryCollection.find(id);
17870
+ record2 = await ctx.vaultMemoryCollection.find(id);
17654
17871
  } catch (err) {
17655
17872
  log.warn("[memory/topics] vault lookup failed for extraction", err);
17656
17873
  skip(id, "not-found");
17657
17874
  continue;
17658
17875
  }
17659
- if (record.isDeleted || ctx.userId !== void 0 && record.userId !== ctx.userId || record.topicsUserManaged) {
17876
+ if (record2.isDeleted || ctx.userId !== void 0 && record2.userId !== ctx.userId || record2.topicsUserManaged) {
17660
17877
  skip(id, "excluded");
17661
17878
  continue;
17662
17879
  }
17663
17880
  try {
17664
- const stored = await vaultMemoryToStored(
17665
- record,
17881
+ const stored2 = await vaultMemoryToStored(
17882
+ record2,
17666
17883
  ctx.walletAddress,
17667
17884
  ctx.signMessage,
17668
17885
  ctx.embeddedWalletSigner
17669
17886
  );
17670
- inputs.push({ id, content: stored.content });
17887
+ inputs.push({ id, content: stored2.content });
17671
17888
  } catch (err) {
17672
17889
  log.warn("[memory/topics] failed to load memory for extraction", err);
17673
17890
  skip(id, "unreadable");
@@ -17852,6 +18069,780 @@ function createLocalMemoryStore(options) {
17852
18069
  };
17853
18070
  }
17854
18071
 
18072
+ // src/lib/memory/store/remotePersistence.ts
18073
+ var RemoteMemoryError = class extends Error {
18074
+ constructor(message, status, code) {
18075
+ super(message);
18076
+ this.status = status;
18077
+ this.code = code;
18078
+ this.name = "RemoteMemoryError";
18079
+ }
18080
+ };
18081
+ var ciphertextPattern = /^enc:v\d+:[0-9a-f]+$/i;
18082
+ var memoryFields = {
18083
+ memory_id: true,
18084
+ content: true,
18085
+ scope: true,
18086
+ created_at: true,
18087
+ updated_at: true,
18088
+ is_deleted: true,
18089
+ embedding: true,
18090
+ embedding_model: true,
18091
+ kind: true,
18092
+ kind_value: true,
18093
+ level: true,
18094
+ folder_id: true,
18095
+ source_chunk_ids: true,
18096
+ proof_count: true,
18097
+ source: true,
18098
+ event_time_start: true,
18099
+ event_time_end: true,
18100
+ event_time_kind: true,
18101
+ topics_user_managed: true,
18102
+ topics: true,
18103
+ topics_updated_at: true,
18104
+ media: true,
18105
+ topics_extracted_at: true,
18106
+ topics_extracted_version: true,
18107
+ superseded_by: true,
18108
+ superseded_at: true,
18109
+ last_observed_at: true,
18110
+ fact_type: true,
18111
+ archived_at: true,
18112
+ trust_tier: true,
18113
+ visibility: true,
18114
+ twin_opt_in: true,
18115
+ published_at: true,
18116
+ geohash: true
18117
+ };
18118
+ var candidateListLimits = [
18119
+ ["scopes", 20],
18120
+ ["fact_types", 20],
18121
+ ["memory_ids", 1e3],
18122
+ ["force_ids", 100]
18123
+ ];
18124
+ function record(value) {
18125
+ return typeof value === "object" && value !== null && !Array.isArray(value);
18126
+ }
18127
+ function memoryRecord(value) {
18128
+ 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))) {
18129
+ throw new Error("Invalid nearby private-memory response");
18130
+ }
18131
+ return value;
18132
+ }
18133
+ async function createRemoteMemoryPersistence(options) {
18134
+ const base = new URL(options.baseUrl);
18135
+ if (!/^https?:$/.test(base.protocol) || base.username || base.password || base.search || base.hash) {
18136
+ throw new Error(
18137
+ "baseUrl must be an HTTP(S) origin or base path without credentials, query or fragment"
18138
+ );
18139
+ }
18140
+ if (!options.keyId || options.keyId.length > 256)
18141
+ throw new Error("A canonical keyId is required");
18142
+ const timeoutMs = options.timeoutMs ?? 3e4;
18143
+ if (!Number.isFinite(timeoutMs) || timeoutMs <= 0)
18144
+ throw new Error("timeoutMs must be a positive number");
18145
+ const root = base.href.replace(/\/$/, "") + "/api/private-memories";
18146
+ const fetcher = options.fetch ?? globalThis.fetch;
18147
+ const request = async (path, init = {}, signal) => {
18148
+ const controller = new AbortController();
18149
+ let timedOut = false;
18150
+ const timer = setTimeout(() => {
18151
+ timedOut = true;
18152
+ controller.abort();
18153
+ }, timeoutMs);
18154
+ const forwardAbort = () => controller.abort(signal?.reason);
18155
+ if (signal?.aborted) forwardAbort();
18156
+ else signal?.addEventListener("abort", forwardAbort, { once: true });
18157
+ let rejectAborted;
18158
+ const aborted = new Promise((_, reject) => {
18159
+ rejectAborted = () => reject(
18160
+ controller.signal.reason instanceof Error ? controller.signal.reason : new Error("Nearby request aborted")
18161
+ );
18162
+ if (controller.signal.aborted) rejectAborted();
18163
+ else controller.signal.addEventListener("abort", rejectAborted, { once: true });
18164
+ });
18165
+ aborted.catch(() => void 0);
18166
+ try {
18167
+ const token = await Promise.race([options.getToken(), aborted]);
18168
+ if (controller.signal.aborted) await aborted;
18169
+ if (!token) throw new RemoteMemoryError("Authentication required", 401);
18170
+ const response = await fetcher(root + path, {
18171
+ ...init,
18172
+ headers: {
18173
+ Authorization: `Bearer ${token}`,
18174
+ ...init.body ? { "Content-Type": "application/json" } : {}
18175
+ },
18176
+ redirect: "error",
18177
+ signal: controller.signal
18178
+ });
18179
+ if (!response.ok) {
18180
+ const body = await response.json().catch(() => null);
18181
+ throw new RemoteMemoryError(
18182
+ record(body) && typeof body.detail === "string" ? body.detail : `Nearby request failed (${response.status})`,
18183
+ response.status,
18184
+ record(body) && typeof body.code === "string" ? body.code : void 0
18185
+ );
18186
+ }
18187
+ return await response.json();
18188
+ } catch (error) {
18189
+ if (timedOut) throw new RemoteMemoryError("Nearby request timed out", 408, "timeout");
18190
+ throw error;
18191
+ } finally {
18192
+ clearTimeout(timer);
18193
+ signal?.removeEventListener("abort", forwardAbort);
18194
+ if (rejectAborted) controller.signal.removeEventListener("abort", rejectAborted);
18195
+ }
18196
+ };
18197
+ const account = await request("/account", {}, options.signal);
18198
+ if (!record(account) || account.state !== "active") {
18199
+ throw new RemoteMemoryError(
18200
+ "Complete and verify migration before using remote memories",
18201
+ 409,
18202
+ "memory_not_active"
18203
+ );
18204
+ }
18205
+ if (account.key_id !== options.keyId) {
18206
+ throw new RemoteMemoryError(
18207
+ "The canonical memory key does not match this account",
18208
+ 409,
18209
+ "key_mismatch"
18210
+ );
18211
+ }
18212
+ const snapshots = /* @__PURE__ */ new WeakMap();
18213
+ const decode = async (value) => {
18214
+ const item = memoryRecord(value);
18215
+ const decrypt = async (ciphertext) => {
18216
+ if (!ciphertextPattern.test(ciphertext))
18217
+ throw new Error("Nearby returned unencrypted memory content");
18218
+ const plaintext = await options.decrypt(ciphertext);
18219
+ if (plaintext === ciphertext) throw new Error("Memory decryption failed");
18220
+ return plaintext;
18221
+ };
18222
+ const decoded = {
18223
+ ...item,
18224
+ memory: {
18225
+ ...item.memory,
18226
+ content: await decrypt(item.memory.content),
18227
+ ...item.memory.kind_value !== void 0 && {
18228
+ kind_value: await decrypt(item.memory.kind_value)
18229
+ }
18230
+ }
18231
+ };
18232
+ return remember(decoded, item);
18233
+ };
18234
+ const remember = (decoded, item) => {
18235
+ snapshots.set(decoded, {
18236
+ id: item.memory.memory_id,
18237
+ version: item.version,
18238
+ content: decoded.memory.content,
18239
+ kindValue: decoded.memory.kind_value,
18240
+ encryptedContent: item.memory.content,
18241
+ encryptedKindValue: item.memory.kind_value
18242
+ });
18243
+ return decoded;
18244
+ };
18245
+ const decodeAll = async (values) => {
18246
+ const records = values.map(memoryRecord);
18247
+ const settled = await Promise.allSettled(records.map(decode));
18248
+ const items = [];
18249
+ const failed = [];
18250
+ settled.forEach((result, i) => {
18251
+ if (result.status === "fulfilled") items.push(result.value);
18252
+ else
18253
+ failed.push({
18254
+ memory_id: records[i].memory.memory_id,
18255
+ version: records[i].version,
18256
+ error: result.reason instanceof Error ? result.reason : new Error(String(result.reason))
18257
+ });
18258
+ });
18259
+ return { items, failed };
18260
+ };
18261
+ const decodeCommitted = async (value, write) => {
18262
+ const item = memoryRecord(value);
18263
+ 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)
18264
+ return decode(item);
18265
+ return remember(
18266
+ {
18267
+ ...item,
18268
+ memory: {
18269
+ ...item.memory,
18270
+ content: write.content,
18271
+ ...write.kindValue !== void 0 && { kind_value: write.kindValue }
18272
+ }
18273
+ },
18274
+ item
18275
+ );
18276
+ };
18277
+ const encryptField2 = async (plaintext) => {
18278
+ const ciphertext = await options.encrypt(plaintext);
18279
+ if (ciphertext === plaintext || !ciphertextPattern.test(ciphertext))
18280
+ throw new Error("Field encryption must return SDK ciphertext; refusing to upload plaintext");
18281
+ return ciphertext;
18282
+ };
18283
+ const memoryPath = (id) => {
18284
+ if (!id || id.length > 128) throw new Error("memory_id must be 1\u2013128 characters");
18285
+ return "/memories/" + encodeURIComponent(id);
18286
+ };
18287
+ const prepareWrite = async (memory, expectedVersion, signal) => {
18288
+ const unknown = Object.keys(memory).filter(
18289
+ (key) => !Object.prototype.hasOwnProperty.call(memoryFields, key)
18290
+ );
18291
+ if (unknown.length) {
18292
+ throw new RemoteMemoryError(
18293
+ `Unknown private-memory fields (${unknown.join(", ")}); refusing to forward them`,
18294
+ 400,
18295
+ "unknown_field"
18296
+ );
18297
+ }
18298
+ memory = { ...memory, ...memory.embedding && { embedding: [...memory.embedding] } };
18299
+ const path = memoryPath(memory.memory_id);
18300
+ const snapshot = typeof expectedVersion === "number" ? void 0 : snapshots.get(expectedVersion);
18301
+ if (typeof expectedVersion !== "number" && (!snapshot || snapshot.id !== memory.memory_id || snapshot.version !== expectedVersion.version))
18302
+ throw new Error(
18303
+ "Expected snapshot must be an unmodified version from this persistence instance"
18304
+ );
18305
+ expectedVersion = typeof expectedVersion === "number" ? expectedVersion : snapshot.version;
18306
+ if (!Number.isSafeInteger(expectedVersion) || expectedVersion < 0)
18307
+ throw new Error("expectedVersion must be a nonnegative integer");
18308
+ const conflict = () => new RemoteMemoryError("The memory changed since it was read", 409, "version_conflict");
18309
+ let existing;
18310
+ if (expectedVersion !== 0 && !snapshot) {
18311
+ try {
18312
+ existing = memoryRecord(await request(path, {}, signal));
18313
+ } catch (error) {
18314
+ if (error instanceof RemoteMemoryError && error.status === 404) throw conflict();
18315
+ throw error;
18316
+ }
18317
+ }
18318
+ if (existing && existing.version !== expectedVersion) throw conflict();
18319
+ const decoded = existing ? await decode(existing).catch(() => void 0) : void 0;
18320
+ const content = (snapshot?.content ?? decoded?.memory.content) === memory.content ? snapshot?.encryptedContent ?? existing.memory.content : await encryptField2(memory.content);
18321
+ 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);
18322
+ return {
18323
+ body: {
18324
+ expected_version: expectedVersion,
18325
+ memory: { ...memory, content, ...kindValue !== void 0 && { kind_value: kindValue } }
18326
+ },
18327
+ content: memory.content,
18328
+ kindValue: memory.kind_value
18329
+ };
18330
+ };
18331
+ const fetchCandidates = async (embedding, candidateOptions, withCounts) => {
18332
+ const limit = candidateOptions.limit ?? 100;
18333
+ if (!Number.isInteger(limit) || limit < 1 || limit > 100)
18334
+ throw new Error("Candidate limit must be 1\u2013100");
18335
+ for (const [key, max] of candidateListLimits) {
18336
+ const values = candidateOptions[key];
18337
+ if (values && values.length > max)
18338
+ throw new Error(`Candidate ${key} accepts at most ${max} entries (got ${values.length})`);
18339
+ }
18340
+ const result = await request(
18341
+ "/candidates",
18342
+ {
18343
+ method: "POST",
18344
+ body: JSON.stringify({
18345
+ embedding,
18346
+ limit,
18347
+ force_ids: candidateOptions.force_ids ?? [],
18348
+ ...withCounts && { with_counts: true },
18349
+ ...Object.fromEntries(
18350
+ [
18351
+ "scopes",
18352
+ "memory_ids",
18353
+ "embedding_model",
18354
+ "strict_model",
18355
+ "include_deleted",
18356
+ "deleted_only"
18357
+ ].filter(
18358
+ (key) => candidateOptions[key] !== void 0
18359
+ ).map((key) => [key, candidateOptions[key]])
18360
+ ),
18361
+ ...candidateOptions.fact_types !== void 0 && {
18362
+ fact_types: candidateOptions.fact_types
18363
+ },
18364
+ ...candidateOptions.include_archived !== void 0 && {
18365
+ include_archived: candidateOptions.include_archived
18366
+ },
18367
+ ...candidateOptions.include_quarantined !== void 0 && {
18368
+ include_quarantined: candidateOptions.include_quarantined
18369
+ },
18370
+ ...candidateOptions.include_superseded !== void 0 && {
18371
+ include_superseded: candidateOptions.include_superseded
18372
+ }
18373
+ })
18374
+ },
18375
+ candidateOptions.signal
18376
+ );
18377
+ if (!record(result) || !Array.isArray(result.items))
18378
+ throw new Error("Invalid nearby candidate response");
18379
+ return result;
18380
+ };
18381
+ const candidateSet = async (embedding, candidateOptions = {}) => {
18382
+ const result = await fetchCandidates(embedding, candidateOptions, true);
18383
+ if (!Number.isSafeInteger(result.total_count) || result.total_count < 0 || !Number.isSafeInteger(result.unavailable_count) || result.unavailable_count < 0)
18384
+ throw new Error("Invalid nearby candidate response");
18385
+ return {
18386
+ ...await decodeAll(result.items),
18387
+ total_count: result.total_count,
18388
+ unavailable_count: result.unavailable_count
18389
+ };
18390
+ };
18391
+ return {
18392
+ get: async (id, signal) => {
18393
+ try {
18394
+ return await decode(await request(memoryPath(id), {}, signal));
18395
+ } catch (error) {
18396
+ if (error instanceof RemoteMemoryError && error.status === 404) return null;
18397
+ throw error;
18398
+ }
18399
+ },
18400
+ list: async (listOptions = {}) => {
18401
+ const { signal, ...query } = listOptions;
18402
+ if (query.limit !== void 0 && (!Number.isInteger(query.limit) || query.limit < 1 || query.limit > 200)) {
18403
+ throw new Error("Page limit must be 1\u2013200");
18404
+ }
18405
+ const params = new URLSearchParams();
18406
+ for (const key of [
18407
+ "cursor",
18408
+ "limit",
18409
+ "include_deleted",
18410
+ "include_archived",
18411
+ "include_quarantined",
18412
+ "include_superseded",
18413
+ "include_embeddings"
18414
+ ]) {
18415
+ if (query[key] !== void 0) params.set(key, String(query[key]));
18416
+ }
18417
+ const page = await request("/memories?" + params.toString(), {}, signal);
18418
+ if (!record(page) || !Array.isArray(page.items) || page.next_cursor !== void 0 && typeof page.next_cursor !== "string") {
18419
+ throw new Error("Invalid nearby private-memory page");
18420
+ }
18421
+ return {
18422
+ ...await decodeAll(page.items),
18423
+ ...page.next_cursor !== void 0 && { next_cursor: page.next_cursor }
18424
+ };
18425
+ },
18426
+ put: async (memory, expectedVersion, signal) => {
18427
+ const write = await prepareWrite(memory, expectedVersion, signal);
18428
+ return decodeCommitted(
18429
+ await request(
18430
+ memoryPath(write.body.memory.memory_id),
18431
+ {
18432
+ method: "PUT",
18433
+ body: JSON.stringify({ key_id: options.keyId, ...write.body })
18434
+ },
18435
+ signal
18436
+ ),
18437
+ write
18438
+ );
18439
+ },
18440
+ putMany: async (writes, signal) => {
18441
+ if (writes.length < 1 || writes.length > 50 || new Set(writes.map((w) => w.memory.memory_id)).size !== writes.length)
18442
+ throw new Error("Batch must contain 1\u201350 distinct memory ids");
18443
+ const prepared = await Promise.all(
18444
+ writes.map((w) => prepareWrite(w.memory, w.expectedVersion, signal))
18445
+ );
18446
+ const result = await request(
18447
+ "/memories/batch",
18448
+ {
18449
+ method: "POST",
18450
+ body: JSON.stringify({ key_id: options.keyId, writes: prepared.map((w) => w.body) })
18451
+ },
18452
+ signal
18453
+ );
18454
+ if (!record(result) || !Array.isArray(result.items) || result.items.length !== prepared.length)
18455
+ throw new Error("Invalid nearby batch response");
18456
+ return Promise.all(result.items.map((item, i) => decodeCommitted(item, prepared[i])));
18457
+ },
18458
+ candidateSet,
18459
+ candidates: async (embedding, candidateOptions = {}) => decodeAll((await fetchCandidates(embedding, candidateOptions, false)).items)
18460
+ };
18461
+ }
18462
+
18463
+ // src/lib/memory/store/remotePipeline.ts
18464
+ import { v7 as uuidv74 } from "uuid";
18465
+ function storedVector(vector) {
18466
+ if (!Array.isArray(vector) || vector.length !== 1536 && vector.length !== 4096 || vector.some((v) => !Number.isFinite(v)))
18467
+ throw new Error("Remote memories require a finite 1536/4096-dimensional vector");
18468
+ const out = vector.slice(0, 1536);
18469
+ const norm = Math.sqrt(out.reduce((sum, v) => sum + v * v, 0));
18470
+ if (!norm) throw new Error("Remote query/content vector has no direction after MRL truncation");
18471
+ return out.map((v) => v / norm);
18472
+ }
18473
+ function sourceIds(value) {
18474
+ if (!value) return [];
18475
+ try {
18476
+ const parsed = JSON.parse(value);
18477
+ return Array.isArray(parsed) ? parsed.filter((id) => typeof id === "string") : [];
18478
+ } catch {
18479
+ return [];
18480
+ }
18481
+ }
18482
+ function isMemoryLevel(value) {
18483
+ return MEMORY_LEVELS.includes(value);
18484
+ }
18485
+ function stored(row) {
18486
+ return {
18487
+ uniqueId: row.memory_id,
18488
+ content: row.content,
18489
+ scope: row.scope,
18490
+ folderId: row.folder_id ?? null,
18491
+ userId: null,
18492
+ kind: row.kind ?? null,
18493
+ kindValue: row.kind_value ?? null,
18494
+ ...isMemoryLevel(row.level) && { level: row.level },
18495
+ embedding: row.embedding ? JSON.stringify(row.embedding) : null,
18496
+ embeddingModel: row.embedding_model ?? null,
18497
+ sourceChunkIds: row.source_chunk_ids === void 0 ? null : sourceIds(row.source_chunk_ids),
18498
+ proofCount: row.proof_count ?? null,
18499
+ source: row.source ?? null,
18500
+ media: parseMedia(row.media),
18501
+ eventTimeStart: row.event_time_start ?? null,
18502
+ eventTimeEnd: row.event_time_end ?? null,
18503
+ eventTimeKind: row.event_time_kind ?? null,
18504
+ topicsUserManaged: row.topics_user_managed ?? false,
18505
+ topics: parseTopics(row.topics),
18506
+ topicsUpdatedAt: row.topics_updated_at ?? null,
18507
+ topicsExtractedAt: row.topics_extracted_at ?? null,
18508
+ topicsExtractedVersion: row.topics_extracted_version ?? null,
18509
+ supersededBy: row.superseded_by ?? null,
18510
+ supersededAt: row.superseded_at ?? null,
18511
+ lastObservedAt: row.last_observed_at ?? null,
18512
+ factType: row.fact_type ?? null,
18513
+ archivedAt: row.archived_at ?? null,
18514
+ trustTier: row.trust_tier ?? null,
18515
+ visibility: row.visibility === "public" ? "public" : "private",
18516
+ twinOptIn: row.twin_opt_in ?? false,
18517
+ publishedAt: row.published_at ?? null,
18518
+ geohash: row.geohash ?? null,
18519
+ createdAt: new Date(row.created_at),
18520
+ updatedAt: new Date(row.updated_at),
18521
+ isDeleted: row.is_deleted
18522
+ };
18523
+ }
18524
+ function createRemoteMemoryPipeline(options) {
18525
+ const { persistence, embeddingOptions } = options;
18526
+ const model = embeddingOptions.model ?? DEFAULT_API_EMBEDDING_MODEL;
18527
+ const operation = (mode) => {
18528
+ const rejectUndecryptable = (failed) => {
18529
+ if (!failed.length) return;
18530
+ if (mode === "retain")
18531
+ throw new Error(
18532
+ `Remote memories could not decrypt ${failed.length} candidate row(s); refusing to retain until they are repaired`
18533
+ );
18534
+ getLogger().warn(
18535
+ `[memory/remote] Skipping ${failed.length} undecryptable candidate row(s)`,
18536
+ failed.map((failure) => failure.memory_id)
18537
+ );
18538
+ };
18539
+ const snapshots = /* @__PURE__ */ new Map();
18540
+ const remember = (items) => {
18541
+ items.forEach((item) => snapshots.set(item.memory.memory_id, item));
18542
+ return items.map((item) => stored(item.memory));
18543
+ };
18544
+ const get = async (id) => {
18545
+ const snapshot = snapshots.get(id) ?? await persistence.get(id);
18546
+ if (!snapshot || snapshot.memory.is_deleted || snapshot.memory.superseded_by) return null;
18547
+ snapshots.set(id, snapshot);
18548
+ return stored(snapshot.memory);
18549
+ };
18550
+ const prepare = async (query, search = {}) => {
18551
+ if (search.folderId !== void 0)
18552
+ throw new Error("Remote memories do not support folder filters");
18553
+ const facets = normalizeSubQueries(search.subQueries);
18554
+ const facetQueries = facets.length >= 2 ? facets : [];
18555
+ const start = Date.now();
18556
+ const budgetMs = search.queryEmbedTotalTimeoutMs ?? 8e3;
18557
+ const embed = (texts) => generateEmbeddings(texts, {
18558
+ ...embeddingOptions,
18559
+ totalTimeoutMs: budgetMs
18560
+ });
18561
+ const embedFacets = async () => {
18562
+ if (!facetQueries.length) return [];
18563
+ try {
18564
+ const vectors2 = await embed(facetQueries);
18565
+ if (vectors2.length !== facetQueries.length)
18566
+ throw new Error("Incomplete facet embeddings");
18567
+ return vectors2.map(storedVector);
18568
+ } catch (error) {
18569
+ getLogger().warn(
18570
+ "[memory/remote] Facet embeddings unavailable; using primary query",
18571
+ error
18572
+ );
18573
+ return [];
18574
+ }
18575
+ };
18576
+ const [primary, facetEmbeddings] = await Promise.all([
18577
+ search.queryEmbedding ?? embed([query]).then((vectors2) => vectors2[0]),
18578
+ embedFacets()
18579
+ ]);
18580
+ const queryEmbedding = storedVector(primary);
18581
+ const queryEmbedMs = Date.now() - start;
18582
+ const graph = search.entityRanking ?? [];
18583
+ const temporal = search.temporalRanking ?? [];
18584
+ const forced = /* @__PURE__ */ new Set();
18585
+ for (let i = 0; i < Math.max(graph.length, temporal.length) && forced.size < 100; i++) {
18586
+ if (graph[i] !== void 0) forced.add(graph[i]);
18587
+ if (forced.size < 100 && temporal[i] !== void 0) forced.add(temporal[i]);
18588
+ }
18589
+ const forceIds = [...forced];
18590
+ const windowOptions = (i, signal) => ({
18591
+ limit: Math.min(100, Math.max((search.limit ?? 8) * 3, 30)),
18592
+ force_ids: i === 0 ? forceIds : [],
18593
+ ...search.scopes && { scopes: search.scopes },
18594
+ ...search.factTypes && { fact_types: search.factTypes },
18595
+ ...search.memoryIds !== void 0 && { memory_ids: search.memoryIds },
18596
+ include_archived: search.includeArchived,
18597
+ embedding_model: model,
18598
+ ...signal && { signal }
18599
+ });
18600
+ const vectors = [queryEmbedding, ...facetEmbeddings];
18601
+ let windows;
18602
+ if (mode === "retain") {
18603
+ windows = await Promise.all(
18604
+ vectors.map((embedding, i) => persistence.candidateSet(embedding, windowOptions(i)))
18605
+ );
18606
+ } else {
18607
+ const deadline = new AbortController();
18608
+ const timer = setTimeout(
18609
+ () => deadline.abort(
18610
+ new RemoteMemoryError("Remote recall exceeded its query budget", 408, "timeout")
18611
+ ),
18612
+ Math.max(0, start + budgetMs - Date.now())
18613
+ );
18614
+ try {
18615
+ windows = await Promise.all(
18616
+ vectors.map(
18617
+ (embedding, i) => persistence.candidates(embedding, windowOptions(i, deadline.signal))
18618
+ )
18619
+ );
18620
+ } finally {
18621
+ clearTimeout(timer);
18622
+ }
18623
+ }
18624
+ rejectUndecryptable([
18625
+ ...new Map(
18626
+ windows.flatMap((window2) => window2.failed).map((failure) => [failure.memory_id, failure])
18627
+ ).values()
18628
+ ]);
18629
+ const items = [
18630
+ ...new Map(
18631
+ windows.flatMap((window2) => window2.items).map((item) => [item.memory.memory_id, item])
18632
+ ).values()
18633
+ ];
18634
+ const memories = remember(items);
18635
+ return {
18636
+ memories,
18637
+ embeddedItems: memories.map((memory) => ({
18638
+ id: memory.uniqueId,
18639
+ content: memory.content,
18640
+ embedding: JSON.parse(memory.embedding ?? "[]"),
18641
+ createdAt: memory.createdAt,
18642
+ updatedAt: memory.updatedAt,
18643
+ proofCount: memory.proofCount,
18644
+ lastObservedAt: memory.lastObservedAt,
18645
+ eventTimeStart: memory.eventTimeStart,
18646
+ eventTimeEnd: memory.eventTimeEnd,
18647
+ eventTimeKind: memory.eventTimeKind === "point" || memory.eventTimeKind === "range" || memory.eventTimeKind === "ongoing" ? memory.eventTimeKind : null,
18648
+ factType: memory.factType,
18649
+ sourceChunkIds: memory.sourceChunkIds
18650
+ })),
18651
+ queryEmbedding,
18652
+ facetEmbeddings,
18653
+ vaultSize: Math.max(windows[0].total_count ?? 0, items.length),
18654
+ embeddingFailure: windows.some((window2) => (window2.unavailable_count ?? 0) > 0),
18655
+ embeddingsUnavailable: (windows[0].total_count ?? items.length) > 0 && !memories.some((memory) => memory.embedding),
18656
+ decryptLast: true,
18657
+ rowsDecrypted: items.length,
18658
+ queryEmbedMs,
18659
+ rowsEmbedded: 0
18660
+ };
18661
+ };
18662
+ const createRow = (input) => {
18663
+ if (input.folderId !== void 0 && input.folderId !== null)
18664
+ throw new Error("Remote memories do not support folders");
18665
+ const now = Date.now();
18666
+ return {
18667
+ memory_id: uuidv74(),
18668
+ content: input.content,
18669
+ scope: input.scope ?? "private",
18670
+ created_at: now,
18671
+ updated_at: now,
18672
+ is_deleted: false,
18673
+ ...input.embedding !== void 0 && {
18674
+ embedding: storedVector(JSON.parse(input.embedding)),
18675
+ embedding_model: input.embeddingModel
18676
+ },
18677
+ source_chunk_ids: JSON.stringify(input.sourceChunkIds ?? []),
18678
+ proof_count: input.proofCount ?? 1,
18679
+ source: input.source ?? "manual",
18680
+ ...input.eventTime && {
18681
+ event_time_start: input.eventTime.start ?? void 0,
18682
+ event_time_end: input.eventTime.end ?? void 0,
18683
+ event_time_kind: input.eventTime.kind ?? void 0
18684
+ },
18685
+ fact_type: input.factType,
18686
+ trust_tier: normalizeTrustTier(input.trustTier) ?? void 0,
18687
+ geohash: input.geohash,
18688
+ visibility: "private",
18689
+ twin_opt_in: false
18690
+ };
18691
+ };
18692
+ const write = async (memory, snapshot) => remember([await persistence.put(memory, snapshot)])[0];
18693
+ const port = {
18694
+ prepare,
18695
+ get,
18696
+ getFresh: async (id) => {
18697
+ const current = await persistence.get(id);
18698
+ return current && !current.memory.is_deleted && !current.memory.superseded_by ? stored(current.memory) : null;
18699
+ },
18700
+ tombstones: async (embedding, embeddingModel, scope, folderId) => {
18701
+ if (folderId !== void 0) throw new Error("Remote memories do not support folders");
18702
+ const window2 = await persistence.candidateSet(storedVector(embedding), {
18703
+ limit: 1,
18704
+ scopes: [scope],
18705
+ embedding_model: embeddingModel,
18706
+ strict_model: true,
18707
+ include_deleted: true,
18708
+ deleted_only: true
18709
+ });
18710
+ rejectUndecryptable(window2.failed);
18711
+ return remember(window2.items);
18712
+ },
18713
+ create: (input) => write(createRow(input), 0),
18714
+ update: async (id, patch) => {
18715
+ const existing = await get(id);
18716
+ if (!existing || patch.freeFormOnly && existing.kind !== null && existing.kind !== void 0)
18717
+ return null;
18718
+ const snapshot = snapshots.get(id);
18719
+ const memory = {
18720
+ ...snapshot.memory,
18721
+ content: patch.content,
18722
+ updated_at: patch.preserveUpdatedAt ? snapshot.memory.updated_at : Date.now()
18723
+ };
18724
+ if (patch.scope !== void 0) memory.scope = patch.scope;
18725
+ if (patch.embedding === void 0 && patch.content !== snapshot.memory.content) {
18726
+ delete memory.embedding;
18727
+ delete memory.embedding_model;
18728
+ }
18729
+ if (patch.embedding !== void 0) {
18730
+ memory.embedding = patch.embedding === null ? [] : storedVector(JSON.parse(patch.embedding));
18731
+ memory.embedding_model = patch.embeddingModel ?? void 0;
18732
+ }
18733
+ const observed = sourceIds(memory.source_chunk_ids);
18734
+ const replay = !!patch.observationSourceIds?.length && patch.observationSourceIds.every((id2) => observed.includes(id2));
18735
+ if (patch.sourceChunkIds !== void 0)
18736
+ memory.source_chunk_ids = JSON.stringify(
18737
+ patch.observationSourceIds?.length ? [.../* @__PURE__ */ new Set([...observed, ...patch.sourceChunkIds])] : patch.sourceChunkIds
18738
+ );
18739
+ if (!replay) {
18740
+ if (patch.proofCountIncrement !== void 0)
18741
+ memory.proof_count = (memory.proof_count ?? 1) + patch.proofCountIncrement;
18742
+ else if (patch.proofCount !== void 0) memory.proof_count = patch.proofCount;
18743
+ if (patch.lastObservedAt !== void 0) memory.last_observed_at = patch.lastObservedAt;
18744
+ }
18745
+ if (patch.source !== void 0) memory.source = patch.source;
18746
+ if (patch.factType !== void 0) memory.fact_type = patch.factType;
18747
+ if (patch.trustTier !== void 0)
18748
+ memory.trust_tier = normalizeTrustTier(patch.trustTier) ?? void 0;
18749
+ if (patch.topicsUserManaged !== void 0)
18750
+ memory.topics_user_managed = patch.topicsUserManaged;
18751
+ if (patch.eventTime !== void 0) {
18752
+ memory.event_time_start = patch.eventTime.start ?? void 0;
18753
+ memory.event_time_end = patch.eventTime.end ?? void 0;
18754
+ memory.event_time_kind = patch.eventTime.kind ?? void 0;
18755
+ }
18756
+ if (patch.restore) memory.archived_at = void 0;
18757
+ return write(memory, snapshot);
18758
+ },
18759
+ supersede: async (id, successor) => {
18760
+ const [target, newer] = await Promise.all([get(id), get(successor)]);
18761
+ if (!target || !newer || id === successor) return false;
18762
+ const old = snapshots.get(id);
18763
+ const next = snapshots.get(successor);
18764
+ remember(
18765
+ await persistence.putMany([
18766
+ {
18767
+ memory: { ...old.memory, superseded_by: successor, superseded_at: Date.now() },
18768
+ expectedVersion: old
18769
+ },
18770
+ { memory: next.memory, expectedVersion: next }
18771
+ ])
18772
+ );
18773
+ return true;
18774
+ },
18775
+ createSuperseding: async (input, targetId) => {
18776
+ const target = await get(targetId);
18777
+ if (!target) return { created: null, retired: false };
18778
+ const snapshot = snapshots.get(targetId);
18779
+ const successor = createRow(input);
18780
+ const rows = remember(
18781
+ await persistence.putMany([
18782
+ { memory: successor, expectedVersion: 0 },
18783
+ {
18784
+ memory: {
18785
+ ...snapshot.memory,
18786
+ superseded_by: successor.memory_id,
18787
+ superseded_at: Date.now()
18788
+ },
18789
+ expectedVersion: snapshot
18790
+ }
18791
+ ])
18792
+ );
18793
+ return { created: rows[0], retired: true };
18794
+ }
18795
+ };
18796
+ return { prepare, port };
18797
+ };
18798
+ return {
18799
+ recall: async (query, recallOptions = {}) => {
18800
+ const { prepare } = operation("recall");
18801
+ return recall(
18802
+ query,
18803
+ {
18804
+ embeddingOptions,
18805
+ factSource: {
18806
+ graphRanking: options.graphRanking,
18807
+ temporalRanking: options.temporalRanking,
18808
+ search: async (text12, searchOptions) => {
18809
+ const prepared = await prepare(text12, searchOptions);
18810
+ const ranked = await rankPreparedVaultCandidates(
18811
+ text12,
18812
+ prepared,
18813
+ embeddingOptions,
18814
+ searchOptions
18815
+ );
18816
+ return {
18817
+ ...ranked,
18818
+ rankedOnCosine: prepared.memories.length > 0 && !prepared.embeddingsUnavailable,
18819
+ decryptLast: true,
18820
+ rowsDecrypted: prepared.rowsDecrypted,
18821
+ queryEmbedMs: prepared.queryEmbedMs,
18822
+ rowsEmbedded: 0
18823
+ };
18824
+ }
18825
+ }
18826
+ },
18827
+ { ...recallOptions, types: ["fact"] }
18828
+ );
18829
+ },
18830
+ retain: async (content, retainOptions) => {
18831
+ const { port } = operation("retain");
18832
+ return retainWithPersistence(
18833
+ content,
18834
+ {
18835
+ persistence: port,
18836
+ embeddingOptions,
18837
+ vaultCache: /* @__PURE__ */ new Map(),
18838
+ normalizeEmbedding: storedVector
18839
+ },
18840
+ retainOptions
18841
+ );
18842
+ }
18843
+ };
18844
+ }
18845
+
17855
18846
  // src/lib/memory/synthesizeProfile.ts
17856
18847
  var DEFAULT_SYNTHESIS_MODEL = "inclusionai/ling-2.6-flash";
17857
18848
  var DEFAULT_FACET_RECALL_LIMIT = 20;
@@ -21262,7 +22253,7 @@ function useChat(options) {
21262
22253
 
21263
22254
  // src/expo/useChatStorage.ts
21264
22255
  import { useCallback as useCallback4, useEffect as useEffect4, useMemo, useRef as useRef4, useState as useState4 } from "react";
21265
- import { v7 as uuidv75 } from "uuid";
22256
+ import { v7 as uuidv76 } from "uuid";
21266
22257
 
21267
22258
  // src/lib/chat/assembleMessages.ts
21268
22259
  function assembleMessagesWithHistory(historyMessages, callerMessages, summarySystemMessage) {
@@ -21919,9 +22910,9 @@ async function decryptMediaFields(media, address, signMessage, embeddedWalletSig
21919
22910
  }
21920
22911
 
21921
22912
  // src/lib/db/media/types.ts
21922
- import { v7 as uuidv74 } from "uuid";
22913
+ import { v7 as uuidv75 } from "uuid";
21923
22914
  function generateMediaId() {
21924
- return `media_${uuidv74()}`;
22915
+ return `media_${uuidv75()}`;
21925
22916
  }
21926
22917
 
21927
22918
  // src/lib/db/media/operations.ts
@@ -22128,10 +23119,10 @@ function extractImageModelFromToolEvents(toolCallEvents) {
22128
23119
  }
22129
23120
  return void 0;
22130
23121
  }
22131
- function storedToLlmapiMessage(stored) {
22132
- const content = [{ type: "text", text: stored.content }];
22133
- if (stored.role !== "assistant" && stored.files?.length) {
22134
- for (const file of stored.files) {
23122
+ function storedToLlmapiMessage(stored2) {
23123
+ const content = [{ type: "text", text: stored2.content }];
23124
+ if (stored2.role !== "assistant" && stored2.files?.length) {
23125
+ for (const file of stored2.files) {
22135
23126
  if (isSendableImageURL(file.url)) {
22136
23127
  content.push({
22137
23128
  type: "image_url",
@@ -22141,11 +23132,11 @@ function storedToLlmapiMessage(stored) {
22141
23132
  }
22142
23133
  }
22143
23134
  const messages = [];
22144
- if (stored.role === "assistant" && stored.toolCallEvents?.length) {
23135
+ if (stored2.role === "assistant" && stored2.toolCallEvents?.length) {
22145
23136
  messages.push({
22146
- role: stored.role,
23137
+ role: stored2.role,
22147
23138
  content: void 0,
22148
- tool_calls: stored.toolCallEvents.map((event) => ({
23139
+ tool_calls: stored2.toolCallEvents.map((event) => ({
22149
23140
  id: event.id,
22150
23141
  type: "function",
22151
23142
  function: {
@@ -22154,7 +23145,7 @@ function storedToLlmapiMessage(stored) {
22154
23145
  }
22155
23146
  }))
22156
23147
  });
22157
- for (const event of stored.toolCallEvents) {
23148
+ for (const event of stored2.toolCallEvents) {
22158
23149
  if (event.id && event.output !== void 0 && event.output !== null) {
22159
23150
  messages.push({
22160
23151
  role: "tool",
@@ -22163,14 +23154,14 @@ function storedToLlmapiMessage(stored) {
22163
23154
  });
22164
23155
  }
22165
23156
  }
22166
- 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();
23157
+ 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();
22167
23158
  messages.push({
22168
- role: stored.role,
23159
+ role: stored2.role,
22169
23160
  content: [{ type: "text", text: postToolText }]
22170
23161
  });
22171
23162
  } else {
22172
23163
  messages.push({
22173
- role: stored.role,
23164
+ role: stored2.role,
22174
23165
  content
22175
23166
  });
22176
23167
  }
@@ -22877,7 +23868,7 @@ function useChatStorage(options) {
22877
23868
  };
22878
23869
  };
22879
23870
  pendingResumeRef.current = null;
22880
- const effectiveAssistantUniqueId = assistantUniqueId ?? (resumable ? `msg_${uuidv75()}` : void 0);
23871
+ const effectiveAssistantUniqueId = assistantUniqueId ?? (resumable ? `msg_${uuidv76()}` : void 0);
22881
23872
  const embedToolText = (text12, mask, masked, token) => {
22882
23873
  const opts = {
22883
23874
  getToken: token,
@@ -23395,7 +24386,7 @@ function useChatStorage(options) {
23395
24386
  const detachedResult = result;
23396
24387
  if (detachedResult.detached) {
23397
24388
  recordToolSetTurn(database, convId, matchedToolSets);
23398
- const rowId = effectiveAssistantUniqueId ?? `msg_${uuidv75()}`;
24389
+ const rowId = effectiveAssistantUniqueId ?? `msg_${uuidv76()}`;
23399
24390
  pendingResumeRef.current = {
23400
24391
  handle: detachedResult.resume ?? null,
23401
24392
  convId,
@@ -23904,6 +24895,9 @@ export {
23904
24895
  LoggerProvider,
23905
24896
  MAX_HOPS,
23906
24897
  MEDIUM_TTL_MS,
24898
+ MEMORY_KINDS,
24899
+ MEMORY_LEVELS,
24900
+ MemoryLevelError,
23907
24901
  NEVER_TTL_MS,
23908
24902
  NODE_BUDGET,
23909
24903
  NOTION_OAUTH_CONFIG,
@@ -23914,6 +24908,7 @@ export {
23914
24908
  QueueManager,
23915
24909
  RECALL_MAX_LIMIT,
23916
24910
  RECALL_TOOL_NAME,
24911
+ RemoteMemoryError,
23917
24912
  RerankerUnavailableError,
23918
24913
  SDK_SCHEMA_VERSION,
23919
24914
  SHORT_TTL_MS,
@@ -23977,6 +24972,8 @@ export {
23977
24972
  createNotionTools,
23978
24973
  createPlatformCursorStore,
23979
24974
  createRecallTool,
24975
+ createRemoteMemoryPersistence,
24976
+ createRemoteMemoryPipeline,
23980
24977
  createStockPricePreProcessor,
23981
24978
  createStreamingDeAnonymizer,
23982
24979
  createVaultEmbeddingCache,