@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.
@@ -2681,8 +2681,9 @@ async function getConversationsByProjectOp(ctx, projectId) {
2681
2681
  )
2682
2682
  );
2683
2683
  }
2684
- async function getMessagesOp(ctx, convId) {
2685
- const results = await ctx.messagesCollection.query(Q.where("conversation_id", convId), Q.sortBy("message_id", Q.asc)).unsafeFetchRaw();
2684
+ async function getMessagesOp(ctx, convId, opts) {
2685
+ const fetched = await ctx.messagesCollection.query(Q.where("conversation_id", convId), Q.sortBy("message_id", Q.asc)).unsafeFetchRaw();
2686
+ const results = opts?.rawFilter ? fetched.filter(opts.rawFilter) : fetched;
2686
2687
  return Promise.all(
2687
2688
  results.map(
2688
2689
  (raw) => messageRawToStored(raw, ctx.walletAddress, ctx.signMessage, ctx.embeddedWalletSigner)
@@ -4927,6 +4928,37 @@ async function chunkAndEmbedMessage(ctx, messageId, options) {
4927
4928
  }));
4928
4929
  return updateMessageChunksOp(ctx, messageId, messageChunks, embeddingModel);
4929
4930
  }
4931
+ var MIN_SEALED_EMBEDDING_HEX = 256;
4932
+ function rawHasEmbedding(value) {
4933
+ if (Array.isArray(value)) return value.length > 0;
4934
+ if (typeof value !== "string" || value.length === 0) return false;
4935
+ if (isEncrypted(value)) {
4936
+ return value.length - value.indexOf(":", 4) - 1 >= MIN_SEALED_EMBEDDING_HEX;
4937
+ }
4938
+ try {
4939
+ const parsed = JSON.parse(value);
4940
+ return Array.isArray(parsed) && parsed.length > 0;
4941
+ } catch {
4942
+ return false;
4943
+ }
4944
+ }
4945
+ function sealedVersion(value) {
4946
+ if (typeof value !== "string" || !isEncrypted(value)) return null;
4947
+ return value.startsWith("enc:v2:") ? "v2" : "v3";
4948
+ }
4949
+ function mayNeedChunkEmbedding(raw, embeddingModel, filter) {
4950
+ const role = raw.role;
4951
+ if (role === "system") return false;
4952
+ if (filter?.roles && !filter.roles.includes(role ?? "")) return false;
4953
+ if (isNonEmbeddableOrigin(raw.origin, filter?.reembedDiscarded)) {
4954
+ return false;
4955
+ }
4956
+ const model = raw.embedding_model;
4957
+ if (typeof model === "string" && model !== embeddingModel) return true;
4958
+ if (rawHasEmbedding(raw.chunks)) return false;
4959
+ if (rawHasEmbedding(raw.vector) && !filter?.rechunkExisting) return false;
4960
+ return true;
4961
+ }
4930
4962
  async function chunkAndEmbedAllMessages(ctx, options, filter) {
4931
4963
  const embeddingModel = options.model ?? DEFAULT_API_EMBEDDING_MODEL;
4932
4964
  const { chunkSize = DEFAULT_CHUNK_SIZE } = options;
@@ -4939,11 +4971,31 @@ async function chunkAndEmbedAllMessages(ctx, options, filter) {
4939
4971
  let considered = 0;
4940
4972
  let sealedRowsSeen = 0;
4941
4973
  let rowsSeen = 0;
4974
+ const keptSealed = /* @__PURE__ */ new Map();
4975
+ const candidatesStillSealed = /* @__PURE__ */ new Map();
4976
+ const droppedSealed = /* @__PURE__ */ new Map();
4977
+ const rawFilter = (raw) => {
4978
+ rowsSeen++;
4979
+ const keep = mayNeedChunkEmbedding(raw, embeddingModel, filter);
4980
+ const version = sealedVersion(raw.content);
4981
+ if (!version) return keep;
4982
+ if (keep) {
4983
+ keptSealed.set(version, (keptSealed.get(version) ?? 0) + 1);
4984
+ } else {
4985
+ const dropped = droppedSealed.get(version);
4986
+ if (dropped) dropped.count++;
4987
+ else droppedSealed.set(version, { count: 1, probeId: raw.id });
4988
+ }
4989
+ return keep;
4990
+ };
4942
4991
  for (const conv of targetConversations) {
4943
- const messages = await getMessagesOp(ctx, conv.conversationId);
4992
+ const messages = await getMessagesOp(ctx, conv.conversationId, { rawFilter });
4944
4993
  for (const message of messages) {
4945
- rowsSeen++;
4946
- if (isEncrypted(message.content)) sealedRowsSeen++;
4994
+ const stillSealed = sealedVersion(message.content);
4995
+ if (stillSealed) {
4996
+ sealedRowsSeen++;
4997
+ candidatesStillSealed.set(stillSealed, (candidatesStillSealed.get(stillSealed) ?? 0) + 1);
4998
+ }
4947
4999
  const isStale = message.embeddingModel !== void 0 && message.embeddingModel !== null && message.embeddingModel !== embeddingModel;
4948
5000
  if (message.chunks && message.chunks.length > 0 && !isStale) continue;
4949
5001
  const hasVector = message.vector && message.vector.length > 0;
@@ -4956,6 +5008,7 @@ async function chunkAndEmbedAllMessages(ctx, options, filter) {
4956
5008
  stillEncrypted++;
4957
5009
  continue;
4958
5010
  }
5011
+ if (isToolResultsRow(message)) continue;
4959
5012
  if (message.content.length < minLength) continue;
4960
5013
  if (shouldChunkMessage(message.content, chunkSize)) {
4961
5014
  longMessages.push({
@@ -4967,6 +5020,12 @@ async function chunkAndEmbedAllMessages(ctx, options, filter) {
4967
5020
  }
4968
5021
  }
4969
5022
  }
5023
+ for (const [version, dropped] of droppedSealed) {
5024
+ const keyOpenedACandidate = (keptSealed.get(version) ?? 0) > (candidatesStillSealed.get(version) ?? 0);
5025
+ if (keyOpenedACandidate) continue;
5026
+ const probe = await getMessageOp(ctx, dropped.probeId);
5027
+ if (!probe || isEncrypted(probe.content)) sealedRowsSeen += dropped.count;
5028
+ }
4970
5029
  if (stillEncrypted > 0 || sealedRowsSeen > 0) {
4971
5030
  getLogger().error(
4972
5031
  "memoryEngine: messages still encrypted (key unavailable?) \u2014 excluded from embedding",
@@ -10414,6 +10473,11 @@ function parseTopics(value) {
10414
10473
  }
10415
10474
 
10416
10475
  // src/lib/db/entities/operations.ts
10476
+ async function assertCanWrite(ctx) {
10477
+ if (ctx.canWrite && !await ctx.canWrite()) {
10478
+ throw new Error("Memory source is no longer eligible");
10479
+ }
10480
+ }
10417
10481
  function entityToStored(e) {
10418
10482
  return {
10419
10483
  uniqueId: e.id,
@@ -10554,6 +10618,7 @@ async function linkMemoryEntitiesOp(ctx, memoryId, entityInputs, options) {
10554
10618
  let skipped = false;
10555
10619
  let entities = [];
10556
10620
  await ctx.database.write(async () => {
10621
+ await assertCanWrite(ctx);
10557
10622
  const {
10558
10623
  entities: byName,
10559
10624
  operations: entityOps,
@@ -10629,6 +10694,7 @@ async function replaceMemoryEntities(ctx, memoryId, entityInputs, options) {
10629
10694
  let skipped = false;
10630
10695
  let entities = [];
10631
10696
  await ctx.database.write(async () => {
10697
+ await assertCanWrite(ctx);
10632
10698
  const vaultRow = await findVaultRowInWrite(ctx, memoryId);
10633
10699
  if (options.guarded && autoLinkBlocked(vaultRow)) {
10634
10700
  skipped = true;
@@ -10689,6 +10755,7 @@ async function unlinkMemoryEntitiesOp(ctx, memoryIds) {
10689
10755
  const links = await ctx.memoryEntityCollection.query(Q5.where("memory_id", Q5.oneOf(Array.from(memoryIds)))).fetch();
10690
10756
  if (links.length === 0) return;
10691
10757
  await ctx.database.write(async () => {
10758
+ await assertCanWrite(ctx);
10692
10759
  await ctx.database.batch(...links.map((l) => l.prepareDestroyPermanently()));
10693
10760
  });
10694
10761
  }
@@ -10697,6 +10764,7 @@ async function unlinkAllMemoryEntitiesForUserOp(ctx, userId) {
10697
10764
  const links = await ctx.memoryEntityCollection.query(Q5.where("user_id", userId)).fetch();
10698
10765
  if (links.length === 0) return;
10699
10766
  await ctx.database.write(async () => {
10767
+ await assertCanWrite(ctx);
10700
10768
  await ctx.database.batch(...links.map((l) => l.prepareDestroyPermanently()));
10701
10769
  });
10702
10770
  }
@@ -10716,6 +10784,7 @@ async function backfillMemoryEntityUserIdsOp(ctx, vaultMemoryCollection) {
10716
10784
  }
10717
10785
  if (toUpdate.length === 0) return 0;
10718
10786
  await ctx.database.write(async () => {
10787
+ await assertCanWrite(ctx);
10719
10788
  await ctx.database.batch(
10720
10789
  ...toUpdate.map(({ link, userId }) => link.prepareUpdate((r) => r._setRaw("user_id", userId)))
10721
10790
  );
@@ -13109,6 +13178,11 @@ function visibilityConditions(requested) {
13109
13178
  function isKinded(record2) {
13110
13179
  return record2.kind !== null && record2.kind !== void 0;
13111
13180
  }
13181
+ async function assertCanWrite2(ctx) {
13182
+ if (ctx.canWrite && !await ctx.canWrite()) {
13183
+ throw new Error("Memory source is no longer eligible");
13184
+ }
13185
+ }
13112
13186
  function assertValidKindLevel(kind, level) {
13113
13187
  const hasKind = kind !== null && kind !== void 0;
13114
13188
  if (hasKind && !MEMORY_KINDS.includes(kind)) {
@@ -13289,8 +13363,7 @@ async function createVaultMemoryOp(ctx, opts) {
13289
13363
  ctx.embeddedWalletSigner
13290
13364
  ) : opts.content;
13291
13365
  const created = await ctx.database.write(async () => {
13292
- if (ctx.canWrite && !await ctx.canWrite())
13293
- throw new Error("Memory source is no longer eligible");
13366
+ await assertCanWrite2(ctx);
13294
13367
  return ctx.vaultMemoryCollection.create(
13295
13368
  (record2) => populateNewVaultMemory(record2, ctx, opts, encryptedContent, encryptedKindValue)
13296
13369
  );
@@ -13309,8 +13382,7 @@ async function createSupersedingMemoryOp(ctx, opts, targetId) {
13309
13382
  ) : opts.content;
13310
13383
  let createdRecord = null;
13311
13384
  await ctx.database.write(async () => {
13312
- if (ctx.canWrite && !await ctx.canWrite())
13313
- throw new Error("Memory source is no longer eligible");
13385
+ await assertCanWrite2(ctx);
13314
13386
  let target;
13315
13387
  try {
13316
13388
  target = await ctx.vaultMemoryCollection.find(targetId);
@@ -13402,8 +13474,7 @@ async function createVaultMemoriesBatchOp(ctx, optionsArray) {
13402
13474
  })
13403
13475
  );
13404
13476
  const created = await ctx.database.write(async () => {
13405
- if (ctx.canWrite && !await ctx.canWrite())
13406
- throw new Error("Memory source is no longer eligible");
13477
+ await assertCanWrite2(ctx);
13407
13478
  const prepared = optionsArray.map(
13408
13479
  (opts, i) => ctx.vaultMemoryCollection.prepareCreate(
13409
13480
  (record2) => populateNewVaultMemory(record2, ctx, opts, encryptedContents[i], encryptedKindValues[i])
@@ -13708,8 +13779,7 @@ async function updateVaultMemoryOp(ctx, id, opts) {
13708
13779
  const record2 = probe;
13709
13780
  const originalUpdatedAt = record2.updatedAt.getTime();
13710
13781
  await ctx.database.write(async () => {
13711
- if (ctx.canWrite && !await ctx.canWrite())
13712
- throw new Error("Memory source is no longer eligible");
13782
+ await assertCanWrite2(ctx);
13713
13783
  if (record2.isDeleted || record2.supersededBy || !isOwnedByCtxUser(ctx, record2) || opts.freeFormOnly && isKinded(record2)) {
13714
13784
  stale = true;
13715
13785
  return;
@@ -13820,6 +13890,7 @@ async function setMemoryEntitiesOp(ctx, memoryId, entities) {
13820
13890
  let stale = false;
13821
13891
  const originalUpdatedAt = record2.updatedAt.getTime();
13822
13892
  await ctx.database.write(async (writer) => {
13893
+ await assertCanWrite2(ctx);
13823
13894
  if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2)) {
13824
13895
  stale = true;
13825
13896
  return;
@@ -13861,6 +13932,7 @@ async function clearMemoryTopicsOverrideOp(ctx, memoryId, options) {
13861
13932
  const originalUpdatedAt = record2.updatedAt.getTime();
13862
13933
  let cleared = false;
13863
13934
  await ctx.database.write(async () => {
13935
+ await assertCanWrite2(ctx);
13864
13936
  if (options?.unlessTopicsRecorded && parseTopics(record2.topics) !== null) return;
13865
13937
  cleared = true;
13866
13938
  await record2.update((r) => {
@@ -13884,6 +13956,7 @@ async function setMemoryVisibilityOp(ctx, id, opts) {
13884
13956
  if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2)) return null;
13885
13957
  let stale = false;
13886
13958
  await ctx.database.write(async () => {
13959
+ await assertCanWrite2(ctx);
13887
13960
  if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2)) {
13888
13961
  stale = true;
13889
13962
  return;
@@ -13912,6 +13985,7 @@ async function deleteVaultMemoryOp(ctx, id) {
13912
13985
  if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2)) return false;
13913
13986
  let stale = false;
13914
13987
  await ctx.database.write(async () => {
13988
+ await assertCanWrite2(ctx);
13915
13989
  if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2)) {
13916
13990
  stale = true;
13917
13991
  return;
@@ -13949,8 +14023,7 @@ async function supersedeVaultMemoryOp(ctx, id, supersededById) {
13949
14023
  }
13950
14024
  let stale = false;
13951
14025
  await ctx.database.write(async () => {
13952
- if (ctx.canWrite && !await ctx.canWrite())
13953
- throw new Error("Memory source is no longer eligible");
14026
+ await assertCanWrite2(ctx);
13954
14027
  if (record2.isDeleted || record2.supersededBy || !isOwnedByCtxUser(ctx, record2)) {
13955
14028
  stale = true;
13956
14029
  return;
@@ -14112,6 +14185,7 @@ async function stampTopicsExtractedAtOp(ctx, memoryIds, extractedAt, version = T
14112
14185
  for (let i = 0; i < uniqueIds.length; i += CHUNK) {
14113
14186
  const chunkIds = uniqueIds.slice(i, i + CHUNK);
14114
14187
  await ctx.database.write(async () => {
14188
+ await assertCanWrite2(ctx);
14115
14189
  const records = [];
14116
14190
  for (const id of chunkIds) {
14117
14191
  try {
@@ -14145,6 +14219,7 @@ async function relinkMemoryTopicsOp(ctx, memoryIds) {
14145
14219
  for (const id of Array.from(new Set(memoryIds))) {
14146
14220
  try {
14147
14221
  await ctx.database.write(async (writer) => {
14222
+ await assertCanWrite2(ctx);
14148
14223
  let record2;
14149
14224
  try {
14150
14225
  record2 = await ctx.vaultMemoryCollection.find(id);
@@ -14175,6 +14250,7 @@ async function backfillMemoryTopicsOp(ctx, memoryIds) {
14175
14250
  for (let i = 0; i < uniqueIds.length; i += CHUNK) {
14176
14251
  const chunkIds = uniqueIds.slice(i, i + CHUNK);
14177
14252
  await ctx.database.write(async () => {
14253
+ await assertCanWrite2(ctx);
14178
14254
  const writes = [];
14179
14255
  for (const id of chunkIds) {
14180
14256
  let record2;
@@ -14207,6 +14283,7 @@ async function deleteAllVaultMemoriesForUserOp(ctx, userId) {
14207
14283
  const records = await ctx.vaultMemoryCollection.query(Q8.where("user_id", userId), Q8.where("is_deleted", false)).fetch();
14208
14284
  if (records.length === 0) return 0;
14209
14285
  await ctx.database.write(async () => {
14286
+ await assertCanWrite2(ctx);
14210
14287
  const prepared = records.map(
14211
14288
  (record2) => record2.prepareUpdate((r) => {
14212
14289
  r._setRaw("is_deleted", true);
@@ -14261,6 +14338,7 @@ async function archiveVaultMemoryOp(ctx, id, opts) {
14261
14338
  let stale = false;
14262
14339
  const archivedAtValue = opts?.now ?? Date.now();
14263
14340
  await ctx.database.write(async () => {
14341
+ await assertCanWrite2(ctx);
14264
14342
  if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2) || record2.archivedAt !== null) {
14265
14343
  stale = true;
14266
14344
  return;
@@ -14284,6 +14362,7 @@ async function restoreVaultMemoryOp(ctx, id) {
14284
14362
  if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2)) return false;
14285
14363
  let stale = false;
14286
14364
  await ctx.database.write(async () => {
14365
+ await assertCanWrite2(ctx);
14287
14366
  if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2)) {
14288
14367
  stale = true;
14289
14368
  return;
@@ -14304,6 +14383,7 @@ async function hardDeleteDecayedOp(ctx, id, opts) {
14304
14383
  const now = opts.now ?? Date.now();
14305
14384
  let stale = false;
14306
14385
  await ctx.database.write(async () => {
14386
+ await assertCanWrite2(ctx);
14307
14387
  const archivedAt = record2.archivedAt;
14308
14388
  if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2) || archivedAt === null || now - archivedAt <= opts.hardDeleteWindowMs) {
14309
14389
  stale = true;
@@ -14343,6 +14423,7 @@ async function updateVaultMemoryEmbeddingOp(ctx, id, embedding2, embeddingModel,
14343
14423
  }
14344
14424
  let written = false;
14345
14425
  await ctx.database.write(async () => {
14426
+ await assertCanWrite2(ctx);
14346
14427
  if (record2.isDeleted || !isOwnedByCtxUser(ctx, record2)) return;
14347
14428
  const originalUpdatedAt = record2.updatedAt.getTime();
14348
14429
  if (originalUpdatedAt !== readUpdatedAt || record2._getRaw("content") !== readStoredContent)
@@ -18312,6 +18393,13 @@ function restoreCandidates(candidates, redactor, ownNames) {
18312
18393
  ).map((c) => c.candidate);
18313
18394
  }
18314
18395
  async function extractAndRetain(messages, retainCtx, options) {
18396
+ const { memoryStore, signal } = options;
18397
+ if (memoryStore === null) throw new Error("Memory store is not ready");
18398
+ if (memoryStore && options.folderId !== void 0 && options.folderId !== null)
18399
+ throw new Error("Remote memory extraction does not support folders");
18400
+ if (memoryStore && options.extract.piiRedaction && !memoryStore.masksEmbeddingInput)
18401
+ throw new Error("PII-redacted extraction requires a memory store that masks embedding inputs");
18402
+ signal?.throwIfAborted();
18315
18403
  const minConfidence = options.minConfidence ?? DEFAULT_MIN_CONFIDENCE;
18316
18404
  const resolvedConsolidatePii = options.consolidateOptions?.piiRedaction ?? options.extract.piiRedaction;
18317
18405
  const consolidateOptions = options.consolidateOptions !== void 0 ? {
@@ -18345,6 +18433,7 @@ async function extractAndRetain(messages, retainCtx, options) {
18345
18433
  }
18346
18434
  });
18347
18435
  const extractMs = Date.now() - tExtract;
18436
+ signal?.throwIfAborted();
18348
18437
  const filtered = candidates.filter((c) => c.confidence >= minConfidence);
18349
18438
  const log = getLogger();
18350
18439
  const screened = screenCandidatesForInjection(filtered);
@@ -18392,16 +18481,33 @@ async function extractAndRetain(messages, retainCtx, options) {
18392
18481
  const results = [];
18393
18482
  const quarantinedInfo = [];
18394
18483
  let failedWrites = 0;
18484
+ let auditRows;
18395
18485
  const tRetain = Date.now();
18396
18486
  for (const { candidate, isQuarantined, reason, signature } of toRetain) {
18397
18487
  try {
18488
+ signal?.throwIfAborted();
18398
18489
  if (isQuarantined) {
18399
- const existingId = await findQuarantinedDuplicateOp(
18400
- retainCtx.vaultCtx,
18401
- candidate.content,
18402
- candidate.sourceMessageIds,
18403
- { scope: options.scope ?? "private", folderId: options.folderId ?? null }
18404
- ).catch(() => null);
18490
+ let existingId;
18491
+ if (memoryStore) {
18492
+ auditRows ?? (auditRows = memoryStore.list({
18493
+ scopes: [options.scope ?? "private"],
18494
+ includeArchived: true,
18495
+ includeQuarantined: true,
18496
+ includeSuperseded: true
18497
+ }));
18498
+ const sourceKey = [...new Set(candidate.sourceMessageIds)].sort().join("\0");
18499
+ const normalize = (value) => value.normalize("NFKC").trim().replace(/\s+/g, " ").toLowerCase();
18500
+ existingId = (await auditRows).find(
18501
+ (row) => row.trustTier === "quarantined" && row.scope === (options.scope ?? "private") && [...new Set(row.sourceChunkIds ?? [])].sort().join("\0") === sourceKey && normalize(row.content) === normalize(candidate.content)
18502
+ )?.uniqueId ?? null;
18503
+ } else {
18504
+ existingId = await findQuarantinedDuplicateOp(
18505
+ retainCtx.vaultCtx,
18506
+ candidate.content,
18507
+ candidate.sourceMessageIds,
18508
+ { scope: options.scope ?? "private", folderId: options.folderId ?? null }
18509
+ ).catch(() => null);
18510
+ }
18405
18511
  if (existingId) {
18406
18512
  quarantinedInfo.push({
18407
18513
  candidate,
@@ -18412,18 +18518,26 @@ async function extractAndRetain(messages, retainCtx, options) {
18412
18518
  continue;
18413
18519
  }
18414
18520
  }
18415
- const result = await retain(candidate.content, retainCtx, {
18521
+ const retainOptions = {
18416
18522
  source: "auto-extracted",
18417
18523
  sourceChunkIds: candidate.sourceMessageIds,
18418
18524
  respectTombstones: true,
18419
18525
  ...options.scope !== void 0 && { scope: options.scope },
18420
- ...options.folderId !== void 0 && { folderId: options.folderId },
18421
18526
  ...consolidateOptions !== void 0 && { consolidateOptions },
18422
18527
  ...candidate.eventTime !== null && { eventTime: candidate.eventTime },
18423
18528
  factType: candidate.type,
18424
18529
  ...isQuarantined && { trustTier: "quarantined", enableAutoMerge: false }
18530
+ };
18531
+ const result = memoryStore ? await memoryStore.retain(candidate.content, {
18532
+ ...retainOptions,
18533
+ canWrite: retainCtx.vaultCtx.canWrite,
18534
+ signal
18535
+ }) : await retain(candidate.content, retainCtx, {
18536
+ ...retainOptions,
18537
+ ...options.folderId !== void 0 && { folderId: options.folderId }
18425
18538
  });
18426
18539
  if (isQuarantined) {
18540
+ auditRows = void 0;
18427
18541
  const info = {
18428
18542
  candidate,
18429
18543
  memoryId: result.memoryId,
@@ -18442,9 +18556,16 @@ async function extractAndRetain(messages, retainCtx, options) {
18442
18556
  }
18443
18557
  succeededCandidates.push(candidate);
18444
18558
  results.push(result);
18445
- if (result.action !== "suppressed" && options.entityCtx && candidate.entities.length > 0) {
18559
+ if (result.action !== "suppressed" && candidate.entities.length > 0) {
18446
18560
  try {
18447
- if (!await isMemoryTopicsUserManaged(options.entityCtx, result.memoryId)) {
18561
+ signal?.throwIfAborted();
18562
+ if (memoryStore) {
18563
+ await memoryStore.addTopics(result.memoryId, candidate.entities, {
18564
+ unlessUserManaged: true,
18565
+ canWrite: retainCtx.vaultCtx.canWrite,
18566
+ signal
18567
+ });
18568
+ } else if (options.entityCtx && !await isMemoryTopicsUserManaged(options.entityCtx, result.memoryId)) {
18448
18569
  await linkMemoryEntitiesOp(options.entityCtx, result.memoryId, candidate.entities, {
18449
18570
  unlessTopicsUserManaged: true
18450
18571
  });
@@ -18692,7 +18813,7 @@ function createAutoExtractor(options) {
18692
18813
  };
18693
18814
  const consolidateOptions = options.consolidate ? { ...options.consolidate, ...subPassAuth(options.consolidate.baseUrl) } : void 0;
18694
18815
  const injectionClassifierOptions = options.injectionClassifier ? { ...options.injectionClassifier, ...subPassAuth(options.injectionClassifier.baseUrl) } : void 0;
18695
- if (options.retainCtx.vaultCtx.entityCtx && !options.entityCtx) {
18816
+ if (!options.memoryStore && options.retainCtx.vaultCtx.entityCtx && !options.entityCtx) {
18696
18817
  getLogger().warn(
18697
18818
  "[memory/extract] retainCtx.vaultCtx.entityCtx is set but extractor was created without `entityCtx` \u2014 W5 graph lane will receive no writes"
18698
18819
  );
@@ -18737,6 +18858,8 @@ function createAutoExtractor(options) {
18737
18858
  try {
18738
18859
  const { candidates, results, failedCount, outcome: outcome2, failure, funnel, timings, model } = await extractAndRetain(window2, retainCtx, {
18739
18860
  extract,
18861
+ memoryStore: options.memoryStore,
18862
+ signal: options.signal,
18740
18863
  ...options.minConfidence !== void 0 && { minConfidence: options.minConfidence },
18741
18864
  ...options.entityCtx !== void 0 && { entityCtx: options.entityCtx },
18742
18865
  ...options.scope !== void 0 && { scope: options.scope },
@@ -20845,6 +20968,7 @@ function createLocalMemoryStore(options) {
20845
20968
  database,
20846
20969
  entityCollection: database.get("entity"),
20847
20970
  memoryEntityCollection: database.get("memory_entity"),
20971
+ canWrite: options.canWrite,
20848
20972
  ...userId !== void 0 && { userId },
20849
20973
  ...options.allowUnscopedRows !== void 0 && {
20850
20974
  allowUnscopedRows: options.allowUnscopedRows
@@ -20856,10 +20980,21 @@ function createLocalMemoryStore(options) {
20856
20980
  walletAddress: options.walletAddress,
20857
20981
  signMessage: options.signMessage,
20858
20982
  embeddedWalletSigner: options.embeddedWalletSigner,
20983
+ canWrite: options.canWrite,
20859
20984
  ...userId !== void 0 && { userId },
20860
20985
  ...options.singleTenant !== void 0 && { singleTenant: options.singleTenant },
20861
20986
  entityCtx
20862
20987
  };
20988
+ const assertWrite = async (writeOptions) => {
20989
+ writeOptions?.signal?.throwIfAborted();
20990
+ if (writeOptions?.canWrite && !await writeOptions.canWrite()) {
20991
+ throw new Error("Memory source is no longer eligible");
20992
+ }
20993
+ if (options.canWrite && !await options.canWrite()) {
20994
+ throw new Error("Memory source is no longer eligible");
20995
+ }
20996
+ writeOptions?.signal?.throwIfAborted();
20997
+ };
20863
20998
  const vaultCache = options.vaultCache ?? createVaultEmbeddingCache();
20864
20999
  const ownedBy = userId !== void 0 ? [Q15.where("user_id", userId)] : [];
20865
21000
  const linksOwnedBy = userId === void 0 ? [] : options.allowUnscopedRows ? [Q15.or(Q15.where("user_id", userId), Q15.where("user_id", null))] : [Q15.where("user_id", userId)];
@@ -20971,9 +21106,25 @@ function createLocalMemoryStore(options) {
20971
21106
  archive: (id) => archiveVaultMemoryOp(vaultCtx, id),
20972
21107
  restore: (id) => restoreVaultMemoryOp(vaultCtx, id),
20973
21108
  setTopics: (memoryId, topics) => setMemoryEntitiesOp(vaultCtx, memoryId, topics),
20974
- addTopics: (memoryId, topics) => database.write(async (writer) => {
21109
+ addTopics: (memoryId, topics, writeOptions) => database.write(async (writer) => {
21110
+ await assertWrite(writeOptions);
20975
21111
  const owned = await vaultCtx.vaultMemoryCollection.query(Q15.where("id", memoryId), Q15.where("is_deleted", false), ...ownedBy).fetchCount();
20976
- return owned > 0 ? writer.callWriter(() => linkMemoryEntitiesOp(entityCtx, memoryId, topics)) : [];
21112
+ return owned > 0 ? writer.callWriter(
21113
+ () => linkMemoryEntitiesOp(
21114
+ {
21115
+ ...entityCtx,
21116
+ canWrite: async () => {
21117
+ await assertWrite(writeOptions);
21118
+ return true;
21119
+ }
21120
+ },
21121
+ memoryId,
21122
+ topics,
21123
+ {
21124
+ unlessTopicsUserManaged: writeOptions?.unlessUserManaged
21125
+ }
21126
+ )
21127
+ ) : [];
20977
21128
  }),
20978
21129
  setVisibility: (id, visibility, visibilityOptions) => setMemoryVisibilityOp(vaultCtx, id, { visibility, ...visibilityOptions }),
20979
21130
  recall: (query, recallOptions) => recall(
@@ -20983,7 +21134,17 @@ function createLocalMemoryStore(options) {
20983
21134
  ),
20984
21135
  retain: (content, retainOptions) => retain(
20985
21136
  content,
20986
- { vaultCtx, embeddingOptions: options.embeddingOptions, vaultCache },
21137
+ {
21138
+ vaultCtx: {
21139
+ ...vaultCtx,
21140
+ canWrite: async () => {
21141
+ await assertWrite(retainOptions);
21142
+ return true;
21143
+ }
21144
+ },
21145
+ embeddingOptions: options.embeddingOptions,
21146
+ vaultCache
21147
+ },
20987
21148
  retainOptions
20988
21149
  ),
20989
21150
  factSource: {
@@ -21620,7 +21781,14 @@ function stored(row) {
21620
21781
  function createRemoteMemoryPipeline(options) {
21621
21782
  const { persistence, embeddingOptions } = options;
21622
21783
  const model = embeddingOptions.model ?? DEFAULT_API_EMBEDDING_MODEL;
21623
- const operation = (mode) => {
21784
+ const operation = (mode, writeOptions) => {
21785
+ const signal = writeOptions?.signal;
21786
+ const assertWrite = async () => {
21787
+ signal?.throwIfAborted();
21788
+ if (writeOptions?.canWrite && !await writeOptions.canWrite())
21789
+ throw new Error("Memory source is no longer eligible");
21790
+ signal?.throwIfAborted();
21791
+ };
21624
21792
  const rejectUndecryptable = (failed) => {
21625
21793
  if (!failed.length) return;
21626
21794
  if (mode === "retain")
@@ -21638,7 +21806,7 @@ function createRemoteMemoryPipeline(options) {
21638
21806
  return items.map((item) => stored(item.memory));
21639
21807
  };
21640
21808
  const get = async (id) => {
21641
- const snapshot = snapshots.get(id) ?? await persistence.get(id);
21809
+ const snapshot = snapshots.get(id) ?? await (signal ? persistence.get(id, signal) : persistence.get(id));
21642
21810
  if (!snapshot || snapshot.memory.is_deleted || snapshot.memory.superseded_by) return null;
21643
21811
  snapshots.set(id, snapshot);
21644
21812
  return stored(snapshot.memory);
@@ -21684,7 +21852,7 @@ function createRemoteMemoryPipeline(options) {
21684
21852
  if (forced.size < 100 && temporal[i] !== void 0) forced.add(temporal[i]);
21685
21853
  }
21686
21854
  const forceIds = [...forced];
21687
- const windowOptions = (i, signal) => ({
21855
+ const windowOptions = (i, signal2) => ({
21688
21856
  limit: Math.min(100, Math.max((search.limit ?? 8) * 3, 30)),
21689
21857
  force_ids: i === 0 ? forceIds : [],
21690
21858
  ...search.scopes && { scopes: search.scopes },
@@ -21692,13 +21860,15 @@ function createRemoteMemoryPipeline(options) {
21692
21860
  ...search.memoryIds !== void 0 && { memory_ids: search.memoryIds },
21693
21861
  include_archived: search.includeArchived,
21694
21862
  embedding_model: model,
21695
- ...signal && { signal }
21863
+ ...signal2 && { signal: signal2 }
21696
21864
  });
21697
21865
  const vectors = [queryEmbedding, ...facetEmbeddings];
21698
21866
  let windows;
21699
21867
  if (mode === "retain") {
21700
21868
  windows = await Promise.all(
21701
- vectors.map((embedding2, i) => persistence.candidateSet(embedding2, windowOptions(i)))
21869
+ vectors.map(
21870
+ (embedding2, i) => persistence.candidateSet(embedding2, windowOptions(i, signal))
21871
+ )
21702
21872
  );
21703
21873
  } else {
21704
21874
  const deadline = new AbortController();
@@ -21786,12 +21956,15 @@ function createRemoteMemoryPipeline(options) {
21786
21956
  twin_opt_in: false
21787
21957
  };
21788
21958
  };
21789
- const write = async (memory, snapshot) => remember([await persistence.put(memory, snapshot)])[0];
21959
+ const write = async (memory, snapshot) => {
21960
+ await assertWrite();
21961
+ return remember([await persistence.put(memory, snapshot, signal)])[0];
21962
+ };
21790
21963
  const port = {
21791
21964
  prepare,
21792
21965
  get,
21793
21966
  getFresh: async (id) => {
21794
- const current = await persistence.get(id);
21967
+ const current = await (signal ? persistence.get(id, signal) : persistence.get(id));
21795
21968
  return current && !current.memory.is_deleted && !current.memory.superseded_by ? stored(current.memory) : null;
21796
21969
  },
21797
21970
  tombstones: async (embedding2, embeddingModel, scope, folderId) => {
@@ -21802,7 +21975,8 @@ function createRemoteMemoryPipeline(options) {
21802
21975
  embedding_model: embeddingModel,
21803
21976
  strict_model: true,
21804
21977
  include_deleted: true,
21805
- deleted_only: true
21978
+ deleted_only: true,
21979
+ signal
21806
21980
  });
21807
21981
  rejectUndecryptable(window2.failed);
21808
21982
  return remember(window2.items);
@@ -21858,14 +22032,18 @@ function createRemoteMemoryPipeline(options) {
21858
22032
  if (!target || !newer || id === successor) return false;
21859
22033
  const old = snapshots.get(id);
21860
22034
  const next = snapshots.get(successor);
22035
+ await assertWrite();
21861
22036
  remember(
21862
- await persistence.putMany([
21863
- {
21864
- memory: { ...old.memory, superseded_by: successor, superseded_at: Date.now() },
21865
- expectedVersion: old
21866
- },
21867
- { memory: next.memory, expectedVersion: next }
21868
- ])
22037
+ await persistence.putMany(
22038
+ [
22039
+ {
22040
+ memory: { ...old.memory, superseded_by: successor, superseded_at: Date.now() },
22041
+ expectedVersion: old
22042
+ },
22043
+ { memory: next.memory, expectedVersion: next }
22044
+ ],
22045
+ signal
22046
+ )
21869
22047
  );
21870
22048
  return true;
21871
22049
  },
@@ -21874,18 +22052,22 @@ function createRemoteMemoryPipeline(options) {
21874
22052
  if (!target) return { created: null, retired: false };
21875
22053
  const snapshot = snapshots.get(targetId);
21876
22054
  const successor = createRow(input);
22055
+ await assertWrite();
21877
22056
  const rows = remember(
21878
- await persistence.putMany([
21879
- { memory: successor, expectedVersion: 0 },
21880
- {
21881
- memory: {
21882
- ...snapshot.memory,
21883
- superseded_by: successor.memory_id,
21884
- superseded_at: Date.now()
21885
- },
21886
- expectedVersion: snapshot
21887
- }
21888
- ])
22057
+ await persistence.putMany(
22058
+ [
22059
+ { memory: successor, expectedVersion: 0 },
22060
+ {
22061
+ memory: {
22062
+ ...snapshot.memory,
22063
+ superseded_by: successor.memory_id,
22064
+ superseded_at: Date.now()
22065
+ },
22066
+ expectedVersion: snapshot
22067
+ }
22068
+ ],
22069
+ signal
22070
+ )
21889
22071
  );
21890
22072
  return { created: rows[0], retired: true };
21891
22073
  }
@@ -21918,7 +22100,7 @@ function createRemoteMemoryPipeline(options) {
21918
22100
  factSource,
21919
22101
  recall: async (query, recallOptions = {}) => recall(query, { embeddingOptions, factSource }, { ...recallOptions, types: ["fact"] }),
21920
22102
  retain: async (content, retainOptions) => {
21921
- const { port } = operation("retain");
22103
+ const { port } = operation("retain", retainOptions);
21922
22104
  return retainWithPersistence(
21923
22105
  content,
21924
22106
  {
@@ -22500,16 +22682,21 @@ function createRemoteMemoryStore(options) {
22500
22682
  const record2 = await persistence.get(id);
22501
22683
  return record2 && !record2.memory.is_deleted ? record2 : null;
22502
22684
  };
22503
- const mutateLocked = async (id, change, edit) => {
22504
- const record2 = await live(id);
22685
+ const mutateLocked = async (id, change, edit, writeOptions) => {
22686
+ writeOptions?.signal?.throwIfAborted();
22687
+ const record2 = writeOptions?.signal ? await persistence.get(id, writeOptions.signal) : await live(id);
22505
22688
  if (!record2) return null;
22689
+ if (record2.memory.is_deleted) return null;
22690
+ if (writeOptions?.canWrite && !await writeOptions.canWrite())
22691
+ throw new Error("Memory source is no longer eligible");
22692
+ writeOptions?.signal?.throwIfAborted();
22506
22693
  const next = edit(structuredClone(record2.memory));
22507
22694
  if (!next) return null;
22508
- const saved = await persistence.put(next, record2);
22695
+ const saved = writeOptions?.signal ? await persistence.put(next, record2, writeOptions.signal) : await persistence.put(next, record2);
22509
22696
  notify(typeof change === "function" ? change(record2.memory) : change, [saved]);
22510
22697
  return saved;
22511
22698
  };
22512
- const mutate = (id, change, edit) => serialized(id, () => mutateLocked(id, change, edit));
22699
+ const mutate = (id, change, edit, writeOptions) => serialized(id, () => mutateLocked(id, change, edit, writeOptions));
22513
22700
  const serializedAll = (ids, task) => [...new Set(ids)].sort().reduceRight((inner, id) => () => serialized(id, inner), task)();
22514
22701
  const mutateMany = async (ids, change, edit) => {
22515
22702
  const saved = /* @__PURE__ */ new Map();
@@ -23022,13 +23209,21 @@ function createRemoteMemoryStore(options) {
23022
23209
  }))
23023
23210
  );
23024
23211
  },
23025
- addTopics: async (memoryId, topics) => {
23212
+ addTopics: async (memoryId, topics, writeOptions) => {
23026
23213
  const added = await withKnownKinds(topicInputs(topics, "auto"));
23027
- const saved = await mutate(memoryId, "edit", (memory) => ({
23028
- ...memory,
23029
- topics: serializeTopics(mergeTopics(parseTopics(memory.topics) ?? [], added)),
23030
- topics_updated_at: Date.now()
23031
- }));
23214
+ const saved = await mutate(
23215
+ memoryId,
23216
+ "edit",
23217
+ (memory) => {
23218
+ if (writeOptions?.unlessUserManaged && memory.topics_user_managed) return null;
23219
+ return {
23220
+ ...memory,
23221
+ topics: serializeTopics(mergeTopics(parseTopics(memory.topics) ?? [], added)),
23222
+ topics_updated_at: Date.now()
23223
+ };
23224
+ },
23225
+ writeOptions
23226
+ );
23032
23227
  if (!saved) return [];
23033
23228
  const now = /* @__PURE__ */ new Date();
23034
23229
  return mergeTopics([], added).map(
@@ -23879,6 +24074,7 @@ function createDurableAutoExtractor(options) {
23879
24074
  };
23880
24075
  const folderId = options.folderId ?? null;
23881
24076
  let disposed = false;
24077
+ let activeBatch = null;
23882
24078
  let running = false;
23883
24079
  let wakeRequested = false;
23884
24080
  let timer;
@@ -23915,14 +24111,18 @@ function createDurableAutoExtractor(options) {
23915
24111
  }, delay);
23916
24112
  }
23917
24113
  async function extractBatch(messages, conversationId, ids, jobScope, jobFolderId) {
24114
+ if (disposed) throw new Error("Extraction session was disposed");
23918
24115
  let watchdog;
23919
24116
  let cancelled = false;
24117
+ const controller = new AbortController();
24118
+ activeBatch = controller;
23920
24119
  const model = options.modelForScope?.(jobScope) ?? options.extract.model;
23921
24120
  try {
23922
24121
  return await Promise.race([
23923
24122
  new Promise((resolve, reject) => {
23924
24123
  const worker = createAutoExtractor({
23925
24124
  ...options,
24125
+ signal: controller.signal,
23926
24126
  retainCtx: {
23927
24127
  ...options.retainCtx,
23928
24128
  vaultCtx: {
@@ -23951,6 +24151,8 @@ function createDurableAutoExtractor(options) {
23951
24151
  ]);
23952
24152
  } finally {
23953
24153
  cancelled = true;
24154
+ controller.abort();
24155
+ if (activeBatch === controller) activeBatch = null;
23954
24156
  if (watchdog !== void 0) clearTimeout(watchdog);
23955
24157
  }
23956
24158
  }
@@ -23962,6 +24164,7 @@ function createDurableAutoExtractor(options) {
23962
24164
  for (const message of loaded)
23963
24165
  if (message && message.messageId > 0) sequences.set(message.uniqueId, message.messageId);
23964
24166
  await database.write(async () => {
24167
+ if (disposed) return;
23965
24168
  const current = idsOf(job);
23966
24169
  const acknowledged = ids.filter((id) => current.includes(id));
23967
24170
  if (!acknowledged.length) return;
@@ -24134,6 +24337,7 @@ function createDurableAutoExtractor(options) {
24134
24337
  jobScope,
24135
24338
  jobFolderId
24136
24339
  );
24340
+ if (disposed) throw new Error("Extraction session was disposed");
24137
24341
  options.onTurnComplete?.(result);
24138
24342
  return result;
24139
24343
  };
@@ -24170,6 +24374,7 @@ function createDurableAutoExtractor(options) {
24170
24374
  );
24171
24375
  scheduleAfterSuccess = true;
24172
24376
  } catch (error) {
24377
+ if (disposed) break;
24173
24378
  attempts.set(job.id, attempted + 1);
24174
24379
  retry = true;
24175
24380
  reportError(error, conversationId);
@@ -24192,6 +24397,14 @@ function createDurableAutoExtractor(options) {
24192
24397
  schedule(retry ? options.retryDelayMs ?? 3e4 : 0);
24193
24398
  }
24194
24399
  }
24400
+ function dispose() {
24401
+ disposed = true;
24402
+ activeBatch?.abort(options.signal?.reason);
24403
+ if (timer !== void 0) clearTimeout(timer);
24404
+ options.signal?.removeEventListener("abort", dispose);
24405
+ }
24406
+ if (options.signal?.aborted) dispose();
24407
+ else options.signal?.addEventListener("abort", dispose, { once: true });
24195
24408
  schedule(0);
24196
24409
  return {
24197
24410
  processTurn(messages, conversationId) {
@@ -24271,10 +24484,7 @@ function createDurableAutoExtractor(options) {
24271
24484
  return true;
24272
24485
  },
24273
24486
  isProcessing: () => running,
24274
- dispose() {
24275
- disposed = true;
24276
- if (timer !== void 0) clearTimeout(timer);
24277
- }
24487
+ dispose
24278
24488
  };
24279
24489
  }
24280
24490
 
@@ -30535,6 +30745,7 @@ var CONVERSATION_REDACTOR_LIMIT = 50;
30535
30745
  var NO_CONVERSATION_KEY = "__no_conversation__";
30536
30746
  var NO_STORE_FOLDERS = "Folders are not supported with a memoryStore";
30537
30747
  var NO_STORE_MASK = "piiRedaction needs a memoryStore built with embeddingOptions.maskInput";
30748
+ var MEMORY_STORE_NOT_READY = "Memory store is not ready";
30538
30749
  var conversationRedactors = /* @__PURE__ */ new Map();
30539
30750
  function getConversationRedactor(conversationId, nerDetector) {
30540
30751
  const key = conversationId ?? NO_CONVERSATION_KEY;
@@ -30625,7 +30836,7 @@ function useChatStorage(options) {
30625
30836
  () => ({ getToken, baseUrl, model: embeddingModel, maskInput: maskEmbeddingInput }),
30626
30837
  [getToken, baseUrl, embeddingModel, maskEmbeddingInput]
30627
30838
  );
30628
- const storeMaskMissing = memoryStore !== void 0 && maskEmbeddingInput !== void 0 && !memoryStore.masksEmbeddingInput;
30839
+ const storeMaskMissing = memoryStore !== void 0 && memoryStore !== null && maskEmbeddingInput !== void 0 && !memoryStore.masksEmbeddingInput;
30629
30840
  const blobManagerRef = useRef4(new BlobUrlManager());
30630
30841
  useEffect4(() => {
30631
30842
  const manager = blobManagerRef.current;
@@ -30902,6 +31113,7 @@ function useChatStorage(options) {
30902
31113
  );
30903
31114
  const retainVaultMemory = useCallback5(
30904
31115
  async (input) => {
31116
+ if (memoryStore === null) throw new Error(MEMORY_STORE_NOT_READY);
30905
31117
  if (memoryStore) {
30906
31118
  if (storeMaskMissing) throw new Error(NO_STORE_MASK);
30907
31119
  if (input.folderId !== void 0) throw new Error(NO_STORE_FOLDERS);
@@ -30933,6 +31145,7 @@ function useChatStorage(options) {
30933
31145
  );
30934
31146
  const createMemoryVaultTool2 = useCallback5(
30935
31147
  (options2) => {
31148
+ if (memoryStore === null) throw new Error(MEMORY_STORE_NOT_READY);
30936
31149
  if (storeMaskMissing) throw new Error(NO_STORE_MASK);
30937
31150
  const embOpts = getToken ? vaultEmbeddingOptions : void 0;
30938
31151
  return createMemoryVaultTool(
@@ -30954,6 +31167,7 @@ function useChatStorage(options) {
30954
31167
  );
30955
31168
  const getVaultMemories = useCallback5(
30956
31169
  (options2) => {
31170
+ if (memoryStore === null) return Promise.resolve([]);
30957
31171
  if (!memoryStore) return getAllVaultMemoriesOp(vaultCtx, options2);
30958
31172
  const { folderId, levels, kinds, ...listOptions } = options2 ?? {};
30959
31173
  if (folderId !== void 0) throw new Error(NO_STORE_FOLDERS);
@@ -30965,6 +31179,7 @@ function useChatStorage(options) {
30965
31179
  );
30966
31180
  const createVaultMemory = useCallback5(
30967
31181
  async (content, scope) => {
31182
+ if (memoryStore === null) throw new Error(MEMORY_STORE_NOT_READY);
30968
31183
  if (storeMaskMissing) throw new Error(NO_STORE_MASK);
30969
31184
  if (memoryStore) return memoryStore.create({ content, scope });
30970
31185
  const result = await createVaultMemoryOp(vaultCtx, { content, scope });
@@ -30986,6 +31201,7 @@ function useChatStorage(options) {
30986
31201
  );
30987
31202
  const updateVaultMemory = useCallback5(
30988
31203
  async (id, content, scope) => {
31204
+ if (memoryStore === null) throw new Error(MEMORY_STORE_NOT_READY);
30989
31205
  if (storeMaskMissing) throw new Error(NO_STORE_MASK);
30990
31206
  if (memoryStore) return memoryStore.update(id, { content, scope });
30991
31207
  const existing = await getVaultMemoryOp(vaultCtx, id);
@@ -31011,6 +31227,7 @@ function useChatStorage(options) {
31011
31227
  );
31012
31228
  const deleteVaultMemory = useCallback5(
31013
31229
  async (id) => {
31230
+ if (memoryStore === null) throw new Error(MEMORY_STORE_NOT_READY);
31014
31231
  if (memoryStore) return memoryStore.delete(id);
31015
31232
  const existing = await getVaultMemoryOp(vaultCtx, id);
31016
31233
  const result = await deleteVaultMemoryOp(vaultCtx, id);
@@ -31024,7 +31241,7 @@ function useChatStorage(options) {
31024
31241
  const chunkVectorCacheRef = useRef4(createChunkVectorCache());
31025
31242
  const clientToolEmbeddingsCacheRef = useRef4(/* @__PURE__ */ new Map());
31026
31243
  useEffect4(() => {
31027
- if (!getToken || memoryStore) return;
31244
+ if (!getToken || memoryStore !== void 0) return;
31028
31245
  void (async () => {
31029
31246
  try {
31030
31247
  await preEmbedVaultMemories(vaultCtx, vaultEmbeddingOptions, vaultEmbeddingCache);
@@ -31040,6 +31257,7 @@ function useChatStorage(options) {
31040
31257
  }, [vaultEmbeddingCache]);
31041
31258
  const createMemoryVaultSearchTool2 = useCallback5(
31042
31259
  (searchOptions) => {
31260
+ if (memoryStore === null) throw new Error(MEMORY_STORE_NOT_READY);
31043
31261
  if (!getToken && !memoryStore) {
31044
31262
  throw new Error("getToken is required for memory vault search tool");
31045
31263
  }
@@ -31055,6 +31273,7 @@ function useChatStorage(options) {
31055
31273
  );
31056
31274
  const createRecallTool2 = useCallback5(
31057
31275
  (toolOptions, callbacks) => {
31276
+ if (memoryStore === null) throw new Error(MEMORY_STORE_NOT_READY);
31058
31277
  if (!getToken && !memoryStore) {
31059
31278
  throw new Error("getToken is required for recall tool");
31060
31279
  }
@@ -31094,6 +31313,7 @@ function useChatStorage(options) {
31094
31313
  );
31095
31314
  const searchVaultMemoriesFn = useCallback5(
31096
31315
  async (query, searchOptions) => {
31316
+ if (memoryStore === null) return [];
31097
31317
  if (storeMaskMissing) throw new Error(NO_STORE_MASK);
31098
31318
  if (memoryStore) return (await memoryStore.factSource.search(query, searchOptions)).results;
31099
31319
  if (!getToken) return [];
@@ -31109,7 +31329,7 @@ function useChatStorage(options) {
31109
31329
  );
31110
31330
  const recallFn = useCallback5(
31111
31331
  async (query, options2) => {
31112
- if (!getToken && !memoryStore) {
31332
+ if (memoryStore === null || !getToken && !memoryStore) {
31113
31333
  return {
31114
31334
  memories: [],
31115
31335
  usedBudget: options2?.budget ?? "low",