@anuma/sdk 7.0.6 → 7.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -26140,6 +26140,11 @@ function parseTopics(value) {
26140
26140
  }
26141
26141
 
26142
26142
  // src/lib/db/entities/operations.ts
26143
+ async function assertCanWrite(ctx) {
26144
+ if (ctx.canWrite && !await ctx.canWrite()) {
26145
+ throw new Error("Memory source is no longer eligible");
26146
+ }
26147
+ }
26143
26148
  function entityToStored(e) {
26144
26149
  return {
26145
26150
  uniqueId: e.id,
@@ -26280,6 +26285,7 @@ async function linkMemoryEntitiesOp(ctx, memoryId, entityInputs, options) {
26280
26285
  let skipped = false;
26281
26286
  let entities = [];
26282
26287
  await ctx.database.write(async () => {
26288
+ await assertCanWrite(ctx);
26283
26289
  const {
26284
26290
  entities: byName,
26285
26291
  operations: entityOps,
@@ -26355,6 +26361,7 @@ async function replaceMemoryEntities(ctx, memoryId, entityInputs, options) {
26355
26361
  let skipped = false;
26356
26362
  let entities = [];
26357
26363
  await ctx.database.write(async () => {
26364
+ await assertCanWrite(ctx);
26358
26365
  const vaultRow = await findVaultRowInWrite(ctx, memoryId);
26359
26366
  if (options.guarded && autoLinkBlocked(vaultRow)) {
26360
26367
  skipped = true;
@@ -26415,6 +26422,7 @@ async function unlinkMemoryEntitiesOp(ctx, memoryIds) {
26415
26422
  const links = await ctx.memoryEntityCollection.query(import_watermelondb18.Q.where("memory_id", import_watermelondb18.Q.oneOf(Array.from(memoryIds)))).fetch();
26416
26423
  if (links.length === 0) return;
26417
26424
  await ctx.database.write(async () => {
26425
+ await assertCanWrite(ctx);
26418
26426
  await ctx.database.batch(...links.map((l) => l.prepareDestroyPermanently()));
26419
26427
  });
26420
26428
  }
@@ -26423,6 +26431,7 @@ async function unlinkAllMemoryEntitiesForUserOp(ctx, userId) {
26423
26431
  const links = await ctx.memoryEntityCollection.query(import_watermelondb18.Q.where("user_id", userId)).fetch();
26424
26432
  if (links.length === 0) return;
26425
26433
  await ctx.database.write(async () => {
26434
+ await assertCanWrite(ctx);
26426
26435
  await ctx.database.batch(...links.map((l) => l.prepareDestroyPermanently()));
26427
26436
  });
26428
26437
  }
@@ -26514,6 +26523,17 @@ async function decryptVaultMemoryFields(memory, address, signMessage, embeddedWa
26514
26523
  };
26515
26524
  }
26516
26525
 
26526
+ // src/lib/db/memoryVault/sourceChunkIds.ts
26527
+ var MAX_SOURCE_CHUNK_IDS_BYTES = 16 << 10;
26528
+ var utf8 = new TextEncoder();
26529
+ function serializeSourceChunkIds(ids) {
26530
+ const sizes = ids.map((id) => utf8.encode(JSON.stringify(id)).length + 1);
26531
+ let total = sizes.reduce((sum, size) => sum + size, 1);
26532
+ let start = 0;
26533
+ while (total > MAX_SOURCE_CHUNK_IDS_BYTES && start < ids.length) total -= sizes[start++];
26534
+ return JSON.stringify(ids.slice(start));
26535
+ }
26536
+
26517
26537
  // src/lib/db/memoryVault/types.ts
26518
26538
  var MEMORY_KINDS = [
26519
26539
  "display_name",
@@ -26586,6 +26606,11 @@ function visibilityConditions(requested) {
26586
26606
  function isKinded(record) {
26587
26607
  return record.kind !== null && record.kind !== void 0;
26588
26608
  }
26609
+ async function assertCanWrite2(ctx) {
26610
+ if (ctx.canWrite && !await ctx.canWrite()) {
26611
+ throw new Error("Memory source is no longer eligible");
26612
+ }
26613
+ }
26589
26614
  function assertValidKindLevel(kind, level) {
26590
26615
  const hasKind = kind !== null && kind !== void 0;
26591
26616
  if (hasKind && !MEMORY_KINDS.includes(kind)) {
@@ -26732,7 +26757,7 @@ function populateNewVaultMemory(record, ctx, opts, encryptedContent, encryptedKi
26732
26757
  record._setRaw("embedding_model", opts.embeddingModel ?? null);
26733
26758
  }
26734
26759
  if (opts.sourceChunkIds !== void 0) {
26735
- record._setRaw("source_chunk_ids", JSON.stringify(opts.sourceChunkIds));
26760
+ record._setRaw("source_chunk_ids", serializeSourceChunkIds(opts.sourceChunkIds));
26736
26761
  }
26737
26762
  record._setRaw("proof_count", opts.proofCount ?? 1);
26738
26763
  record._setRaw("source", opts.source ?? "manual");
@@ -26766,8 +26791,7 @@ async function createVaultMemoryOp(ctx, opts) {
26766
26791
  ctx.embeddedWalletSigner
26767
26792
  ) : opts.content;
26768
26793
  const created = await ctx.database.write(async () => {
26769
- if (ctx.canWrite && !await ctx.canWrite())
26770
- throw new Error("Memory source is no longer eligible");
26794
+ await assertCanWrite2(ctx);
26771
26795
  return ctx.vaultMemoryCollection.create(
26772
26796
  (record) => populateNewVaultMemory(record, ctx, opts, encryptedContent, encryptedKindValue)
26773
26797
  );
@@ -26786,8 +26810,7 @@ async function createSupersedingMemoryOp(ctx, opts, targetId) {
26786
26810
  ) : opts.content;
26787
26811
  let createdRecord = null;
26788
26812
  await ctx.database.write(async () => {
26789
- if (ctx.canWrite && !await ctx.canWrite())
26790
- throw new Error("Memory source is no longer eligible");
26813
+ await assertCanWrite2(ctx);
26791
26814
  let target;
26792
26815
  try {
26793
26816
  target = await ctx.vaultMemoryCollection.find(targetId);
@@ -26879,8 +26902,7 @@ async function createVaultMemoriesBatchOp(ctx, optionsArray) {
26879
26902
  })
26880
26903
  );
26881
26904
  const created = await ctx.database.write(async () => {
26882
- if (ctx.canWrite && !await ctx.canWrite())
26883
- throw new Error("Memory source is no longer eligible");
26905
+ await assertCanWrite2(ctx);
26884
26906
  const prepared = optionsArray.map(
26885
26907
  (opts, i) => ctx.vaultMemoryCollection.prepareCreate(
26886
26908
  (record) => populateNewVaultMemory(record, ctx, opts, encryptedContents[i], encryptedKindValues[i])
@@ -27171,8 +27193,7 @@ async function updateVaultMemoryOp(ctx, id, opts) {
27171
27193
  const record = probe;
27172
27194
  const originalUpdatedAt = record.updatedAt.getTime();
27173
27195
  await ctx.database.write(async () => {
27174
- if (ctx.canWrite && !await ctx.canWrite())
27175
- throw new Error("Memory source is no longer eligible");
27196
+ await assertCanWrite2(ctx);
27176
27197
  if (record.isDeleted || record.supersededBy || !isOwnedByCtxUser(ctx, record) || opts.freeFormOnly && isKinded(record)) {
27177
27198
  stale = true;
27178
27199
  return;
@@ -27216,7 +27237,7 @@ async function updateVaultMemoryOp(ctx, id, opts) {
27216
27237
  if (opts.sourceChunkIds !== void 0) {
27217
27238
  r._setRaw(
27218
27239
  "source_chunk_ids",
27219
- JSON.stringify(
27240
+ serializeSourceChunkIds(
27220
27241
  opts.observationSourceIds?.length ? [.../* @__PURE__ */ new Set([...observedSources, ...opts.sourceChunkIds])] : opts.sourceChunkIds
27221
27242
  )
27222
27243
  );
@@ -27283,6 +27304,7 @@ async function setMemoryEntitiesOp(ctx, memoryId, entities) {
27283
27304
  let stale = false;
27284
27305
  const originalUpdatedAt = record.updatedAt.getTime();
27285
27306
  await ctx.database.write(async (writer) => {
27307
+ await assertCanWrite2(ctx);
27286
27308
  if (record.isDeleted || !isOwnedByCtxUser(ctx, record)) {
27287
27309
  stale = true;
27288
27310
  return;
@@ -27324,6 +27346,7 @@ async function clearMemoryTopicsOverrideOp(ctx, memoryId, options) {
27324
27346
  const originalUpdatedAt = record.updatedAt.getTime();
27325
27347
  let cleared = false;
27326
27348
  await ctx.database.write(async () => {
27349
+ await assertCanWrite2(ctx);
27327
27350
  if (options?.unlessTopicsRecorded && parseTopics(record.topics) !== null) return;
27328
27351
  cleared = true;
27329
27352
  await record.update((r) => {
@@ -27347,6 +27370,7 @@ async function setMemoryVisibilityOp(ctx, id, opts) {
27347
27370
  if (record.isDeleted || !isOwnedByCtxUser(ctx, record)) return null;
27348
27371
  let stale = false;
27349
27372
  await ctx.database.write(async () => {
27373
+ await assertCanWrite2(ctx);
27350
27374
  if (record.isDeleted || !isOwnedByCtxUser(ctx, record)) {
27351
27375
  stale = true;
27352
27376
  return;
@@ -27375,6 +27399,7 @@ async function deleteVaultMemoryOp(ctx, id) {
27375
27399
  if (record.isDeleted || !isOwnedByCtxUser(ctx, record)) return false;
27376
27400
  let stale = false;
27377
27401
  await ctx.database.write(async () => {
27402
+ await assertCanWrite2(ctx);
27378
27403
  if (record.isDeleted || !isOwnedByCtxUser(ctx, record)) {
27379
27404
  stale = true;
27380
27405
  return;
@@ -27412,8 +27437,7 @@ async function supersedeVaultMemoryOp(ctx, id, supersededById) {
27412
27437
  }
27413
27438
  let stale = false;
27414
27439
  await ctx.database.write(async () => {
27415
- if (ctx.canWrite && !await ctx.canWrite())
27416
- throw new Error("Memory source is no longer eligible");
27440
+ await assertCanWrite2(ctx);
27417
27441
  if (record.isDeleted || record.supersededBy || !isOwnedByCtxUser(ctx, record)) {
27418
27442
  stale = true;
27419
27443
  return;
@@ -27575,6 +27599,7 @@ async function stampTopicsExtractedAtOp(ctx, memoryIds, extractedAt, version = T
27575
27599
  for (let i = 0; i < uniqueIds.length; i += CHUNK) {
27576
27600
  const chunkIds = uniqueIds.slice(i, i + CHUNK);
27577
27601
  await ctx.database.write(async () => {
27602
+ await assertCanWrite2(ctx);
27578
27603
  const records = [];
27579
27604
  for (const id of chunkIds) {
27580
27605
  try {
@@ -27608,6 +27633,7 @@ async function relinkMemoryTopicsOp(ctx, memoryIds) {
27608
27633
  for (const id of Array.from(new Set(memoryIds))) {
27609
27634
  try {
27610
27635
  await ctx.database.write(async (writer) => {
27636
+ await assertCanWrite2(ctx);
27611
27637
  let record;
27612
27638
  try {
27613
27639
  record = await ctx.vaultMemoryCollection.find(id);
@@ -27638,6 +27664,7 @@ async function backfillMemoryTopicsOp(ctx, memoryIds) {
27638
27664
  for (let i = 0; i < uniqueIds.length; i += CHUNK) {
27639
27665
  const chunkIds = uniqueIds.slice(i, i + CHUNK);
27640
27666
  await ctx.database.write(async () => {
27667
+ await assertCanWrite2(ctx);
27641
27668
  const writes = [];
27642
27669
  for (const id of chunkIds) {
27643
27670
  let record;
@@ -27670,6 +27697,7 @@ async function deleteAllVaultMemoriesForUserOp(ctx, userId) {
27670
27697
  const records = await ctx.vaultMemoryCollection.query(import_watermelondb19.Q.where("user_id", userId), import_watermelondb19.Q.where("is_deleted", false)).fetch();
27671
27698
  if (records.length === 0) return 0;
27672
27699
  await ctx.database.write(async () => {
27700
+ await assertCanWrite2(ctx);
27673
27701
  const prepared = records.map(
27674
27702
  (record) => record.prepareUpdate((r) => {
27675
27703
  r._setRaw("is_deleted", true);
@@ -27724,6 +27752,7 @@ async function archiveVaultMemoryOp(ctx, id, opts) {
27724
27752
  let stale = false;
27725
27753
  const archivedAtValue = opts?.now ?? Date.now();
27726
27754
  await ctx.database.write(async () => {
27755
+ await assertCanWrite2(ctx);
27727
27756
  if (record.isDeleted || !isOwnedByCtxUser(ctx, record) || record.archivedAt !== null) {
27728
27757
  stale = true;
27729
27758
  return;
@@ -27747,6 +27776,7 @@ async function restoreVaultMemoryOp(ctx, id) {
27747
27776
  if (record.isDeleted || !isOwnedByCtxUser(ctx, record)) return false;
27748
27777
  let stale = false;
27749
27778
  await ctx.database.write(async () => {
27779
+ await assertCanWrite2(ctx);
27750
27780
  if (record.isDeleted || !isOwnedByCtxUser(ctx, record)) {
27751
27781
  stale = true;
27752
27782
  return;
@@ -27767,6 +27797,7 @@ async function hardDeleteDecayedOp(ctx, id, opts) {
27767
27797
  const now = opts.now ?? Date.now();
27768
27798
  let stale = false;
27769
27799
  await ctx.database.write(async () => {
27800
+ await assertCanWrite2(ctx);
27770
27801
  const archivedAt = record.archivedAt;
27771
27802
  if (record.isDeleted || !isOwnedByCtxUser(ctx, record) || archivedAt === null || now - archivedAt <= opts.hardDeleteWindowMs) {
27772
27803
  stale = true;
@@ -27806,6 +27837,7 @@ async function updateVaultMemoryEmbeddingOp(ctx, id, embedding, embeddingModel,
27806
27837
  }
27807
27838
  let written = false;
27808
27839
  await ctx.database.write(async () => {
27840
+ await assertCanWrite2(ctx);
27809
27841
  if (record.isDeleted || !isOwnedByCtxUser(ctx, record)) return;
27810
27842
  const originalUpdatedAt = record.updatedAt.getTime();
27811
27843
  if (originalUpdatedAt !== readUpdatedAt || record._getRaw("content") !== readStoredContent)
@@ -31477,6 +31509,13 @@ function restoreCandidates(candidates, redactor, ownNames) {
31477
31509
  ).map((c) => c.candidate);
31478
31510
  }
31479
31511
  async function extractAndRetain(messages, retainCtx, options) {
31512
+ const { memoryStore, signal } = options;
31513
+ if (memoryStore === null) throw new Error("Memory store is not ready");
31514
+ if (memoryStore && options.folderId !== void 0 && options.folderId !== null)
31515
+ throw new Error("Remote memory extraction does not support folders");
31516
+ if (memoryStore && options.extract.piiRedaction && !memoryStore.masksEmbeddingInput)
31517
+ throw new Error("PII-redacted extraction requires a memory store that masks embedding inputs");
31518
+ signal?.throwIfAborted();
31480
31519
  const minConfidence = options.minConfidence ?? DEFAULT_MIN_CONFIDENCE;
31481
31520
  const resolvedConsolidatePii = options.consolidateOptions?.piiRedaction ?? options.extract.piiRedaction;
31482
31521
  const consolidateOptions = options.consolidateOptions !== void 0 ? {
@@ -31510,6 +31549,7 @@ async function extractAndRetain(messages, retainCtx, options) {
31510
31549
  }
31511
31550
  });
31512
31551
  const extractMs = Date.now() - tExtract;
31552
+ signal?.throwIfAborted();
31513
31553
  const filtered = candidates.filter((c) => c.confidence >= minConfidence);
31514
31554
  const log = getLogger();
31515
31555
  const screened = screenCandidatesForInjection(filtered);
@@ -31557,16 +31597,33 @@ async function extractAndRetain(messages, retainCtx, options) {
31557
31597
  const results = [];
31558
31598
  const quarantinedInfo = [];
31559
31599
  let failedWrites = 0;
31600
+ let auditRows;
31560
31601
  const tRetain = Date.now();
31561
31602
  for (const { candidate, isQuarantined, reason, signature } of toRetain) {
31562
31603
  try {
31604
+ signal?.throwIfAborted();
31563
31605
  if (isQuarantined) {
31564
- const existingId = await findQuarantinedDuplicateOp(
31565
- retainCtx.vaultCtx,
31566
- candidate.content,
31567
- candidate.sourceMessageIds,
31568
- { scope: options.scope ?? "private", folderId: options.folderId ?? null }
31569
- ).catch(() => null);
31606
+ let existingId;
31607
+ if (memoryStore) {
31608
+ auditRows ?? (auditRows = memoryStore.list({
31609
+ scopes: [options.scope ?? "private"],
31610
+ includeArchived: true,
31611
+ includeQuarantined: true,
31612
+ includeSuperseded: true
31613
+ }));
31614
+ const sourceKey = [...new Set(candidate.sourceMessageIds)].sort().join("\0");
31615
+ const normalize = (value) => value.normalize("NFKC").trim().replace(/\s+/g, " ").toLowerCase();
31616
+ existingId = (await auditRows).find(
31617
+ (row) => row.trustTier === "quarantined" && row.scope === (options.scope ?? "private") && [...new Set(row.sourceChunkIds ?? [])].sort().join("\0") === sourceKey && normalize(row.content) === normalize(candidate.content)
31618
+ )?.uniqueId ?? null;
31619
+ } else {
31620
+ existingId = await findQuarantinedDuplicateOp(
31621
+ retainCtx.vaultCtx,
31622
+ candidate.content,
31623
+ candidate.sourceMessageIds,
31624
+ { scope: options.scope ?? "private", folderId: options.folderId ?? null }
31625
+ ).catch(() => null);
31626
+ }
31570
31627
  if (existingId) {
31571
31628
  quarantinedInfo.push({
31572
31629
  candidate,
@@ -31577,18 +31634,26 @@ async function extractAndRetain(messages, retainCtx, options) {
31577
31634
  continue;
31578
31635
  }
31579
31636
  }
31580
- const result = await retain(candidate.content, retainCtx, {
31637
+ const retainOptions = {
31581
31638
  source: "auto-extracted",
31582
31639
  sourceChunkIds: candidate.sourceMessageIds,
31583
31640
  respectTombstones: true,
31584
31641
  ...options.scope !== void 0 && { scope: options.scope },
31585
- ...options.folderId !== void 0 && { folderId: options.folderId },
31586
31642
  ...consolidateOptions !== void 0 && { consolidateOptions },
31587
31643
  ...candidate.eventTime !== null && { eventTime: candidate.eventTime },
31588
31644
  factType: candidate.type,
31589
31645
  ...isQuarantined && { trustTier: "quarantined", enableAutoMerge: false }
31646
+ };
31647
+ const result = memoryStore ? await memoryStore.retain(candidate.content, {
31648
+ ...retainOptions,
31649
+ canWrite: retainCtx.vaultCtx.canWrite,
31650
+ signal
31651
+ }) : await retain(candidate.content, retainCtx, {
31652
+ ...retainOptions,
31653
+ ...options.folderId !== void 0 && { folderId: options.folderId }
31590
31654
  });
31591
31655
  if (isQuarantined) {
31656
+ auditRows = void 0;
31592
31657
  const info = {
31593
31658
  candidate,
31594
31659
  memoryId: result.memoryId,
@@ -31607,9 +31672,16 @@ async function extractAndRetain(messages, retainCtx, options) {
31607
31672
  }
31608
31673
  succeededCandidates.push(candidate);
31609
31674
  results.push(result);
31610
- if (result.action !== "suppressed" && options.entityCtx && candidate.entities.length > 0) {
31675
+ if (result.action !== "suppressed" && candidate.entities.length > 0) {
31611
31676
  try {
31612
- if (!await isMemoryTopicsUserManaged(options.entityCtx, result.memoryId)) {
31677
+ signal?.throwIfAborted();
31678
+ if (memoryStore) {
31679
+ await memoryStore.addTopics(result.memoryId, candidate.entities, {
31680
+ unlessUserManaged: true,
31681
+ canWrite: retainCtx.vaultCtx.canWrite,
31682
+ signal
31683
+ });
31684
+ } else if (options.entityCtx && !await isMemoryTopicsUserManaged(options.entityCtx, result.memoryId)) {
31613
31685
  await linkMemoryEntitiesOp(options.entityCtx, result.memoryId, candidate.entities, {
31614
31686
  unlessTopicsUserManaged: true
31615
31687
  });
@@ -31857,7 +31929,7 @@ function createAutoExtractor(options) {
31857
31929
  };
31858
31930
  const consolidateOptions = options.consolidate ? { ...options.consolidate, ...subPassAuth(options.consolidate.baseUrl) } : void 0;
31859
31931
  const injectionClassifierOptions = options.injectionClassifier ? { ...options.injectionClassifier, ...subPassAuth(options.injectionClassifier.baseUrl) } : void 0;
31860
- if (options.retainCtx.vaultCtx.entityCtx && !options.entityCtx) {
31932
+ if (!options.memoryStore && options.retainCtx.vaultCtx.entityCtx && !options.entityCtx) {
31861
31933
  getLogger().warn(
31862
31934
  "[memory/extract] retainCtx.vaultCtx.entityCtx is set but extractor was created without `entityCtx` \u2014 W5 graph lane will receive no writes"
31863
31935
  );
@@ -31902,6 +31974,8 @@ function createAutoExtractor(options) {
31902
31974
  try {
31903
31975
  const { candidates, results, failedCount, outcome, failure, funnel, timings, model } = await extractAndRetain(window2, retainCtx, {
31904
31976
  extract,
31977
+ memoryStore: options.memoryStore,
31978
+ signal: options.signal,
31905
31979
  ...options.minConfidence !== void 0 && { minConfidence: options.minConfidence },
31906
31980
  ...options.entityCtx !== void 0 && { entityCtx: options.entityCtx },
31907
31981
  ...options.scope !== void 0 && { scope: options.scope },
@@ -34014,6 +34088,7 @@ function createLocalMemoryStore(options) {
34014
34088
  database,
34015
34089
  entityCollection: database.get("entity"),
34016
34090
  memoryEntityCollection: database.get("memory_entity"),
34091
+ canWrite: options.canWrite,
34017
34092
  ...userId !== void 0 && { userId },
34018
34093
  ...options.allowUnscopedRows !== void 0 && {
34019
34094
  allowUnscopedRows: options.allowUnscopedRows
@@ -34025,10 +34100,21 @@ function createLocalMemoryStore(options) {
34025
34100
  walletAddress: options.walletAddress,
34026
34101
  signMessage: options.signMessage,
34027
34102
  embeddedWalletSigner: options.embeddedWalletSigner,
34103
+ canWrite: options.canWrite,
34028
34104
  ...userId !== void 0 && { userId },
34029
34105
  ...options.singleTenant !== void 0 && { singleTenant: options.singleTenant },
34030
34106
  entityCtx
34031
34107
  };
34108
+ const assertWrite = async (writeOptions) => {
34109
+ writeOptions?.signal?.throwIfAborted();
34110
+ if (writeOptions?.canWrite && !await writeOptions.canWrite()) {
34111
+ throw new Error("Memory source is no longer eligible");
34112
+ }
34113
+ if (options.canWrite && !await options.canWrite()) {
34114
+ throw new Error("Memory source is no longer eligible");
34115
+ }
34116
+ writeOptions?.signal?.throwIfAborted();
34117
+ };
34032
34118
  const vaultCache = options.vaultCache ?? createVaultEmbeddingCache();
34033
34119
  const ownedBy = userId !== void 0 ? [import_watermelondb24.Q.where("user_id", userId)] : [];
34034
34120
  const linksOwnedBy = userId === void 0 ? [] : options.allowUnscopedRows ? [import_watermelondb24.Q.or(import_watermelondb24.Q.where("user_id", userId), import_watermelondb24.Q.where("user_id", null))] : [import_watermelondb24.Q.where("user_id", userId)];
@@ -34140,9 +34226,25 @@ function createLocalMemoryStore(options) {
34140
34226
  archive: (id) => archiveVaultMemoryOp(vaultCtx, id),
34141
34227
  restore: (id) => restoreVaultMemoryOp(vaultCtx, id),
34142
34228
  setTopics: (memoryId, topics) => setMemoryEntitiesOp(vaultCtx, memoryId, topics),
34143
- addTopics: (memoryId, topics) => database.write(async (writer) => {
34229
+ addTopics: (memoryId, topics, writeOptions) => database.write(async (writer) => {
34230
+ await assertWrite(writeOptions);
34144
34231
  const owned = await vaultCtx.vaultMemoryCollection.query(import_watermelondb24.Q.where("id", memoryId), import_watermelondb24.Q.where("is_deleted", false), ...ownedBy).fetchCount();
34145
- return owned > 0 ? writer.callWriter(() => linkMemoryEntitiesOp(entityCtx, memoryId, topics)) : [];
34232
+ return owned > 0 ? writer.callWriter(
34233
+ () => linkMemoryEntitiesOp(
34234
+ {
34235
+ ...entityCtx,
34236
+ canWrite: async () => {
34237
+ await assertWrite(writeOptions);
34238
+ return true;
34239
+ }
34240
+ },
34241
+ memoryId,
34242
+ topics,
34243
+ {
34244
+ unlessTopicsUserManaged: writeOptions?.unlessUserManaged
34245
+ }
34246
+ )
34247
+ ) : [];
34146
34248
  }),
34147
34249
  setVisibility: (id, visibility, visibilityOptions) => setMemoryVisibilityOp(vaultCtx, id, { visibility, ...visibilityOptions }),
34148
34250
  recall: (query, recallOptions) => recall(
@@ -34152,7 +34254,17 @@ function createLocalMemoryStore(options) {
34152
34254
  ),
34153
34255
  retain: (content, retainOptions) => retain(
34154
34256
  content,
34155
- { vaultCtx, embeddingOptions: options.embeddingOptions, vaultCache },
34257
+ {
34258
+ vaultCtx: {
34259
+ ...vaultCtx,
34260
+ canWrite: async () => {
34261
+ await assertWrite(retainOptions);
34262
+ return true;
34263
+ }
34264
+ },
34265
+ embeddingOptions: options.embeddingOptions,
34266
+ vaultCache
34267
+ },
34156
34268
  retainOptions
34157
34269
  ),
34158
34270
  factSource: {
@@ -35002,6 +35114,7 @@ function createDurableAutoExtractor(options) {
35002
35114
  };
35003
35115
  const folderId = options.folderId ?? null;
35004
35116
  let disposed = false;
35117
+ let activeBatch = null;
35005
35118
  let running = false;
35006
35119
  let wakeRequested = false;
35007
35120
  let timer;
@@ -35038,14 +35151,18 @@ function createDurableAutoExtractor(options) {
35038
35151
  }, delay);
35039
35152
  }
35040
35153
  async function extractBatch(messages, conversationId, ids, jobScope, jobFolderId) {
35154
+ if (disposed) throw new Error("Extraction session was disposed");
35041
35155
  let watchdog;
35042
35156
  let cancelled = false;
35157
+ const controller = new AbortController();
35158
+ activeBatch = controller;
35043
35159
  const model = options.modelForScope?.(jobScope) ?? options.extract.model;
35044
35160
  try {
35045
35161
  return await Promise.race([
35046
35162
  new Promise((resolve, reject) => {
35047
35163
  const worker = createAutoExtractor({
35048
35164
  ...options,
35165
+ signal: controller.signal,
35049
35166
  retainCtx: {
35050
35167
  ...options.retainCtx,
35051
35168
  vaultCtx: {
@@ -35074,6 +35191,8 @@ function createDurableAutoExtractor(options) {
35074
35191
  ]);
35075
35192
  } finally {
35076
35193
  cancelled = true;
35194
+ controller.abort();
35195
+ if (activeBatch === controller) activeBatch = null;
35077
35196
  if (watchdog !== void 0) clearTimeout(watchdog);
35078
35197
  }
35079
35198
  }
@@ -35085,6 +35204,7 @@ function createDurableAutoExtractor(options) {
35085
35204
  for (const message of loaded)
35086
35205
  if (message && message.messageId > 0) sequences.set(message.uniqueId, message.messageId);
35087
35206
  await database.write(async () => {
35207
+ if (disposed) return;
35088
35208
  const current = idsOf(job);
35089
35209
  const acknowledged = ids.filter((id) => current.includes(id));
35090
35210
  if (!acknowledged.length) return;
@@ -35257,6 +35377,7 @@ function createDurableAutoExtractor(options) {
35257
35377
  jobScope,
35258
35378
  jobFolderId
35259
35379
  );
35380
+ if (disposed) throw new Error("Extraction session was disposed");
35260
35381
  options.onTurnComplete?.(result);
35261
35382
  return result;
35262
35383
  };
@@ -35293,6 +35414,7 @@ function createDurableAutoExtractor(options) {
35293
35414
  );
35294
35415
  scheduleAfterSuccess = true;
35295
35416
  } catch (error) {
35417
+ if (disposed) break;
35296
35418
  attempts.set(job.id, attempted + 1);
35297
35419
  retry = true;
35298
35420
  reportError(error, conversationId);
@@ -35315,6 +35437,14 @@ function createDurableAutoExtractor(options) {
35315
35437
  schedule(retry ? options.retryDelayMs ?? 3e4 : 0);
35316
35438
  }
35317
35439
  }
35440
+ function dispose() {
35441
+ disposed = true;
35442
+ activeBatch?.abort(options.signal?.reason);
35443
+ if (timer !== void 0) clearTimeout(timer);
35444
+ options.signal?.removeEventListener("abort", dispose);
35445
+ }
35446
+ if (options.signal?.aborted) dispose();
35447
+ else options.signal?.addEventListener("abort", dispose, { once: true });
35318
35448
  schedule(0);
35319
35449
  return {
35320
35450
  processTurn(messages, conversationId) {
@@ -35394,10 +35524,7 @@ function createDurableAutoExtractor(options) {
35394
35524
  return true;
35395
35525
  },
35396
35526
  isProcessing: () => running,
35397
- dispose() {
35398
- disposed = true;
35399
- if (timer !== void 0) clearTimeout(timer);
35400
- }
35527
+ dispose
35401
35528
  };
35402
35529
  }
35403
35530
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@anuma/sdk",
3
- "version": "7.0.6",
3
+ "version": "7.1.0",
4
4
  "description": "",
5
5
  "main": "./dist/index.cjs",
6
6
  "module": "./dist/index.mjs",