@anuma/sdk 3.9.3 → 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-RSLYPJ5L.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 },
@@ -5717,6 +5741,18 @@ var STOPWORDS2 = new Set(
5717
5741
  ].map((w) => w.toLowerCase())
5718
5742
  );
5719
5743
  var ENTITY_REGEX = /\b\p{Lu}[\p{L}'-]{2,}(?:\s+\p{Lu}[\p{L}'-]+){0,2}\b/gu;
5744
+ var FALLBACK_ONLY_STOPWORDS = "a an and or but nor not if then than because so too also just very really about above after again against all am any anyone anybody anything are around as at be been being before behind below between both by can cannot could currently did do does doing done down during each ever every everybody everyone everything few find finds finding for from get gets getting go goes going gone got had has have having he help her here hers him his hmm i in into is it its knew know knows later like liked likes live lived lives living look looked looking looks made make makes may me meet meets might mine more most must my near need needed needs never nobody nothing now of off okay on once only onto other our ours out over own people person please recently said same say says see seen shall she should since some somebody someone something soon still such talk tell tells thank that the their theirs them there these they think thinks this those thought through to today told tomorrow under until up us want wanted wants was we went were which while will with without work worked working works would yeah year years yep yesterday you your yours aren't can't couldn't didn't doesn't don't hadn't hasn't haven't he's how's i'd i'll i'm i've isn't it's let's she's shouldn't that's there's they're they've wasn't we're we've weren't what's when's where's who's why's won't wouldn't you'll you're you've".split(" ");
5745
+ var FALLBACK_STOPWORDS = /* @__PURE__ */ new Set([...STOPWORDS2, ...FALLBACK_ONLY_STOPWORDS]);
5746
+ var MAX_FALLBACK_CANDIDATES = 12;
5747
+ var MAX_FALLBACK_TOKENS = 3;
5748
+ function hasMeaningfulCandidate(candidates) {
5749
+ for (const candidate of candidates) {
5750
+ if (!candidate.split(/\s+/).every((token) => FALLBACK_STOPWORDS.has(token))) {
5751
+ return true;
5752
+ }
5753
+ }
5754
+ return false;
5755
+ }
5720
5756
  function extractQueryEntities(query) {
5721
5757
  if (!query) return [];
5722
5758
  const matches = query.matchAll(ENTITY_REGEX);
@@ -5732,7 +5768,25 @@ function extractQueryEntities(query) {
5732
5768
  seen.add(candidate);
5733
5769
  }
5734
5770
  }
5735
- return [...seen];
5771
+ if (hasMeaningfulCandidate(seen)) return [...seen];
5772
+ return [.../* @__PURE__ */ new Set([...extractFallbackCandidates(query), ...seen])];
5773
+ }
5774
+ function extractFallbackCandidates(query) {
5775
+ const tokens = (query.match(/\p{L}[\p{L}'-]*/gu) ?? []).map(normalizeEntityName);
5776
+ const out = [];
5777
+ const seen = /* @__PURE__ */ new Set();
5778
+ for (let n = 1; n <= MAX_FALLBACK_TOKENS; n++) {
5779
+ for (let start = 0; start + n <= tokens.length; start++) {
5780
+ const gram = tokens.slice(start, start + n);
5781
+ if (gram.some((t) => t.length < 2 || FALLBACK_STOPWORDS.has(t))) continue;
5782
+ const candidate = gram.join(" ");
5783
+ if (seen.has(candidate)) continue;
5784
+ seen.add(candidate);
5785
+ out.push(candidate);
5786
+ if (out.length >= MAX_FALLBACK_CANDIDATES) return out;
5787
+ }
5788
+ }
5789
+ return out;
5736
5790
  }
5737
5791
 
5738
5792
  // src/lib/memory/graphTraversal.ts
@@ -6608,6 +6662,8 @@ export {
6608
6662
  recall,
6609
6663
  preEmbedVaultMemories,
6610
6664
  eagerEmbedContent,
6665
+ prepareVaultCandidates,
6666
+ rankPreparedVaultCandidates,
6611
6667
  searchVaultMemories,
6612
6668
  createMemoryVaultSearchTool
6613
6669
  };
@@ -5880,6 +5880,14 @@ var init_lruCache = __esm({
5880
5880
  });
5881
5881
 
5882
5882
  // src/lib/memory/queryEntities.ts
5883
+ function hasMeaningfulCandidate(candidates) {
5884
+ for (const candidate of candidates) {
5885
+ if (!candidate.split(/\s+/).every((token) => FALLBACK_STOPWORDS.has(token))) {
5886
+ return true;
5887
+ }
5888
+ }
5889
+ return false;
5890
+ }
5883
5891
  function extractQueryEntities(query) {
5884
5892
  if (!query) return [];
5885
5893
  const matches = query.matchAll(ENTITY_REGEX);
@@ -5895,9 +5903,27 @@ function extractQueryEntities(query) {
5895
5903
  seen.add(candidate);
5896
5904
  }
5897
5905
  }
5898
- return [...seen];
5906
+ if (hasMeaningfulCandidate(seen)) return [...seen];
5907
+ return [.../* @__PURE__ */ new Set([...extractFallbackCandidates(query), ...seen])];
5899
5908
  }
5900
- var STOPWORDS2, ENTITY_REGEX;
5909
+ function extractFallbackCandidates(query) {
5910
+ const tokens = (query.match(/\p{L}[\p{L}'-]*/gu) ?? []).map(normalizeEntityName);
5911
+ const out = [];
5912
+ const seen = /* @__PURE__ */ new Set();
5913
+ for (let n = 1; n <= MAX_FALLBACK_TOKENS; n++) {
5914
+ for (let start = 0; start + n <= tokens.length; start++) {
5915
+ const gram = tokens.slice(start, start + n);
5916
+ if (gram.some((t) => t.length < 2 || FALLBACK_STOPWORDS.has(t))) continue;
5917
+ const candidate = gram.join(" ");
5918
+ if (seen.has(candidate)) continue;
5919
+ seen.add(candidate);
5920
+ out.push(candidate);
5921
+ if (out.length >= MAX_FALLBACK_CANDIDATES) return out;
5922
+ }
5923
+ }
5924
+ return out;
5925
+ }
5926
+ var STOPWORDS2, ENTITY_REGEX, FALLBACK_ONLY_STOPWORDS, FALLBACK_STOPWORDS, MAX_FALLBACK_CANDIDATES, MAX_FALLBACK_TOKENS;
5901
5927
  var init_queryEntities = __esm({
5902
5928
  "src/lib/memory/queryEntities.ts"() {
5903
5929
  "use strict";
@@ -5949,6 +5975,10 @@ var init_queryEntities = __esm({
5949
5975
  ].map((w) => w.toLowerCase())
5950
5976
  );
5951
5977
  ENTITY_REGEX = /\b\p{Lu}[\p{L}'-]{2,}(?:\s+\p{Lu}[\p{L}'-]+){0,2}\b/gu;
5978
+ FALLBACK_ONLY_STOPWORDS = "a an and or but nor not if then than because so too also just very really about above after again against all am any anyone anybody anything are around as at be been being before behind below between both by can cannot could currently did do does doing done down during each ever every everybody everyone everything few find finds finding for from get gets getting go goes going gone got had has have having he help her here hers him his hmm i in into is it its knew know knows later like liked likes live lived lives living look looked looking looks made make makes may me meet meets might mine more most must my near need needed needs never nobody nothing now of off okay on once only onto other our ours out over own people person please recently said same say says see seen shall she should since some somebody someone something soon still such talk tell tells thank that the their theirs them there these they think thinks this those thought through to today told tomorrow under until up us want wanted wants was we went were which while will with without work worked working works would yeah year years yep yesterday you your yours aren't can't couldn't didn't doesn't don't hadn't hasn't haven't he's how's i'd i'll i'm i've isn't it's let's she's shouldn't that's there's they're they've wasn't we're we've weren't what's when's where's who's why's won't wouldn't you'll you're you've".split(" ");
5979
+ FALLBACK_STOPWORDS = /* @__PURE__ */ new Set([...STOPWORDS2, ...FALLBACK_ONLY_STOPWORDS]);
5980
+ MAX_FALLBACK_CANDIDATES = 12;
5981
+ MAX_FALLBACK_TOKENS = 3;
5952
5982
  }
5953
5983
  });
5954
5984
 
@@ -7402,13 +7432,12 @@ async function buildProjectedCorpus(query, vaultCtx, embeddingOptions, cache, qu
7402
7432
  }));
7403
7433
  return { memories, embeddedItems, queryEmbedding, vaultSize };
7404
7434
  }
7405
- async function searchVaultMemoriesWithSize(query, vaultCtx, embeddingOptions, cache, searchOptions) {
7406
- const limit = searchOptions?.limit ?? 5;
7407
- const minSimilarity = searchOptions?.minSimilarity ?? 0.1;
7408
- const scopes = searchOptions?.scopes;
7435
+ async function prepareVaultCandidates(query, vaultCtx, embeddingOptions, cache, searchOptions) {
7409
7436
  if (!query || typeof query !== "string") {
7410
- return { results: [], vaultSize: 0, reranked: false, hadV2Head: false };
7437
+ return { memories: [], embeddedItems: [], queryEmbedding: [], vaultSize: 0 };
7411
7438
  }
7439
+ const limit = searchOptions?.limit ?? 5;
7440
+ const scopes = searchOptions?.scopes;
7412
7441
  const folderId = searchOptions?.folderId;
7413
7442
  const queryOpts = {};
7414
7443
  if (scopes?.length) queryOpts.scopes = scopes;
@@ -7435,11 +7464,11 @@ async function searchVaultMemoriesWithSize(query, vaultCtx, embeddingOptions, ca
7435
7464
  ...forceIncludeIds.length > 0 && { forceIncludeIds }
7436
7465
  });
7437
7466
  if (corpus.vaultSize === 0) {
7438
- return { results: [], vaultSize: 0, reranked: false, hadV2Head: false };
7467
+ return { memories: [], embeddedItems: [], queryEmbedding: [], vaultSize: 0 };
7439
7468
  }
7440
7469
  ({ memories, embeddedItems, queryEmbedding, vaultSize } = corpus);
7441
7470
  if (memories.length === 0) {
7442
- return { results: [], vaultSize, reranked: false, hadV2Head: false };
7471
+ return { memories: [], embeddedItems: [], queryEmbedding: [], vaultSize };
7443
7472
  }
7444
7473
  } else {
7445
7474
  const loaded = await getAllVaultMemoriesOp(
@@ -7454,7 +7483,7 @@ async function searchVaultMemoriesWithSize(query, vaultCtx, embeddingOptions, ca
7454
7483
  );
7455
7484
  }
7456
7485
  if (memories.length === 0) {
7457
- return { results: [], vaultSize: loaded.length, reranked: false, hadV2Head: false };
7486
+ return { memories: [], embeddedItems: [], queryEmbedding: [], vaultSize: loaded.length };
7458
7487
  }
7459
7488
  queryEmbedding = await generateEmbedding(query, embeddingOptions);
7460
7489
  const currentModel = embeddingOptions.model ?? DEFAULT_API_EMBEDDING_MODEL;
@@ -7519,6 +7548,12 @@ async function searchVaultMemoriesWithSize(query, vaultCtx, embeddingOptions, ca
7519
7548
  factType: m.factType
7520
7549
  }));
7521
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;
7522
7557
  if (queryEmbedding.length > 0) {
7523
7558
  const mismatched = embeddedItems.filter(
7524
7559
  (it) => it.embedding.length > 0 && it.embedding.length !== queryEmbedding.length
@@ -7656,6 +7691,25 @@ async function searchVaultMemoriesWithSize(query, vaultCtx, embeddingOptions, ca
7656
7691
  });
7657
7692
  return stampTimestamps({ results, vaultSize, hadV2Head: results.length > 0 });
7658
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
+ }
7659
7713
  async function searchVaultMemories(query, vaultCtx, embeddingOptions, cache, searchOptions) {
7660
7714
  const { results } = await searchVaultMemoriesWithSize(
7661
7715
  query,
@@ -14453,9 +14507,25 @@ async function retain(content, ctx, options = {}) {
14453
14507
  const resolvedScope = options.scope ?? DEFAULT_SCOPE;
14454
14508
  let supersedeTargetIds = [];
14455
14509
  let supersedeContent;
14510
+ let prepared;
14456
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
+ );
14457
14527
  if (options.consolidateOptions) {
14458
- const outcome = await tryConsolidate(trimmed, ctx, options);
14528
+ const outcome = await tryConsolidate(trimmed, ctx, options, prepared);
14459
14529
  if (outcome) {
14460
14530
  if ("done" in outcome) return outcome.done;
14461
14531
  supersedeTargetIds = outcome.supersede;
@@ -14463,23 +14533,14 @@ async function retain(content, ctx, options = {}) {
14463
14533
  }
14464
14534
  }
14465
14535
  if (supersedeTargetIds.length === 0) {
14466
- const matches = await searchVaultMemories(
14536
+ const { results: matches } = await rankPreparedVaultCandidates(
14467
14537
  trimmed,
14468
- ctx.vaultCtx,
14538
+ prepared,
14469
14539
  ctx.embeddingOptions,
14470
- ctx.vaultCache,
14471
14540
  {
14472
14541
  limit: 1,
14473
14542
  minSimilarity: threshold,
14474
- useFusion: false,
14475
- scopes: [resolvedScope],
14476
- // PR5 — include archived rows as merge candidates so a re-observed
14477
- // fact resurrects (un-archives) the decayed row instead of creating a
14478
- // fresh duplicate. The resurrection is applied on the merge write
14479
- // below, but ONLY for a row that is not superseded/deleted (the
14480
- // guards below preserve main's tombstone/supersession suppression).
14481
- includeArchived: true,
14482
- ...options.folderId !== void 0 && { folderId: options.folderId }
14543
+ useFusion: false
14483
14544
  }
14484
14545
  );
14485
14546
  if (matches.length > 0) {
@@ -14527,7 +14588,8 @@ async function retain(content, ctx, options = {}) {
14527
14588
  }
14528
14589
  }
14529
14590
  const contentToWrite = supersedeContent ?? trimmed;
14530
- 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);
14531
14593
  const embeddingModel = ctx.embeddingOptions.model ?? DEFAULT_API_EMBEDDING_MODEL;
14532
14594
  if (options.respectTombstones) {
14533
14595
  const tombstoneId = await findTombstoneMatch(embedding, embeddingModel, resolvedScope, ctx, {
@@ -14656,26 +14718,19 @@ function pickFactTypeUpdate(existing, incoming) {
14656
14718
  function resurrectFields(existing) {
14657
14719
  return typeof existing.archivedAt === "number" ? { restore: true } : { preserveUpdatedAt: true };
14658
14720
  }
14659
- async function tryConsolidate(trimmed, ctx, options) {
14721
+ async function tryConsolidate(trimmed, ctx, options, prepared) {
14660
14722
  const consolidateOptions = options.consolidateOptions;
14661
14723
  if (!consolidateOptions) return null;
14662
14724
  const consolidateThreshold = options.consolidateThreshold ?? DEFAULT_CONSOLIDATE_THRESHOLD;
14663
14725
  const topK = options.consolidateTopK ?? DEFAULT_CONSOLIDATE_TOP_K;
14664
- const resolvedScope = options.scope ?? DEFAULT_SCOPE;
14665
- const matches = await searchVaultMemories(
14726
+ const { results: matches } = await rankPreparedVaultCandidates(
14666
14727
  trimmed,
14667
- ctx.vaultCtx,
14728
+ prepared,
14668
14729
  ctx.embeddingOptions,
14669
- ctx.vaultCache,
14670
14730
  {
14671
14731
  limit: topK,
14672
14732
  minSimilarity: consolidateThreshold,
14673
- useFusion: false,
14674
- scopes: [resolvedScope],
14675
- // PR5 — archived rows are consolidation candidates too, so a paraphrased
14676
- // re-observation resurrects a decayed row rather than duplicating it.
14677
- includeArchived: true,
14678
- ...options.folderId !== void 0 && { folderId: options.folderId }
14733
+ useFusion: false
14679
14734
  }
14680
14735
  );
14681
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-UQQCL7KP.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-UQQCL7KP.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-UCCIEG37.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 },
@@ -6018,6 +6042,18 @@ var STOPWORDS2 = new Set(
6018
6042
  ].map((w) => w.toLowerCase())
6019
6043
  );
6020
6044
  var ENTITY_REGEX = /\b\p{Lu}[\p{L}'-]{2,}(?:\s+\p{Lu}[\p{L}'-]+){0,2}\b/gu;
6045
+ var FALLBACK_ONLY_STOPWORDS = "a an and or but nor not if then than because so too also just very really about above after again against all am any anyone anybody anything are around as at be been being before behind below between both by can cannot could currently did do does doing done down during each ever every everybody everyone everything few find finds finding for from get gets getting go goes going gone got had has have having he help her here hers him his hmm i in into is it its knew know knows later like liked likes live lived lives living look looked looking looks made make makes may me meet meets might mine more most must my near need needed needs never nobody nothing now of off okay on once only onto other our ours out over own people person please recently said same say says see seen shall she should since some somebody someone something soon still such talk tell tells thank that the their theirs them there these they think thinks this those thought through to today told tomorrow under until up us want wanted wants was we went were which while will with without work worked working works would yeah year years yep yesterday you your yours aren't can't couldn't didn't doesn't don't hadn't hasn't haven't he's how's i'd i'll i'm i've isn't it's let's she's shouldn't that's there's they're they've wasn't we're we've weren't what's when's where's who's why's won't wouldn't you'll you're you've".split(" ");
6046
+ var FALLBACK_STOPWORDS = /* @__PURE__ */ new Set([...STOPWORDS2, ...FALLBACK_ONLY_STOPWORDS]);
6047
+ var MAX_FALLBACK_CANDIDATES = 12;
6048
+ var MAX_FALLBACK_TOKENS = 3;
6049
+ function hasMeaningfulCandidate(candidates) {
6050
+ for (const candidate of candidates) {
6051
+ if (!candidate.split(/\s+/).every((token) => FALLBACK_STOPWORDS.has(token))) {
6052
+ return true;
6053
+ }
6054
+ }
6055
+ return false;
6056
+ }
6021
6057
  function extractQueryEntities(query) {
6022
6058
  if (!query) return [];
6023
6059
  const matches = query.matchAll(ENTITY_REGEX);
@@ -6033,7 +6069,25 @@ function extractQueryEntities(query) {
6033
6069
  seen.add(candidate);
6034
6070
  }
6035
6071
  }
6036
- return [...seen];
6072
+ if (hasMeaningfulCandidate(seen)) return [...seen];
6073
+ return [.../* @__PURE__ */ new Set([...extractFallbackCandidates(query), ...seen])];
6074
+ }
6075
+ function extractFallbackCandidates(query) {
6076
+ const tokens = (query.match(/\p{L}[\p{L}'-]*/gu) ?? []).map(normalizeEntityName);
6077
+ const out = [];
6078
+ const seen = /* @__PURE__ */ new Set();
6079
+ for (let n = 1; n <= MAX_FALLBACK_TOKENS; n++) {
6080
+ for (let start = 0; start + n <= tokens.length; start++) {
6081
+ const gram = tokens.slice(start, start + n);
6082
+ if (gram.some((t) => t.length < 2 || FALLBACK_STOPWORDS.has(t))) continue;
6083
+ const candidate = gram.join(" ");
6084
+ if (seen.has(candidate)) continue;
6085
+ seen.add(candidate);
6086
+ out.push(candidate);
6087
+ if (out.length >= MAX_FALLBACK_CANDIDATES) return out;
6088
+ }
6089
+ }
6090
+ return out;
6037
6091
  }
6038
6092
 
6039
6093
  // src/lib/memory/graphTraversal.ts
@@ -6954,6 +7008,8 @@ export {
6954
7008
  recall,
6955
7009
  preEmbedVaultMemories,
6956
7010
  eagerEmbedContent,
7011
+ prepareVaultCandidates,
7012
+ rankPreparedVaultCandidates,
6957
7013
  searchVaultMemories,
6958
7014
  createMemoryVaultSearchTool
6959
7015
  };