@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.
@@ -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
  }
@@ -18069,6 +18069,65 @@ function createLocalMemoryStore(options) {
18069
18069
  };
18070
18070
  }
18071
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
+
18072
18131
  // src/lib/memory/store/remotePersistence.ts
18073
18132
  var RemoteMemoryError = class extends Error {
18074
18133
  constructor(message, status, code) {
@@ -18121,6 +18180,30 @@ var candidateListLimits = [
18121
18180
  ["memory_ids", 1e3],
18122
18181
  ["force_ids", 100]
18123
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
+ ];
18124
18207
  function record(value) {
18125
18208
  return typeof value === "object" && value !== null && !Array.isArray(value);
18126
18209
  }
@@ -18455,6 +18538,35 @@ async function createRemoteMemoryPersistence(options) {
18455
18538
  throw new Error("Invalid nearby batch response");
18456
18539
  return Promise.all(result.items.map((item, i) => decodeCommitted(item, prepared[i])));
18457
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
+ },
18458
18570
  candidateSet,
18459
18571
  candidates: async (embedding, candidateOptions = {}) => decodeAll((await fetchCandidates(embedding, candidateOptions, false)).items)
18460
18572
  };
@@ -18843,6 +18955,489 @@ function createRemoteMemoryPipeline(options) {
18843
18955
  };
18844
18956
  }
18845
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
+
18846
19441
  // src/lib/memory/synthesizeProfile.ts
18847
19442
  var DEFAULT_SYNTHESIS_MODEL = "inclusionai/ling-2.6-flash";
18848
19443
  var DEFAULT_FACET_RECALL_LIMIT = 20;
@@ -22253,7 +22848,7 @@ function useChat(options) {
22253
22848
 
22254
22849
  // src/expo/useChatStorage.ts
22255
22850
  import { useCallback as useCallback4, useEffect as useEffect4, useMemo, useRef as useRef4, useState as useState4 } from "react";
22256
- import { v7 as uuidv76 } from "uuid";
22851
+ import { v7 as uuidv77 } from "uuid";
22257
22852
 
22258
22853
  // src/lib/chat/assembleMessages.ts
22259
22854
  function assembleMessagesWithHistory(historyMessages, callerMessages, summarySystemMessage) {
@@ -22910,9 +23505,9 @@ async function decryptMediaFields(media, address, signMessage, embeddedWalletSig
22910
23505
  }
22911
23506
 
22912
23507
  // src/lib/db/media/types.ts
22913
- import { v7 as uuidv75 } from "uuid";
23508
+ import { v7 as uuidv76 } from "uuid";
22914
23509
  function generateMediaId() {
22915
- return `media_${uuidv75()}`;
23510
+ return `media_${uuidv76()}`;
22916
23511
  }
22917
23512
 
22918
23513
  // src/lib/db/media/operations.ts
@@ -23868,7 +24463,7 @@ function useChatStorage(options) {
23868
24463
  };
23869
24464
  };
23870
24465
  pendingResumeRef.current = null;
23871
- const effectiveAssistantUniqueId = assistantUniqueId ?? (resumable ? `msg_${uuidv76()}` : void 0);
24466
+ const effectiveAssistantUniqueId = assistantUniqueId ?? (resumable ? `msg_${uuidv77()}` : void 0);
23872
24467
  const embedToolText = (text12, mask, masked, token) => {
23873
24468
  const opts = {
23874
24469
  getToken: token,
@@ -24386,7 +24981,7 @@ function useChatStorage(options) {
24386
24981
  const detachedResult = result;
24387
24982
  if (detachedResult.detached) {
24388
24983
  recordToolSetTurn(database, convId, matchedToolSets);
24389
- const rowId = effectiveAssistantUniqueId ?? `msg_${uuidv76()}`;
24984
+ const rowId = effectiveAssistantUniqueId ?? `msg_${uuidv77()}`;
24390
24985
  pendingResumeRef.current = {
24391
24986
  handle: detachedResult.resume ?? null,
24392
24987
  convId,
@@ -24897,6 +25492,7 @@ export {
24897
25492
  MEDIUM_TTL_MS,
24898
25493
  MEMORY_KINDS,
24899
25494
  MEMORY_LEVELS,
25495
+ MemoryKeyError,
24900
25496
  MemoryLevelError,
24901
25497
  NEVER_TTL_MS,
24902
25498
  NODE_BUDGET,
@@ -24909,6 +25505,7 @@ export {
24909
25505
  RECALL_MAX_LIMIT,
24910
25506
  RECALL_TOOL_NAME,
24911
25507
  RemoteMemoryError,
25508
+ RemoteMemoryPartialCreateError,
24912
25509
  RerankerUnavailableError,
24913
25510
  SDK_SCHEMA_VERSION,
24914
25511
  SHORT_TTL_MS,
@@ -24974,6 +25571,7 @@ export {
24974
25571
  createRecallTool,
24975
25572
  createRemoteMemoryPersistence,
24976
25573
  createRemoteMemoryPipeline,
25574
+ createRemoteMemoryStore,
24977
25575
  createStockPricePreProcessor,
24978
25576
  createStreamingDeAnonymizer,
24979
25577
  createVaultEmbeddingCache,
@@ -24990,6 +25588,7 @@ export {
24990
25588
  deleteVaultMemoryOp,
24991
25589
  dequantizeEmbedding,
24992
25590
  deriveKeyFromSignatureBytes,
25591
+ deriveMemoryKeyRing,
24993
25592
  discoverNotionOAuthEndpoints,
24994
25593
  eagerEmbedContent,
24995
25594
  embedAllMessages,
@@ -25033,6 +25632,7 @@ export {
25033
25632
  isPiiRedactor,
25034
25633
  isRerankerAvailable,
25035
25634
  maskScopedEmbeddingCache,
25635
+ memoryCipher,
25036
25636
  moveMemoriesToFolderOp,
25037
25637
  noopLogger,
25038
25638
  onKeyAvailable,
@@ -25042,6 +25642,7 @@ export {
25042
25642
  queueManager,
25043
25643
  rankProfileCandidates,
25044
25644
  recall,
25645
+ reencryptMemoryField,
25045
25646
  reflect,
25046
25647
  refreshEncryptionKeyIfMatches,
25047
25648
  refreshNotionAccessToken,