@anuma/sdk 7.0.3 → 7.0.4-next.20261015010856

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.
@@ -4456,8 +4456,9 @@ async function getConversationsByProjectOp(ctx, projectId) {
4456
4456
  )
4457
4457
  );
4458
4458
  }
4459
- async function getMessagesOp(ctx, convId) {
4460
- const results = await ctx.messagesCollection.query(import_watermelondb2.Q.where("conversation_id", convId), import_watermelondb2.Q.sortBy("message_id", import_watermelondb2.Q.asc)).unsafeFetchRaw();
4459
+ async function getMessagesOp(ctx, convId, opts) {
4460
+ const fetched = await ctx.messagesCollection.query(import_watermelondb2.Q.where("conversation_id", convId), import_watermelondb2.Q.sortBy("message_id", import_watermelondb2.Q.asc)).unsafeFetchRaw();
4461
+ const results = opts?.rawFilter ? fetched.filter(opts.rawFilter) : fetched;
4461
4462
  return Promise.all(
4462
4463
  results.map(
4463
4464
  (raw) => messageRawToStored(raw, ctx.walletAddress, ctx.signMessage, ctx.embeddedWalletSigner)
@@ -6708,6 +6709,37 @@ async function chunkAndEmbedMessage(ctx, messageId, options) {
6708
6709
  }));
6709
6710
  return updateMessageChunksOp(ctx, messageId, messageChunks, embeddingModel);
6710
6711
  }
6712
+ var MIN_SEALED_EMBEDDING_HEX = 256;
6713
+ function rawHasEmbedding(value) {
6714
+ if (Array.isArray(value)) return value.length > 0;
6715
+ if (typeof value !== "string" || value.length === 0) return false;
6716
+ if (isEncrypted(value)) {
6717
+ return value.length - value.indexOf(":", 4) - 1 >= MIN_SEALED_EMBEDDING_HEX;
6718
+ }
6719
+ try {
6720
+ const parsed = JSON.parse(value);
6721
+ return Array.isArray(parsed) && parsed.length > 0;
6722
+ } catch {
6723
+ return false;
6724
+ }
6725
+ }
6726
+ function sealedVersion(value) {
6727
+ if (typeof value !== "string" || !isEncrypted(value)) return null;
6728
+ return value.startsWith("enc:v2:") ? "v2" : "v3";
6729
+ }
6730
+ function mayNeedChunkEmbedding(raw, embeddingModel, filter) {
6731
+ const role = raw.role;
6732
+ if (role === "system") return false;
6733
+ if (filter?.roles && !filter.roles.includes(role ?? "")) return false;
6734
+ if (isNonEmbeddableOrigin(raw.origin, filter?.reembedDiscarded)) {
6735
+ return false;
6736
+ }
6737
+ const model = raw.embedding_model;
6738
+ if (typeof model === "string" && model !== embeddingModel) return true;
6739
+ if (rawHasEmbedding(raw.chunks)) return false;
6740
+ if (rawHasEmbedding(raw.vector) && !filter?.rechunkExisting) return false;
6741
+ return true;
6742
+ }
6711
6743
  async function chunkAndEmbedAllMessages(ctx, options, filter) {
6712
6744
  const embeddingModel = options.model ?? DEFAULT_API_EMBEDDING_MODEL;
6713
6745
  const { chunkSize = DEFAULT_CHUNK_SIZE } = options;
@@ -6720,11 +6752,31 @@ async function chunkAndEmbedAllMessages(ctx, options, filter) {
6720
6752
  let considered = 0;
6721
6753
  let sealedRowsSeen = 0;
6722
6754
  let rowsSeen = 0;
6755
+ const keptSealed = /* @__PURE__ */ new Map();
6756
+ const candidatesStillSealed = /* @__PURE__ */ new Map();
6757
+ const droppedSealed = /* @__PURE__ */ new Map();
6758
+ const rawFilter = (raw) => {
6759
+ rowsSeen++;
6760
+ const keep = mayNeedChunkEmbedding(raw, embeddingModel, filter);
6761
+ const version = sealedVersion(raw.content);
6762
+ if (!version) return keep;
6763
+ if (keep) {
6764
+ keptSealed.set(version, (keptSealed.get(version) ?? 0) + 1);
6765
+ } else {
6766
+ const dropped = droppedSealed.get(version);
6767
+ if (dropped) dropped.count++;
6768
+ else droppedSealed.set(version, { count: 1, probeId: raw.id });
6769
+ }
6770
+ return keep;
6771
+ };
6723
6772
  for (const conv of targetConversations) {
6724
- const messages = await getMessagesOp(ctx, conv.conversationId);
6773
+ const messages = await getMessagesOp(ctx, conv.conversationId, { rawFilter });
6725
6774
  for (const message of messages) {
6726
- rowsSeen++;
6727
- if (isEncrypted(message.content)) sealedRowsSeen++;
6775
+ const stillSealed = sealedVersion(message.content);
6776
+ if (stillSealed) {
6777
+ sealedRowsSeen++;
6778
+ candidatesStillSealed.set(stillSealed, (candidatesStillSealed.get(stillSealed) ?? 0) + 1);
6779
+ }
6728
6780
  const isStale = message.embeddingModel !== void 0 && message.embeddingModel !== null && message.embeddingModel !== embeddingModel;
6729
6781
  if (message.chunks && message.chunks.length > 0 && !isStale) continue;
6730
6782
  const hasVector = message.vector && message.vector.length > 0;
@@ -6737,6 +6789,7 @@ async function chunkAndEmbedAllMessages(ctx, options, filter) {
6737
6789
  stillEncrypted++;
6738
6790
  continue;
6739
6791
  }
6792
+ if (isToolResultsRow(message)) continue;
6740
6793
  if (message.content.length < minLength) continue;
6741
6794
  if (shouldChunkMessage(message.content, chunkSize)) {
6742
6795
  longMessages.push({
@@ -6748,6 +6801,12 @@ async function chunkAndEmbedAllMessages(ctx, options, filter) {
6748
6801
  }
6749
6802
  }
6750
6803
  }
6804
+ for (const [version, dropped] of droppedSealed) {
6805
+ const keyOpenedACandidate = (keptSealed.get(version) ?? 0) > (candidatesStillSealed.get(version) ?? 0);
6806
+ if (keyOpenedACandidate) continue;
6807
+ const probe = await getMessageOp(ctx, dropped.probeId);
6808
+ if (!probe || isEncrypted(probe.content)) sealedRowsSeen += dropped.count;
6809
+ }
6751
6810
  if (stillEncrypted > 0 || sealedRowsSeen > 0) {
6752
6811
  getLogger().error(
6753
6812
  "memoryEngine: messages still encrypted (key unavailable?) \u2014 excluded from embedding",
@@ -12209,6 +12268,11 @@ function parseTopics(value) {
12209
12268
  }
12210
12269
 
12211
12270
  // src/lib/db/entities/operations.ts
12271
+ async function assertCanWrite(ctx) {
12272
+ if (ctx.canWrite && !await ctx.canWrite()) {
12273
+ throw new Error("Memory source is no longer eligible");
12274
+ }
12275
+ }
12212
12276
  function entityToStored(e) {
12213
12277
  return {
12214
12278
  uniqueId: e.id,
@@ -12349,6 +12413,7 @@ async function linkMemoryEntitiesOp(ctx, memoryId, entityInputs, options) {
12349
12413
  let skipped = false;
12350
12414
  let entities = [];
12351
12415
  await ctx.database.write(async () => {
12416
+ await assertCanWrite(ctx);
12352
12417
  const {
12353
12418
  entities: byName,
12354
12419
  operations: entityOps,
@@ -12424,6 +12489,7 @@ async function replaceMemoryEntities(ctx, memoryId, entityInputs, options) {
12424
12489
  let skipped = false;
12425
12490
  let entities = [];
12426
12491
  await ctx.database.write(async () => {
12492
+ await assertCanWrite(ctx);
12427
12493
  const vaultRow = await findVaultRowInWrite(ctx, memoryId);
12428
12494
  if (options.guarded && autoLinkBlocked(vaultRow)) {
12429
12495
  skipped = true;
@@ -12484,6 +12550,7 @@ async function unlinkMemoryEntitiesOp(ctx, memoryIds) {
12484
12550
  const links = await ctx.memoryEntityCollection.query(import_watermelondb11.Q.where("memory_id", import_watermelondb11.Q.oneOf(Array.from(memoryIds)))).fetch();
12485
12551
  if (links.length === 0) return;
12486
12552
  await ctx.database.write(async () => {
12553
+ await assertCanWrite(ctx);
12487
12554
  await ctx.database.batch(...links.map((l) => l.prepareDestroyPermanently()));
12488
12555
  });
12489
12556
  }
@@ -12492,6 +12559,7 @@ async function unlinkAllMemoryEntitiesForUserOp(ctx, userId) {
12492
12559
  const links = await ctx.memoryEntityCollection.query(import_watermelondb11.Q.where("user_id", userId)).fetch();
12493
12560
  if (links.length === 0) return;
12494
12561
  await ctx.database.write(async () => {
12562
+ await assertCanWrite(ctx);
12495
12563
  await ctx.database.batch(...links.map((l) => l.prepareDestroyPermanently()));
12496
12564
  });
12497
12565
  }
@@ -12511,6 +12579,7 @@ async function backfillMemoryEntityUserIdsOp(ctx, vaultMemoryCollection) {
12511
12579
  }
12512
12580
  if (toUpdate.length === 0) return 0;
12513
12581
  await ctx.database.write(async () => {
12582
+ await assertCanWrite(ctx);
12514
12583
  await ctx.database.batch(
12515
12584
  ...toUpdate.map(({ link, userId }) => link.prepareUpdate((r) => r._setRaw("user_id", userId)))
12516
12585
  );
@@ -14904,6 +14973,11 @@ function visibilityConditions(requested) {
14904
14973
  function isKinded(record2) {
14905
14974
  return record2.kind !== null && record2.kind !== void 0;
14906
14975
  }
14976
+ async function assertCanWrite2(ctx) {
14977
+ if (ctx.canWrite && !await ctx.canWrite()) {
14978
+ throw new Error("Memory source is no longer eligible");
14979
+ }
14980
+ }
14907
14981
  function assertValidKindLevel(kind, level) {
14908
14982
  const hasKind = kind !== null && kind !== void 0;
14909
14983
  if (hasKind && !MEMORY_KINDS.includes(kind)) {
@@ -15084,8 +15158,7 @@ async function createVaultMemoryOp(ctx, opts) {
15084
15158
  ctx.embeddedWalletSigner
15085
15159
  ) : opts.content;
15086
15160
  const created = await ctx.database.write(async () => {
15087
- if (ctx.canWrite && !await ctx.canWrite())
15088
- throw new Error("Memory source is no longer eligible");
15161
+ await assertCanWrite2(ctx);
15089
15162
  return ctx.vaultMemoryCollection.create(
15090
15163
  (record2) => populateNewVaultMemory(record2, ctx, opts, encryptedContent, encryptedKindValue)
15091
15164
  );
@@ -15104,8 +15177,7 @@ async function createSupersedingMemoryOp(ctx, opts, targetId) {
15104
15177
  ) : opts.content;
15105
15178
  let createdRecord = null;
15106
15179
  await ctx.database.write(async () => {
15107
- if (ctx.canWrite && !await ctx.canWrite())
15108
- throw new Error("Memory source is no longer eligible");
15180
+ await assertCanWrite2(ctx);
15109
15181
  let target;
15110
15182
  try {
15111
15183
  target = await ctx.vaultMemoryCollection.find(targetId);
@@ -15197,8 +15269,7 @@ async function createVaultMemoriesBatchOp(ctx, optionsArray) {
15197
15269
  })
15198
15270
  );
15199
15271
  const created = await ctx.database.write(async () => {
15200
- if (ctx.canWrite && !await ctx.canWrite())
15201
- throw new Error("Memory source is no longer eligible");
15272
+ await assertCanWrite2(ctx);
15202
15273
  const prepared = optionsArray.map(
15203
15274
  (opts, i) => ctx.vaultMemoryCollection.prepareCreate(
15204
15275
  (record2) => populateNewVaultMemory(record2, ctx, opts, encryptedContents[i], encryptedKindValues[i])
@@ -15503,8 +15574,7 @@ async function updateVaultMemoryOp(ctx, id, opts) {
15503
15574
  const record2 = probe;
15504
15575
  const originalUpdatedAt = record2.updatedAt.getTime();
15505
15576
  await ctx.database.write(async () => {
15506
- if (ctx.canWrite && !await ctx.canWrite())
15507
- throw new Error("Memory source is no longer eligible");
15577
+ await assertCanWrite2(ctx);
15508
15578
  if (record2.isDeleted || record2.supersededBy || !isOwnedByCtxUser(ctx, record2) || opts.freeFormOnly && isKinded(record2)) {
15509
15579
  stale = true;
15510
15580
  return;
@@ -15615,6 +15685,7 @@ async function setMemoryEntitiesOp(ctx, memoryId, entities) {
15615
15685
  let stale = false;
15616
15686
  const originalUpdatedAt = record2.updatedAt.getTime();
15617
15687
  await ctx.database.write(async (writer) => {
15688
+ await assertCanWrite2(ctx);
15618
15689
  if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2)) {
15619
15690
  stale = true;
15620
15691
  return;
@@ -15656,6 +15727,7 @@ async function clearMemoryTopicsOverrideOp(ctx, memoryId, options) {
15656
15727
  const originalUpdatedAt = record2.updatedAt.getTime();
15657
15728
  let cleared = false;
15658
15729
  await ctx.database.write(async () => {
15730
+ await assertCanWrite2(ctx);
15659
15731
  if (options?.unlessTopicsRecorded && parseTopics(record2.topics) !== null) return;
15660
15732
  cleared = true;
15661
15733
  await record2.update((r) => {
@@ -15679,6 +15751,7 @@ async function setMemoryVisibilityOp(ctx, id, opts) {
15679
15751
  if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2)) return null;
15680
15752
  let stale = false;
15681
15753
  await ctx.database.write(async () => {
15754
+ await assertCanWrite2(ctx);
15682
15755
  if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2)) {
15683
15756
  stale = true;
15684
15757
  return;
@@ -15707,6 +15780,7 @@ async function deleteVaultMemoryOp(ctx, id) {
15707
15780
  if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2)) return false;
15708
15781
  let stale = false;
15709
15782
  await ctx.database.write(async () => {
15783
+ await assertCanWrite2(ctx);
15710
15784
  if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2)) {
15711
15785
  stale = true;
15712
15786
  return;
@@ -15744,8 +15818,7 @@ async function supersedeVaultMemoryOp(ctx, id, supersededById) {
15744
15818
  }
15745
15819
  let stale = false;
15746
15820
  await ctx.database.write(async () => {
15747
- if (ctx.canWrite && !await ctx.canWrite())
15748
- throw new Error("Memory source is no longer eligible");
15821
+ await assertCanWrite2(ctx);
15749
15822
  if (record2.isDeleted || record2.supersededBy || !isOwnedByCtxUser(ctx, record2)) {
15750
15823
  stale = true;
15751
15824
  return;
@@ -15907,6 +15980,7 @@ async function stampTopicsExtractedAtOp(ctx, memoryIds, extractedAt, version = T
15907
15980
  for (let i = 0; i < uniqueIds.length; i += CHUNK) {
15908
15981
  const chunkIds = uniqueIds.slice(i, i + CHUNK);
15909
15982
  await ctx.database.write(async () => {
15983
+ await assertCanWrite2(ctx);
15910
15984
  const records = [];
15911
15985
  for (const id of chunkIds) {
15912
15986
  try {
@@ -15940,6 +16014,7 @@ async function relinkMemoryTopicsOp(ctx, memoryIds) {
15940
16014
  for (const id of Array.from(new Set(memoryIds))) {
15941
16015
  try {
15942
16016
  await ctx.database.write(async (writer) => {
16017
+ await assertCanWrite2(ctx);
15943
16018
  let record2;
15944
16019
  try {
15945
16020
  record2 = await ctx.vaultMemoryCollection.find(id);
@@ -15970,6 +16045,7 @@ async function backfillMemoryTopicsOp(ctx, memoryIds) {
15970
16045
  for (let i = 0; i < uniqueIds.length; i += CHUNK) {
15971
16046
  const chunkIds = uniqueIds.slice(i, i + CHUNK);
15972
16047
  await ctx.database.write(async () => {
16048
+ await assertCanWrite2(ctx);
15973
16049
  const writes = [];
15974
16050
  for (const id of chunkIds) {
15975
16051
  let record2;
@@ -16002,6 +16078,7 @@ async function deleteAllVaultMemoriesForUserOp(ctx, userId) {
16002
16078
  const records = await ctx.vaultMemoryCollection.query(import_watermelondb23.Q.where("user_id", userId), import_watermelondb23.Q.where("is_deleted", false)).fetch();
16003
16079
  if (records.length === 0) return 0;
16004
16080
  await ctx.database.write(async () => {
16081
+ await assertCanWrite2(ctx);
16005
16082
  const prepared = records.map(
16006
16083
  (record2) => record2.prepareUpdate((r) => {
16007
16084
  r._setRaw("is_deleted", true);
@@ -16056,6 +16133,7 @@ async function archiveVaultMemoryOp(ctx, id, opts) {
16056
16133
  let stale = false;
16057
16134
  const archivedAtValue = opts?.now ?? Date.now();
16058
16135
  await ctx.database.write(async () => {
16136
+ await assertCanWrite2(ctx);
16059
16137
  if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2) || record2.archivedAt !== null) {
16060
16138
  stale = true;
16061
16139
  return;
@@ -16079,6 +16157,7 @@ async function restoreVaultMemoryOp(ctx, id) {
16079
16157
  if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2)) return false;
16080
16158
  let stale = false;
16081
16159
  await ctx.database.write(async () => {
16160
+ await assertCanWrite2(ctx);
16082
16161
  if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2)) {
16083
16162
  stale = true;
16084
16163
  return;
@@ -16099,6 +16178,7 @@ async function hardDeleteDecayedOp(ctx, id, opts) {
16099
16178
  const now = opts.now ?? Date.now();
16100
16179
  let stale = false;
16101
16180
  await ctx.database.write(async () => {
16181
+ await assertCanWrite2(ctx);
16102
16182
  const archivedAt = record2.archivedAt;
16103
16183
  if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2) || archivedAt === null || now - archivedAt <= opts.hardDeleteWindowMs) {
16104
16184
  stale = true;
@@ -16138,6 +16218,7 @@ async function updateVaultMemoryEmbeddingOp(ctx, id, embedding2, embeddingModel,
16138
16218
  }
16139
16219
  let written = false;
16140
16220
  await ctx.database.write(async () => {
16221
+ await assertCanWrite2(ctx);
16141
16222
  if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2)) return;
16142
16223
  const originalUpdatedAt = record2.updatedAt.getTime();
16143
16224
  if (originalUpdatedAt !== readUpdatedAt || record2._getRaw("content") !== readStoredContent)
@@ -20134,6 +20215,13 @@ function restoreCandidates(candidates, redactor, ownNames) {
20134
20215
  ).map((c) => c.candidate);
20135
20216
  }
20136
20217
  async function extractAndRetain(messages, retainCtx, options) {
20218
+ const { memoryStore, signal } = options;
20219
+ if (memoryStore === null) throw new Error("Memory store is not ready");
20220
+ if (memoryStore && options.folderId !== void 0 && options.folderId !== null)
20221
+ throw new Error("Remote memory extraction does not support folders");
20222
+ if (memoryStore && options.extract.piiRedaction && !memoryStore.masksEmbeddingInput)
20223
+ throw new Error("PII-redacted extraction requires a memory store that masks embedding inputs");
20224
+ signal?.throwIfAborted();
20137
20225
  const minConfidence = options.minConfidence ?? DEFAULT_MIN_CONFIDENCE;
20138
20226
  const resolvedConsolidatePii = options.consolidateOptions?.piiRedaction ?? options.extract.piiRedaction;
20139
20227
  const consolidateOptions = options.consolidateOptions !== void 0 ? {
@@ -20167,6 +20255,7 @@ async function extractAndRetain(messages, retainCtx, options) {
20167
20255
  }
20168
20256
  });
20169
20257
  const extractMs = Date.now() - tExtract;
20258
+ signal?.throwIfAborted();
20170
20259
  const filtered = candidates.filter((c) => c.confidence >= minConfidence);
20171
20260
  const log = getLogger();
20172
20261
  const screened = screenCandidatesForInjection(filtered);
@@ -20214,16 +20303,33 @@ async function extractAndRetain(messages, retainCtx, options) {
20214
20303
  const results = [];
20215
20304
  const quarantinedInfo = [];
20216
20305
  let failedWrites = 0;
20306
+ let auditRows;
20217
20307
  const tRetain = Date.now();
20218
20308
  for (const { candidate, isQuarantined, reason, signature } of toRetain) {
20219
20309
  try {
20310
+ signal?.throwIfAborted();
20220
20311
  if (isQuarantined) {
20221
- const existingId = await findQuarantinedDuplicateOp(
20222
- retainCtx.vaultCtx,
20223
- candidate.content,
20224
- candidate.sourceMessageIds,
20225
- { scope: options.scope ?? "private", folderId: options.folderId ?? null }
20226
- ).catch(() => null);
20312
+ let existingId;
20313
+ if (memoryStore) {
20314
+ auditRows ?? (auditRows = memoryStore.list({
20315
+ scopes: [options.scope ?? "private"],
20316
+ includeArchived: true,
20317
+ includeQuarantined: true,
20318
+ includeSuperseded: true
20319
+ }));
20320
+ const sourceKey = [...new Set(candidate.sourceMessageIds)].sort().join("\0");
20321
+ const normalize = (value) => value.normalize("NFKC").trim().replace(/\s+/g, " ").toLowerCase();
20322
+ existingId = (await auditRows).find(
20323
+ (row) => row.trustTier === "quarantined" && row.scope === (options.scope ?? "private") && [...new Set(row.sourceChunkIds ?? [])].sort().join("\0") === sourceKey && normalize(row.content) === normalize(candidate.content)
20324
+ )?.uniqueId ?? null;
20325
+ } else {
20326
+ existingId = await findQuarantinedDuplicateOp(
20327
+ retainCtx.vaultCtx,
20328
+ candidate.content,
20329
+ candidate.sourceMessageIds,
20330
+ { scope: options.scope ?? "private", folderId: options.folderId ?? null }
20331
+ ).catch(() => null);
20332
+ }
20227
20333
  if (existingId) {
20228
20334
  quarantinedInfo.push({
20229
20335
  candidate,
@@ -20234,18 +20340,26 @@ async function extractAndRetain(messages, retainCtx, options) {
20234
20340
  continue;
20235
20341
  }
20236
20342
  }
20237
- const result = await retain(candidate.content, retainCtx, {
20343
+ const retainOptions = {
20238
20344
  source: "auto-extracted",
20239
20345
  sourceChunkIds: candidate.sourceMessageIds,
20240
20346
  respectTombstones: true,
20241
20347
  ...options.scope !== void 0 && { scope: options.scope },
20242
- ...options.folderId !== void 0 && { folderId: options.folderId },
20243
20348
  ...consolidateOptions !== void 0 && { consolidateOptions },
20244
20349
  ...candidate.eventTime !== null && { eventTime: candidate.eventTime },
20245
20350
  factType: candidate.type,
20246
20351
  ...isQuarantined && { trustTier: "quarantined", enableAutoMerge: false }
20352
+ };
20353
+ const result = memoryStore ? await memoryStore.retain(candidate.content, {
20354
+ ...retainOptions,
20355
+ canWrite: retainCtx.vaultCtx.canWrite,
20356
+ signal
20357
+ }) : await retain(candidate.content, retainCtx, {
20358
+ ...retainOptions,
20359
+ ...options.folderId !== void 0 && { folderId: options.folderId }
20247
20360
  });
20248
20361
  if (isQuarantined) {
20362
+ auditRows = void 0;
20249
20363
  const info = {
20250
20364
  candidate,
20251
20365
  memoryId: result.memoryId,
@@ -20264,9 +20378,16 @@ async function extractAndRetain(messages, retainCtx, options) {
20264
20378
  }
20265
20379
  succeededCandidates.push(candidate);
20266
20380
  results.push(result);
20267
- if (result.action !== "suppressed" && options.entityCtx && candidate.entities.length > 0) {
20381
+ if (result.action !== "suppressed" && candidate.entities.length > 0) {
20268
20382
  try {
20269
- if (!await isMemoryTopicsUserManaged(options.entityCtx, result.memoryId)) {
20383
+ signal?.throwIfAborted();
20384
+ if (memoryStore) {
20385
+ await memoryStore.addTopics(result.memoryId, candidate.entities, {
20386
+ unlessUserManaged: true,
20387
+ canWrite: retainCtx.vaultCtx.canWrite,
20388
+ signal
20389
+ });
20390
+ } else if (options.entityCtx && !await isMemoryTopicsUserManaged(options.entityCtx, result.memoryId)) {
20270
20391
  await linkMemoryEntitiesOp(options.entityCtx, result.memoryId, candidate.entities, {
20271
20392
  unlessTopicsUserManaged: true
20272
20393
  });
@@ -20516,7 +20637,7 @@ function createAutoExtractor(options) {
20516
20637
  };
20517
20638
  const consolidateOptions = options.consolidate ? { ...options.consolidate, ...subPassAuth(options.consolidate.baseUrl) } : void 0;
20518
20639
  const injectionClassifierOptions = options.injectionClassifier ? { ...options.injectionClassifier, ...subPassAuth(options.injectionClassifier.baseUrl) } : void 0;
20519
- if (options.retainCtx.vaultCtx.entityCtx && !options.entityCtx) {
20640
+ if (!options.memoryStore && options.retainCtx.vaultCtx.entityCtx && !options.entityCtx) {
20520
20641
  getLogger().warn(
20521
20642
  "[memory/extract] retainCtx.vaultCtx.entityCtx is set but extractor was created without `entityCtx` \u2014 W5 graph lane will receive no writes"
20522
20643
  );
@@ -20561,6 +20682,8 @@ function createAutoExtractor(options) {
20561
20682
  try {
20562
20683
  const { candidates, results, failedCount, outcome: outcome2, failure, funnel, timings, model } = await extractAndRetain(window2, retainCtx, {
20563
20684
  extract,
20685
+ memoryStore: options.memoryStore,
20686
+ signal: options.signal,
20564
20687
  ...options.minConfidence !== void 0 && { minConfidence: options.minConfidence },
20565
20688
  ...options.entityCtx !== void 0 && { entityCtx: options.entityCtx },
20566
20689
  ...options.scope !== void 0 && { scope: options.scope },
@@ -22688,6 +22811,7 @@ function createLocalMemoryStore(options) {
22688
22811
  database,
22689
22812
  entityCollection: database.get("entity"),
22690
22813
  memoryEntityCollection: database.get("memory_entity"),
22814
+ canWrite: options.canWrite,
22691
22815
  ...userId !== void 0 && { userId },
22692
22816
  ...options.allowUnscopedRows !== void 0 && {
22693
22817
  allowUnscopedRows: options.allowUnscopedRows
@@ -22699,10 +22823,21 @@ function createLocalMemoryStore(options) {
22699
22823
  walletAddress: options.walletAddress,
22700
22824
  signMessage: options.signMessage,
22701
22825
  embeddedWalletSigner: options.embeddedWalletSigner,
22826
+ canWrite: options.canWrite,
22702
22827
  ...userId !== void 0 && { userId },
22703
22828
  ...options.singleTenant !== void 0 && { singleTenant: options.singleTenant },
22704
22829
  entityCtx
22705
22830
  };
22831
+ const assertWrite = async (writeOptions) => {
22832
+ writeOptions?.signal?.throwIfAborted();
22833
+ if (writeOptions?.canWrite && !await writeOptions.canWrite()) {
22834
+ throw new Error("Memory source is no longer eligible");
22835
+ }
22836
+ if (options.canWrite && !await options.canWrite()) {
22837
+ throw new Error("Memory source is no longer eligible");
22838
+ }
22839
+ writeOptions?.signal?.throwIfAborted();
22840
+ };
22706
22841
  const vaultCache = options.vaultCache ?? createVaultEmbeddingCache();
22707
22842
  const ownedBy = userId !== void 0 ? [import_watermelondb32.Q.where("user_id", userId)] : [];
22708
22843
  const linksOwnedBy = userId === void 0 ? [] : options.allowUnscopedRows ? [import_watermelondb32.Q.or(import_watermelondb32.Q.where("user_id", userId), import_watermelondb32.Q.where("user_id", null))] : [import_watermelondb32.Q.where("user_id", userId)];
@@ -22814,9 +22949,25 @@ function createLocalMemoryStore(options) {
22814
22949
  archive: (id) => archiveVaultMemoryOp(vaultCtx, id),
22815
22950
  restore: (id) => restoreVaultMemoryOp(vaultCtx, id),
22816
22951
  setTopics: (memoryId, topics) => setMemoryEntitiesOp(vaultCtx, memoryId, topics),
22817
- addTopics: (memoryId, topics) => database.write(async (writer) => {
22952
+ addTopics: (memoryId, topics, writeOptions) => database.write(async (writer) => {
22953
+ await assertWrite(writeOptions);
22818
22954
  const owned = await vaultCtx.vaultMemoryCollection.query(import_watermelondb32.Q.where("id", memoryId), import_watermelondb32.Q.where("is_deleted", false), ...ownedBy).fetchCount();
22819
- return owned > 0 ? writer.callWriter(() => linkMemoryEntitiesOp(entityCtx, memoryId, topics)) : [];
22955
+ return owned > 0 ? writer.callWriter(
22956
+ () => linkMemoryEntitiesOp(
22957
+ {
22958
+ ...entityCtx,
22959
+ canWrite: async () => {
22960
+ await assertWrite(writeOptions);
22961
+ return true;
22962
+ }
22963
+ },
22964
+ memoryId,
22965
+ topics,
22966
+ {
22967
+ unlessTopicsUserManaged: writeOptions?.unlessUserManaged
22968
+ }
22969
+ )
22970
+ ) : [];
22820
22971
  }),
22821
22972
  setVisibility: (id, visibility, visibilityOptions) => setMemoryVisibilityOp(vaultCtx, id, { visibility, ...visibilityOptions }),
22822
22973
  recall: (query, recallOptions) => recall(
@@ -22826,7 +22977,17 @@ function createLocalMemoryStore(options) {
22826
22977
  ),
22827
22978
  retain: (content, retainOptions) => retain(
22828
22979
  content,
22829
- { vaultCtx, embeddingOptions: options.embeddingOptions, vaultCache },
22980
+ {
22981
+ vaultCtx: {
22982
+ ...vaultCtx,
22983
+ canWrite: async () => {
22984
+ await assertWrite(retainOptions);
22985
+ return true;
22986
+ }
22987
+ },
22988
+ embeddingOptions: options.embeddingOptions,
22989
+ vaultCache
22990
+ },
22830
22991
  retainOptions
22831
22992
  ),
22832
22993
  factSource: {
@@ -23465,7 +23626,14 @@ function stored(row) {
23465
23626
  function createRemoteMemoryPipeline(options) {
23466
23627
  const { persistence, embeddingOptions } = options;
23467
23628
  const model = embeddingOptions.model ?? DEFAULT_API_EMBEDDING_MODEL;
23468
- const operation = (mode) => {
23629
+ const operation = (mode, writeOptions) => {
23630
+ const signal = writeOptions?.signal;
23631
+ const assertWrite = async () => {
23632
+ signal?.throwIfAborted();
23633
+ if (writeOptions?.canWrite && !await writeOptions.canWrite())
23634
+ throw new Error("Memory source is no longer eligible");
23635
+ signal?.throwIfAborted();
23636
+ };
23469
23637
  const rejectUndecryptable = (failed) => {
23470
23638
  if (!failed.length) return;
23471
23639
  if (mode === "retain")
@@ -23483,7 +23651,7 @@ function createRemoteMemoryPipeline(options) {
23483
23651
  return items.map((item) => stored(item.memory));
23484
23652
  };
23485
23653
  const get = async (id) => {
23486
- const snapshot = snapshots.get(id) ?? await persistence.get(id);
23654
+ const snapshot = snapshots.get(id) ?? await (signal ? persistence.get(id, signal) : persistence.get(id));
23487
23655
  if (!snapshot || snapshot.memory.is_deleted || snapshot.memory.superseded_by) return null;
23488
23656
  snapshots.set(id, snapshot);
23489
23657
  return stored(snapshot.memory);
@@ -23529,7 +23697,7 @@ function createRemoteMemoryPipeline(options) {
23529
23697
  if (forced.size < 100 && temporal[i] !== void 0) forced.add(temporal[i]);
23530
23698
  }
23531
23699
  const forceIds = [...forced];
23532
- const windowOptions = (i, signal) => ({
23700
+ const windowOptions = (i, signal2) => ({
23533
23701
  limit: Math.min(100, Math.max((search.limit ?? 8) * 3, 30)),
23534
23702
  force_ids: i === 0 ? forceIds : [],
23535
23703
  ...search.scopes && { scopes: search.scopes },
@@ -23537,13 +23705,15 @@ function createRemoteMemoryPipeline(options) {
23537
23705
  ...search.memoryIds !== void 0 && { memory_ids: search.memoryIds },
23538
23706
  include_archived: search.includeArchived,
23539
23707
  embedding_model: model,
23540
- ...signal && { signal }
23708
+ ...signal2 && { signal: signal2 }
23541
23709
  });
23542
23710
  const vectors = [queryEmbedding, ...facetEmbeddings];
23543
23711
  let windows;
23544
23712
  if (mode === "retain") {
23545
23713
  windows = await Promise.all(
23546
- vectors.map((embedding2, i) => persistence.candidateSet(embedding2, windowOptions(i)))
23714
+ vectors.map(
23715
+ (embedding2, i) => persistence.candidateSet(embedding2, windowOptions(i, signal))
23716
+ )
23547
23717
  );
23548
23718
  } else {
23549
23719
  const deadline = new AbortController();
@@ -23631,12 +23801,15 @@ function createRemoteMemoryPipeline(options) {
23631
23801
  twin_opt_in: false
23632
23802
  };
23633
23803
  };
23634
- const write = async (memory, snapshot) => remember([await persistence.put(memory, snapshot)])[0];
23804
+ const write = async (memory, snapshot) => {
23805
+ await assertWrite();
23806
+ return remember([await persistence.put(memory, snapshot, signal)])[0];
23807
+ };
23635
23808
  const port = {
23636
23809
  prepare,
23637
23810
  get,
23638
23811
  getFresh: async (id) => {
23639
- const current = await persistence.get(id);
23812
+ const current = await (signal ? persistence.get(id, signal) : persistence.get(id));
23640
23813
  return current && !current.memory.is_deleted && !current.memory.superseded_by ? stored(current.memory) : null;
23641
23814
  },
23642
23815
  tombstones: async (embedding2, embeddingModel, scope, folderId) => {
@@ -23647,7 +23820,8 @@ function createRemoteMemoryPipeline(options) {
23647
23820
  embedding_model: embeddingModel,
23648
23821
  strict_model: true,
23649
23822
  include_deleted: true,
23650
- deleted_only: true
23823
+ deleted_only: true,
23824
+ signal
23651
23825
  });
23652
23826
  rejectUndecryptable(window2.failed);
23653
23827
  return remember(window2.items);
@@ -23703,14 +23877,18 @@ function createRemoteMemoryPipeline(options) {
23703
23877
  if (!target || !newer || id === successor) return false;
23704
23878
  const old = snapshots.get(id);
23705
23879
  const next = snapshots.get(successor);
23880
+ await assertWrite();
23706
23881
  remember(
23707
- await persistence.putMany([
23708
- {
23709
- memory: { ...old.memory, superseded_by: successor, superseded_at: Date.now() },
23710
- expectedVersion: old
23711
- },
23712
- { memory: next.memory, expectedVersion: next }
23713
- ])
23882
+ await persistence.putMany(
23883
+ [
23884
+ {
23885
+ memory: { ...old.memory, superseded_by: successor, superseded_at: Date.now() },
23886
+ expectedVersion: old
23887
+ },
23888
+ { memory: next.memory, expectedVersion: next }
23889
+ ],
23890
+ signal
23891
+ )
23714
23892
  );
23715
23893
  return true;
23716
23894
  },
@@ -23719,18 +23897,22 @@ function createRemoteMemoryPipeline(options) {
23719
23897
  if (!target) return { created: null, retired: false };
23720
23898
  const snapshot = snapshots.get(targetId);
23721
23899
  const successor = createRow(input);
23900
+ await assertWrite();
23722
23901
  const rows = remember(
23723
- await persistence.putMany([
23724
- { memory: successor, expectedVersion: 0 },
23725
- {
23726
- memory: {
23727
- ...snapshot.memory,
23728
- superseded_by: successor.memory_id,
23729
- superseded_at: Date.now()
23730
- },
23731
- expectedVersion: snapshot
23732
- }
23733
- ])
23902
+ await persistence.putMany(
23903
+ [
23904
+ { memory: successor, expectedVersion: 0 },
23905
+ {
23906
+ memory: {
23907
+ ...snapshot.memory,
23908
+ superseded_by: successor.memory_id,
23909
+ superseded_at: Date.now()
23910
+ },
23911
+ expectedVersion: snapshot
23912
+ }
23913
+ ],
23914
+ signal
23915
+ )
23734
23916
  );
23735
23917
  return { created: rows[0], retired: true };
23736
23918
  }
@@ -23763,7 +23945,7 @@ function createRemoteMemoryPipeline(options) {
23763
23945
  factSource,
23764
23946
  recall: async (query, recallOptions = {}) => recall(query, { embeddingOptions, factSource }, { ...recallOptions, types: ["fact"] }),
23765
23947
  retain: async (content, retainOptions) => {
23766
- const { port } = operation("retain");
23948
+ const { port } = operation("retain", retainOptions);
23767
23949
  return retainWithPersistence(
23768
23950
  content,
23769
23951
  {
@@ -24346,16 +24528,21 @@ function createRemoteMemoryStore(options) {
24346
24528
  const record2 = await persistence.get(id);
24347
24529
  return record2 && !record2.memory.is_deleted ? record2 : null;
24348
24530
  };
24349
- const mutateLocked = async (id, change, edit) => {
24350
- const record2 = await live(id);
24531
+ const mutateLocked = async (id, change, edit, writeOptions) => {
24532
+ writeOptions?.signal?.throwIfAborted();
24533
+ const record2 = writeOptions?.signal ? await persistence.get(id, writeOptions.signal) : await live(id);
24351
24534
  if (!record2) return null;
24535
+ if (record2.memory.is_deleted) return null;
24536
+ if (writeOptions?.canWrite && !await writeOptions.canWrite())
24537
+ throw new Error("Memory source is no longer eligible");
24538
+ writeOptions?.signal?.throwIfAborted();
24352
24539
  const next = edit(structuredClone(record2.memory));
24353
24540
  if (!next) return null;
24354
- const saved = await persistence.put(next, record2);
24541
+ const saved = writeOptions?.signal ? await persistence.put(next, record2, writeOptions.signal) : await persistence.put(next, record2);
24355
24542
  notify(typeof change === "function" ? change(record2.memory) : change, [saved]);
24356
24543
  return saved;
24357
24544
  };
24358
- const mutate = (id, change, edit) => serialized(id, () => mutateLocked(id, change, edit));
24545
+ const mutate = (id, change, edit, writeOptions) => serialized(id, () => mutateLocked(id, change, edit, writeOptions));
24359
24546
  const serializedAll = (ids, task) => [...new Set(ids)].sort().reduceRight((inner, id) => () => serialized(id, inner), task)();
24360
24547
  const mutateMany = async (ids, change, edit) => {
24361
24548
  const saved = /* @__PURE__ */ new Map();
@@ -24868,13 +25055,21 @@ function createRemoteMemoryStore(options) {
24868
25055
  }))
24869
25056
  );
24870
25057
  },
24871
- addTopics: async (memoryId, topics) => {
25058
+ addTopics: async (memoryId, topics, writeOptions) => {
24872
25059
  const added = await withKnownKinds(topicInputs(topics, "auto"));
24873
- const saved = await mutate(memoryId, "edit", (memory) => ({
24874
- ...memory,
24875
- topics: serializeTopics(mergeTopics(parseTopics(memory.topics) ?? [], added)),
24876
- topics_updated_at: Date.now()
24877
- }));
25060
+ const saved = await mutate(
25061
+ memoryId,
25062
+ "edit",
25063
+ (memory) => {
25064
+ if (writeOptions?.unlessUserManaged && memory.topics_user_managed) return null;
25065
+ return {
25066
+ ...memory,
25067
+ topics: serializeTopics(mergeTopics(parseTopics(memory.topics) ?? [], added)),
25068
+ topics_updated_at: Date.now()
25069
+ };
25070
+ },
25071
+ writeOptions
25072
+ );
24878
25073
  if (!saved) return [];
24879
25074
  const now = /* @__PURE__ */ new Date();
24880
25075
  return mergeTopics([], added).map(
@@ -25727,6 +25922,7 @@ function createDurableAutoExtractor(options) {
25727
25922
  };
25728
25923
  const folderId = options.folderId ?? null;
25729
25924
  let disposed = false;
25925
+ let activeBatch = null;
25730
25926
  let running = false;
25731
25927
  let wakeRequested = false;
25732
25928
  let timer;
@@ -25763,14 +25959,18 @@ function createDurableAutoExtractor(options) {
25763
25959
  }, delay);
25764
25960
  }
25765
25961
  async function extractBatch(messages, conversationId, ids, jobScope, jobFolderId) {
25962
+ if (disposed) throw new Error("Extraction session was disposed");
25766
25963
  let watchdog;
25767
25964
  let cancelled = false;
25965
+ const controller = new AbortController();
25966
+ activeBatch = controller;
25768
25967
  const model = options.modelForScope?.(jobScope) ?? options.extract.model;
25769
25968
  try {
25770
25969
  return await Promise.race([
25771
25970
  new Promise((resolve, reject) => {
25772
25971
  const worker = createAutoExtractor({
25773
25972
  ...options,
25973
+ signal: controller.signal,
25774
25974
  retainCtx: {
25775
25975
  ...options.retainCtx,
25776
25976
  vaultCtx: {
@@ -25799,6 +25999,8 @@ function createDurableAutoExtractor(options) {
25799
25999
  ]);
25800
26000
  } finally {
25801
26001
  cancelled = true;
26002
+ controller.abort();
26003
+ if (activeBatch === controller) activeBatch = null;
25802
26004
  if (watchdog !== void 0) clearTimeout(watchdog);
25803
26005
  }
25804
26006
  }
@@ -25810,6 +26012,7 @@ function createDurableAutoExtractor(options) {
25810
26012
  for (const message of loaded)
25811
26013
  if (message && message.messageId > 0) sequences.set(message.uniqueId, message.messageId);
25812
26014
  await database.write(async () => {
26015
+ if (disposed) return;
25813
26016
  const current = idsOf(job);
25814
26017
  const acknowledged = ids.filter((id) => current.includes(id));
25815
26018
  if (!acknowledged.length) return;
@@ -25982,6 +26185,7 @@ function createDurableAutoExtractor(options) {
25982
26185
  jobScope,
25983
26186
  jobFolderId
25984
26187
  );
26188
+ if (disposed) throw new Error("Extraction session was disposed");
25985
26189
  options.onTurnComplete?.(result);
25986
26190
  return result;
25987
26191
  };
@@ -26018,6 +26222,7 @@ function createDurableAutoExtractor(options) {
26018
26222
  );
26019
26223
  scheduleAfterSuccess = true;
26020
26224
  } catch (error) {
26225
+ if (disposed) break;
26021
26226
  attempts.set(job.id, attempted + 1);
26022
26227
  retry = true;
26023
26228
  reportError(error, conversationId);
@@ -26040,6 +26245,14 @@ function createDurableAutoExtractor(options) {
26040
26245
  schedule(retry ? options.retryDelayMs ?? 3e4 : 0);
26041
26246
  }
26042
26247
  }
26248
+ function dispose() {
26249
+ disposed = true;
26250
+ activeBatch?.abort(options.signal?.reason);
26251
+ if (timer !== void 0) clearTimeout(timer);
26252
+ options.signal?.removeEventListener("abort", dispose);
26253
+ }
26254
+ if (options.signal?.aborted) dispose();
26255
+ else options.signal?.addEventListener("abort", dispose, { once: true });
26043
26256
  schedule(0);
26044
26257
  return {
26045
26258
  processTurn(messages, conversationId) {
@@ -26119,10 +26332,7 @@ function createDurableAutoExtractor(options) {
26119
26332
  return true;
26120
26333
  },
26121
26334
  isProcessing: () => running,
26122
- dispose() {
26123
- disposed = true;
26124
- if (timer !== void 0) clearTimeout(timer);
26125
- }
26335
+ dispose
26126
26336
  };
26127
26337
  }
26128
26338
 
@@ -32392,6 +32602,7 @@ var CONVERSATION_REDACTOR_LIMIT = 50;
32392
32602
  var NO_CONVERSATION_KEY = "__no_conversation__";
32393
32603
  var NO_STORE_FOLDERS = "Folders are not supported with a memoryStore";
32394
32604
  var NO_STORE_MASK = "piiRedaction needs a memoryStore built with embeddingOptions.maskInput";
32605
+ var MEMORY_STORE_NOT_READY = "Memory store is not ready";
32395
32606
  var conversationRedactors = /* @__PURE__ */ new Map();
32396
32607
  function getConversationRedactor(conversationId, nerDetector) {
32397
32608
  const key = conversationId ?? NO_CONVERSATION_KEY;
@@ -32482,7 +32693,7 @@ function useChatStorage(options) {
32482
32693
  () => ({ getToken, baseUrl, model: embeddingModel, maskInput: maskEmbeddingInput }),
32483
32694
  [getToken, baseUrl, embeddingModel, maskEmbeddingInput]
32484
32695
  );
32485
- const storeMaskMissing = memoryStore !== void 0 && maskEmbeddingInput !== void 0 && !memoryStore.masksEmbeddingInput;
32696
+ const storeMaskMissing = memoryStore !== void 0 && memoryStore !== null && maskEmbeddingInput !== void 0 && !memoryStore.masksEmbeddingInput;
32486
32697
  const blobManagerRef = (0, import_react6.useRef)(new BlobUrlManager());
32487
32698
  (0, import_react6.useEffect)(() => {
32488
32699
  const manager = blobManagerRef.current;
@@ -32759,6 +32970,7 @@ function useChatStorage(options) {
32759
32970
  );
32760
32971
  const retainVaultMemory = (0, import_react6.useCallback)(
32761
32972
  async (input) => {
32973
+ if (memoryStore === null) throw new Error(MEMORY_STORE_NOT_READY);
32762
32974
  if (memoryStore) {
32763
32975
  if (storeMaskMissing) throw new Error(NO_STORE_MASK);
32764
32976
  if (input.folderId !== void 0) throw new Error(NO_STORE_FOLDERS);
@@ -32790,6 +33002,7 @@ function useChatStorage(options) {
32790
33002
  );
32791
33003
  const createMemoryVaultTool2 = (0, import_react6.useCallback)(
32792
33004
  (options2) => {
33005
+ if (memoryStore === null) throw new Error(MEMORY_STORE_NOT_READY);
32793
33006
  if (storeMaskMissing) throw new Error(NO_STORE_MASK);
32794
33007
  const embOpts = getToken ? vaultEmbeddingOptions : void 0;
32795
33008
  return createMemoryVaultTool(
@@ -32811,6 +33024,7 @@ function useChatStorage(options) {
32811
33024
  );
32812
33025
  const getVaultMemories = (0, import_react6.useCallback)(
32813
33026
  (options2) => {
33027
+ if (memoryStore === null) return Promise.resolve([]);
32814
33028
  if (!memoryStore) return getAllVaultMemoriesOp(vaultCtx, options2);
32815
33029
  const { folderId, levels, kinds, ...listOptions } = options2 ?? {};
32816
33030
  if (folderId !== void 0) throw new Error(NO_STORE_FOLDERS);
@@ -32822,6 +33036,7 @@ function useChatStorage(options) {
32822
33036
  );
32823
33037
  const createVaultMemory = (0, import_react6.useCallback)(
32824
33038
  async (content, scope) => {
33039
+ if (memoryStore === null) throw new Error(MEMORY_STORE_NOT_READY);
32825
33040
  if (storeMaskMissing) throw new Error(NO_STORE_MASK);
32826
33041
  if (memoryStore) return memoryStore.create({ content, scope });
32827
33042
  const result = await createVaultMemoryOp(vaultCtx, { content, scope });
@@ -32843,6 +33058,7 @@ function useChatStorage(options) {
32843
33058
  );
32844
33059
  const updateVaultMemory = (0, import_react6.useCallback)(
32845
33060
  async (id, content, scope) => {
33061
+ if (memoryStore === null) throw new Error(MEMORY_STORE_NOT_READY);
32846
33062
  if (storeMaskMissing) throw new Error(NO_STORE_MASK);
32847
33063
  if (memoryStore) return memoryStore.update(id, { content, scope });
32848
33064
  const existing = await getVaultMemoryOp(vaultCtx, id);
@@ -32868,6 +33084,7 @@ function useChatStorage(options) {
32868
33084
  );
32869
33085
  const deleteVaultMemory = (0, import_react6.useCallback)(
32870
33086
  async (id) => {
33087
+ if (memoryStore === null) throw new Error(MEMORY_STORE_NOT_READY);
32871
33088
  if (memoryStore) return memoryStore.delete(id);
32872
33089
  const existing = await getVaultMemoryOp(vaultCtx, id);
32873
33090
  const result = await deleteVaultMemoryOp(vaultCtx, id);
@@ -32881,7 +33098,7 @@ function useChatStorage(options) {
32881
33098
  const chunkVectorCacheRef = (0, import_react6.useRef)(createChunkVectorCache());
32882
33099
  const clientToolEmbeddingsCacheRef = (0, import_react6.useRef)(/* @__PURE__ */ new Map());
32883
33100
  (0, import_react6.useEffect)(() => {
32884
- if (!getToken || memoryStore) return;
33101
+ if (!getToken || memoryStore !== void 0) return;
32885
33102
  void (async () => {
32886
33103
  try {
32887
33104
  await preEmbedVaultMemories(vaultCtx, vaultEmbeddingOptions, vaultEmbeddingCache);
@@ -32897,6 +33114,7 @@ function useChatStorage(options) {
32897
33114
  }, [vaultEmbeddingCache]);
32898
33115
  const createMemoryVaultSearchTool2 = (0, import_react6.useCallback)(
32899
33116
  (searchOptions) => {
33117
+ if (memoryStore === null) throw new Error(MEMORY_STORE_NOT_READY);
32900
33118
  if (!getToken && !memoryStore) {
32901
33119
  throw new Error("getToken is required for memory vault search tool");
32902
33120
  }
@@ -32912,6 +33130,7 @@ function useChatStorage(options) {
32912
33130
  );
32913
33131
  const createRecallTool2 = (0, import_react6.useCallback)(
32914
33132
  (toolOptions, callbacks) => {
33133
+ if (memoryStore === null) throw new Error(MEMORY_STORE_NOT_READY);
32915
33134
  if (!getToken && !memoryStore) {
32916
33135
  throw new Error("getToken is required for recall tool");
32917
33136
  }
@@ -32951,6 +33170,7 @@ function useChatStorage(options) {
32951
33170
  );
32952
33171
  const searchVaultMemoriesFn = (0, import_react6.useCallback)(
32953
33172
  async (query, searchOptions) => {
33173
+ if (memoryStore === null) return [];
32954
33174
  if (storeMaskMissing) throw new Error(NO_STORE_MASK);
32955
33175
  if (memoryStore) return (await memoryStore.factSource.search(query, searchOptions)).results;
32956
33176
  if (!getToken) return [];
@@ -32966,7 +33186,7 @@ function useChatStorage(options) {
32966
33186
  );
32967
33187
  const recallFn = (0, import_react6.useCallback)(
32968
33188
  async (query, options2) => {
32969
- if (!getToken && !memoryStore) {
33189
+ if (memoryStore === null || !getToken && !memoryStore) {
32970
33190
  return {
32971
33191
  memories: [],
32972
33192
  usedBudget: options2?.budget ?? "low",