@anuma/sdk 6.34.0 → 6.36.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.
@@ -2358,14 +2358,14 @@ async function updateMessageEmbeddingOp(ctx, uniqueId, vector, embeddingModel) {
2358
2358
  });
2359
2359
  return messageToStored(message, ctx.walletAddress, ctx.signMessage, ctx.embeddedWalletSigner);
2360
2360
  }
2361
- async function updateMessageChunksOp(ctx, uniqueId, chunks, embeddingModel) {
2361
+ async function updateMessageChunksOp(ctx, uniqueId, chunks2, embeddingModel) {
2362
2362
  let message;
2363
2363
  try {
2364
2364
  message = await ctx.messagesCollection.find(uniqueId);
2365
2365
  } catch {
2366
2366
  return null;
2367
2367
  }
2368
- const storedChunks = chunks.map(({ text: _text, ...rest }) => rest);
2368
+ const storedChunks = chunks2.map(({ text: _text, ...rest }) => rest);
2369
2369
  await ctx.database.write(async () => {
2370
2370
  await message.update((msg) => {
2371
2371
  msg._setRaw("chunks", JSON.stringify(storedChunks));
@@ -2409,12 +2409,12 @@ async function stripLegacyChunkTextOp(ctx) {
2409
2409
  const messages = await ctx.messagesCollection.query(Q.where("id", Q.oneOf(changedIds))).fetch();
2410
2410
  const updates = messages.flatMap((message) => {
2411
2411
  const raw = message._raw;
2412
- const chunks = chunksWithoutText(raw.chunks);
2413
- if (!chunks) return [];
2412
+ const chunks2 = chunksWithoutText(raw.chunks);
2413
+ if (!chunks2) return [];
2414
2414
  const updatedAt = raw.updated_at;
2415
2415
  return [
2416
2416
  message.prepareUpdate((msg) => {
2417
- msg._setRaw("chunks", JSON.stringify(chunks));
2417
+ msg._setRaw("chunks", JSON.stringify(chunks2));
2418
2418
  msg._setRaw("updated_at", updatedAt);
2419
2419
  })
2420
2420
  ];
@@ -2575,15 +2575,15 @@ async function searchChunksOp(ctx, queryVector, options) {
2575
2575
  }
2576
2576
  continue;
2577
2577
  }
2578
- const chunks = await readRawJsonField(message, "chunks", ctx.walletAddress);
2579
- if (chunks && chunks.length > 0) {
2580
- const vectors = chunks.map(
2578
+ const chunks2 = await readRawJsonField(message, "chunks", ctx.walletAddress);
2579
+ if (chunks2 && chunks2.length > 0) {
2580
+ const vectors = chunks2.map(
2581
2581
  (chunk) => decodeChunkVector(chunk.vector, () => {
2582
2582
  unreadableVectors++;
2583
2583
  })
2584
2584
  );
2585
2585
  chunkCache?.set(message.id, { version, chunks: vectors });
2586
- for (let ci = 0; ci < chunks.length; ci++) {
2586
+ for (let ci = 0; ci < chunks2.length; ci++) {
2587
2587
  const vec = vectors[ci];
2588
2588
  if (vec.length === 0) continue;
2589
2589
  const similarity = cosineSimilarity(queryVector, vec);
@@ -2591,7 +2591,7 @@ async function searchChunksOp(ctx, queryVector, options) {
2591
2591
  candidates.push({
2592
2592
  message,
2593
2593
  similarity,
2594
- chunkTextSource: { kind: "chunk", chunk: chunks[ci], siblings: chunks }
2594
+ chunkTextSource: { kind: "chunk", chunk: chunks2[ci], siblings: chunks2 }
2595
2595
  });
2596
2596
  }
2597
2597
  }
@@ -2740,7 +2740,7 @@ function chunkText(text12, options) {
2740
2740
  ];
2741
2741
  }
2742
2742
  const sentences = splitIntoSentences(text12);
2743
- const chunks = [];
2743
+ const chunks2 = [];
2744
2744
  let currentChunkSentences = [];
2745
2745
  let currentChunkStart = 0;
2746
2746
  let currentOffset = 0;
@@ -2754,7 +2754,7 @@ function chunkText(text12, options) {
2754
2754
  if (sentence.length > chunkSize) {
2755
2755
  if (currentChunkSentences.length > 0) {
2756
2756
  const chunkText2 = currentChunkSentences.join(" ");
2757
- chunks.push({
2757
+ chunks2.push({
2758
2758
  text: chunkText2,
2759
2759
  startOffset: currentChunkStart,
2760
2760
  endOffset: currentOffset
@@ -2765,7 +2765,7 @@ function chunkText(text12, options) {
2765
2765
  const chunkEnd = Math.min(j + chunkSize, sentence.length);
2766
2766
  const chunk = sentence.slice(j, chunkEnd);
2767
2767
  if (chunk.length >= minChunkSize) {
2768
- chunks.push({
2768
+ chunks2.push({
2769
2769
  text: chunk,
2770
2770
  startOffset: sentenceStart + j,
2771
2771
  endOffset: sentenceStart + chunkEnd
@@ -2779,7 +2779,7 @@ function chunkText(text12, options) {
2779
2779
  const currentText = currentChunkSentences.join(" ");
2780
2780
  const potentialLength = currentText.length + (currentText ? 1 : 0) + sentence.length;
2781
2781
  if (potentialLength > chunkSize && currentChunkSentences.length > 0) {
2782
- chunks.push({
2782
+ chunks2.push({
2783
2783
  text: currentText,
2784
2784
  startOffset: currentChunkStart,
2785
2785
  endOffset: currentOffset
@@ -2810,14 +2810,14 @@ function chunkText(text12, options) {
2810
2810
  if (currentChunkSentences.length > 0) {
2811
2811
  const chunkText2 = currentChunkSentences.join(" ");
2812
2812
  if (chunkText2.length >= minChunkSize) {
2813
- chunks.push({
2813
+ chunks2.push({
2814
2814
  text: chunkText2,
2815
2815
  startOffset: currentChunkStart,
2816
2816
  endOffset: text12.length
2817
2817
  });
2818
2818
  }
2819
2819
  }
2820
- if (chunks.length === 0) {
2820
+ if (chunks2.length === 0) {
2821
2821
  const trimmedText = text12.trim();
2822
2822
  if (trimmedText.length > 0) {
2823
2823
  return [
@@ -2829,7 +2829,7 @@ function chunkText(text12, options) {
2829
2829
  ];
2830
2830
  }
2831
2831
  }
2832
- return chunks;
2832
+ return chunks2;
2833
2833
  }
2834
2834
  function shouldChunkMessage(content, chunkSize = DEFAULT_CHUNK_SIZE) {
2835
2835
  return content.length > chunkSize;
@@ -2901,9 +2901,9 @@ function createSseClient({
2901
2901
  if (done) break;
2902
2902
  buffer += value;
2903
2903
  buffer = buffer.replace(/\r\n?/g, "\n");
2904
- const chunks = buffer.split("\n\n");
2905
- buffer = chunks.pop() ?? "";
2906
- for (const chunk of chunks) {
2904
+ const chunks2 = buffer.split("\n\n");
2905
+ buffer = chunks2.pop() ?? "";
2906
+ for (const chunk of chunks2) {
2907
2907
  const lines = chunk.split("\n");
2908
2908
  const dataLines = [];
2909
2909
  let eventName;
@@ -3848,18 +3848,18 @@ async function embedMany(texts, options, outer) {
3848
3848
  outer
3849
3849
  );
3850
3850
  } else {
3851
- const chunks = [];
3851
+ const chunks2 = [];
3852
3852
  for (let i = 0; i < uncachedTexts.length; i += chunkSize) {
3853
- chunks.push(uncachedTexts.slice(i, i + chunkSize));
3853
+ chunks2.push(uncachedTexts.slice(i, i + chunkSize));
3854
3854
  }
3855
- const allEmbeddings = new Array(chunks.length);
3855
+ const allEmbeddings = new Array(chunks2.length);
3856
3856
  let nextIndex = 0;
3857
3857
  const worker = async () => {
3858
- while (nextIndex < chunks.length) {
3858
+ while (nextIndex < chunks2.length) {
3859
3859
  if (outer?.aborted) throw outer.reason;
3860
3860
  const idx = nextIndex++;
3861
3861
  allEmbeddings[idx] = await generateEmbeddingsBatch(
3862
- chunks[idx],
3862
+ chunks2[idx],
3863
3863
  headers,
3864
3864
  baseUrl,
3865
3865
  embeddingModel,
@@ -3871,7 +3871,7 @@ async function embedMany(texts, options, outer) {
3871
3871
  }
3872
3872
  };
3873
3873
  const workers = Array.from(
3874
- { length: Math.min(DEFAULT_EMBEDDING_BATCH_CONCURRENCY, chunks.length) },
3874
+ { length: Math.min(DEFAULT_EMBEDDING_BATCH_CONCURRENCY, chunks2.length) },
3875
3875
  () => worker()
3876
3876
  );
3877
3877
  await Promise.all(workers);
@@ -8507,7 +8507,7 @@ function sseFailureMessage(status, statusText, detail = "") {
8507
8507
  return `SSE failed: ${status} ${statusText}${detail}`;
8508
8508
  }
8509
8509
  function parseSseChunks(raw, incompleteBuffer) {
8510
- const chunks = [];
8510
+ const chunks2 = [];
8511
8511
  const text12 = incompleteBuffer + raw;
8512
8512
  const lines = text12.split("\n");
8513
8513
  const remaining = raw.endsWith("\n") ? "" : lines.pop() ?? "";
@@ -8516,11 +8516,11 @@ function parseSseChunks(raw, incompleteBuffer) {
8516
8516
  const data = line.substring(6).trim();
8517
8517
  if (data === "[DONE]") continue;
8518
8518
  try {
8519
- chunks.push(JSON.parse(data));
8519
+ chunks2.push(JSON.parse(data));
8520
8520
  } catch {
8521
8521
  }
8522
8522
  }
8523
- return { chunks, remaining };
8523
+ return { chunks: chunks2, remaining };
8524
8524
  }
8525
8525
  var xhrTransport = (options) => {
8526
8526
  const queue = [];
@@ -8589,18 +8589,18 @@ var xhrTransport = (options) => {
8589
8589
  const newData = xhr.responseText.substring(lastProcessedIndex);
8590
8590
  lastProcessedIndex = xhr.responseText.length;
8591
8591
  if (newData.length > 0) options.onActivity?.();
8592
- const { chunks, remaining } = parseSseChunks(newData, incompleteBuffer);
8592
+ const { chunks: chunks2, remaining } = parseSseChunks(newData, incompleteBuffer);
8593
8593
  incompleteBuffer = remaining;
8594
- for (const chunk of chunks) {
8594
+ for (const chunk of chunks2) {
8595
8595
  push({ type: "data", value: chunk });
8596
8596
  }
8597
8597
  };
8598
8598
  xhr.onload = () => {
8599
8599
  options.signal?.removeEventListener("abort", abortHandler);
8600
8600
  if (incompleteBuffer) {
8601
- const { chunks } = parseSseChunks(incompleteBuffer + "\n", "");
8601
+ const { chunks: chunks2 } = parseSseChunks(incompleteBuffer + "\n", "");
8602
8602
  incompleteBuffer = "";
8603
- for (const chunk of chunks) {
8603
+ for (const chunk of chunks2) {
8604
8604
  push({ type: "data", value: chunk });
8605
8605
  }
8606
8606
  }
@@ -9246,6 +9246,15 @@ __decorateClass([
9246
9246
  __decorateClass([
9247
9247
  text6("scope")
9248
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);
9249
9258
  __decorateClass([
9250
9259
  field5("folder_id")
9251
9260
  ], VaultMemory.prototype, "folderId", 2);
@@ -9471,7 +9480,7 @@ __decorateClass([
9471
9480
  ], VaultFolder.prototype, "context", 2);
9472
9481
 
9473
9482
  // src/lib/db/schema.ts
9474
- var SDK_SCHEMA_VERSION = 47;
9483
+ var SDK_SCHEMA_VERSION = 48;
9475
9484
  var sdkSchema = appSchema2({
9476
9485
  version: SDK_SCHEMA_VERSION,
9477
9486
  tables: [
@@ -9566,6 +9575,9 @@ var sdkSchema = appSchema2({
9566
9575
  columns: [
9567
9576
  { name: "content", type: "string" },
9568
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 },
9569
9581
  { name: "folder_id", type: "string", isOptional: true, isIndexed: true },
9570
9582
  { name: "created_at", type: "number", isIndexed: true },
9571
9583
  { name: "updated_at", type: "number", isIndexed: true },
@@ -10242,6 +10254,22 @@ var sdkMigrations = schemaMigrations2({
10242
10254
  ]
10243
10255
  })
10244
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
+ ]
10245
10273
  }
10246
10274
  ]
10247
10275
  });
@@ -10807,13 +10835,54 @@ async function decryptVaultMemoryFields(memory, address, signMessage, embeddedWa
10807
10835
  }
10808
10836
  }
10809
10837
  const decryptedContent = await decryptField(memory.content, address);
10838
+ const decryptedKindValue = typeof memory.kindValue === "string" ? await decryptField(memory.kindValue, address) : memory.kindValue;
10810
10839
  return {
10811
10840
  ...memory,
10812
- content: decryptedContent
10841
+ content: decryptedContent,
10842
+ ...decryptedKindValue !== void 0 && { kindValue: decryptedKindValue }
10813
10843
  };
10814
10844
  }
10815
10845
 
10816
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
+ }
10817
10886
  function parseMedia(value) {
10818
10887
  if (typeof value !== "string" || value === "") return null;
10819
10888
  try {
@@ -10843,6 +10912,56 @@ function visibilityConditions(requested) {
10843
10912
  if (excluded.length === 0) return [];
10844
10913
  return [Q5.or(Q5.where("visibility", null), Q5.where("visibility", Q5.notIn(excluded)))];
10845
10914
  }
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
+ }
10846
10965
  function isOwnedByCtxUser(ctx, record2) {
10847
10966
  return ctx.userId === void 0 || record2.userId === ctx.userId;
10848
10967
  }
@@ -10886,6 +11005,9 @@ function vaultMemoryToStoredRaw(memory) {
10886
11005
  uniqueId: memory.id,
10887
11006
  content: memory.content,
10888
11007
  scope: memory.scope,
11008
+ kind: memory.kind ?? null,
11009
+ kindValue: memory.kindValue ?? null,
11010
+ level: resolveMemoryLevel(memory.level, memory.scope),
10889
11011
  folderId: memory.folderId ?? null,
10890
11012
  userId: memory.userId ?? null,
10891
11013
  embedding: memory.embedding ?? null,
@@ -10924,9 +11046,13 @@ async function vaultMemoryToStored(memory, walletAddress, signMessage, embeddedW
10924
11046
  }
10925
11047
  return raw;
10926
11048
  }
10927
- function populateNewVaultMemory(record2, ctx, opts, encryptedContent) {
11049
+ function populateNewVaultMemory(record2, ctx, opts, encryptedContent, encryptedKindValue) {
11050
+ const { level, scope } = resolveCreateLevel(opts);
10928
11051
  record2._setRaw("content", encryptedContent);
10929
- record2._setRaw("scope", opts.scope ?? "private");
11052
+ record2._setRaw("scope", scope);
11053
+ record2._setRaw("level", level);
11054
+ record2._setRaw("kind", opts.kind ?? null);
11055
+ record2._setRaw("kind_value", encryptedKindValue ?? null);
10930
11056
  record2._setRaw("folder_id", opts.folderId ?? null);
10931
11057
  record2._setRaw("user_id", ctx.userId ?? null);
10932
11058
  record2._setRaw("is_deleted", false);
@@ -10960,6 +11086,8 @@ function populateNewVaultMemory(record2, ctx, opts, encryptedContent) {
10960
11086
  }
10961
11087
  }
10962
11088
  async function createVaultMemoryOp(ctx, opts) {
11089
+ assertValidKindLevel(opts.kind, resolveCreateLevel(opts).level);
11090
+ const encryptedKindValue = await encryptKindValue(ctx, opts.kindValue);
10963
11091
  const encryptedContent = ctx.walletAddress && ctx.signMessage ? await encryptVaultMemoryContent(
10964
11092
  opts.content,
10965
11093
  ctx.walletAddress,
@@ -10970,13 +11098,15 @@ async function createVaultMemoryOp(ctx, opts) {
10970
11098
  if (ctx.canWrite && !await ctx.canWrite())
10971
11099
  throw new Error("Memory source is no longer eligible");
10972
11100
  return ctx.vaultMemoryCollection.create(
10973
- (record2) => populateNewVaultMemory(record2, ctx, opts, encryptedContent)
11101
+ (record2) => populateNewVaultMemory(record2, ctx, opts, encryptedContent, encryptedKindValue)
10974
11102
  );
10975
11103
  });
10976
11104
  return vaultMemoryToStored(created, ctx.walletAddress, ctx.signMessage, ctx.embeddedWalletSigner);
10977
11105
  }
10978
11106
  async function createSupersedingMemoryOp(ctx, opts, targetId) {
10979
11107
  if (!targetId) return { created: null, retired: false };
11108
+ assertValidKindLevel(opts.kind, resolveCreateLevel(opts).level);
11109
+ const encryptedKindValue = await encryptKindValue(ctx, opts.kindValue);
10980
11110
  const encryptedContent = ctx.walletAddress && ctx.signMessage ? await encryptVaultMemoryContent(
10981
11111
  opts.content,
10982
11112
  ctx.walletAddress,
@@ -10993,9 +11123,10 @@ async function createSupersedingMemoryOp(ctx, opts, targetId) {
10993
11123
  } catch {
10994
11124
  return;
10995
11125
  }
10996
- if (target.isDeleted || target.supersededBy || !isOwnedByCtxUser(ctx, target)) return;
11126
+ if (target.isDeleted || target.supersededBy || isKinded(target) || !isOwnedByCtxUser(ctx, target))
11127
+ return;
10997
11128
  createdRecord = await ctx.vaultMemoryCollection.create(
10998
- (record2) => populateNewVaultMemory(record2, ctx, opts, encryptedContent)
11129
+ (record2) => populateNewVaultMemory(record2, ctx, opts, encryptedContent, encryptedKindValue)
10999
11130
  );
11000
11131
  await target.update((r) => {
11001
11132
  r._setRaw("superseded_by", createdRecord.id);
@@ -11059,6 +11190,10 @@ async function getMemoriesByEventTimeOp(ctx, windowStart, windowEnd) {
11059
11190
  }
11060
11191
  async function createVaultMemoriesBatchOp(ctx, optionsArray) {
11061
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
+ );
11062
11197
  const encryptedContents = await Promise.all(
11063
11198
  optionsArray.map(async (opts) => {
11064
11199
  if (ctx.walletAddress && ctx.signMessage) {
@@ -11077,7 +11212,7 @@ async function createVaultMemoriesBatchOp(ctx, optionsArray) {
11077
11212
  throw new Error("Memory source is no longer eligible");
11078
11213
  const prepared = optionsArray.map(
11079
11214
  (opts, i) => ctx.vaultMemoryCollection.prepareCreate(
11080
- (record2) => populateNewVaultMemory(record2, ctx, opts, encryptedContents[i])
11215
+ (record2) => populateNewVaultMemory(record2, ctx, opts, encryptedContents[i], encryptedKindValues[i])
11081
11216
  )
11082
11217
  );
11083
11218
  await ctx.database.batch(...prepared);
@@ -11120,6 +11255,9 @@ function vaultMemoryRawToStoredRaw(raw) {
11120
11255
  uniqueId: raw.id,
11121
11256
  content: raw.content ?? "",
11122
11257
  scope: raw.scope ?? "",
11258
+ kind: raw.kind ?? null,
11259
+ kindValue: raw.kind_value ?? null,
11260
+ level: resolveMemoryLevel(raw.level, raw.scope),
11123
11261
  folderId: raw.folder_id ?? null,
11124
11262
  userId: raw.user_id ?? null,
11125
11263
  embedding: raw.embedding ?? null,
@@ -11163,6 +11301,8 @@ async function getAllVaultMemoriesOp(ctx, options) {
11163
11301
  ...baseVaultConditions(ctx, options),
11164
11302
  ...options?.scopes?.length ? [Q5.where("scope", Q5.oneOf(options.scopes))] : [],
11165
11303
  ...visibilityConditions(options?.visibility),
11304
+ ...levelConditions(options?.levels),
11305
+ ...options?.kinds?.length ? [Q5.where("kind", Q5.oneOf(options.kinds))] : [],
11166
11306
  ...options?.folderId !== void 0 ? [Q5.where("folder_id", options.folderId)] : [],
11167
11307
  ...options?.factTypes?.length ? [Q5.where("fact_type", Q5.oneOf(options.factTypes))] : [],
11168
11308
  Q5.sortBy(options?.since ? "updated_at" : "created_at", Q5.desc),
@@ -11329,6 +11469,14 @@ async function updateVaultMemoryOp(ctx, id, opts) {
11329
11469
  try {
11330
11470
  const probe = await ctx.vaultMemoryCollection.find(id);
11331
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);
11332
11480
  const encryptedContent = ctx.walletAddress && ctx.signMessage ? await encryptVaultMemoryContent(
11333
11481
  opts.content,
11334
11482
  ctx.walletAddress,
@@ -11341,10 +11489,13 @@ async function updateVaultMemoryOp(ctx, id, opts) {
11341
11489
  await ctx.database.write(async () => {
11342
11490
  if (ctx.canWrite && !await ctx.canWrite())
11343
11491
  throw new Error("Memory source is no longer eligible");
11344
- if (record2.isDeleted || record2.supersededBy || !isOwnedByCtxUser(ctx, record2)) {
11492
+ if (record2.isDeleted || record2.supersededBy || !isOwnedByCtxUser(ctx, record2) || opts.freeFormOnly && isKinded(record2)) {
11345
11493
  stale = true;
11346
11494
  return;
11347
11495
  }
11496
+ const nextKind = opts.kind !== void 0 ? opts.kind : record2.kind;
11497
+ const nextLevel = levelAfter(record2);
11498
+ assertValidKindLevel(nextKind, nextLevel);
11348
11499
  let observedSources = [];
11349
11500
  let replayedObservation = false;
11350
11501
  if (opts.observationSourceIds?.length) {
@@ -11358,8 +11509,18 @@ async function updateVaultMemoryOp(ctx, id, opts) {
11358
11509
  }
11359
11510
  await record2.update((r) => {
11360
11511
  r._setRaw("content", encryptedContent);
11361
- 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) {
11362
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);
11363
11524
  }
11364
11525
  if (opts.folderId !== void 0) {
11365
11526
  r._setRaw("folder_id", opts.folderId);
@@ -11418,7 +11579,8 @@ async function updateVaultMemoryOp(ctx, id, opts) {
11418
11579
  ctx.signMessage,
11419
11580
  ctx.embeddedWalletSigner
11420
11581
  );
11421
- } catch {
11582
+ } catch (err) {
11583
+ if (err instanceof MemoryLevelError) throw err;
11422
11584
  return null;
11423
11585
  }
11424
11586
  }
@@ -11554,6 +11716,7 @@ async function supersedeVaultMemoryOp(ctx, id, supersededById) {
11554
11716
  try {
11555
11717
  const record2 = await ctx.vaultMemoryCollection.find(id);
11556
11718
  if (record2.isDeleted || record2.supersededBy || !isOwnedByCtxUser(ctx, record2)) return false;
11719
+ if (isKinded(record2)) return false;
11557
11720
  let successor;
11558
11721
  try {
11559
11722
  successor = await ctx.vaultMemoryCollection.find(supersededById);
@@ -11854,7 +12017,10 @@ function assertVaultScopeForSweep(ctx) {
11854
12017
  }
11855
12018
  async function getDecayCandidatesRawOp(ctx) {
11856
12019
  assertVaultScopeForSweep(ctx);
11857
- 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();
11858
12024
  return results.map((raw) => ({
11859
12025
  uniqueId: raw.id,
11860
12026
  factType: raw.fact_type ?? null,
@@ -12114,6 +12280,7 @@ async function ingestPublishedPhotoMemoriesOp(ctx, rows) {
12114
12280
  record2._raw.id = row.memoryId;
12115
12281
  record2._setRaw("content", content);
12116
12282
  record2._setRaw("scope", "shared");
12283
+ record2._setRaw("level", "matching");
12117
12284
  record2._setRaw("folder_id", null);
12118
12285
  record2._setRaw("user_id", ctx.userId ?? null);
12119
12286
  record2._setRaw("is_deleted", false);
@@ -12522,6 +12689,7 @@ async function updateVaultFolderOp(ctx, id, opts) {
12522
12689
  for (const memory of memories) {
12523
12690
  updates.push(
12524
12691
  memory.prepareUpdate((r) => {
12692
+ r._setRaw("level", levelForScopeChange(r, opts.scope));
12525
12693
  r._setRaw("scope", opts.scope);
12526
12694
  })
12527
12695
  );
@@ -12543,6 +12711,7 @@ async function deleteVaultFolderOp(ctx, id) {
12543
12711
  const preparedMemories = memories.map(
12544
12712
  (memory) => memory.prepareUpdate((r) => {
12545
12713
  r._setRaw("folder_id", null);
12714
+ r._setRaw("level", levelForScopeChange(r, "private"));
12546
12715
  r._setRaw("scope", "private");
12547
12716
  })
12548
12717
  );
@@ -12579,6 +12748,7 @@ async function moveMemoriesToFolderOp(ctx, memoryIds, folderId) {
12579
12748
  const prepared = memories.map(
12580
12749
  (memory) => memory.prepareUpdate((r) => {
12581
12750
  r._setRaw("folder_id", folderId);
12751
+ r._setRaw("level", levelForScopeChange(r, targetScope));
12582
12752
  r._setRaw("scope", targetScope);
12583
12753
  })
12584
12754
  );
@@ -14886,6 +15056,7 @@ async function retainWithPersistence(content, ctx, options = {}) {
14886
15056
  includeArchived: true,
14887
15057
  ...options.folderId !== void 0 && { folderId: options.folderId }
14888
15058
  });
15059
+ prepared = withoutKindedRows(prepared);
14889
15060
  if (prepared.embeddingFailure || prepared.embeddingsUnavailable) {
14890
15061
  throw new Error(
14891
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."
@@ -14927,6 +15098,7 @@ async function retainWithPersistence(content, ctx, options = {}) {
14927
15098
  const resurrect = resurrectFields(existing);
14928
15099
  const updated = await ctx.persistence.update(targetId, {
14929
15100
  content: existing.content,
15101
+ freeFormOnly: true,
14930
15102
  proofCountIncrement: 1,
14931
15103
  observationSourceIds: options.sourceChunkIds,
14932
15104
  sourceChunkIds: mergedSourceIds,
@@ -15055,6 +15227,17 @@ async function retainWithPersistence(content, ctx, options = {}) {
15055
15227
  ...consolidationDecidedCreate && { consolidation: "create" }
15056
15228
  };
15057
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
+ }
15058
15241
  function unionStrings(a, b) {
15059
15242
  return [.../* @__PURE__ */ new Set([...a, ...b])];
15060
15243
  }
@@ -15154,6 +15337,7 @@ async function tryConsolidate(trimmed, ctx, options, prepared) {
15154
15337
  const resurrect = resurrectFields(existing);
15155
15338
  const updated = await ctx.persistence.update(decision.targetId, {
15156
15339
  content: existing.content,
15340
+ freeFormOnly: true,
15157
15341
  proofCountIncrement: 1,
15158
15342
  observationSourceIds: options.sourceChunkIds,
15159
15343
  sourceChunkIds: mergedSourceIds,
@@ -15199,6 +15383,7 @@ async function tryConsolidate(trimmed, ctx, options, prepared) {
15199
15383
  const resurrect = resurrectFields(existing);
15200
15384
  const updated = await ctx.persistence.update(decision.targetId, {
15201
15385
  content: decision.content,
15386
+ freeFormOnly: true,
15202
15387
  proofCountIncrement: 1,
15203
15388
  observationSourceIds: options.sourceChunkIds,
15204
15389
  sourceChunkIds: mergedSourceIds,
@@ -15242,7 +15427,7 @@ async function tryConsolidate(trimmed, ctx, options, prepared) {
15242
15427
  }
15243
15428
  async function assertMergeTargetGoneOrThrow(ctx, targetId) {
15244
15429
  const stillExists = await (ctx.persistence.getFresh ? ctx.persistence.getFresh(targetId) : ctx.persistence.get(targetId));
15245
- if (stillExists) {
15430
+ if (stillExists && (stillExists.kind === null || stillExists.kind === void 0)) {
15246
15431
  throw new Error(`retain: merge into memory ${targetId} failed to persist`);
15247
15432
  }
15248
15433
  }
@@ -17884,6 +18069,65 @@ function createLocalMemoryStore(options) {
17884
18069
  };
17885
18070
  }
17886
18071
 
18072
+ // src/lib/memory/store/memoryKeys.ts
18073
+ var KEY_ID_DOMAIN = "anuma-private-memory-key-id-v1";
18074
+ var MemoryKeyError = class extends Error {
18075
+ constructor(message) {
18076
+ super(message);
18077
+ this.name = "MemoryKeyError";
18078
+ }
18079
+ };
18080
+ async function importAesKey(hex) {
18081
+ return crypto.subtle.importKey(
18082
+ "raw",
18083
+ hexToBytes(hex).buffer,
18084
+ { name: "AES-GCM" },
18085
+ false,
18086
+ ["encrypt", "decrypt"]
18087
+ );
18088
+ }
18089
+ async function deriveMemoryKeyRing(signatureHex) {
18090
+ const v3Hex = await deriveKeyFromSignatureV3(signatureHex);
18091
+ const digest = await crypto.subtle.digest(
18092
+ "SHA-256",
18093
+ new TextEncoder().encode(`${KEY_ID_DOMAIN}:${v3Hex}`)
18094
+ );
18095
+ const keyId = "v3:" + Array.from(new Uint8Array(digest), (byte) => byte.toString(16).padStart(2, "0")).join("");
18096
+ return {
18097
+ keyId,
18098
+ v3: await importAesKey(v3Hex),
18099
+ v2: await importAesKey(await deriveKeyFromSignature(signatureHex))
18100
+ };
18101
+ }
18102
+ async function decryptWith(value, rings) {
18103
+ const version = value.startsWith("enc:v3:") ? "v3" : "v2";
18104
+ for (const ring of rings) {
18105
+ try {
18106
+ return await decryptDataWithKey(value.slice(`enc:${version}:`.length), ring[version]);
18107
+ } catch {
18108
+ continue;
18109
+ }
18110
+ }
18111
+ throw new MemoryKeyError(`No supplied key decrypts this enc:${version} field`);
18112
+ }
18113
+ function memoryCipher(canonical) {
18114
+ return {
18115
+ encrypt: async (plaintext) => `enc:v3:${await encryptDataWithKey(plaintext, canonical.v3)}`,
18116
+ decrypt: async (ciphertext) => {
18117
+ if (!ciphertext.startsWith("enc:v3:") || !isEncrypted(ciphertext))
18118
+ throw new MemoryKeyError("Remote memory content must be enc:v3 ciphertext");
18119
+ return decryptWith(ciphertext, [canonical]);
18120
+ }
18121
+ };
18122
+ }
18123
+ async function reencryptMemoryField(value, canonical, fallbacks = []) {
18124
+ const { encrypt } = memoryCipher(canonical);
18125
+ if (!value.startsWith("enc:")) return encrypt(value);
18126
+ if (!isEncrypted(value))
18127
+ throw new MemoryKeyError("Field has an encryption prefix but an invalid payload");
18128
+ return encrypt(await decryptWith(value, [canonical, ...fallbacks]));
18129
+ }
18130
+
17887
18131
  // src/lib/memory/store/remotePersistence.ts
17888
18132
  var RemoteMemoryError = class extends Error {
17889
18133
  constructor(message, status, code) {
@@ -17936,6 +18180,30 @@ var candidateListLimits = [
17936
18180
  ["memory_ids", 1e3],
17937
18181
  ["force_ids", 100]
17938
18182
  ];
18183
+ var queryListLimits = [
18184
+ ["scopes", 20],
18185
+ ["fact_types", 20],
18186
+ ["visibility", 20],
18187
+ ["memory_ids", 1e3],
18188
+ ["topics", 100]
18189
+ ];
18190
+ var queryFields = [
18191
+ "include_deleted",
18192
+ "include_archived",
18193
+ "include_quarantined",
18194
+ "include_superseded",
18195
+ "archived_only",
18196
+ "scopes",
18197
+ "fact_types",
18198
+ "visibility",
18199
+ "memory_ids",
18200
+ "topics",
18201
+ "updated_after",
18202
+ "order",
18203
+ "cursor",
18204
+ "limit",
18205
+ "include_embeddings"
18206
+ ];
17939
18207
  function record(value) {
17940
18208
  return typeof value === "object" && value !== null && !Array.isArray(value);
17941
18209
  }
@@ -18270,6 +18538,35 @@ async function createRemoteMemoryPersistence(options) {
18270
18538
  throw new Error("Invalid nearby batch response");
18271
18539
  return Promise.all(result.items.map((item, i) => decodeCommitted(item, prepared[i])));
18272
18540
  },
18541
+ query: async (queryOptions = {}) => {
18542
+ const { signal, ...query } = queryOptions;
18543
+ if (query.limit !== void 0 && (!Number.isInteger(query.limit) || query.limit < 1 || query.limit > 200))
18544
+ throw new Error("Page limit must be 1\u2013200");
18545
+ for (const [key, max] of queryListLimits) {
18546
+ const values = query[key];
18547
+ if (values && values.length > max)
18548
+ throw new Error(`Query ${key} accepts at most ${max} entries (got ${values.length})`);
18549
+ }
18550
+ const page = await request(
18551
+ "/memories/query",
18552
+ {
18553
+ method: "POST",
18554
+ body: JSON.stringify(
18555
+ Object.fromEntries(
18556
+ queryFields.filter((key) => query[key] !== void 0).map((key) => [key, query[key]])
18557
+ )
18558
+ )
18559
+ },
18560
+ signal
18561
+ );
18562
+ if (!record(page) || !Array.isArray(page.items) || page.next_cursor !== void 0 && typeof page.next_cursor !== "string" || page.changes_cursor !== void 0 && typeof page.changes_cursor !== "string")
18563
+ throw new Error("Invalid nearby private-memory page");
18564
+ return {
18565
+ ...await decodeAll(page.items),
18566
+ ...page.next_cursor !== void 0 && { next_cursor: page.next_cursor },
18567
+ ...page.changes_cursor !== void 0 && { changes_cursor: page.changes_cursor }
18568
+ };
18569
+ },
18273
18570
  candidateSet,
18274
18571
  candidates: async (embedding, candidateOptions = {}) => decodeAll((await fetchCandidates(embedding, candidateOptions, false)).items)
18275
18572
  };
@@ -18294,6 +18591,9 @@ function sourceIds(value) {
18294
18591
  return [];
18295
18592
  }
18296
18593
  }
18594
+ function isMemoryLevel(value) {
18595
+ return MEMORY_LEVELS.includes(value);
18596
+ }
18297
18597
  function stored(row) {
18298
18598
  return {
18299
18599
  uniqueId: row.memory_id,
@@ -18301,6 +18601,9 @@ function stored(row) {
18301
18601
  scope: row.scope,
18302
18602
  folderId: row.folder_id ?? null,
18303
18603
  userId: null,
18604
+ kind: row.kind ?? null,
18605
+ kindValue: row.kind_value ?? null,
18606
+ ...isMemoryLevel(row.level) && { level: row.level },
18304
18607
  embedding: row.embedding ? JSON.stringify(row.embedding) : null,
18305
18608
  embeddingModel: row.embedding_model ?? null,
18306
18609
  sourceChunkIds: row.source_chunk_ids === void 0 ? null : sourceIds(row.source_chunk_ids),
@@ -18522,7 +18825,8 @@ function createRemoteMemoryPipeline(options) {
18522
18825
  create: (input) => write(createRow(input), 0),
18523
18826
  update: async (id, patch) => {
18524
18827
  const existing = await get(id);
18525
- if (!existing) return null;
18828
+ if (!existing || patch.freeFormOnly && existing.kind !== null && existing.kind !== void 0)
18829
+ return null;
18526
18830
  const snapshot = snapshots.get(id);
18527
18831
  const memory = {
18528
18832
  ...snapshot.memory,
@@ -18651,6 +18955,489 @@ function createRemoteMemoryPipeline(options) {
18651
18955
  };
18652
18956
  }
18653
18957
 
18958
+ // src/lib/memory/store/remoteStore.ts
18959
+ import { v7 as uuidv75 } from "uuid";
18960
+ function relevant(change, options) {
18961
+ return options.includeDeleted ? change === "membership" : change !== "embedding" || !!options.embeddings;
18962
+ }
18963
+ function safely(onChange) {
18964
+ try {
18965
+ onChange();
18966
+ } catch (error) {
18967
+ getLogger().warn("[memory/remote-store] Subscriber threw:", error);
18968
+ }
18969
+ }
18970
+ var MAX_BATCH = 50;
18971
+ var MAX_QUERY_IDS = 1e3;
18972
+ var MAX_QUERY_TOPICS = 100;
18973
+ var MAX_QUERY_FILTER = 20;
18974
+ var RemoteMemoryPartialCreateError = class extends Error {
18975
+ constructor(created, cause) {
18976
+ super(`createMany stored ${created.length} memories before a batch failed`);
18977
+ this.created = created;
18978
+ this.cause = cause;
18979
+ this.name = "RemoteMemoryPartialCreateError";
18980
+ }
18981
+ };
18982
+ function warnFailed(failed) {
18983
+ if (failed.length)
18984
+ getLogger().warn(
18985
+ `[memory/remote-store] Skipping ${failed.length} undecryptable row(s)`,
18986
+ failed.map((failure) => failure.memory_id)
18987
+ );
18988
+ }
18989
+ function bounded(filters, key) {
18990
+ const values = filters[key];
18991
+ if (!values || values.length <= MAX_QUERY_FILTER) return [filters];
18992
+ return chunks(values, MAX_QUERY_FILTER).map((chunk) => ({ ...filters, [key]: chunk }));
18993
+ }
18994
+ function chunks(values, size) {
18995
+ const out = [];
18996
+ for (let i = 0; i < values.length; i += size) out.push(values.slice(i, i + size));
18997
+ return out;
18998
+ }
18999
+ function stateFilters(options) {
19000
+ return {
19001
+ include_deleted: options.includeDeleted,
19002
+ include_archived: options.includeArchived,
19003
+ include_quarantined: options.includeQuarantined,
19004
+ include_superseded: options.includeSuperseded
19005
+ };
19006
+ }
19007
+ function hidden(memory, options) {
19008
+ if (memory.trust_tier === "quarantined") return true;
19009
+ if (options.includeDeleted) return false;
19010
+ return !!memory.is_deleted || memory.archived_at !== void 0 && memory.archived_at !== null || !!memory.superseded_by;
19011
+ }
19012
+ function subscriptionKey({ memory, version }, options) {
19013
+ if (hidden(memory, options)) return void 0;
19014
+ if (options.includeDeleted) return String(!!memory.is_deleted);
19015
+ return JSON.stringify([
19016
+ options.embeddings ? version : null,
19017
+ memory.content,
19018
+ memory.scope,
19019
+ memory.updated_at,
19020
+ memory.fact_type,
19021
+ memory.event_time_start,
19022
+ memory.event_time_end,
19023
+ memory.event_time_kind,
19024
+ memory.trust_tier,
19025
+ memory.visibility,
19026
+ memory.published_at,
19027
+ memory.geohash,
19028
+ memory.topics,
19029
+ memory.topics_user_managed,
19030
+ memory.media,
19031
+ memory.source
19032
+ ]);
19033
+ }
19034
+ function topicInputs(topics, source) {
19035
+ return topics.flatMap((topic) => {
19036
+ const name = (typeof topic === "string" ? topic : topic.name).trim();
19037
+ const kind = typeof topic === "string" ? void 0 : topic.kind;
19038
+ return name ? [{ name, ...kind && { kind }, source }] : [];
19039
+ });
19040
+ }
19041
+ function mergeTopics(existing, added) {
19042
+ const byName = /* @__PURE__ */ new Map();
19043
+ for (const topic of [...existing, ...added]) {
19044
+ const key = normalizeEntityName(topic.name);
19045
+ if (!byName.has(key)) byName.set(key, topic);
19046
+ }
19047
+ return [...byName.values()];
19048
+ }
19049
+ function canonicalTopics(row) {
19050
+ return new Set((parseTopics(row.topics) ?? []).map((topic) => normalizeEntityName(topic.name)));
19051
+ }
19052
+ function createRemoteMemoryStore(options) {
19053
+ const { persistence, embeddingOptions } = options;
19054
+ const model = embeddingOptions.model ?? DEFAULT_API_EMBEDDING_MODEL;
19055
+ const pollIntervalMs = options.pollIntervalMs ?? 6e4;
19056
+ const pipeline = createRemoteMemoryPipeline(options);
19057
+ const subscribers = /* @__PURE__ */ new Set();
19058
+ const seen = /* @__PURE__ */ new Map();
19059
+ let timer;
19060
+ const notify = (change, records = []) => {
19061
+ if (timer) for (const record2 of records) seen.set(record2.memory.memory_id, record2);
19062
+ for (const subscriber of [...subscribers])
19063
+ if (relevant(change, subscriber.options)) safely(subscriber.onChange);
19064
+ };
19065
+ const enumerate = async (filters, max = Infinity) => {
19066
+ const records = [];
19067
+ let cursor2;
19068
+ do {
19069
+ const page = await persistence.query({
19070
+ ...filters,
19071
+ limit: Math.min(200, Math.max(1, max - records.length)),
19072
+ ...cursor2 && { cursor: cursor2 }
19073
+ });
19074
+ warnFailed(page.failed);
19075
+ records.push(...page.items);
19076
+ cursor2 = page.next_cursor;
19077
+ } while (cursor2 && records.length < max);
19078
+ return records.slice(0, max);
19079
+ };
19080
+ const enumerateIds = async (ids, filters) => (await Promise.all(
19081
+ chunks([...new Set(ids)], MAX_QUERY_IDS).map(
19082
+ (memory_ids) => enumerate({ ...filters, memory_ids })
19083
+ )
19084
+ )).flat();
19085
+ const queues = /* @__PURE__ */ new Map();
19086
+ const serialized = (id, task) => {
19087
+ const run = (queues.get(id) ?? Promise.resolve()).then(task, task);
19088
+ const settled = run.catch(() => void 0);
19089
+ queues.set(id, settled);
19090
+ void settled.then(() => {
19091
+ if (queues.get(id) === settled) queues.delete(id);
19092
+ });
19093
+ return run;
19094
+ };
19095
+ const live = async (id) => {
19096
+ const record2 = await persistence.get(id);
19097
+ return record2 && !record2.memory.is_deleted ? record2 : null;
19098
+ };
19099
+ const mutate = async (id, change, edit) => serialized(id, async () => {
19100
+ const record2 = await live(id);
19101
+ if (!record2) return null;
19102
+ const next = edit(structuredClone(record2.memory));
19103
+ if (!next) return null;
19104
+ const saved = await persistence.put(next, record2);
19105
+ notify(change, [saved]);
19106
+ return saved;
19107
+ });
19108
+ const embedInBackground = ({ memory: { memory_id: id, content } }) => {
19109
+ generateEmbedding(content, embeddingOptions).then(
19110
+ (vector) => serialized(id, async () => {
19111
+ const current = await live(id);
19112
+ if (!current || current.memory.content !== content || current.memory.embedding?.length)
19113
+ return;
19114
+ const saved = await persistence.put(
19115
+ { ...current.memory, embedding: storedVector(vector), embedding_model: model },
19116
+ current
19117
+ );
19118
+ notify("embedding", [saved]);
19119
+ })
19120
+ ).catch((error) => {
19121
+ getLogger().warn("[memory/remote-store] Failed to embed memory:", error);
19122
+ });
19123
+ };
19124
+ const newRow = (input) => {
19125
+ const now = Date.now();
19126
+ const scope = input.scope ?? "private";
19127
+ return {
19128
+ memory_id: uuidv75(),
19129
+ content: input.content,
19130
+ scope,
19131
+ level: levelFromScope(scope),
19132
+ created_at: now,
19133
+ updated_at: now,
19134
+ is_deleted: false,
19135
+ ...input.embedding !== void 0 && {
19136
+ embedding: storedVector(JSON.parse(input.embedding)),
19137
+ embedding_model: input.embeddingModel ?? model
19138
+ },
19139
+ proof_count: 1,
19140
+ source: "manual",
19141
+ ...input.eventTime && {
19142
+ event_time_start: input.eventTime.start ?? void 0,
19143
+ event_time_end: input.eventTime.end ?? void 0,
19144
+ event_time_kind: input.eventTime.kind ?? void 0
19145
+ },
19146
+ fact_type: input.factType,
19147
+ geohash: input.geohash,
19148
+ visibility: "private",
19149
+ twin_opt_in: false
19150
+ };
19151
+ };
19152
+ const created = (records, inputs) => {
19153
+ records.forEach((record2, i) => {
19154
+ if (inputs[i].embedding === void 0) embedInBackground(record2);
19155
+ });
19156
+ notify("membership", records);
19157
+ return records.map((record2) => stored(record2.memory));
19158
+ };
19159
+ const asStored = (record2) => record2 ? stored(record2.memory) : null;
19160
+ const everyState = {
19161
+ include_deleted: true,
19162
+ include_archived: true,
19163
+ include_quarantined: true,
19164
+ include_superseded: true
19165
+ };
19166
+ const changesSince = async (cursor2, pending2) => {
19167
+ const records = [];
19168
+ const failed = /* @__PURE__ */ new Set();
19169
+ const collect = (page) => {
19170
+ warnFailed(page.failed);
19171
+ records.push(...page.items);
19172
+ for (const failure of page.failed) failed.add(failure.memory_id);
19173
+ };
19174
+ let resume = cursor2;
19175
+ let next;
19176
+ do {
19177
+ const page = await persistence.query({
19178
+ ...everyState,
19179
+ order: "changed",
19180
+ limit: 200,
19181
+ ...(next ?? resume) && { cursor: next ?? resume }
19182
+ });
19183
+ collect(page);
19184
+ resume = page.changes_cursor ?? resume;
19185
+ next = page.next_cursor;
19186
+ } while (next);
19187
+ for (const memory_ids of chunks([...pending2], MAX_QUERY_IDS)) {
19188
+ let retry;
19189
+ do {
19190
+ const page = await persistence.query({
19191
+ ...everyState,
19192
+ memory_ids,
19193
+ limit: 200,
19194
+ ...retry && { cursor: retry }
19195
+ });
19196
+ collect(page);
19197
+ retry = page.next_cursor;
19198
+ } while (retry);
19199
+ }
19200
+ return { records, resume, failed };
19201
+ };
19202
+ let generation = 0;
19203
+ let ready = false;
19204
+ let cursor;
19205
+ let pending = /* @__PURE__ */ new Set();
19206
+ let polling = false;
19207
+ const poll = () => {
19208
+ if (polling) return;
19209
+ polling = true;
19210
+ const current = generation;
19211
+ changesSince(cursor, pending).then(({ records, resume, failed }) => {
19212
+ if (current !== generation) return;
19213
+ const changed = /* @__PURE__ */ new Set();
19214
+ for (const record2 of records) {
19215
+ const id = record2.memory.memory_id;
19216
+ const previous = seen.get(id);
19217
+ seen.set(id, record2);
19218
+ if (!ready) continue;
19219
+ for (const subscriber of subscribers) {
19220
+ const before = previous && subscriptionKey(previous, subscriber.options);
19221
+ if (before !== subscriptionKey(record2, subscriber.options)) changed.add(subscriber);
19222
+ }
19223
+ }
19224
+ ready = true;
19225
+ cursor = resume;
19226
+ pending = failed;
19227
+ for (const subscriber of changed)
19228
+ if (subscribers.has(subscriber)) safely(subscriber.onChange);
19229
+ }).catch((error) => {
19230
+ getLogger().warn("[memory/remote-store] Subscription poll failed:", error);
19231
+ }).finally(() => {
19232
+ polling = false;
19233
+ });
19234
+ };
19235
+ return {
19236
+ list: async (listOptions = {}) => {
19237
+ const order = listOptions.since ? "updated" : "created";
19238
+ const filters = {
19239
+ ...stateFilters(listOptions),
19240
+ include_embeddings: true,
19241
+ order,
19242
+ ...listOptions.scopes?.length && { scopes: listOptions.scopes },
19243
+ ...listOptions.factTypes?.length && { fact_types: listOptions.factTypes },
19244
+ ...listOptions.visibility?.length && { visibility: listOptions.visibility },
19245
+ ...listOptions.since && { updated_after: listOptions.since.getTime() }
19246
+ };
19247
+ const max = listOptions.limit && listOptions.limit > 0 ? listOptions.limit : Infinity;
19248
+ const variants = bounded(filters, "scopes").flatMap((f) => bounded(f, "fact_types"));
19249
+ if (!listOptions.memoryIds && variants.length === 1)
19250
+ return (await enumerate(filters, max)).map((r) => stored(r.memory));
19251
+ const fetched = await Promise.all(
19252
+ variants.map(
19253
+ (variant) => listOptions.memoryIds ? enumerateIds(listOptions.memoryIds, variant) : enumerate(variant, max)
19254
+ )
19255
+ );
19256
+ const rows = [...new Map(fetched.flat().map((r) => [r.memory.memory_id, r])).values()].map((record2) => stored(record2.memory)).sort(
19257
+ (a, b) => order === "updated" ? b.updatedAt.getTime() - a.updatedAt.getTime() || (a.uniqueId < b.uniqueId ? 1 : -1) : b.createdAt.getTime() - a.createdAt.getTime() || (a.uniqueId < b.uniqueId ? 1 : -1)
19258
+ );
19259
+ return rows.slice(0, max);
19260
+ },
19261
+ get: async (id) => asStored(await live(id)),
19262
+ listArchived: async () => (await enumerate({ archived_only: true, order: "archived", include_embeddings: true })).map(
19263
+ (record2) => stored(record2.memory)
19264
+ ),
19265
+ memoriesByTopics: async (names) => {
19266
+ const wanted = new Set(names.map(normalizeEntityName).filter(Boolean));
19267
+ const out = /* @__PURE__ */ new Map();
19268
+ const pages = await Promise.all(
19269
+ chunks([...wanted], MAX_QUERY_TOPICS).map((topics) => enumerate({ topics }))
19270
+ );
19271
+ for (const { memory } of pages.flat()) {
19272
+ const matched = [...canonicalTopics(memory)].filter((name) => wanted.has(name));
19273
+ if (matched.length) out.set(memory.memory_id, new Set(matched));
19274
+ }
19275
+ return out;
19276
+ },
19277
+ topicsByMemories: async (memoryIds) => {
19278
+ const out = /* @__PURE__ */ new Map();
19279
+ for (const { memory } of await enumerateIds(memoryIds, {
19280
+ include_archived: true,
19281
+ include_superseded: true,
19282
+ include_quarantined: true
19283
+ })) {
19284
+ const topics = canonicalTopics(memory);
19285
+ if (topics.size) out.set(memory.memory_id, topics);
19286
+ }
19287
+ return out;
19288
+ },
19289
+ create: async (input) => {
19290
+ const record2 = await persistence.put(newRow(input), 0);
19291
+ return created([record2], [input])[0];
19292
+ },
19293
+ createMany: async (inputs) => {
19294
+ const out = [];
19295
+ for (const batch of chunks(inputs, MAX_BATCH)) {
19296
+ let records;
19297
+ try {
19298
+ records = await persistence.putMany(
19299
+ batch.map((input) => ({ memory: newRow(input), expectedVersion: 0 }))
19300
+ );
19301
+ } catch (error) {
19302
+ if (out.length === 0) throw error;
19303
+ throw new RemoteMemoryPartialCreateError(out, error);
19304
+ }
19305
+ out.push(...created(records, batch));
19306
+ }
19307
+ return out;
19308
+ },
19309
+ update: async (id, patch) => {
19310
+ const saved = await mutate(id, "edit", (memory) => {
19311
+ if (memory.superseded_by) return null;
19312
+ memory.content = patch.content;
19313
+ memory.updated_at = Date.now();
19314
+ if (patch.scope !== void 0) {
19315
+ memory.level = levelForScopeChange(
19316
+ { level: memory.level, scope: memory.scope },
19317
+ patch.scope
19318
+ );
19319
+ memory.scope = patch.scope;
19320
+ }
19321
+ if (patch.factType !== void 0) memory.fact_type = patch.factType ?? void 0;
19322
+ if (patch.eventTime !== void 0) {
19323
+ memory.event_time_start = patch.eventTime?.start ?? void 0;
19324
+ memory.event_time_end = patch.eventTime?.end ?? void 0;
19325
+ memory.event_time_kind = patch.eventTime?.kind ?? void 0;
19326
+ }
19327
+ if (patch.embedding === void 0 || patch.embedding === null) {
19328
+ memory.embedding = [];
19329
+ delete memory.embedding_model;
19330
+ } else {
19331
+ memory.embedding = storedVector(JSON.parse(patch.embedding));
19332
+ memory.embedding_model = patch.embeddingModel ?? model;
19333
+ }
19334
+ return memory;
19335
+ });
19336
+ if (saved && patch.embedding === void 0) embedInBackground(saved);
19337
+ return asStored(saved);
19338
+ },
19339
+ delete: async (id) => !!await mutate(id, "membership", (memory) => ({ ...memory, is_deleted: true })),
19340
+ supersede: async (id, supersededById) => {
19341
+ if (id === supersededById) return false;
19342
+ const [first, second] = [id, supersededById].sort();
19343
+ return serialized(
19344
+ first,
19345
+ () => serialized(second, async () => {
19346
+ const [old, next] = await Promise.all([live(id), live(supersededById)]);
19347
+ if (!old || !next || old.memory.superseded_by || next.memory.superseded_by) return false;
19348
+ if (old.memory.kind !== void 0 && old.memory.kind !== null) return false;
19349
+ const saved = await persistence.putMany([
19350
+ {
19351
+ memory: { ...old.memory, superseded_by: supersededById, superseded_at: Date.now() },
19352
+ expectedVersion: old
19353
+ },
19354
+ { memory: next.memory, expectedVersion: next }
19355
+ ]);
19356
+ notify("membership", saved);
19357
+ return true;
19358
+ })
19359
+ );
19360
+ },
19361
+ archive: async (id) => !!await mutate(
19362
+ id,
19363
+ "edit",
19364
+ (memory) => memory.archived_at === void 0 || memory.archived_at === null ? { ...memory, archived_at: Date.now() } : null
19365
+ ),
19366
+ restore: (id) => serialized(id, async () => {
19367
+ const record2 = await live(id);
19368
+ if (!record2) return false;
19369
+ if (record2.memory.archived_at === void 0 || record2.memory.archived_at === null)
19370
+ return true;
19371
+ const { archived_at: _archivedAt, ...memory } = record2.memory;
19372
+ notify("edit", [await persistence.put(memory, record2)]);
19373
+ return true;
19374
+ }),
19375
+ setTopics: async (memoryId, topics) => asStored(
19376
+ await mutate(memoryId, "edit", (memory) => ({
19377
+ ...memory,
19378
+ topics: serializeTopics(mergeTopics([], topicInputs(topics, "user"))),
19379
+ topics_user_managed: true,
19380
+ topics_updated_at: Date.now()
19381
+ }))
19382
+ ),
19383
+ addTopics: async (memoryId, topics) => {
19384
+ const added = topicInputs(topics, "auto");
19385
+ const saved = await mutate(memoryId, "edit", (memory) => ({
19386
+ ...memory,
19387
+ topics: serializeTopics(mergeTopics(parseTopics(memory.topics) ?? [], added)),
19388
+ topics_updated_at: Date.now()
19389
+ }));
19390
+ if (!saved) return [];
19391
+ const now = /* @__PURE__ */ new Date();
19392
+ return mergeTopics([], added).map(
19393
+ (topic) => ({
19394
+ uniqueId: normalizeEntityName(topic.name),
19395
+ canonicalName: normalizeEntityName(topic.name),
19396
+ kind: topic.kind ?? null,
19397
+ createdAt: now,
19398
+ updatedAt: now
19399
+ })
19400
+ );
19401
+ },
19402
+ setVisibility: async (id, visibility, visibilityOptions) => asStored(
19403
+ await mutate(id, "edit", (memory) => {
19404
+ memory.visibility = visibility;
19405
+ if (visibility === "private") delete memory.published_at;
19406
+ else memory.published_at ?? (memory.published_at = Date.now());
19407
+ if (visibilityOptions?.twinOptIn !== void 0)
19408
+ memory.twin_opt_in = visibilityOptions.twinOptIn;
19409
+ return memory;
19410
+ })
19411
+ ),
19412
+ recall: (query, recallOptions) => pipeline.recall(query, recallOptions),
19413
+ retain: async (content, retainOptions) => {
19414
+ const result = await pipeline.retain(content, retainOptions);
19415
+ if (result.action === "create" || result.action === "supersede") notify("membership");
19416
+ else if (result.action === "update" || result.action === "merge") notify("edit");
19417
+ return result;
19418
+ },
19419
+ subscribe: (onChange, subscribeOptions = {}) => {
19420
+ const subscriber = { onChange, options: subscribeOptions };
19421
+ subscribers.add(subscriber);
19422
+ if (pollIntervalMs > 0 && !timer) {
19423
+ timer = setInterval(poll, pollIntervalMs);
19424
+ poll();
19425
+ }
19426
+ return () => {
19427
+ subscribers.delete(subscriber);
19428
+ if (subscribers.size || !timer) return;
19429
+ clearInterval(timer);
19430
+ timer = void 0;
19431
+ generation++;
19432
+ seen.clear();
19433
+ ready = false;
19434
+ cursor = void 0;
19435
+ pending = /* @__PURE__ */ new Set();
19436
+ };
19437
+ }
19438
+ };
19439
+ }
19440
+
18654
19441
  // src/lib/memory/synthesizeProfile.ts
18655
19442
  var DEFAULT_SYNTHESIS_MODEL = "inclusionai/ling-2.6-flash";
18656
19443
  var DEFAULT_FACET_RECALL_LIMIT = 20;
@@ -22061,7 +22848,7 @@ function useChat(options) {
22061
22848
 
22062
22849
  // src/expo/useChatStorage.ts
22063
22850
  import { useCallback as useCallback4, useEffect as useEffect4, useMemo, useRef as useRef4, useState as useState4 } from "react";
22064
- import { v7 as uuidv76 } from "uuid";
22851
+ import { v7 as uuidv77 } from "uuid";
22065
22852
 
22066
22853
  // src/lib/chat/assembleMessages.ts
22067
22854
  function assembleMessagesWithHistory(historyMessages, callerMessages, summarySystemMessage) {
@@ -22718,9 +23505,9 @@ async function decryptMediaFields(media, address, signMessage, embeddedWalletSig
22718
23505
  }
22719
23506
 
22720
23507
  // src/lib/db/media/types.ts
22721
- import { v7 as uuidv75 } from "uuid";
23508
+ import { v7 as uuidv76 } from "uuid";
22722
23509
  function generateMediaId() {
22723
- return `media_${uuidv75()}`;
23510
+ return `media_${uuidv76()}`;
22724
23511
  }
22725
23512
 
22726
23513
  // src/lib/db/media/operations.ts
@@ -23676,7 +24463,7 @@ function useChatStorage(options) {
23676
24463
  };
23677
24464
  };
23678
24465
  pendingResumeRef.current = null;
23679
- const effectiveAssistantUniqueId = assistantUniqueId ?? (resumable ? `msg_${uuidv76()}` : void 0);
24466
+ const effectiveAssistantUniqueId = assistantUniqueId ?? (resumable ? `msg_${uuidv77()}` : void 0);
23680
24467
  const embedToolText = (text12, mask, masked, token) => {
23681
24468
  const opts = {
23682
24469
  getToken: token,
@@ -24194,7 +24981,7 @@ function useChatStorage(options) {
24194
24981
  const detachedResult = result;
24195
24982
  if (detachedResult.detached) {
24196
24983
  recordToolSetTurn(database, convId, matchedToolSets);
24197
- const rowId = effectiveAssistantUniqueId ?? `msg_${uuidv76()}`;
24984
+ const rowId = effectiveAssistantUniqueId ?? `msg_${uuidv77()}`;
24198
24985
  pendingResumeRef.current = {
24199
24986
  handle: detachedResult.resume ?? null,
24200
24987
  convId,
@@ -24703,6 +25490,10 @@ export {
24703
25490
  LoggerProvider,
24704
25491
  MAX_HOPS,
24705
25492
  MEDIUM_TTL_MS,
25493
+ MEMORY_KINDS,
25494
+ MEMORY_LEVELS,
25495
+ MemoryKeyError,
25496
+ MemoryLevelError,
24706
25497
  NEVER_TTL_MS,
24707
25498
  NODE_BUDGET,
24708
25499
  NOTION_OAUTH_CONFIG,
@@ -24714,6 +25505,7 @@ export {
24714
25505
  RECALL_MAX_LIMIT,
24715
25506
  RECALL_TOOL_NAME,
24716
25507
  RemoteMemoryError,
25508
+ RemoteMemoryPartialCreateError,
24717
25509
  RerankerUnavailableError,
24718
25510
  SDK_SCHEMA_VERSION,
24719
25511
  SHORT_TTL_MS,
@@ -24779,6 +25571,7 @@ export {
24779
25571
  createRecallTool,
24780
25572
  createRemoteMemoryPersistence,
24781
25573
  createRemoteMemoryPipeline,
25574
+ createRemoteMemoryStore,
24782
25575
  createStockPricePreProcessor,
24783
25576
  createStreamingDeAnonymizer,
24784
25577
  createVaultEmbeddingCache,
@@ -24795,6 +25588,7 @@ export {
24795
25588
  deleteVaultMemoryOp,
24796
25589
  dequantizeEmbedding,
24797
25590
  deriveKeyFromSignatureBytes,
25591
+ deriveMemoryKeyRing,
24798
25592
  discoverNotionOAuthEndpoints,
24799
25593
  eagerEmbedContent,
24800
25594
  embedAllMessages,
@@ -24838,6 +25632,7 @@ export {
24838
25632
  isPiiRedactor,
24839
25633
  isRerankerAvailable,
24840
25634
  maskScopedEmbeddingCache,
25635
+ memoryCipher,
24841
25636
  moveMemoriesToFolderOp,
24842
25637
  noopLogger,
24843
25638
  onKeyAvailable,
@@ -24847,6 +25642,7 @@ export {
24847
25642
  queueManager,
24848
25643
  rankProfileCandidates,
24849
25644
  recall,
25645
+ reencryptMemoryField,
24850
25646
  reflect,
24851
25647
  refreshEncryptionKeyIfMatches,
24852
25648
  refreshNotionAccessToken,