@anuma/sdk 6.35.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.
@@ -1391,6 +1391,7 @@ __export(index_exports, {
1391
1391
  MEDIUM_TTL_MS: () => MEDIUM_TTL_MS,
1392
1392
  MEMORY_KINDS: () => MEMORY_KINDS,
1393
1393
  MEMORY_LEVELS: () => MEMORY_LEVELS,
1394
+ MemoryKeyError: () => MemoryKeyError,
1394
1395
  MemoryLevelError: () => MemoryLevelError,
1395
1396
  NEVER_TTL_MS: () => NEVER_TTL_MS,
1396
1397
  NODE_BUDGET: () => NODE_BUDGET,
@@ -1403,6 +1404,7 @@ __export(index_exports, {
1403
1404
  RECALL_MAX_LIMIT: () => RECALL_MAX_LIMIT,
1404
1405
  RECALL_TOOL_NAME: () => RECALL_TOOL_NAME,
1405
1406
  RemoteMemoryError: () => RemoteMemoryError,
1407
+ RemoteMemoryPartialCreateError: () => RemoteMemoryPartialCreateError,
1406
1408
  RerankerUnavailableError: () => RerankerUnavailableError,
1407
1409
  SDK_SCHEMA_VERSION: () => SDK_SCHEMA_VERSION,
1408
1410
  SHORT_TTL_MS: () => SHORT_TTL_MS,
@@ -1468,6 +1470,7 @@ __export(index_exports, {
1468
1470
  createRecallTool: () => createRecallTool,
1469
1471
  createRemoteMemoryPersistence: () => createRemoteMemoryPersistence,
1470
1472
  createRemoteMemoryPipeline: () => createRemoteMemoryPipeline,
1473
+ createRemoteMemoryStore: () => createRemoteMemoryStore,
1471
1474
  createStockPricePreProcessor: () => createStockPricePreProcessor,
1472
1475
  createStreamingDeAnonymizer: () => createStreamingDeAnonymizer,
1473
1476
  createVaultEmbeddingCache: () => createVaultEmbeddingCache,
@@ -1484,6 +1487,7 @@ __export(index_exports, {
1484
1487
  deleteVaultMemoryOp: () => deleteVaultMemoryOp,
1485
1488
  dequantizeEmbedding: () => dequantizeEmbedding,
1486
1489
  deriveKeyFromSignatureBytes: () => deriveKeyFromSignatureBytes,
1490
+ deriveMemoryKeyRing: () => deriveMemoryKeyRing,
1487
1491
  discoverNotionOAuthEndpoints: () => discoverNotionOAuthEndpoints,
1488
1492
  eagerEmbedContent: () => eagerEmbedContent,
1489
1493
  embedAllMessages: () => embedAllMessages,
@@ -1527,6 +1531,7 @@ __export(index_exports, {
1527
1531
  isPiiRedactor: () => isPiiRedactor,
1528
1532
  isRerankerAvailable: () => isRerankerAvailable,
1529
1533
  maskScopedEmbeddingCache: () => maskScopedEmbeddingCache,
1534
+ memoryCipher: () => memoryCipher,
1530
1535
  moveMemoriesToFolderOp: () => moveMemoriesToFolderOp,
1531
1536
  noopLogger: () => noopLogger,
1532
1537
  onKeyAvailable: () => onKeyAvailable,
@@ -1536,6 +1541,7 @@ __export(index_exports, {
1536
1541
  queueManager: () => queueManager,
1537
1542
  rankProfileCandidates: () => rankProfileCandidates,
1538
1543
  recall: () => recall,
1544
+ reencryptMemoryField: () => reencryptMemoryField,
1539
1545
  reflect: () => reflect,
1540
1546
  refreshEncryptionKeyIfMatches: () => refreshEncryptionKeyIfMatches,
1541
1547
  refreshNotionAccessToken: () => refreshNotionAccessToken,
@@ -3919,14 +3925,14 @@ async function updateMessageEmbeddingOp(ctx, uniqueId, vector, embeddingModel) {
3919
3925
  });
3920
3926
  return messageToStored(message, ctx.walletAddress, ctx.signMessage, ctx.embeddedWalletSigner);
3921
3927
  }
3922
- async function updateMessageChunksOp(ctx, uniqueId, chunks, embeddingModel) {
3928
+ async function updateMessageChunksOp(ctx, uniqueId, chunks2, embeddingModel) {
3923
3929
  let message;
3924
3930
  try {
3925
3931
  message = await ctx.messagesCollection.find(uniqueId);
3926
3932
  } catch {
3927
3933
  return null;
3928
3934
  }
3929
- const storedChunks = chunks.map(({ text: _text, ...rest }) => rest);
3935
+ const storedChunks = chunks2.map(({ text: _text, ...rest }) => rest);
3930
3936
  await ctx.database.write(async () => {
3931
3937
  await message.update((msg) => {
3932
3938
  msg._setRaw("chunks", JSON.stringify(storedChunks));
@@ -3970,12 +3976,12 @@ async function stripLegacyChunkTextOp(ctx) {
3970
3976
  const messages = await ctx.messagesCollection.query(import_watermelondb2.Q.where("id", import_watermelondb2.Q.oneOf(changedIds))).fetch();
3971
3977
  const updates = messages.flatMap((message) => {
3972
3978
  const raw = message._raw;
3973
- const chunks = chunksWithoutText(raw.chunks);
3974
- if (!chunks) return [];
3979
+ const chunks2 = chunksWithoutText(raw.chunks);
3980
+ if (!chunks2) return [];
3975
3981
  const updatedAt = raw.updated_at;
3976
3982
  return [
3977
3983
  message.prepareUpdate((msg) => {
3978
- msg._setRaw("chunks", JSON.stringify(chunks));
3984
+ msg._setRaw("chunks", JSON.stringify(chunks2));
3979
3985
  msg._setRaw("updated_at", updatedAt);
3980
3986
  })
3981
3987
  ];
@@ -4136,15 +4142,15 @@ async function searchChunksOp(ctx, queryVector, options) {
4136
4142
  }
4137
4143
  continue;
4138
4144
  }
4139
- const chunks = await readRawJsonField(message, "chunks", ctx.walletAddress);
4140
- if (chunks && chunks.length > 0) {
4141
- const vectors = chunks.map(
4145
+ const chunks2 = await readRawJsonField(message, "chunks", ctx.walletAddress);
4146
+ if (chunks2 && chunks2.length > 0) {
4147
+ const vectors = chunks2.map(
4142
4148
  (chunk) => decodeChunkVector(chunk.vector, () => {
4143
4149
  unreadableVectors++;
4144
4150
  })
4145
4151
  );
4146
4152
  chunkCache?.set(message.id, { version, chunks: vectors });
4147
- for (let ci = 0; ci < chunks.length; ci++) {
4153
+ for (let ci = 0; ci < chunks2.length; ci++) {
4148
4154
  const vec = vectors[ci];
4149
4155
  if (vec.length === 0) continue;
4150
4156
  const similarity = cosineSimilarity(queryVector, vec);
@@ -4152,7 +4158,7 @@ async function searchChunksOp(ctx, queryVector, options) {
4152
4158
  candidates.push({
4153
4159
  message,
4154
4160
  similarity,
4155
- chunkTextSource: { kind: "chunk", chunk: chunks[ci], siblings: chunks }
4161
+ chunkTextSource: { kind: "chunk", chunk: chunks2[ci], siblings: chunks2 }
4156
4162
  });
4157
4163
  }
4158
4164
  }
@@ -4304,7 +4310,7 @@ function chunkText(text12, options) {
4304
4310
  ];
4305
4311
  }
4306
4312
  const sentences = splitIntoSentences(text12);
4307
- const chunks = [];
4313
+ const chunks2 = [];
4308
4314
  let currentChunkSentences = [];
4309
4315
  let currentChunkStart = 0;
4310
4316
  let currentOffset = 0;
@@ -4318,7 +4324,7 @@ function chunkText(text12, options) {
4318
4324
  if (sentence.length > chunkSize) {
4319
4325
  if (currentChunkSentences.length > 0) {
4320
4326
  const chunkText2 = currentChunkSentences.join(" ");
4321
- chunks.push({
4327
+ chunks2.push({
4322
4328
  text: chunkText2,
4323
4329
  startOffset: currentChunkStart,
4324
4330
  endOffset: currentOffset
@@ -4329,7 +4335,7 @@ function chunkText(text12, options) {
4329
4335
  const chunkEnd = Math.min(j + chunkSize, sentence.length);
4330
4336
  const chunk = sentence.slice(j, chunkEnd);
4331
4337
  if (chunk.length >= minChunkSize) {
4332
- chunks.push({
4338
+ chunks2.push({
4333
4339
  text: chunk,
4334
4340
  startOffset: sentenceStart + j,
4335
4341
  endOffset: sentenceStart + chunkEnd
@@ -4343,7 +4349,7 @@ function chunkText(text12, options) {
4343
4349
  const currentText = currentChunkSentences.join(" ");
4344
4350
  const potentialLength = currentText.length + (currentText ? 1 : 0) + sentence.length;
4345
4351
  if (potentialLength > chunkSize && currentChunkSentences.length > 0) {
4346
- chunks.push({
4352
+ chunks2.push({
4347
4353
  text: currentText,
4348
4354
  startOffset: currentChunkStart,
4349
4355
  endOffset: currentOffset
@@ -4374,14 +4380,14 @@ function chunkText(text12, options) {
4374
4380
  if (currentChunkSentences.length > 0) {
4375
4381
  const chunkText2 = currentChunkSentences.join(" ");
4376
4382
  if (chunkText2.length >= minChunkSize) {
4377
- chunks.push({
4383
+ chunks2.push({
4378
4384
  text: chunkText2,
4379
4385
  startOffset: currentChunkStart,
4380
4386
  endOffset: text12.length
4381
4387
  });
4382
4388
  }
4383
4389
  }
4384
- if (chunks.length === 0) {
4390
+ if (chunks2.length === 0) {
4385
4391
  const trimmedText = text12.trim();
4386
4392
  if (trimmedText.length > 0) {
4387
4393
  return [
@@ -4393,7 +4399,7 @@ function chunkText(text12, options) {
4393
4399
  ];
4394
4400
  }
4395
4401
  }
4396
- return chunks;
4402
+ return chunks2;
4397
4403
  }
4398
4404
  function shouldChunkMessage(content, chunkSize = DEFAULT_CHUNK_SIZE) {
4399
4405
  return content.length > chunkSize;
@@ -4465,9 +4471,9 @@ function createSseClient({
4465
4471
  if (done) break;
4466
4472
  buffer += value;
4467
4473
  buffer = buffer.replace(/\r\n?/g, "\n");
4468
- const chunks = buffer.split("\n\n");
4469
- buffer = chunks.pop() ?? "";
4470
- for (const chunk of chunks) {
4474
+ const chunks2 = buffer.split("\n\n");
4475
+ buffer = chunks2.pop() ?? "";
4476
+ for (const chunk of chunks2) {
4471
4477
  const lines = chunk.split("\n");
4472
4478
  const dataLines = [];
4473
4479
  let eventName;
@@ -5414,18 +5420,18 @@ async function embedMany(texts, options, outer) {
5414
5420
  outer
5415
5421
  );
5416
5422
  } else {
5417
- const chunks = [];
5423
+ const chunks2 = [];
5418
5424
  for (let i = 0; i < uncachedTexts.length; i += chunkSize) {
5419
- chunks.push(uncachedTexts.slice(i, i + chunkSize));
5425
+ chunks2.push(uncachedTexts.slice(i, i + chunkSize));
5420
5426
  }
5421
- const allEmbeddings = new Array(chunks.length);
5427
+ const allEmbeddings = new Array(chunks2.length);
5422
5428
  let nextIndex = 0;
5423
5429
  const worker = async () => {
5424
- while (nextIndex < chunks.length) {
5430
+ while (nextIndex < chunks2.length) {
5425
5431
  if (outer?.aborted) throw outer.reason;
5426
5432
  const idx = nextIndex++;
5427
5433
  allEmbeddings[idx] = await generateEmbeddingsBatch(
5428
- chunks[idx],
5434
+ chunks2[idx],
5429
5435
  headers,
5430
5436
  baseUrl,
5431
5437
  embeddingModel,
@@ -5437,7 +5443,7 @@ async function embedMany(texts, options, outer) {
5437
5443
  }
5438
5444
  };
5439
5445
  const workers = Array.from(
5440
- { length: Math.min(DEFAULT_EMBEDDING_BATCH_CONCURRENCY, chunks.length) },
5446
+ { length: Math.min(DEFAULT_EMBEDDING_BATCH_CONCURRENCY, chunks2.length) },
5441
5447
  () => worker()
5442
5448
  );
5443
5449
  await Promise.all(workers);
@@ -10087,7 +10093,7 @@ function sseFailureMessage(status, statusText, detail = "") {
10087
10093
  return `SSE failed: ${status} ${statusText}${detail}`;
10088
10094
  }
10089
10095
  function parseSseChunks(raw, incompleteBuffer) {
10090
- const chunks = [];
10096
+ const chunks2 = [];
10091
10097
  const text12 = incompleteBuffer + raw;
10092
10098
  const lines = text12.split("\n");
10093
10099
  const remaining = raw.endsWith("\n") ? "" : lines.pop() ?? "";
@@ -10096,11 +10102,11 @@ function parseSseChunks(raw, incompleteBuffer) {
10096
10102
  const data = line.substring(6).trim();
10097
10103
  if (data === "[DONE]") continue;
10098
10104
  try {
10099
- chunks.push(JSON.parse(data));
10105
+ chunks2.push(JSON.parse(data));
10100
10106
  } catch {
10101
10107
  }
10102
10108
  }
10103
- return { chunks, remaining };
10109
+ return { chunks: chunks2, remaining };
10104
10110
  }
10105
10111
  var xhrTransport = (options) => {
10106
10112
  const queue = [];
@@ -10169,18 +10175,18 @@ var xhrTransport = (options) => {
10169
10175
  const newData = xhr.responseText.substring(lastProcessedIndex);
10170
10176
  lastProcessedIndex = xhr.responseText.length;
10171
10177
  if (newData.length > 0) options.onActivity?.();
10172
- const { chunks, remaining } = parseSseChunks(newData, incompleteBuffer);
10178
+ const { chunks: chunks2, remaining } = parseSseChunks(newData, incompleteBuffer);
10173
10179
  incompleteBuffer = remaining;
10174
- for (const chunk of chunks) {
10180
+ for (const chunk of chunks2) {
10175
10181
  push({ type: "data", value: chunk });
10176
10182
  }
10177
10183
  };
10178
10184
  xhr.onload = () => {
10179
10185
  options.signal?.removeEventListener("abort", abortHandler);
10180
10186
  if (incompleteBuffer) {
10181
- const { chunks } = parseSseChunks(incompleteBuffer + "\n", "");
10187
+ const { chunks: chunks2 } = parseSseChunks(incompleteBuffer + "\n", "");
10182
10188
  incompleteBuffer = "";
10183
- for (const chunk of chunks) {
10189
+ for (const chunk of chunks2) {
10184
10190
  push({ type: "data", value: chunk });
10185
10191
  }
10186
10192
  }
@@ -19691,6 +19697,65 @@ function createLocalMemoryStore(options) {
19691
19697
  };
19692
19698
  }
19693
19699
 
19700
+ // src/lib/memory/store/memoryKeys.ts
19701
+ var KEY_ID_DOMAIN = "anuma-private-memory-key-id-v1";
19702
+ var MemoryKeyError = class extends Error {
19703
+ constructor(message) {
19704
+ super(message);
19705
+ this.name = "MemoryKeyError";
19706
+ }
19707
+ };
19708
+ async function importAesKey(hex) {
19709
+ return crypto.subtle.importKey(
19710
+ "raw",
19711
+ hexToBytes(hex).buffer,
19712
+ { name: "AES-GCM" },
19713
+ false,
19714
+ ["encrypt", "decrypt"]
19715
+ );
19716
+ }
19717
+ async function deriveMemoryKeyRing(signatureHex) {
19718
+ const v3Hex = await deriveKeyFromSignatureV3(signatureHex);
19719
+ const digest = await crypto.subtle.digest(
19720
+ "SHA-256",
19721
+ new TextEncoder().encode(`${KEY_ID_DOMAIN}:${v3Hex}`)
19722
+ );
19723
+ const keyId = "v3:" + Array.from(new Uint8Array(digest), (byte) => byte.toString(16).padStart(2, "0")).join("");
19724
+ return {
19725
+ keyId,
19726
+ v3: await importAesKey(v3Hex),
19727
+ v2: await importAesKey(await deriveKeyFromSignature(signatureHex))
19728
+ };
19729
+ }
19730
+ async function decryptWith(value, rings) {
19731
+ const version = value.startsWith("enc:v3:") ? "v3" : "v2";
19732
+ for (const ring of rings) {
19733
+ try {
19734
+ return await decryptDataWithKey(value.slice(`enc:${version}:`.length), ring[version]);
19735
+ } catch {
19736
+ continue;
19737
+ }
19738
+ }
19739
+ throw new MemoryKeyError(`No supplied key decrypts this enc:${version} field`);
19740
+ }
19741
+ function memoryCipher(canonical) {
19742
+ return {
19743
+ encrypt: async (plaintext) => `enc:v3:${await encryptDataWithKey(plaintext, canonical.v3)}`,
19744
+ decrypt: async (ciphertext) => {
19745
+ if (!ciphertext.startsWith("enc:v3:") || !isEncrypted(ciphertext))
19746
+ throw new MemoryKeyError("Remote memory content must be enc:v3 ciphertext");
19747
+ return decryptWith(ciphertext, [canonical]);
19748
+ }
19749
+ };
19750
+ }
19751
+ async function reencryptMemoryField(value, canonical, fallbacks = []) {
19752
+ const { encrypt } = memoryCipher(canonical);
19753
+ if (!value.startsWith("enc:")) return encrypt(value);
19754
+ if (!isEncrypted(value))
19755
+ throw new MemoryKeyError("Field has an encryption prefix but an invalid payload");
19756
+ return encrypt(await decryptWith(value, [canonical, ...fallbacks]));
19757
+ }
19758
+
19694
19759
  // src/lib/memory/store/remotePersistence.ts
19695
19760
  var RemoteMemoryError = class extends Error {
19696
19761
  constructor(message, status, code) {
@@ -19743,6 +19808,30 @@ var candidateListLimits = [
19743
19808
  ["memory_ids", 1e3],
19744
19809
  ["force_ids", 100]
19745
19810
  ];
19811
+ var queryListLimits = [
19812
+ ["scopes", 20],
19813
+ ["fact_types", 20],
19814
+ ["visibility", 20],
19815
+ ["memory_ids", 1e3],
19816
+ ["topics", 100]
19817
+ ];
19818
+ var queryFields = [
19819
+ "include_deleted",
19820
+ "include_archived",
19821
+ "include_quarantined",
19822
+ "include_superseded",
19823
+ "archived_only",
19824
+ "scopes",
19825
+ "fact_types",
19826
+ "visibility",
19827
+ "memory_ids",
19828
+ "topics",
19829
+ "updated_after",
19830
+ "order",
19831
+ "cursor",
19832
+ "limit",
19833
+ "include_embeddings"
19834
+ ];
19746
19835
  function record(value) {
19747
19836
  return typeof value === "object" && value !== null && !Array.isArray(value);
19748
19837
  }
@@ -20077,6 +20166,35 @@ async function createRemoteMemoryPersistence(options) {
20077
20166
  throw new Error("Invalid nearby batch response");
20078
20167
  return Promise.all(result.items.map((item, i) => decodeCommitted(item, prepared[i])));
20079
20168
  },
20169
+ query: async (queryOptions = {}) => {
20170
+ const { signal, ...query } = queryOptions;
20171
+ if (query.limit !== void 0 && (!Number.isInteger(query.limit) || query.limit < 1 || query.limit > 200))
20172
+ throw new Error("Page limit must be 1\u2013200");
20173
+ for (const [key, max] of queryListLimits) {
20174
+ const values = query[key];
20175
+ if (values && values.length > max)
20176
+ throw new Error(`Query ${key} accepts at most ${max} entries (got ${values.length})`);
20177
+ }
20178
+ const page = await request(
20179
+ "/memories/query",
20180
+ {
20181
+ method: "POST",
20182
+ body: JSON.stringify(
20183
+ Object.fromEntries(
20184
+ queryFields.filter((key) => query[key] !== void 0).map((key) => [key, query[key]])
20185
+ )
20186
+ )
20187
+ },
20188
+ signal
20189
+ );
20190
+ 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")
20191
+ throw new Error("Invalid nearby private-memory page");
20192
+ return {
20193
+ ...await decodeAll(page.items),
20194
+ ...page.next_cursor !== void 0 && { next_cursor: page.next_cursor },
20195
+ ...page.changes_cursor !== void 0 && { changes_cursor: page.changes_cursor }
20196
+ };
20197
+ },
20080
20198
  candidateSet,
20081
20199
  candidates: async (embedding, candidateOptions = {}) => decodeAll((await fetchCandidates(embedding, candidateOptions, false)).items)
20082
20200
  };
@@ -20466,6 +20584,490 @@ function createRemoteMemoryPipeline(options) {
20466
20584
  };
20467
20585
  }
20468
20586
 
20587
+ // src/lib/memory/store/remoteStore.ts
20588
+ var import_uuid5 = require("uuid");
20589
+ init_logger();
20590
+ function relevant(change, options) {
20591
+ return options.includeDeleted ? change === "membership" : change !== "embedding" || !!options.embeddings;
20592
+ }
20593
+ function safely(onChange) {
20594
+ try {
20595
+ onChange();
20596
+ } catch (error) {
20597
+ getLogger().warn("[memory/remote-store] Subscriber threw:", error);
20598
+ }
20599
+ }
20600
+ var MAX_BATCH = 50;
20601
+ var MAX_QUERY_IDS = 1e3;
20602
+ var MAX_QUERY_TOPICS = 100;
20603
+ var MAX_QUERY_FILTER = 20;
20604
+ var RemoteMemoryPartialCreateError = class extends Error {
20605
+ constructor(created, cause) {
20606
+ super(`createMany stored ${created.length} memories before a batch failed`);
20607
+ this.created = created;
20608
+ this.cause = cause;
20609
+ this.name = "RemoteMemoryPartialCreateError";
20610
+ }
20611
+ };
20612
+ function warnFailed(failed) {
20613
+ if (failed.length)
20614
+ getLogger().warn(
20615
+ `[memory/remote-store] Skipping ${failed.length} undecryptable row(s)`,
20616
+ failed.map((failure) => failure.memory_id)
20617
+ );
20618
+ }
20619
+ function bounded(filters, key) {
20620
+ const values = filters[key];
20621
+ if (!values || values.length <= MAX_QUERY_FILTER) return [filters];
20622
+ return chunks(values, MAX_QUERY_FILTER).map((chunk) => ({ ...filters, [key]: chunk }));
20623
+ }
20624
+ function chunks(values, size) {
20625
+ const out = [];
20626
+ for (let i = 0; i < values.length; i += size) out.push(values.slice(i, i + size));
20627
+ return out;
20628
+ }
20629
+ function stateFilters(options) {
20630
+ return {
20631
+ include_deleted: options.includeDeleted,
20632
+ include_archived: options.includeArchived,
20633
+ include_quarantined: options.includeQuarantined,
20634
+ include_superseded: options.includeSuperseded
20635
+ };
20636
+ }
20637
+ function hidden(memory, options) {
20638
+ if (memory.trust_tier === "quarantined") return true;
20639
+ if (options.includeDeleted) return false;
20640
+ return !!memory.is_deleted || memory.archived_at !== void 0 && memory.archived_at !== null || !!memory.superseded_by;
20641
+ }
20642
+ function subscriptionKey({ memory, version }, options) {
20643
+ if (hidden(memory, options)) return void 0;
20644
+ if (options.includeDeleted) return String(!!memory.is_deleted);
20645
+ return JSON.stringify([
20646
+ options.embeddings ? version : null,
20647
+ memory.content,
20648
+ memory.scope,
20649
+ memory.updated_at,
20650
+ memory.fact_type,
20651
+ memory.event_time_start,
20652
+ memory.event_time_end,
20653
+ memory.event_time_kind,
20654
+ memory.trust_tier,
20655
+ memory.visibility,
20656
+ memory.published_at,
20657
+ memory.geohash,
20658
+ memory.topics,
20659
+ memory.topics_user_managed,
20660
+ memory.media,
20661
+ memory.source
20662
+ ]);
20663
+ }
20664
+ function topicInputs(topics, source) {
20665
+ return topics.flatMap((topic) => {
20666
+ const name = (typeof topic === "string" ? topic : topic.name).trim();
20667
+ const kind = typeof topic === "string" ? void 0 : topic.kind;
20668
+ return name ? [{ name, ...kind && { kind }, source }] : [];
20669
+ });
20670
+ }
20671
+ function mergeTopics(existing, added) {
20672
+ const byName = /* @__PURE__ */ new Map();
20673
+ for (const topic of [...existing, ...added]) {
20674
+ const key = normalizeEntityName(topic.name);
20675
+ if (!byName.has(key)) byName.set(key, topic);
20676
+ }
20677
+ return [...byName.values()];
20678
+ }
20679
+ function canonicalTopics(row) {
20680
+ return new Set((parseTopics(row.topics) ?? []).map((topic) => normalizeEntityName(topic.name)));
20681
+ }
20682
+ function createRemoteMemoryStore(options) {
20683
+ const { persistence, embeddingOptions } = options;
20684
+ const model = embeddingOptions.model ?? DEFAULT_API_EMBEDDING_MODEL;
20685
+ const pollIntervalMs = options.pollIntervalMs ?? 6e4;
20686
+ const pipeline = createRemoteMemoryPipeline(options);
20687
+ const subscribers = /* @__PURE__ */ new Set();
20688
+ const seen = /* @__PURE__ */ new Map();
20689
+ let timer;
20690
+ const notify = (change, records = []) => {
20691
+ if (timer) for (const record2 of records) seen.set(record2.memory.memory_id, record2);
20692
+ for (const subscriber of [...subscribers])
20693
+ if (relevant(change, subscriber.options)) safely(subscriber.onChange);
20694
+ };
20695
+ const enumerate = async (filters, max = Infinity) => {
20696
+ const records = [];
20697
+ let cursor2;
20698
+ do {
20699
+ const page = await persistence.query({
20700
+ ...filters,
20701
+ limit: Math.min(200, Math.max(1, max - records.length)),
20702
+ ...cursor2 && { cursor: cursor2 }
20703
+ });
20704
+ warnFailed(page.failed);
20705
+ records.push(...page.items);
20706
+ cursor2 = page.next_cursor;
20707
+ } while (cursor2 && records.length < max);
20708
+ return records.slice(0, max);
20709
+ };
20710
+ const enumerateIds = async (ids, filters) => (await Promise.all(
20711
+ chunks([...new Set(ids)], MAX_QUERY_IDS).map(
20712
+ (memory_ids) => enumerate({ ...filters, memory_ids })
20713
+ )
20714
+ )).flat();
20715
+ const queues = /* @__PURE__ */ new Map();
20716
+ const serialized = (id, task) => {
20717
+ const run = (queues.get(id) ?? Promise.resolve()).then(task, task);
20718
+ const settled = run.catch(() => void 0);
20719
+ queues.set(id, settled);
20720
+ void settled.then(() => {
20721
+ if (queues.get(id) === settled) queues.delete(id);
20722
+ });
20723
+ return run;
20724
+ };
20725
+ const live = async (id) => {
20726
+ const record2 = await persistence.get(id);
20727
+ return record2 && !record2.memory.is_deleted ? record2 : null;
20728
+ };
20729
+ const mutate = async (id, change, edit) => serialized(id, async () => {
20730
+ const record2 = await live(id);
20731
+ if (!record2) return null;
20732
+ const next = edit(structuredClone(record2.memory));
20733
+ if (!next) return null;
20734
+ const saved = await persistence.put(next, record2);
20735
+ notify(change, [saved]);
20736
+ return saved;
20737
+ });
20738
+ const embedInBackground = ({ memory: { memory_id: id, content } }) => {
20739
+ generateEmbedding(content, embeddingOptions).then(
20740
+ (vector) => serialized(id, async () => {
20741
+ const current = await live(id);
20742
+ if (!current || current.memory.content !== content || current.memory.embedding?.length)
20743
+ return;
20744
+ const saved = await persistence.put(
20745
+ { ...current.memory, embedding: storedVector(vector), embedding_model: model },
20746
+ current
20747
+ );
20748
+ notify("embedding", [saved]);
20749
+ })
20750
+ ).catch((error) => {
20751
+ getLogger().warn("[memory/remote-store] Failed to embed memory:", error);
20752
+ });
20753
+ };
20754
+ const newRow = (input) => {
20755
+ const now = Date.now();
20756
+ const scope = input.scope ?? "private";
20757
+ return {
20758
+ memory_id: (0, import_uuid5.v7)(),
20759
+ content: input.content,
20760
+ scope,
20761
+ level: levelFromScope(scope),
20762
+ created_at: now,
20763
+ updated_at: now,
20764
+ is_deleted: false,
20765
+ ...input.embedding !== void 0 && {
20766
+ embedding: storedVector(JSON.parse(input.embedding)),
20767
+ embedding_model: input.embeddingModel ?? model
20768
+ },
20769
+ proof_count: 1,
20770
+ source: "manual",
20771
+ ...input.eventTime && {
20772
+ event_time_start: input.eventTime.start ?? void 0,
20773
+ event_time_end: input.eventTime.end ?? void 0,
20774
+ event_time_kind: input.eventTime.kind ?? void 0
20775
+ },
20776
+ fact_type: input.factType,
20777
+ geohash: input.geohash,
20778
+ visibility: "private",
20779
+ twin_opt_in: false
20780
+ };
20781
+ };
20782
+ const created = (records, inputs) => {
20783
+ records.forEach((record2, i) => {
20784
+ if (inputs[i].embedding === void 0) embedInBackground(record2);
20785
+ });
20786
+ notify("membership", records);
20787
+ return records.map((record2) => stored(record2.memory));
20788
+ };
20789
+ const asStored = (record2) => record2 ? stored(record2.memory) : null;
20790
+ const everyState = {
20791
+ include_deleted: true,
20792
+ include_archived: true,
20793
+ include_quarantined: true,
20794
+ include_superseded: true
20795
+ };
20796
+ const changesSince = async (cursor2, pending2) => {
20797
+ const records = [];
20798
+ const failed = /* @__PURE__ */ new Set();
20799
+ const collect = (page) => {
20800
+ warnFailed(page.failed);
20801
+ records.push(...page.items);
20802
+ for (const failure of page.failed) failed.add(failure.memory_id);
20803
+ };
20804
+ let resume = cursor2;
20805
+ let next;
20806
+ do {
20807
+ const page = await persistence.query({
20808
+ ...everyState,
20809
+ order: "changed",
20810
+ limit: 200,
20811
+ ...(next ?? resume) && { cursor: next ?? resume }
20812
+ });
20813
+ collect(page);
20814
+ resume = page.changes_cursor ?? resume;
20815
+ next = page.next_cursor;
20816
+ } while (next);
20817
+ for (const memory_ids of chunks([...pending2], MAX_QUERY_IDS)) {
20818
+ let retry;
20819
+ do {
20820
+ const page = await persistence.query({
20821
+ ...everyState,
20822
+ memory_ids,
20823
+ limit: 200,
20824
+ ...retry && { cursor: retry }
20825
+ });
20826
+ collect(page);
20827
+ retry = page.next_cursor;
20828
+ } while (retry);
20829
+ }
20830
+ return { records, resume, failed };
20831
+ };
20832
+ let generation = 0;
20833
+ let ready = false;
20834
+ let cursor;
20835
+ let pending = /* @__PURE__ */ new Set();
20836
+ let polling = false;
20837
+ const poll = () => {
20838
+ if (polling) return;
20839
+ polling = true;
20840
+ const current = generation;
20841
+ changesSince(cursor, pending).then(({ records, resume, failed }) => {
20842
+ if (current !== generation) return;
20843
+ const changed = /* @__PURE__ */ new Set();
20844
+ for (const record2 of records) {
20845
+ const id = record2.memory.memory_id;
20846
+ const previous = seen.get(id);
20847
+ seen.set(id, record2);
20848
+ if (!ready) continue;
20849
+ for (const subscriber of subscribers) {
20850
+ const before = previous && subscriptionKey(previous, subscriber.options);
20851
+ if (before !== subscriptionKey(record2, subscriber.options)) changed.add(subscriber);
20852
+ }
20853
+ }
20854
+ ready = true;
20855
+ cursor = resume;
20856
+ pending = failed;
20857
+ for (const subscriber of changed)
20858
+ if (subscribers.has(subscriber)) safely(subscriber.onChange);
20859
+ }).catch((error) => {
20860
+ getLogger().warn("[memory/remote-store] Subscription poll failed:", error);
20861
+ }).finally(() => {
20862
+ polling = false;
20863
+ });
20864
+ };
20865
+ return {
20866
+ list: async (listOptions = {}) => {
20867
+ const order = listOptions.since ? "updated" : "created";
20868
+ const filters = {
20869
+ ...stateFilters(listOptions),
20870
+ include_embeddings: true,
20871
+ order,
20872
+ ...listOptions.scopes?.length && { scopes: listOptions.scopes },
20873
+ ...listOptions.factTypes?.length && { fact_types: listOptions.factTypes },
20874
+ ...listOptions.visibility?.length && { visibility: listOptions.visibility },
20875
+ ...listOptions.since && { updated_after: listOptions.since.getTime() }
20876
+ };
20877
+ const max = listOptions.limit && listOptions.limit > 0 ? listOptions.limit : Infinity;
20878
+ const variants = bounded(filters, "scopes").flatMap((f) => bounded(f, "fact_types"));
20879
+ if (!listOptions.memoryIds && variants.length === 1)
20880
+ return (await enumerate(filters, max)).map((r) => stored(r.memory));
20881
+ const fetched = await Promise.all(
20882
+ variants.map(
20883
+ (variant) => listOptions.memoryIds ? enumerateIds(listOptions.memoryIds, variant) : enumerate(variant, max)
20884
+ )
20885
+ );
20886
+ const rows = [...new Map(fetched.flat().map((r) => [r.memory.memory_id, r])).values()].map((record2) => stored(record2.memory)).sort(
20887
+ (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)
20888
+ );
20889
+ return rows.slice(0, max);
20890
+ },
20891
+ get: async (id) => asStored(await live(id)),
20892
+ listArchived: async () => (await enumerate({ archived_only: true, order: "archived", include_embeddings: true })).map(
20893
+ (record2) => stored(record2.memory)
20894
+ ),
20895
+ memoriesByTopics: async (names) => {
20896
+ const wanted = new Set(names.map(normalizeEntityName).filter(Boolean));
20897
+ const out = /* @__PURE__ */ new Map();
20898
+ const pages = await Promise.all(
20899
+ chunks([...wanted], MAX_QUERY_TOPICS).map((topics) => enumerate({ topics }))
20900
+ );
20901
+ for (const { memory } of pages.flat()) {
20902
+ const matched = [...canonicalTopics(memory)].filter((name) => wanted.has(name));
20903
+ if (matched.length) out.set(memory.memory_id, new Set(matched));
20904
+ }
20905
+ return out;
20906
+ },
20907
+ topicsByMemories: async (memoryIds) => {
20908
+ const out = /* @__PURE__ */ new Map();
20909
+ for (const { memory } of await enumerateIds(memoryIds, {
20910
+ include_archived: true,
20911
+ include_superseded: true,
20912
+ include_quarantined: true
20913
+ })) {
20914
+ const topics = canonicalTopics(memory);
20915
+ if (topics.size) out.set(memory.memory_id, topics);
20916
+ }
20917
+ return out;
20918
+ },
20919
+ create: async (input) => {
20920
+ const record2 = await persistence.put(newRow(input), 0);
20921
+ return created([record2], [input])[0];
20922
+ },
20923
+ createMany: async (inputs) => {
20924
+ const out = [];
20925
+ for (const batch of chunks(inputs, MAX_BATCH)) {
20926
+ let records;
20927
+ try {
20928
+ records = await persistence.putMany(
20929
+ batch.map((input) => ({ memory: newRow(input), expectedVersion: 0 }))
20930
+ );
20931
+ } catch (error) {
20932
+ if (out.length === 0) throw error;
20933
+ throw new RemoteMemoryPartialCreateError(out, error);
20934
+ }
20935
+ out.push(...created(records, batch));
20936
+ }
20937
+ return out;
20938
+ },
20939
+ update: async (id, patch) => {
20940
+ const saved = await mutate(id, "edit", (memory) => {
20941
+ if (memory.superseded_by) return null;
20942
+ memory.content = patch.content;
20943
+ memory.updated_at = Date.now();
20944
+ if (patch.scope !== void 0) {
20945
+ memory.level = levelForScopeChange(
20946
+ { level: memory.level, scope: memory.scope },
20947
+ patch.scope
20948
+ );
20949
+ memory.scope = patch.scope;
20950
+ }
20951
+ if (patch.factType !== void 0) memory.fact_type = patch.factType ?? void 0;
20952
+ if (patch.eventTime !== void 0) {
20953
+ memory.event_time_start = patch.eventTime?.start ?? void 0;
20954
+ memory.event_time_end = patch.eventTime?.end ?? void 0;
20955
+ memory.event_time_kind = patch.eventTime?.kind ?? void 0;
20956
+ }
20957
+ if (patch.embedding === void 0 || patch.embedding === null) {
20958
+ memory.embedding = [];
20959
+ delete memory.embedding_model;
20960
+ } else {
20961
+ memory.embedding = storedVector(JSON.parse(patch.embedding));
20962
+ memory.embedding_model = patch.embeddingModel ?? model;
20963
+ }
20964
+ return memory;
20965
+ });
20966
+ if (saved && patch.embedding === void 0) embedInBackground(saved);
20967
+ return asStored(saved);
20968
+ },
20969
+ delete: async (id) => !!await mutate(id, "membership", (memory) => ({ ...memory, is_deleted: true })),
20970
+ supersede: async (id, supersededById) => {
20971
+ if (id === supersededById) return false;
20972
+ const [first, second] = [id, supersededById].sort();
20973
+ return serialized(
20974
+ first,
20975
+ () => serialized(second, async () => {
20976
+ const [old, next] = await Promise.all([live(id), live(supersededById)]);
20977
+ if (!old || !next || old.memory.superseded_by || next.memory.superseded_by) return false;
20978
+ if (old.memory.kind !== void 0 && old.memory.kind !== null) return false;
20979
+ const saved = await persistence.putMany([
20980
+ {
20981
+ memory: { ...old.memory, superseded_by: supersededById, superseded_at: Date.now() },
20982
+ expectedVersion: old
20983
+ },
20984
+ { memory: next.memory, expectedVersion: next }
20985
+ ]);
20986
+ notify("membership", saved);
20987
+ return true;
20988
+ })
20989
+ );
20990
+ },
20991
+ archive: async (id) => !!await mutate(
20992
+ id,
20993
+ "edit",
20994
+ (memory) => memory.archived_at === void 0 || memory.archived_at === null ? { ...memory, archived_at: Date.now() } : null
20995
+ ),
20996
+ restore: (id) => serialized(id, async () => {
20997
+ const record2 = await live(id);
20998
+ if (!record2) return false;
20999
+ if (record2.memory.archived_at === void 0 || record2.memory.archived_at === null)
21000
+ return true;
21001
+ const { archived_at: _archivedAt, ...memory } = record2.memory;
21002
+ notify("edit", [await persistence.put(memory, record2)]);
21003
+ return true;
21004
+ }),
21005
+ setTopics: async (memoryId, topics) => asStored(
21006
+ await mutate(memoryId, "edit", (memory) => ({
21007
+ ...memory,
21008
+ topics: serializeTopics(mergeTopics([], topicInputs(topics, "user"))),
21009
+ topics_user_managed: true,
21010
+ topics_updated_at: Date.now()
21011
+ }))
21012
+ ),
21013
+ addTopics: async (memoryId, topics) => {
21014
+ const added = topicInputs(topics, "auto");
21015
+ const saved = await mutate(memoryId, "edit", (memory) => ({
21016
+ ...memory,
21017
+ topics: serializeTopics(mergeTopics(parseTopics(memory.topics) ?? [], added)),
21018
+ topics_updated_at: Date.now()
21019
+ }));
21020
+ if (!saved) return [];
21021
+ const now = /* @__PURE__ */ new Date();
21022
+ return mergeTopics([], added).map(
21023
+ (topic) => ({
21024
+ uniqueId: normalizeEntityName(topic.name),
21025
+ canonicalName: normalizeEntityName(topic.name),
21026
+ kind: topic.kind ?? null,
21027
+ createdAt: now,
21028
+ updatedAt: now
21029
+ })
21030
+ );
21031
+ },
21032
+ setVisibility: async (id, visibility, visibilityOptions) => asStored(
21033
+ await mutate(id, "edit", (memory) => {
21034
+ memory.visibility = visibility;
21035
+ if (visibility === "private") delete memory.published_at;
21036
+ else memory.published_at ?? (memory.published_at = Date.now());
21037
+ if (visibilityOptions?.twinOptIn !== void 0)
21038
+ memory.twin_opt_in = visibilityOptions.twinOptIn;
21039
+ return memory;
21040
+ })
21041
+ ),
21042
+ recall: (query, recallOptions) => pipeline.recall(query, recallOptions),
21043
+ retain: async (content, retainOptions) => {
21044
+ const result = await pipeline.retain(content, retainOptions);
21045
+ if (result.action === "create" || result.action === "supersede") notify("membership");
21046
+ else if (result.action === "update" || result.action === "merge") notify("edit");
21047
+ return result;
21048
+ },
21049
+ subscribe: (onChange, subscribeOptions = {}) => {
21050
+ const subscriber = { onChange, options: subscribeOptions };
21051
+ subscribers.add(subscriber);
21052
+ if (pollIntervalMs > 0 && !timer) {
21053
+ timer = setInterval(poll, pollIntervalMs);
21054
+ poll();
21055
+ }
21056
+ return () => {
21057
+ subscribers.delete(subscriber);
21058
+ if (subscribers.size || !timer) return;
21059
+ clearInterval(timer);
21060
+ timer = void 0;
21061
+ generation++;
21062
+ seen.clear();
21063
+ ready = false;
21064
+ cursor = void 0;
21065
+ pending = /* @__PURE__ */ new Set();
21066
+ };
21067
+ }
21068
+ };
21069
+ }
21070
+
20469
21071
  // src/lib/memory/synthesizeProfile.ts
20470
21072
  init_internalFlowMarker();
20471
21073
  init_logger();
@@ -23891,7 +24493,7 @@ function useChat(options) {
23891
24493
 
23892
24494
  // src/expo/useChatStorage.ts
23893
24495
  var import_react5 = require("react");
23894
- var import_uuid6 = require("uuid");
24496
+ var import_uuid7 = require("uuid");
23895
24497
  init_clientConfig();
23896
24498
 
23897
24499
  // src/lib/chat/assembleMessages.ts
@@ -24554,9 +25156,9 @@ async function decryptMediaFields(media, address, signMessage, embeddedWalletSig
24554
25156
  }
24555
25157
 
24556
25158
  // src/lib/db/media/types.ts
24557
- var import_uuid5 = require("uuid");
25159
+ var import_uuid6 = require("uuid");
24558
25160
  function generateMediaId() {
24559
- return `media_${(0, import_uuid5.v7)()}`;
25161
+ return `media_${(0, import_uuid6.v7)()}`;
24560
25162
  }
24561
25163
 
24562
25164
  // src/lib/db/media/operations.ts
@@ -25516,7 +26118,7 @@ function useChatStorage(options) {
25516
26118
  };
25517
26119
  };
25518
26120
  pendingResumeRef.current = null;
25519
- const effectiveAssistantUniqueId = assistantUniqueId ?? (resumable ? `msg_${(0, import_uuid6.v7)()}` : void 0);
26121
+ const effectiveAssistantUniqueId = assistantUniqueId ?? (resumable ? `msg_${(0, import_uuid7.v7)()}` : void 0);
25520
26122
  const embedToolText = (text12, mask, masked, token) => {
25521
26123
  const opts = {
25522
26124
  getToken: token,
@@ -26034,7 +26636,7 @@ function useChatStorage(options) {
26034
26636
  const detachedResult = result;
26035
26637
  if (detachedResult.detached) {
26036
26638
  recordToolSetTurn(database, convId, matchedToolSets);
26037
- const rowId = effectiveAssistantUniqueId ?? `msg_${(0, import_uuid6.v7)()}`;
26639
+ const rowId = effectiveAssistantUniqueId ?? `msg_${(0, import_uuid7.v7)()}`;
26038
26640
  pendingResumeRef.current = {
26039
26641
  handle: detachedResult.resume ?? null,
26040
26642
  convId,
@@ -26546,6 +27148,7 @@ function useChatStorage(options) {
26546
27148
  MEDIUM_TTL_MS,
26547
27149
  MEMORY_KINDS,
26548
27150
  MEMORY_LEVELS,
27151
+ MemoryKeyError,
26549
27152
  MemoryLevelError,
26550
27153
  NEVER_TTL_MS,
26551
27154
  NODE_BUDGET,
@@ -26558,6 +27161,7 @@ function useChatStorage(options) {
26558
27161
  RECALL_MAX_LIMIT,
26559
27162
  RECALL_TOOL_NAME,
26560
27163
  RemoteMemoryError,
27164
+ RemoteMemoryPartialCreateError,
26561
27165
  RerankerUnavailableError,
26562
27166
  SDK_SCHEMA_VERSION,
26563
27167
  SHORT_TTL_MS,
@@ -26623,6 +27227,7 @@ function useChatStorage(options) {
26623
27227
  createRecallTool,
26624
27228
  createRemoteMemoryPersistence,
26625
27229
  createRemoteMemoryPipeline,
27230
+ createRemoteMemoryStore,
26626
27231
  createStockPricePreProcessor,
26627
27232
  createStreamingDeAnonymizer,
26628
27233
  createVaultEmbeddingCache,
@@ -26639,6 +27244,7 @@ function useChatStorage(options) {
26639
27244
  deleteVaultMemoryOp,
26640
27245
  dequantizeEmbedding,
26641
27246
  deriveKeyFromSignatureBytes,
27247
+ deriveMemoryKeyRing,
26642
27248
  discoverNotionOAuthEndpoints,
26643
27249
  eagerEmbedContent,
26644
27250
  embedAllMessages,
@@ -26682,6 +27288,7 @@ function useChatStorage(options) {
26682
27288
  isPiiRedactor,
26683
27289
  isRerankerAvailable,
26684
27290
  maskScopedEmbeddingCache,
27291
+ memoryCipher,
26685
27292
  moveMemoriesToFolderOp,
26686
27293
  noopLogger,
26687
27294
  onKeyAvailable,
@@ -26691,6 +27298,7 @@ function useChatStorage(options) {
26691
27298
  queueManager,
26692
27299
  rankProfileCandidates,
26693
27300
  recall,
27301
+ reencryptMemoryField,
26694
27302
  reflect,
26695
27303
  refreshEncryptionKeyIfMatches,
26696
27304
  refreshNotionAccessToken,