@anuma/sdk 3.9.4 → 3.9.5

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.
@@ -5283,13 +5283,12 @@ async function buildProjectedCorpus(query, vaultCtx, embeddingOptions, cache, qu
5283
5283
  }));
5284
5284
  return { memories, embeddedItems, queryEmbedding, vaultSize };
5285
5285
  }
5286
- async function searchVaultMemoriesWithSize(query, vaultCtx, embeddingOptions, cache, searchOptions) {
5287
- const limit = searchOptions?.limit ?? 5;
5288
- const minSimilarity = searchOptions?.minSimilarity ?? 0.1;
5289
- const scopes = searchOptions?.scopes;
5286
+ async function prepareVaultCandidates(query, vaultCtx, embeddingOptions, cache, searchOptions) {
5290
5287
  if (!query || typeof query !== "string") {
5291
- return { results: [], vaultSize: 0, reranked: false, hadV2Head: false };
5288
+ return { memories: [], embeddedItems: [], queryEmbedding: [], vaultSize: 0 };
5292
5289
  }
5290
+ const limit = searchOptions?.limit ?? 5;
5291
+ const scopes = searchOptions?.scopes;
5293
5292
  const folderId = searchOptions?.folderId;
5294
5293
  const queryOpts = {};
5295
5294
  if (scopes?.length) queryOpts.scopes = scopes;
@@ -5316,11 +5315,11 @@ async function searchVaultMemoriesWithSize(query, vaultCtx, embeddingOptions, ca
5316
5315
  ...forceIncludeIds.length > 0 && { forceIncludeIds }
5317
5316
  });
5318
5317
  if (corpus.vaultSize === 0) {
5319
- return { results: [], vaultSize: 0, reranked: false, hadV2Head: false };
5318
+ return { memories: [], embeddedItems: [], queryEmbedding: [], vaultSize: 0 };
5320
5319
  }
5321
5320
  ({ memories, embeddedItems, queryEmbedding, vaultSize } = corpus);
5322
5321
  if (memories.length === 0) {
5323
- return { results: [], vaultSize, reranked: false, hadV2Head: false };
5322
+ return { memories: [], embeddedItems: [], queryEmbedding: [], vaultSize };
5324
5323
  }
5325
5324
  } else {
5326
5325
  const loaded = await getAllVaultMemoriesOp(
@@ -5335,7 +5334,7 @@ async function searchVaultMemoriesWithSize(query, vaultCtx, embeddingOptions, ca
5335
5334
  );
5336
5335
  }
5337
5336
  if (memories.length === 0) {
5338
- return { results: [], vaultSize: loaded.length, reranked: false, hadV2Head: false };
5337
+ return { memories: [], embeddedItems: [], queryEmbedding: [], vaultSize: loaded.length };
5339
5338
  }
5340
5339
  queryEmbedding = await generateEmbedding(query, embeddingOptions);
5341
5340
  const currentModel = embeddingOptions.model ?? DEFAULT_API_EMBEDDING_MODEL;
@@ -5400,6 +5399,12 @@ async function searchVaultMemoriesWithSize(query, vaultCtx, embeddingOptions, ca
5400
5399
  factType: m.factType
5401
5400
  }));
5402
5401
  }
5402
+ return { memories, embeddedItems, queryEmbedding, vaultSize };
5403
+ }
5404
+ async function rankPreparedVaultCandidates(query, prepared, embeddingOptions, searchOptions) {
5405
+ const limit = searchOptions?.limit ?? 5;
5406
+ const minSimilarity = searchOptions?.minSimilarity ?? 0.1;
5407
+ const { memories, embeddedItems, queryEmbedding, vaultSize } = prepared;
5403
5408
  if (queryEmbedding.length > 0) {
5404
5409
  const mismatched = embeddedItems.filter(
5405
5410
  (it) => it.embedding.length > 0 && it.embedding.length !== queryEmbedding.length
@@ -5537,6 +5542,25 @@ async function searchVaultMemoriesWithSize(query, vaultCtx, embeddingOptions, ca
5537
5542
  });
5538
5543
  return stampTimestamps({ results, vaultSize, hadV2Head: results.length > 0 });
5539
5544
  }
5545
+ async function searchVaultMemoriesWithSize(query, vaultCtx, embeddingOptions, cache, searchOptions) {
5546
+ if (!query || typeof query !== "string") {
5547
+ return { results: [], vaultSize: 0, reranked: false, hadV2Head: false };
5548
+ }
5549
+ const prepared = await prepareVaultCandidates(
5550
+ query,
5551
+ vaultCtx,
5552
+ embeddingOptions,
5553
+ cache,
5554
+ searchOptions
5555
+ );
5556
+ if (prepared.vaultSize === 0) {
5557
+ return { results: [], vaultSize: 0, reranked: false, hadV2Head: false };
5558
+ }
5559
+ if (prepared.memories.length === 0) {
5560
+ return { results: [], vaultSize: prepared.vaultSize, reranked: false, hadV2Head: false };
5561
+ }
5562
+ return rankPreparedVaultCandidates(query, prepared, embeddingOptions, searchOptions);
5563
+ }
5540
5564
  async function searchVaultMemories(query, vaultCtx, embeddingOptions, cache, searchOptions) {
5541
5565
  const { results } = await searchVaultMemoriesWithSize(
5542
5566
  query,
@@ -5624,7 +5648,7 @@ function createMemoryVaultSearchTool(vaultCtx, embeddingOptions, cache, searchOp
5624
5648
  legacy.map((r) => ({ id: r.uniqueId, content: r.content, score: r.similarity }))
5625
5649
  );
5626
5650
  }
5627
- const { recall: recall2 } = await import("./recall-XGRLGIEH.mjs");
5651
+ const { recall: recall2 } = await import("./recall-I5AZFOUM.mjs");
5628
5652
  const result = await recall2(
5629
5653
  query,
5630
5654
  { vaultCtx, embeddingOptions, vaultCache: cache },
@@ -6638,6 +6662,8 @@ export {
6638
6662
  recall,
6639
6663
  preEmbedVaultMemories,
6640
6664
  eagerEmbedContent,
6665
+ prepareVaultCandidates,
6666
+ rankPreparedVaultCandidates,
6641
6667
  searchVaultMemories,
6642
6668
  createMemoryVaultSearchTool
6643
6669
  };
@@ -7432,13 +7432,12 @@ async function buildProjectedCorpus(query, vaultCtx, embeddingOptions, cache, qu
7432
7432
  }));
7433
7433
  return { memories, embeddedItems, queryEmbedding, vaultSize };
7434
7434
  }
7435
- async function searchVaultMemoriesWithSize(query, vaultCtx, embeddingOptions, cache, searchOptions) {
7436
- const limit = searchOptions?.limit ?? 5;
7437
- const minSimilarity = searchOptions?.minSimilarity ?? 0.1;
7438
- const scopes = searchOptions?.scopes;
7435
+ async function prepareVaultCandidates(query, vaultCtx, embeddingOptions, cache, searchOptions) {
7439
7436
  if (!query || typeof query !== "string") {
7440
- return { results: [], vaultSize: 0, reranked: false, hadV2Head: false };
7437
+ return { memories: [], embeddedItems: [], queryEmbedding: [], vaultSize: 0 };
7441
7438
  }
7439
+ const limit = searchOptions?.limit ?? 5;
7440
+ const scopes = searchOptions?.scopes;
7442
7441
  const folderId = searchOptions?.folderId;
7443
7442
  const queryOpts = {};
7444
7443
  if (scopes?.length) queryOpts.scopes = scopes;
@@ -7465,11 +7464,11 @@ async function searchVaultMemoriesWithSize(query, vaultCtx, embeddingOptions, ca
7465
7464
  ...forceIncludeIds.length > 0 && { forceIncludeIds }
7466
7465
  });
7467
7466
  if (corpus.vaultSize === 0) {
7468
- return { results: [], vaultSize: 0, reranked: false, hadV2Head: false };
7467
+ return { memories: [], embeddedItems: [], queryEmbedding: [], vaultSize: 0 };
7469
7468
  }
7470
7469
  ({ memories, embeddedItems, queryEmbedding, vaultSize } = corpus);
7471
7470
  if (memories.length === 0) {
7472
- return { results: [], vaultSize, reranked: false, hadV2Head: false };
7471
+ return { memories: [], embeddedItems: [], queryEmbedding: [], vaultSize };
7473
7472
  }
7474
7473
  } else {
7475
7474
  const loaded = await getAllVaultMemoriesOp(
@@ -7484,7 +7483,7 @@ async function searchVaultMemoriesWithSize(query, vaultCtx, embeddingOptions, ca
7484
7483
  );
7485
7484
  }
7486
7485
  if (memories.length === 0) {
7487
- return { results: [], vaultSize: loaded.length, reranked: false, hadV2Head: false };
7486
+ return { memories: [], embeddedItems: [], queryEmbedding: [], vaultSize: loaded.length };
7488
7487
  }
7489
7488
  queryEmbedding = await generateEmbedding(query, embeddingOptions);
7490
7489
  const currentModel = embeddingOptions.model ?? DEFAULT_API_EMBEDDING_MODEL;
@@ -7549,6 +7548,12 @@ async function searchVaultMemoriesWithSize(query, vaultCtx, embeddingOptions, ca
7549
7548
  factType: m.factType
7550
7549
  }));
7551
7550
  }
7551
+ return { memories, embeddedItems, queryEmbedding, vaultSize };
7552
+ }
7553
+ async function rankPreparedVaultCandidates(query, prepared, embeddingOptions, searchOptions) {
7554
+ const limit = searchOptions?.limit ?? 5;
7555
+ const minSimilarity = searchOptions?.minSimilarity ?? 0.1;
7556
+ const { memories, embeddedItems, queryEmbedding, vaultSize } = prepared;
7552
7557
  if (queryEmbedding.length > 0) {
7553
7558
  const mismatched = embeddedItems.filter(
7554
7559
  (it) => it.embedding.length > 0 && it.embedding.length !== queryEmbedding.length
@@ -7686,6 +7691,25 @@ async function searchVaultMemoriesWithSize(query, vaultCtx, embeddingOptions, ca
7686
7691
  });
7687
7692
  return stampTimestamps({ results, vaultSize, hadV2Head: results.length > 0 });
7688
7693
  }
7694
+ async function searchVaultMemoriesWithSize(query, vaultCtx, embeddingOptions, cache, searchOptions) {
7695
+ if (!query || typeof query !== "string") {
7696
+ return { results: [], vaultSize: 0, reranked: false, hadV2Head: false };
7697
+ }
7698
+ const prepared = await prepareVaultCandidates(
7699
+ query,
7700
+ vaultCtx,
7701
+ embeddingOptions,
7702
+ cache,
7703
+ searchOptions
7704
+ );
7705
+ if (prepared.vaultSize === 0) {
7706
+ return { results: [], vaultSize: 0, reranked: false, hadV2Head: false };
7707
+ }
7708
+ if (prepared.memories.length === 0) {
7709
+ return { results: [], vaultSize: prepared.vaultSize, reranked: false, hadV2Head: false };
7710
+ }
7711
+ return rankPreparedVaultCandidates(query, prepared, embeddingOptions, searchOptions);
7712
+ }
7689
7713
  async function searchVaultMemories(query, vaultCtx, embeddingOptions, cache, searchOptions) {
7690
7714
  const { results } = await searchVaultMemoriesWithSize(
7691
7715
  query,
@@ -14483,9 +14507,25 @@ async function retain(content, ctx, options = {}) {
14483
14507
  const resolvedScope = options.scope ?? DEFAULT_SCOPE;
14484
14508
  let supersedeTargetIds = [];
14485
14509
  let supersedeContent;
14510
+ let prepared;
14486
14511
  if (enableAutoMerge) {
14512
+ prepared = await prepareVaultCandidates(
14513
+ trimmed,
14514
+ ctx.vaultCtx,
14515
+ ctx.embeddingOptions,
14516
+ ctx.vaultCache,
14517
+ {
14518
+ limit: Math.max(options.consolidateTopK ?? DEFAULT_CONSOLIDATE_TOP_K, 1),
14519
+ useFusion: false,
14520
+ scopes: [resolvedScope],
14521
+ // PR5 — include archived rows as merge candidates so a re-observed fact
14522
+ // resurrects (un-archives) the decayed row instead of duplicating it.
14523
+ includeArchived: true,
14524
+ ...options.folderId !== void 0 && { folderId: options.folderId }
14525
+ }
14526
+ );
14487
14527
  if (options.consolidateOptions) {
14488
- const outcome = await tryConsolidate(trimmed, ctx, options);
14528
+ const outcome = await tryConsolidate(trimmed, ctx, options, prepared);
14489
14529
  if (outcome) {
14490
14530
  if ("done" in outcome) return outcome.done;
14491
14531
  supersedeTargetIds = outcome.supersede;
@@ -14493,23 +14533,14 @@ async function retain(content, ctx, options = {}) {
14493
14533
  }
14494
14534
  }
14495
14535
  if (supersedeTargetIds.length === 0) {
14496
- const matches = await searchVaultMemories(
14536
+ const { results: matches } = await rankPreparedVaultCandidates(
14497
14537
  trimmed,
14498
- ctx.vaultCtx,
14538
+ prepared,
14499
14539
  ctx.embeddingOptions,
14500
- ctx.vaultCache,
14501
14540
  {
14502
14541
  limit: 1,
14503
14542
  minSimilarity: threshold,
14504
- useFusion: false,
14505
- scopes: [resolvedScope],
14506
- // PR5 — include archived rows as merge candidates so a re-observed
14507
- // fact resurrects (un-archives) the decayed row instead of creating a
14508
- // fresh duplicate. The resurrection is applied on the merge write
14509
- // below, but ONLY for a row that is not superseded/deleted (the
14510
- // guards below preserve main's tombstone/supersession suppression).
14511
- includeArchived: true,
14512
- ...options.folderId !== void 0 && { folderId: options.folderId }
14543
+ useFusion: false
14513
14544
  }
14514
14545
  );
14515
14546
  if (matches.length > 0) {
@@ -14557,7 +14588,8 @@ async function retain(content, ctx, options = {}) {
14557
14588
  }
14558
14589
  }
14559
14590
  const contentToWrite = supersedeContent ?? trimmed;
14560
- const embedding = await generateEmbedding(contentToWrite, ctx.embeddingOptions);
14591
+ const reusableQueryEmbedding = supersedeContent === void 0 && prepared && prepared.queryEmbedding.length > 0 ? prepared.queryEmbedding : void 0;
14592
+ const embedding = reusableQueryEmbedding ?? await generateEmbedding(contentToWrite, ctx.embeddingOptions);
14561
14593
  const embeddingModel = ctx.embeddingOptions.model ?? DEFAULT_API_EMBEDDING_MODEL;
14562
14594
  if (options.respectTombstones) {
14563
14595
  const tombstoneId = await findTombstoneMatch(embedding, embeddingModel, resolvedScope, ctx, {
@@ -14686,26 +14718,19 @@ function pickFactTypeUpdate(existing, incoming) {
14686
14718
  function resurrectFields(existing) {
14687
14719
  return typeof existing.archivedAt === "number" ? { restore: true } : { preserveUpdatedAt: true };
14688
14720
  }
14689
- async function tryConsolidate(trimmed, ctx, options) {
14721
+ async function tryConsolidate(trimmed, ctx, options, prepared) {
14690
14722
  const consolidateOptions = options.consolidateOptions;
14691
14723
  if (!consolidateOptions) return null;
14692
14724
  const consolidateThreshold = options.consolidateThreshold ?? DEFAULT_CONSOLIDATE_THRESHOLD;
14693
14725
  const topK = options.consolidateTopK ?? DEFAULT_CONSOLIDATE_TOP_K;
14694
- const resolvedScope = options.scope ?? DEFAULT_SCOPE;
14695
- const matches = await searchVaultMemories(
14726
+ const { results: matches } = await rankPreparedVaultCandidates(
14696
14727
  trimmed,
14697
- ctx.vaultCtx,
14728
+ prepared,
14698
14729
  ctx.embeddingOptions,
14699
- ctx.vaultCache,
14700
14730
  {
14701
14731
  limit: topK,
14702
14732
  minSimilarity: consolidateThreshold,
14703
- useFusion: false,
14704
- scopes: [resolvedScope],
14705
- // PR5 — archived rows are consolidation candidates too, so a paraphrased
14706
- // re-observation resurrects a decayed row rather than duplicating it.
14707
- includeArchived: true,
14708
- ...options.folderId !== void 0 && { folderId: options.folderId }
14733
+ useFusion: false
14709
14734
  }
14710
14735
  );
14711
14736
  if (matches.length === 0) return null;
@@ -85,6 +85,8 @@ import {
85
85
  onKeyAvailable,
86
86
  postApiV1CreditsPurchase,
87
87
  preEmbedVaultMemories,
88
+ prepareVaultCandidates,
89
+ rankPreparedVaultCandidates,
88
90
  recall,
89
91
  replaceMemoryEntitiesGuardedOp,
90
92
  requestEncryptionKey,
@@ -108,7 +110,7 @@ import {
108
110
  upsertMessageOp,
109
111
  useEncryption,
110
112
  vaultMemoryToStored
111
- } from "./chunk-4VXLX7SL.mjs";
113
+ } from "./chunk-HXBDHRKJ.mjs";
112
114
  import {
113
115
  PII_PATTERNS,
114
116
  PiiRedactor,
@@ -6364,9 +6366,25 @@ async function retain(content, ctx, options = {}) {
6364
6366
  const resolvedScope = options.scope ?? DEFAULT_SCOPE;
6365
6367
  let supersedeTargetIds = [];
6366
6368
  let supersedeContent;
6369
+ let prepared;
6367
6370
  if (enableAutoMerge) {
6371
+ prepared = await prepareVaultCandidates(
6372
+ trimmed,
6373
+ ctx.vaultCtx,
6374
+ ctx.embeddingOptions,
6375
+ ctx.vaultCache,
6376
+ {
6377
+ limit: Math.max(options.consolidateTopK ?? DEFAULT_CONSOLIDATE_TOP_K, 1),
6378
+ useFusion: false,
6379
+ scopes: [resolvedScope],
6380
+ // PR5 — include archived rows as merge candidates so a re-observed fact
6381
+ // resurrects (un-archives) the decayed row instead of duplicating it.
6382
+ includeArchived: true,
6383
+ ...options.folderId !== void 0 && { folderId: options.folderId }
6384
+ }
6385
+ );
6368
6386
  if (options.consolidateOptions) {
6369
- const outcome = await tryConsolidate(trimmed, ctx, options);
6387
+ const outcome = await tryConsolidate(trimmed, ctx, options, prepared);
6370
6388
  if (outcome) {
6371
6389
  if ("done" in outcome) return outcome.done;
6372
6390
  supersedeTargetIds = outcome.supersede;
@@ -6374,23 +6392,14 @@ async function retain(content, ctx, options = {}) {
6374
6392
  }
6375
6393
  }
6376
6394
  if (supersedeTargetIds.length === 0) {
6377
- const matches = await searchVaultMemories(
6395
+ const { results: matches } = await rankPreparedVaultCandidates(
6378
6396
  trimmed,
6379
- ctx.vaultCtx,
6397
+ prepared,
6380
6398
  ctx.embeddingOptions,
6381
- ctx.vaultCache,
6382
6399
  {
6383
6400
  limit: 1,
6384
6401
  minSimilarity: threshold,
6385
- useFusion: false,
6386
- scopes: [resolvedScope],
6387
- // PR5 — include archived rows as merge candidates so a re-observed
6388
- // fact resurrects (un-archives) the decayed row instead of creating a
6389
- // fresh duplicate. The resurrection is applied on the merge write
6390
- // below, but ONLY for a row that is not superseded/deleted (the
6391
- // guards below preserve main's tombstone/supersession suppression).
6392
- includeArchived: true,
6393
- ...options.folderId !== void 0 && { folderId: options.folderId }
6402
+ useFusion: false
6394
6403
  }
6395
6404
  );
6396
6405
  if (matches.length > 0) {
@@ -6438,7 +6447,8 @@ async function retain(content, ctx, options = {}) {
6438
6447
  }
6439
6448
  }
6440
6449
  const contentToWrite = supersedeContent ?? trimmed;
6441
- const embedding = await generateEmbedding(contentToWrite, ctx.embeddingOptions);
6450
+ const reusableQueryEmbedding = supersedeContent === void 0 && prepared && prepared.queryEmbedding.length > 0 ? prepared.queryEmbedding : void 0;
6451
+ const embedding = reusableQueryEmbedding ?? await generateEmbedding(contentToWrite, ctx.embeddingOptions);
6442
6452
  const embeddingModel = ctx.embeddingOptions.model ?? DEFAULT_API_EMBEDDING_MODEL;
6443
6453
  if (options.respectTombstones) {
6444
6454
  const tombstoneId = await findTombstoneMatch(embedding, embeddingModel, resolvedScope, ctx, {
@@ -6567,26 +6577,19 @@ function pickFactTypeUpdate(existing, incoming) {
6567
6577
  function resurrectFields(existing) {
6568
6578
  return typeof existing.archivedAt === "number" ? { restore: true } : { preserveUpdatedAt: true };
6569
6579
  }
6570
- async function tryConsolidate(trimmed, ctx, options) {
6580
+ async function tryConsolidate(trimmed, ctx, options, prepared) {
6571
6581
  const consolidateOptions = options.consolidateOptions;
6572
6582
  if (!consolidateOptions) return null;
6573
6583
  const consolidateThreshold = options.consolidateThreshold ?? DEFAULT_CONSOLIDATE_THRESHOLD;
6574
6584
  const topK = options.consolidateTopK ?? DEFAULT_CONSOLIDATE_TOP_K;
6575
- const resolvedScope = options.scope ?? DEFAULT_SCOPE;
6576
- const matches = await searchVaultMemories(
6585
+ const { results: matches } = await rankPreparedVaultCandidates(
6577
6586
  trimmed,
6578
- ctx.vaultCtx,
6587
+ prepared,
6579
6588
  ctx.embeddingOptions,
6580
- ctx.vaultCache,
6581
6589
  {
6582
6590
  limit: topK,
6583
6591
  minSimilarity: consolidateThreshold,
6584
- useFusion: false,
6585
- scopes: [resolvedScope],
6586
- // PR5 — archived rows are consolidation candidates too, so a paraphrased
6587
- // re-observation resurrects a decayed row rather than duplicating it.
6588
- includeArchived: true,
6589
- ...options.folderId !== void 0 && { folderId: options.folderId }
6592
+ useFusion: false
6590
6593
  }
6591
6594
  );
6592
6595
  if (matches.length === 0) return null;
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  recall
3
- } from "./chunk-4VXLX7SL.mjs";
3
+ } from "./chunk-HXBDHRKJ.mjs";
4
4
  import "./chunk-BOY27A2C.mjs";
5
5
  import "./chunk-GYKJOWEO.mjs";
6
6
  export {
@@ -5584,13 +5584,12 @@ async function buildProjectedCorpus(query, vaultCtx, embeddingOptions, cache, qu
5584
5584
  }));
5585
5585
  return { memories, embeddedItems, queryEmbedding, vaultSize };
5586
5586
  }
5587
- async function searchVaultMemoriesWithSize(query, vaultCtx, embeddingOptions, cache, searchOptions) {
5588
- const limit = searchOptions?.limit ?? 5;
5589
- const minSimilarity = searchOptions?.minSimilarity ?? 0.1;
5590
- const scopes = searchOptions?.scopes;
5587
+ async function prepareVaultCandidates(query, vaultCtx, embeddingOptions, cache, searchOptions) {
5591
5588
  if (!query || typeof query !== "string") {
5592
- return { results: [], vaultSize: 0, reranked: false, hadV2Head: false };
5589
+ return { memories: [], embeddedItems: [], queryEmbedding: [], vaultSize: 0 };
5593
5590
  }
5591
+ const limit = searchOptions?.limit ?? 5;
5592
+ const scopes = searchOptions?.scopes;
5594
5593
  const folderId = searchOptions?.folderId;
5595
5594
  const queryOpts = {};
5596
5595
  if (scopes?.length) queryOpts.scopes = scopes;
@@ -5617,11 +5616,11 @@ async function searchVaultMemoriesWithSize(query, vaultCtx, embeddingOptions, ca
5617
5616
  ...forceIncludeIds.length > 0 && { forceIncludeIds }
5618
5617
  });
5619
5618
  if (corpus.vaultSize === 0) {
5620
- return { results: [], vaultSize: 0, reranked: false, hadV2Head: false };
5619
+ return { memories: [], embeddedItems: [], queryEmbedding: [], vaultSize: 0 };
5621
5620
  }
5622
5621
  ({ memories, embeddedItems, queryEmbedding, vaultSize } = corpus);
5623
5622
  if (memories.length === 0) {
5624
- return { results: [], vaultSize, reranked: false, hadV2Head: false };
5623
+ return { memories: [], embeddedItems: [], queryEmbedding: [], vaultSize };
5625
5624
  }
5626
5625
  } else {
5627
5626
  const loaded = await getAllVaultMemoriesOp(
@@ -5636,7 +5635,7 @@ async function searchVaultMemoriesWithSize(query, vaultCtx, embeddingOptions, ca
5636
5635
  );
5637
5636
  }
5638
5637
  if (memories.length === 0) {
5639
- return { results: [], vaultSize: loaded.length, reranked: false, hadV2Head: false };
5638
+ return { memories: [], embeddedItems: [], queryEmbedding: [], vaultSize: loaded.length };
5640
5639
  }
5641
5640
  queryEmbedding = await generateEmbedding(query, embeddingOptions);
5642
5641
  const currentModel = embeddingOptions.model ?? DEFAULT_API_EMBEDDING_MODEL;
@@ -5701,6 +5700,12 @@ async function searchVaultMemoriesWithSize(query, vaultCtx, embeddingOptions, ca
5701
5700
  factType: m.factType
5702
5701
  }));
5703
5702
  }
5703
+ return { memories, embeddedItems, queryEmbedding, vaultSize };
5704
+ }
5705
+ async function rankPreparedVaultCandidates(query, prepared, embeddingOptions, searchOptions) {
5706
+ const limit = searchOptions?.limit ?? 5;
5707
+ const minSimilarity = searchOptions?.minSimilarity ?? 0.1;
5708
+ const { memories, embeddedItems, queryEmbedding, vaultSize } = prepared;
5704
5709
  if (queryEmbedding.length > 0) {
5705
5710
  const mismatched = embeddedItems.filter(
5706
5711
  (it) => it.embedding.length > 0 && it.embedding.length !== queryEmbedding.length
@@ -5838,6 +5843,25 @@ async function searchVaultMemoriesWithSize(query, vaultCtx, embeddingOptions, ca
5838
5843
  });
5839
5844
  return stampTimestamps({ results, vaultSize, hadV2Head: results.length > 0 });
5840
5845
  }
5846
+ async function searchVaultMemoriesWithSize(query, vaultCtx, embeddingOptions, cache, searchOptions) {
5847
+ if (!query || typeof query !== "string") {
5848
+ return { results: [], vaultSize: 0, reranked: false, hadV2Head: false };
5849
+ }
5850
+ const prepared = await prepareVaultCandidates(
5851
+ query,
5852
+ vaultCtx,
5853
+ embeddingOptions,
5854
+ cache,
5855
+ searchOptions
5856
+ );
5857
+ if (prepared.vaultSize === 0) {
5858
+ return { results: [], vaultSize: 0, reranked: false, hadV2Head: false };
5859
+ }
5860
+ if (prepared.memories.length === 0) {
5861
+ return { results: [], vaultSize: prepared.vaultSize, reranked: false, hadV2Head: false };
5862
+ }
5863
+ return rankPreparedVaultCandidates(query, prepared, embeddingOptions, searchOptions);
5864
+ }
5841
5865
  async function searchVaultMemories(query, vaultCtx, embeddingOptions, cache, searchOptions) {
5842
5866
  const { results } = await searchVaultMemoriesWithSize(
5843
5867
  query,
@@ -5925,7 +5949,7 @@ function createMemoryVaultSearchTool(vaultCtx, embeddingOptions, cache, searchOp
5925
5949
  legacy.map((r) => ({ id: r.uniqueId, content: r.content, score: r.similarity }))
5926
5950
  );
5927
5951
  }
5928
- const { recall: recall2 } = await import("./recall-F33QYRYU.mjs");
5952
+ const { recall: recall2 } = await import("./recall-7NVXMANO.mjs");
5929
5953
  const result = await recall2(
5930
5954
  query,
5931
5955
  { vaultCtx, embeddingOptions, vaultCache: cache },
@@ -6984,6 +7008,8 @@ export {
6984
7008
  recall,
6985
7009
  preEmbedVaultMemories,
6986
7010
  eagerEmbedContent,
7011
+ prepareVaultCandidates,
7012
+ rankPreparedVaultCandidates,
6987
7013
  searchVaultMemories,
6988
7014
  createMemoryVaultSearchTool
6989
7015
  };
@@ -7733,13 +7733,12 @@ async function buildProjectedCorpus(query, vaultCtx, embeddingOptions, cache, qu
7733
7733
  }));
7734
7734
  return { memories, embeddedItems, queryEmbedding, vaultSize };
7735
7735
  }
7736
- async function searchVaultMemoriesWithSize(query, vaultCtx, embeddingOptions, cache, searchOptions) {
7737
- const limit = searchOptions?.limit ?? 5;
7738
- const minSimilarity = searchOptions?.minSimilarity ?? 0.1;
7739
- const scopes = searchOptions?.scopes;
7736
+ async function prepareVaultCandidates(query, vaultCtx, embeddingOptions, cache, searchOptions) {
7740
7737
  if (!query || typeof query !== "string") {
7741
- return { results: [], vaultSize: 0, reranked: false, hadV2Head: false };
7738
+ return { memories: [], embeddedItems: [], queryEmbedding: [], vaultSize: 0 };
7742
7739
  }
7740
+ const limit = searchOptions?.limit ?? 5;
7741
+ const scopes = searchOptions?.scopes;
7743
7742
  const folderId = searchOptions?.folderId;
7744
7743
  const queryOpts = {};
7745
7744
  if (scopes?.length) queryOpts.scopes = scopes;
@@ -7766,11 +7765,11 @@ async function searchVaultMemoriesWithSize(query, vaultCtx, embeddingOptions, ca
7766
7765
  ...forceIncludeIds.length > 0 && { forceIncludeIds }
7767
7766
  });
7768
7767
  if (corpus.vaultSize === 0) {
7769
- return { results: [], vaultSize: 0, reranked: false, hadV2Head: false };
7768
+ return { memories: [], embeddedItems: [], queryEmbedding: [], vaultSize: 0 };
7770
7769
  }
7771
7770
  ({ memories, embeddedItems, queryEmbedding, vaultSize } = corpus);
7772
7771
  if (memories.length === 0) {
7773
- return { results: [], vaultSize, reranked: false, hadV2Head: false };
7772
+ return { memories: [], embeddedItems: [], queryEmbedding: [], vaultSize };
7774
7773
  }
7775
7774
  } else {
7776
7775
  const loaded = await getAllVaultMemoriesOp(
@@ -7785,7 +7784,7 @@ async function searchVaultMemoriesWithSize(query, vaultCtx, embeddingOptions, ca
7785
7784
  );
7786
7785
  }
7787
7786
  if (memories.length === 0) {
7788
- return { results: [], vaultSize: loaded.length, reranked: false, hadV2Head: false };
7787
+ return { memories: [], embeddedItems: [], queryEmbedding: [], vaultSize: loaded.length };
7789
7788
  }
7790
7789
  queryEmbedding = await generateEmbedding(query, embeddingOptions);
7791
7790
  const currentModel = embeddingOptions.model ?? DEFAULT_API_EMBEDDING_MODEL;
@@ -7850,6 +7849,12 @@ async function searchVaultMemoriesWithSize(query, vaultCtx, embeddingOptions, ca
7850
7849
  factType: m.factType
7851
7850
  }));
7852
7851
  }
7852
+ return { memories, embeddedItems, queryEmbedding, vaultSize };
7853
+ }
7854
+ async function rankPreparedVaultCandidates(query, prepared, embeddingOptions, searchOptions) {
7855
+ const limit = searchOptions?.limit ?? 5;
7856
+ const minSimilarity = searchOptions?.minSimilarity ?? 0.1;
7857
+ const { memories, embeddedItems, queryEmbedding, vaultSize } = prepared;
7853
7858
  if (queryEmbedding.length > 0) {
7854
7859
  const mismatched = embeddedItems.filter(
7855
7860
  (it) => it.embedding.length > 0 && it.embedding.length !== queryEmbedding.length
@@ -7987,6 +7992,25 @@ async function searchVaultMemoriesWithSize(query, vaultCtx, embeddingOptions, ca
7987
7992
  });
7988
7993
  return stampTimestamps({ results, vaultSize, hadV2Head: results.length > 0 });
7989
7994
  }
7995
+ async function searchVaultMemoriesWithSize(query, vaultCtx, embeddingOptions, cache, searchOptions) {
7996
+ if (!query || typeof query !== "string") {
7997
+ return { results: [], vaultSize: 0, reranked: false, hadV2Head: false };
7998
+ }
7999
+ const prepared = await prepareVaultCandidates(
8000
+ query,
8001
+ vaultCtx,
8002
+ embeddingOptions,
8003
+ cache,
8004
+ searchOptions
8005
+ );
8006
+ if (prepared.vaultSize === 0) {
8007
+ return { results: [], vaultSize: 0, reranked: false, hadV2Head: false };
8008
+ }
8009
+ if (prepared.memories.length === 0) {
8010
+ return { results: [], vaultSize: prepared.vaultSize, reranked: false, hadV2Head: false };
8011
+ }
8012
+ return rankPreparedVaultCandidates(query, prepared, embeddingOptions, searchOptions);
8013
+ }
7990
8014
  async function searchVaultMemories(query, vaultCtx, embeddingOptions, cache, searchOptions) {
7991
8015
  const { results } = await searchVaultMemoriesWithSize(
7992
8016
  query,
@@ -15800,9 +15824,25 @@ async function retain(content, ctx, options = {}) {
15800
15824
  const resolvedScope = options.scope ?? DEFAULT_SCOPE;
15801
15825
  let supersedeTargetIds = [];
15802
15826
  let supersedeContent;
15827
+ let prepared;
15803
15828
  if (enableAutoMerge) {
15829
+ prepared = await prepareVaultCandidates(
15830
+ trimmed,
15831
+ ctx.vaultCtx,
15832
+ ctx.embeddingOptions,
15833
+ ctx.vaultCache,
15834
+ {
15835
+ limit: Math.max(options.consolidateTopK ?? DEFAULT_CONSOLIDATE_TOP_K, 1),
15836
+ useFusion: false,
15837
+ scopes: [resolvedScope],
15838
+ // PR5 — include archived rows as merge candidates so a re-observed fact
15839
+ // resurrects (un-archives) the decayed row instead of duplicating it.
15840
+ includeArchived: true,
15841
+ ...options.folderId !== void 0 && { folderId: options.folderId }
15842
+ }
15843
+ );
15804
15844
  if (options.consolidateOptions) {
15805
- const outcome = await tryConsolidate(trimmed, ctx, options);
15845
+ const outcome = await tryConsolidate(trimmed, ctx, options, prepared);
15806
15846
  if (outcome) {
15807
15847
  if ("done" in outcome) return outcome.done;
15808
15848
  supersedeTargetIds = outcome.supersede;
@@ -15810,23 +15850,14 @@ async function retain(content, ctx, options = {}) {
15810
15850
  }
15811
15851
  }
15812
15852
  if (supersedeTargetIds.length === 0) {
15813
- const matches = await searchVaultMemories(
15853
+ const { results: matches } = await rankPreparedVaultCandidates(
15814
15854
  trimmed,
15815
- ctx.vaultCtx,
15855
+ prepared,
15816
15856
  ctx.embeddingOptions,
15817
- ctx.vaultCache,
15818
15857
  {
15819
15858
  limit: 1,
15820
15859
  minSimilarity: threshold,
15821
- useFusion: false,
15822
- scopes: [resolvedScope],
15823
- // PR5 — include archived rows as merge candidates so a re-observed
15824
- // fact resurrects (un-archives) the decayed row instead of creating a
15825
- // fresh duplicate. The resurrection is applied on the merge write
15826
- // below, but ONLY for a row that is not superseded/deleted (the
15827
- // guards below preserve main's tombstone/supersession suppression).
15828
- includeArchived: true,
15829
- ...options.folderId !== void 0 && { folderId: options.folderId }
15860
+ useFusion: false
15830
15861
  }
15831
15862
  );
15832
15863
  if (matches.length > 0) {
@@ -15874,7 +15905,8 @@ async function retain(content, ctx, options = {}) {
15874
15905
  }
15875
15906
  }
15876
15907
  const contentToWrite = supersedeContent ?? trimmed;
15877
- const embedding = await generateEmbedding(contentToWrite, ctx.embeddingOptions);
15908
+ const reusableQueryEmbedding = supersedeContent === void 0 && prepared && prepared.queryEmbedding.length > 0 ? prepared.queryEmbedding : void 0;
15909
+ const embedding = reusableQueryEmbedding ?? await generateEmbedding(contentToWrite, ctx.embeddingOptions);
15878
15910
  const embeddingModel = ctx.embeddingOptions.model ?? DEFAULT_API_EMBEDDING_MODEL;
15879
15911
  if (options.respectTombstones) {
15880
15912
  const tombstoneId = await findTombstoneMatch(embedding, embeddingModel, resolvedScope, ctx, {
@@ -16003,26 +16035,19 @@ function pickFactTypeUpdate(existing, incoming) {
16003
16035
  function resurrectFields(existing) {
16004
16036
  return typeof existing.archivedAt === "number" ? { restore: true } : { preserveUpdatedAt: true };
16005
16037
  }
16006
- async function tryConsolidate(trimmed, ctx, options) {
16038
+ async function tryConsolidate(trimmed, ctx, options, prepared) {
16007
16039
  const consolidateOptions = options.consolidateOptions;
16008
16040
  if (!consolidateOptions) return null;
16009
16041
  const consolidateThreshold = options.consolidateThreshold ?? DEFAULT_CONSOLIDATE_THRESHOLD;
16010
16042
  const topK = options.consolidateTopK ?? DEFAULT_CONSOLIDATE_TOP_K;
16011
- const resolvedScope = options.scope ?? DEFAULT_SCOPE;
16012
- const matches = await searchVaultMemories(
16043
+ const { results: matches } = await rankPreparedVaultCandidates(
16013
16044
  trimmed,
16014
- ctx.vaultCtx,
16045
+ prepared,
16015
16046
  ctx.embeddingOptions,
16016
- ctx.vaultCache,
16017
16047
  {
16018
16048
  limit: topK,
16019
16049
  minSimilarity: consolidateThreshold,
16020
- useFusion: false,
16021
- scopes: [resolvedScope],
16022
- // PR5 — archived rows are consolidation candidates too, so a paraphrased
16023
- // re-observation resurrects a decayed row rather than duplicating it.
16024
- includeArchived: true,
16025
- ...options.folderId !== void 0 && { folderId: options.folderId }
16050
+ useFusion: false
16026
16051
  }
16027
16052
  );
16028
16053
  if (matches.length === 0) return null;
@@ -125,6 +125,8 @@ import {
125
125
  postAuthOauthByProviderRefresh,
126
126
  postAuthOauthByProviderRevoke,
127
127
  preEmbedVaultMemories,
128
+ prepareVaultCandidates,
129
+ rankPreparedVaultCandidates,
128
130
  recall,
129
131
  replaceMemoryEntitiesGuardedOp,
130
132
  requestEncryptionKey,
@@ -153,7 +155,7 @@ import {
153
155
  updateVaultMemoryOp,
154
156
  useEncryption,
155
157
  vaultMemoryToStored
156
- } from "./chunk-P5ED24DP.mjs";
158
+ } from "./chunk-IWR7BNER.mjs";
157
159
  import {
158
160
  PiiRedactor,
159
161
  createStreamingDeAnonymizer,
@@ -7181,9 +7183,25 @@ async function retain(content, ctx, options = {}) {
7181
7183
  const resolvedScope = options.scope ?? DEFAULT_SCOPE;
7182
7184
  let supersedeTargetIds = [];
7183
7185
  let supersedeContent;
7186
+ let prepared;
7184
7187
  if (enableAutoMerge) {
7188
+ prepared = await prepareVaultCandidates(
7189
+ trimmed,
7190
+ ctx.vaultCtx,
7191
+ ctx.embeddingOptions,
7192
+ ctx.vaultCache,
7193
+ {
7194
+ limit: Math.max(options.consolidateTopK ?? DEFAULT_CONSOLIDATE_TOP_K, 1),
7195
+ useFusion: false,
7196
+ scopes: [resolvedScope],
7197
+ // PR5 — include archived rows as merge candidates so a re-observed fact
7198
+ // resurrects (un-archives) the decayed row instead of duplicating it.
7199
+ includeArchived: true,
7200
+ ...options.folderId !== void 0 && { folderId: options.folderId }
7201
+ }
7202
+ );
7185
7203
  if (options.consolidateOptions) {
7186
- const outcome = await tryConsolidate(trimmed, ctx, options);
7204
+ const outcome = await tryConsolidate(trimmed, ctx, options, prepared);
7187
7205
  if (outcome) {
7188
7206
  if ("done" in outcome) return outcome.done;
7189
7207
  supersedeTargetIds = outcome.supersede;
@@ -7191,23 +7209,14 @@ async function retain(content, ctx, options = {}) {
7191
7209
  }
7192
7210
  }
7193
7211
  if (supersedeTargetIds.length === 0) {
7194
- const matches = await searchVaultMemories(
7212
+ const { results: matches } = await rankPreparedVaultCandidates(
7195
7213
  trimmed,
7196
- ctx.vaultCtx,
7214
+ prepared,
7197
7215
  ctx.embeddingOptions,
7198
- ctx.vaultCache,
7199
7216
  {
7200
7217
  limit: 1,
7201
7218
  minSimilarity: threshold,
7202
- useFusion: false,
7203
- scopes: [resolvedScope],
7204
- // PR5 — include archived rows as merge candidates so a re-observed
7205
- // fact resurrects (un-archives) the decayed row instead of creating a
7206
- // fresh duplicate. The resurrection is applied on the merge write
7207
- // below, but ONLY for a row that is not superseded/deleted (the
7208
- // guards below preserve main's tombstone/supersession suppression).
7209
- includeArchived: true,
7210
- ...options.folderId !== void 0 && { folderId: options.folderId }
7219
+ useFusion: false
7211
7220
  }
7212
7221
  );
7213
7222
  if (matches.length > 0) {
@@ -7255,7 +7264,8 @@ async function retain(content, ctx, options = {}) {
7255
7264
  }
7256
7265
  }
7257
7266
  const contentToWrite = supersedeContent ?? trimmed;
7258
- const embedding = await generateEmbedding(contentToWrite, ctx.embeddingOptions);
7267
+ const reusableQueryEmbedding = supersedeContent === void 0 && prepared && prepared.queryEmbedding.length > 0 ? prepared.queryEmbedding : void 0;
7268
+ const embedding = reusableQueryEmbedding ?? await generateEmbedding(contentToWrite, ctx.embeddingOptions);
7259
7269
  const embeddingModel = ctx.embeddingOptions.model ?? DEFAULT_API_EMBEDDING_MODEL;
7260
7270
  if (options.respectTombstones) {
7261
7271
  const tombstoneId = await findTombstoneMatch(embedding, embeddingModel, resolvedScope, ctx, {
@@ -7384,26 +7394,19 @@ function pickFactTypeUpdate(existing, incoming) {
7384
7394
  function resurrectFields(existing) {
7385
7395
  return typeof existing.archivedAt === "number" ? { restore: true } : { preserveUpdatedAt: true };
7386
7396
  }
7387
- async function tryConsolidate(trimmed, ctx, options) {
7397
+ async function tryConsolidate(trimmed, ctx, options, prepared) {
7388
7398
  const consolidateOptions = options.consolidateOptions;
7389
7399
  if (!consolidateOptions) return null;
7390
7400
  const consolidateThreshold = options.consolidateThreshold ?? DEFAULT_CONSOLIDATE_THRESHOLD;
7391
7401
  const topK = options.consolidateTopK ?? DEFAULT_CONSOLIDATE_TOP_K;
7392
- const resolvedScope = options.scope ?? DEFAULT_SCOPE;
7393
- const matches = await searchVaultMemories(
7402
+ const { results: matches } = await rankPreparedVaultCandidates(
7394
7403
  trimmed,
7395
- ctx.vaultCtx,
7404
+ prepared,
7396
7405
  ctx.embeddingOptions,
7397
- ctx.vaultCache,
7398
7406
  {
7399
7407
  limit: topK,
7400
7408
  minSimilarity: consolidateThreshold,
7401
- useFusion: false,
7402
- scopes: [resolvedScope],
7403
- // PR5 — archived rows are consolidation candidates too, so a paraphrased
7404
- // re-observation resurrects a decayed row rather than duplicating it.
7405
- includeArchived: true,
7406
- ...options.folderId !== void 0 && { folderId: options.folderId }
7409
+ useFusion: false
7407
7410
  }
7408
7411
  );
7409
7412
  if (matches.length === 0) return null;
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  recall
3
- } from "./chunk-P5ED24DP.mjs";
3
+ } from "./chunk-IWR7BNER.mjs";
4
4
  import "./chunk-BOY27A2C.mjs";
5
5
  import "./chunk-GYKJOWEO.mjs";
6
6
  export {
@@ -19474,13 +19474,12 @@ async function buildProjectedCorpus(query, vaultCtx, embeddingOptions, cache, qu
19474
19474
  }));
19475
19475
  return { memories, embeddedItems, queryEmbedding, vaultSize };
19476
19476
  }
19477
- async function searchVaultMemoriesWithSize(query, vaultCtx, embeddingOptions, cache, searchOptions) {
19478
- const limit = searchOptions?.limit ?? 5;
19479
- const minSimilarity = searchOptions?.minSimilarity ?? 0.1;
19480
- const scopes = searchOptions?.scopes;
19477
+ async function prepareVaultCandidates(query, vaultCtx, embeddingOptions, cache, searchOptions) {
19481
19478
  if (!query || typeof query !== "string") {
19482
- return { results: [], vaultSize: 0, reranked: false, hadV2Head: false };
19479
+ return { memories: [], embeddedItems: [], queryEmbedding: [], vaultSize: 0 };
19483
19480
  }
19481
+ const limit = searchOptions?.limit ?? 5;
19482
+ const scopes = searchOptions?.scopes;
19484
19483
  const folderId = searchOptions?.folderId;
19485
19484
  const queryOpts = {};
19486
19485
  if (scopes?.length) queryOpts.scopes = scopes;
@@ -19507,11 +19506,11 @@ async function searchVaultMemoriesWithSize(query, vaultCtx, embeddingOptions, ca
19507
19506
  ...forceIncludeIds.length > 0 && { forceIncludeIds }
19508
19507
  });
19509
19508
  if (corpus.vaultSize === 0) {
19510
- return { results: [], vaultSize: 0, reranked: false, hadV2Head: false };
19509
+ return { memories: [], embeddedItems: [], queryEmbedding: [], vaultSize: 0 };
19511
19510
  }
19512
19511
  ({ memories, embeddedItems, queryEmbedding, vaultSize } = corpus);
19513
19512
  if (memories.length === 0) {
19514
- return { results: [], vaultSize, reranked: false, hadV2Head: false };
19513
+ return { memories: [], embeddedItems: [], queryEmbedding: [], vaultSize };
19515
19514
  }
19516
19515
  } else {
19517
19516
  const loaded = await getAllVaultMemoriesOp(
@@ -19526,7 +19525,7 @@ async function searchVaultMemoriesWithSize(query, vaultCtx, embeddingOptions, ca
19526
19525
  );
19527
19526
  }
19528
19527
  if (memories.length === 0) {
19529
- return { results: [], vaultSize: loaded.length, reranked: false, hadV2Head: false };
19528
+ return { memories: [], embeddedItems: [], queryEmbedding: [], vaultSize: loaded.length };
19530
19529
  }
19531
19530
  queryEmbedding = await generateEmbedding(query, embeddingOptions);
19532
19531
  const currentModel = embeddingOptions.model ?? DEFAULT_API_EMBEDDING_MODEL;
@@ -19591,6 +19590,12 @@ async function searchVaultMemoriesWithSize(query, vaultCtx, embeddingOptions, ca
19591
19590
  factType: m.factType
19592
19591
  }));
19593
19592
  }
19593
+ return { memories, embeddedItems, queryEmbedding, vaultSize };
19594
+ }
19595
+ async function rankPreparedVaultCandidates(query, prepared, embeddingOptions, searchOptions) {
19596
+ const limit = searchOptions?.limit ?? 5;
19597
+ const minSimilarity = searchOptions?.minSimilarity ?? 0.1;
19598
+ const { memories, embeddedItems, queryEmbedding, vaultSize } = prepared;
19594
19599
  if (queryEmbedding.length > 0) {
19595
19600
  const mismatched = embeddedItems.filter(
19596
19601
  (it) => it.embedding.length > 0 && it.embedding.length !== queryEmbedding.length
@@ -19728,6 +19733,25 @@ async function searchVaultMemoriesWithSize(query, vaultCtx, embeddingOptions, ca
19728
19733
  });
19729
19734
  return stampTimestamps({ results, vaultSize, hadV2Head: results.length > 0 });
19730
19735
  }
19736
+ async function searchVaultMemoriesWithSize(query, vaultCtx, embeddingOptions, cache, searchOptions) {
19737
+ if (!query || typeof query !== "string") {
19738
+ return { results: [], vaultSize: 0, reranked: false, hadV2Head: false };
19739
+ }
19740
+ const prepared = await prepareVaultCandidates(
19741
+ query,
19742
+ vaultCtx,
19743
+ embeddingOptions,
19744
+ cache,
19745
+ searchOptions
19746
+ );
19747
+ if (prepared.vaultSize === 0) {
19748
+ return { results: [], vaultSize: 0, reranked: false, hadV2Head: false };
19749
+ }
19750
+ if (prepared.memories.length === 0) {
19751
+ return { results: [], vaultSize: prepared.vaultSize, reranked: false, hadV2Head: false };
19752
+ }
19753
+ return rankPreparedVaultCandidates(query, prepared, embeddingOptions, searchOptions);
19754
+ }
19731
19755
  async function searchVaultMemories(query, vaultCtx, embeddingOptions, cache, searchOptions) {
19732
19756
  const { results } = await searchVaultMemoriesWithSize(
19733
19757
  query,
@@ -19815,7 +19839,7 @@ function createMemoryVaultSearchTool(vaultCtx, embeddingOptions, cache, searchOp
19815
19839
  legacy.map((r) => ({ id: r.uniqueId, content: r.content, score: r.similarity }))
19816
19840
  );
19817
19841
  }
19818
- const { recall: recall2 } = await import("./recall-23VTTAEG.mjs");
19842
+ const { recall: recall2 } = await import("./recall-RVRZ4RQT.mjs");
19819
19843
  const result = await recall2(
19820
19844
  query,
19821
19845
  { vaultCtx, embeddingOptions, vaultCache: cache },
@@ -20846,6 +20870,8 @@ export {
20846
20870
  recall,
20847
20871
  preEmbedVaultMemories,
20848
20872
  eagerEmbedContent,
20873
+ prepareVaultCandidates,
20874
+ rankPreparedVaultCandidates,
20849
20875
  searchVaultMemories,
20850
20876
  createMemoryVaultSearchTool
20851
20877
  };
@@ -21605,13 +21605,12 @@ async function buildProjectedCorpus(query, vaultCtx, embeddingOptions, cache, qu
21605
21605
  }));
21606
21606
  return { memories, embeddedItems, queryEmbedding, vaultSize };
21607
21607
  }
21608
- async function searchVaultMemoriesWithSize(query, vaultCtx, embeddingOptions, cache, searchOptions) {
21609
- const limit = searchOptions?.limit ?? 5;
21610
- const minSimilarity = searchOptions?.minSimilarity ?? 0.1;
21611
- const scopes = searchOptions?.scopes;
21608
+ async function prepareVaultCandidates(query, vaultCtx, embeddingOptions, cache, searchOptions) {
21612
21609
  if (!query || typeof query !== "string") {
21613
- return { results: [], vaultSize: 0, reranked: false, hadV2Head: false };
21610
+ return { memories: [], embeddedItems: [], queryEmbedding: [], vaultSize: 0 };
21614
21611
  }
21612
+ const limit = searchOptions?.limit ?? 5;
21613
+ const scopes = searchOptions?.scopes;
21615
21614
  const folderId = searchOptions?.folderId;
21616
21615
  const queryOpts = {};
21617
21616
  if (scopes?.length) queryOpts.scopes = scopes;
@@ -21638,11 +21637,11 @@ async function searchVaultMemoriesWithSize(query, vaultCtx, embeddingOptions, ca
21638
21637
  ...forceIncludeIds.length > 0 && { forceIncludeIds }
21639
21638
  });
21640
21639
  if (corpus.vaultSize === 0) {
21641
- return { results: [], vaultSize: 0, reranked: false, hadV2Head: false };
21640
+ return { memories: [], embeddedItems: [], queryEmbedding: [], vaultSize: 0 };
21642
21641
  }
21643
21642
  ({ memories, embeddedItems, queryEmbedding, vaultSize } = corpus);
21644
21643
  if (memories.length === 0) {
21645
- return { results: [], vaultSize, reranked: false, hadV2Head: false };
21644
+ return { memories: [], embeddedItems: [], queryEmbedding: [], vaultSize };
21646
21645
  }
21647
21646
  } else {
21648
21647
  const loaded = await getAllVaultMemoriesOp(
@@ -21657,7 +21656,7 @@ async function searchVaultMemoriesWithSize(query, vaultCtx, embeddingOptions, ca
21657
21656
  );
21658
21657
  }
21659
21658
  if (memories.length === 0) {
21660
- return { results: [], vaultSize: loaded.length, reranked: false, hadV2Head: false };
21659
+ return { memories: [], embeddedItems: [], queryEmbedding: [], vaultSize: loaded.length };
21661
21660
  }
21662
21661
  queryEmbedding = await generateEmbedding(query, embeddingOptions);
21663
21662
  const currentModel = embeddingOptions.model ?? DEFAULT_API_EMBEDDING_MODEL;
@@ -21722,6 +21721,12 @@ async function searchVaultMemoriesWithSize(query, vaultCtx, embeddingOptions, ca
21722
21721
  factType: m.factType
21723
21722
  }));
21724
21723
  }
21724
+ return { memories, embeddedItems, queryEmbedding, vaultSize };
21725
+ }
21726
+ async function rankPreparedVaultCandidates(query, prepared, embeddingOptions, searchOptions) {
21727
+ const limit = searchOptions?.limit ?? 5;
21728
+ const minSimilarity = searchOptions?.minSimilarity ?? 0.1;
21729
+ const { memories, embeddedItems, queryEmbedding, vaultSize } = prepared;
21725
21730
  if (queryEmbedding.length > 0) {
21726
21731
  const mismatched = embeddedItems.filter(
21727
21732
  (it) => it.embedding.length > 0 && it.embedding.length !== queryEmbedding.length
@@ -21859,6 +21864,25 @@ async function searchVaultMemoriesWithSize(query, vaultCtx, embeddingOptions, ca
21859
21864
  });
21860
21865
  return stampTimestamps({ results, vaultSize, hadV2Head: results.length > 0 });
21861
21866
  }
21867
+ async function searchVaultMemoriesWithSize(query, vaultCtx, embeddingOptions, cache, searchOptions) {
21868
+ if (!query || typeof query !== "string") {
21869
+ return { results: [], vaultSize: 0, reranked: false, hadV2Head: false };
21870
+ }
21871
+ const prepared = await prepareVaultCandidates(
21872
+ query,
21873
+ vaultCtx,
21874
+ embeddingOptions,
21875
+ cache,
21876
+ searchOptions
21877
+ );
21878
+ if (prepared.vaultSize === 0) {
21879
+ return { results: [], vaultSize: 0, reranked: false, hadV2Head: false };
21880
+ }
21881
+ if (prepared.memories.length === 0) {
21882
+ return { results: [], vaultSize: prepared.vaultSize, reranked: false, hadV2Head: false };
21883
+ }
21884
+ return rankPreparedVaultCandidates(query, prepared, embeddingOptions, searchOptions);
21885
+ }
21862
21886
  async function searchVaultMemories(query, vaultCtx, embeddingOptions, cache, searchOptions) {
21863
21887
  const { results } = await searchVaultMemoriesWithSize(
21864
21888
  query,
@@ -27639,9 +27663,25 @@ async function retain(content, ctx, options = {}) {
27639
27663
  const resolvedScope = options.scope ?? DEFAULT_SCOPE;
27640
27664
  let supersedeTargetIds = [];
27641
27665
  let supersedeContent;
27666
+ let prepared;
27642
27667
  if (enableAutoMerge) {
27668
+ prepared = await prepareVaultCandidates(
27669
+ trimmed,
27670
+ ctx.vaultCtx,
27671
+ ctx.embeddingOptions,
27672
+ ctx.vaultCache,
27673
+ {
27674
+ limit: Math.max(options.consolidateTopK ?? DEFAULT_CONSOLIDATE_TOP_K, 1),
27675
+ useFusion: false,
27676
+ scopes: [resolvedScope],
27677
+ // PR5 — include archived rows as merge candidates so a re-observed fact
27678
+ // resurrects (un-archives) the decayed row instead of duplicating it.
27679
+ includeArchived: true,
27680
+ ...options.folderId !== void 0 && { folderId: options.folderId }
27681
+ }
27682
+ );
27643
27683
  if (options.consolidateOptions) {
27644
- const outcome = await tryConsolidate(trimmed, ctx, options);
27684
+ const outcome = await tryConsolidate(trimmed, ctx, options, prepared);
27645
27685
  if (outcome) {
27646
27686
  if ("done" in outcome) return outcome.done;
27647
27687
  supersedeTargetIds = outcome.supersede;
@@ -27649,23 +27689,14 @@ async function retain(content, ctx, options = {}) {
27649
27689
  }
27650
27690
  }
27651
27691
  if (supersedeTargetIds.length === 0) {
27652
- const matches = await searchVaultMemories(
27692
+ const { results: matches } = await rankPreparedVaultCandidates(
27653
27693
  trimmed,
27654
- ctx.vaultCtx,
27694
+ prepared,
27655
27695
  ctx.embeddingOptions,
27656
- ctx.vaultCache,
27657
27696
  {
27658
27697
  limit: 1,
27659
27698
  minSimilarity: threshold,
27660
- useFusion: false,
27661
- scopes: [resolvedScope],
27662
- // PR5 — include archived rows as merge candidates so a re-observed
27663
- // fact resurrects (un-archives) the decayed row instead of creating a
27664
- // fresh duplicate. The resurrection is applied on the merge write
27665
- // below, but ONLY for a row that is not superseded/deleted (the
27666
- // guards below preserve main's tombstone/supersession suppression).
27667
- includeArchived: true,
27668
- ...options.folderId !== void 0 && { folderId: options.folderId }
27699
+ useFusion: false
27669
27700
  }
27670
27701
  );
27671
27702
  if (matches.length > 0) {
@@ -27713,7 +27744,8 @@ async function retain(content, ctx, options = {}) {
27713
27744
  }
27714
27745
  }
27715
27746
  const contentToWrite = supersedeContent ?? trimmed;
27716
- const embedding = await generateEmbedding(contentToWrite, ctx.embeddingOptions);
27747
+ const reusableQueryEmbedding = supersedeContent === void 0 && prepared && prepared.queryEmbedding.length > 0 ? prepared.queryEmbedding : void 0;
27748
+ const embedding = reusableQueryEmbedding ?? await generateEmbedding(contentToWrite, ctx.embeddingOptions);
27717
27749
  const embeddingModel = ctx.embeddingOptions.model ?? DEFAULT_API_EMBEDDING_MODEL;
27718
27750
  if (options.respectTombstones) {
27719
27751
  const tombstoneId = await findTombstoneMatch(embedding, embeddingModel, resolvedScope, ctx, {
@@ -27842,26 +27874,19 @@ function pickFactTypeUpdate(existing, incoming) {
27842
27874
  function resurrectFields(existing) {
27843
27875
  return typeof existing.archivedAt === "number" ? { restore: true } : { preserveUpdatedAt: true };
27844
27876
  }
27845
- async function tryConsolidate(trimmed, ctx, options) {
27877
+ async function tryConsolidate(trimmed, ctx, options, prepared) {
27846
27878
  const consolidateOptions = options.consolidateOptions;
27847
27879
  if (!consolidateOptions) return null;
27848
27880
  const consolidateThreshold = options.consolidateThreshold ?? DEFAULT_CONSOLIDATE_THRESHOLD;
27849
27881
  const topK = options.consolidateTopK ?? DEFAULT_CONSOLIDATE_TOP_K;
27850
- const resolvedScope = options.scope ?? DEFAULT_SCOPE;
27851
- const matches = await searchVaultMemories(
27882
+ const { results: matches } = await rankPreparedVaultCandidates(
27852
27883
  trimmed,
27853
- ctx.vaultCtx,
27884
+ prepared,
27854
27885
  ctx.embeddingOptions,
27855
- ctx.vaultCache,
27856
27886
  {
27857
27887
  limit: topK,
27858
27888
  minSimilarity: consolidateThreshold,
27859
- useFusion: false,
27860
- scopes: [resolvedScope],
27861
- // PR5 — archived rows are consolidation candidates too, so a paraphrased
27862
- // re-observation resurrects a decayed row rather than duplicating it.
27863
- includeArchived: true,
27864
- ...options.folderId !== void 0 && { folderId: options.folderId }
27889
+ useFusion: false
27865
27890
  }
27866
27891
  );
27867
27892
  if (matches.length === 0) return null;
@@ -88,6 +88,8 @@ import {
88
88
  onClearAllEncryptionState,
89
89
  onKeyAvailable,
90
90
  preEmbedVaultMemories,
91
+ prepareVaultCandidates,
92
+ rankPreparedVaultCandidates,
91
93
  recall,
92
94
  replaceMemoryEntitiesGuardedOp,
93
95
  requestEncryptionKey,
@@ -125,7 +127,7 @@ import {
125
127
  updateVaultMemoryOp,
126
128
  upsertMessageOp,
127
129
  vaultMemoryToStored
128
- } from "./chunk-FJFPCJRI.mjs";
130
+ } from "./chunk-UU2F523R.mjs";
129
131
  import {
130
132
  createStreamingDeAnonymizer,
131
133
  resolvePiiRedactor
@@ -5265,9 +5267,25 @@ async function retain(content, ctx, options = {}) {
5265
5267
  const resolvedScope = options.scope ?? DEFAULT_SCOPE;
5266
5268
  let supersedeTargetIds = [];
5267
5269
  let supersedeContent;
5270
+ let prepared;
5268
5271
  if (enableAutoMerge) {
5272
+ prepared = await prepareVaultCandidates(
5273
+ trimmed,
5274
+ ctx.vaultCtx,
5275
+ ctx.embeddingOptions,
5276
+ ctx.vaultCache,
5277
+ {
5278
+ limit: Math.max(options.consolidateTopK ?? DEFAULT_CONSOLIDATE_TOP_K, 1),
5279
+ useFusion: false,
5280
+ scopes: [resolvedScope],
5281
+ // PR5 — include archived rows as merge candidates so a re-observed fact
5282
+ // resurrects (un-archives) the decayed row instead of duplicating it.
5283
+ includeArchived: true,
5284
+ ...options.folderId !== void 0 && { folderId: options.folderId }
5285
+ }
5286
+ );
5269
5287
  if (options.consolidateOptions) {
5270
- const outcome = await tryConsolidate(trimmed, ctx, options);
5288
+ const outcome = await tryConsolidate(trimmed, ctx, options, prepared);
5271
5289
  if (outcome) {
5272
5290
  if ("done" in outcome) return outcome.done;
5273
5291
  supersedeTargetIds = outcome.supersede;
@@ -5275,23 +5293,14 @@ async function retain(content, ctx, options = {}) {
5275
5293
  }
5276
5294
  }
5277
5295
  if (supersedeTargetIds.length === 0) {
5278
- const matches = await searchVaultMemories(
5296
+ const { results: matches } = await rankPreparedVaultCandidates(
5279
5297
  trimmed,
5280
- ctx.vaultCtx,
5298
+ prepared,
5281
5299
  ctx.embeddingOptions,
5282
- ctx.vaultCache,
5283
5300
  {
5284
5301
  limit: 1,
5285
5302
  minSimilarity: threshold,
5286
- useFusion: false,
5287
- scopes: [resolvedScope],
5288
- // PR5 — include archived rows as merge candidates so a re-observed
5289
- // fact resurrects (un-archives) the decayed row instead of creating a
5290
- // fresh duplicate. The resurrection is applied on the merge write
5291
- // below, but ONLY for a row that is not superseded/deleted (the
5292
- // guards below preserve main's tombstone/supersession suppression).
5293
- includeArchived: true,
5294
- ...options.folderId !== void 0 && { folderId: options.folderId }
5303
+ useFusion: false
5295
5304
  }
5296
5305
  );
5297
5306
  if (matches.length > 0) {
@@ -5339,7 +5348,8 @@ async function retain(content, ctx, options = {}) {
5339
5348
  }
5340
5349
  }
5341
5350
  const contentToWrite = supersedeContent ?? trimmed;
5342
- const embedding = await generateEmbedding(contentToWrite, ctx.embeddingOptions);
5351
+ const reusableQueryEmbedding = supersedeContent === void 0 && prepared && prepared.queryEmbedding.length > 0 ? prepared.queryEmbedding : void 0;
5352
+ const embedding = reusableQueryEmbedding ?? await generateEmbedding(contentToWrite, ctx.embeddingOptions);
5343
5353
  const embeddingModel = ctx.embeddingOptions.model ?? DEFAULT_API_EMBEDDING_MODEL;
5344
5354
  if (options.respectTombstones) {
5345
5355
  const tombstoneId = await findTombstoneMatch(embedding, embeddingModel, resolvedScope, ctx, {
@@ -5468,26 +5478,19 @@ function pickFactTypeUpdate(existing, incoming) {
5468
5478
  function resurrectFields(existing) {
5469
5479
  return typeof existing.archivedAt === "number" ? { restore: true } : { preserveUpdatedAt: true };
5470
5480
  }
5471
- async function tryConsolidate(trimmed, ctx, options) {
5481
+ async function tryConsolidate(trimmed, ctx, options, prepared) {
5472
5482
  const consolidateOptions = options.consolidateOptions;
5473
5483
  if (!consolidateOptions) return null;
5474
5484
  const consolidateThreshold = options.consolidateThreshold ?? DEFAULT_CONSOLIDATE_THRESHOLD;
5475
5485
  const topK = options.consolidateTopK ?? DEFAULT_CONSOLIDATE_TOP_K;
5476
- const resolvedScope = options.scope ?? DEFAULT_SCOPE;
5477
- const matches = await searchVaultMemories(
5486
+ const { results: matches } = await rankPreparedVaultCandidates(
5478
5487
  trimmed,
5479
- ctx.vaultCtx,
5488
+ prepared,
5480
5489
  ctx.embeddingOptions,
5481
- ctx.vaultCache,
5482
5490
  {
5483
5491
  limit: topK,
5484
5492
  minSimilarity: consolidateThreshold,
5485
- useFusion: false,
5486
- scopes: [resolvedScope],
5487
- // PR5 — archived rows are consolidation candidates too, so a paraphrased
5488
- // re-observation resurrects a decayed row rather than duplicating it.
5489
- includeArchived: true,
5490
- ...options.folderId !== void 0 && { folderId: options.folderId }
5493
+ useFusion: false
5491
5494
  }
5492
5495
  );
5493
5496
  if (matches.length === 0) return null;
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  recall
3
- } from "./chunk-FJFPCJRI.mjs";
3
+ } from "./chunk-UU2F523R.mjs";
4
4
  import "./chunk-MIXEASUP.mjs";
5
5
  import "./chunk-3RPGXXPZ.mjs";
6
6
  export {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@anuma/sdk",
3
- "version": "3.9.4",
3
+ "version": "3.9.5",
4
4
  "description": "",
5
5
  "main": "./dist/index.cjs",
6
6
  "module": "./dist/index.mjs",