@anuma/sdk 2.3.1 → 2.4.1

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.
@@ -1588,7 +1588,13 @@ async function searchMessagesOp(ctx, queryVector, options) {
1588
1588
  );
1589
1589
  }
1590
1590
  async function searchChunksOp(ctx, queryVector, options) {
1591
- const { limit = 10, minSimilarity = 0.5, conversationId, embeddingModel } = options || {};
1591
+ const {
1592
+ limit = 10,
1593
+ minSimilarity = 0.5,
1594
+ conversationId,
1595
+ embeddingModel,
1596
+ chunkCache
1597
+ } = options || {};
1592
1598
  const activeConversations = await ctx.conversationsCollection.query(Q.where("is_deleted", false)).fetch();
1593
1599
  const activeConversationIds = new Set(
1594
1600
  // Use _getRaw for reliable raw column access
@@ -1608,23 +1614,54 @@ async function searchChunksOp(ctx, queryVector, options) {
1608
1614
  continue;
1609
1615
  }
1610
1616
  }
1617
+ const version = Number(message._getRaw("updated_at")) || 0;
1618
+ const cached = chunkCache?.get(message.id);
1619
+ if (cached && cached.version === version) {
1620
+ if (cached.chunks.length > 0) {
1621
+ for (let ci = 0; ci < cached.chunks.length; ci++) {
1622
+ const vec = cached.chunks[ci];
1623
+ if (vec.length === 0) continue;
1624
+ const similarity = cosineSimilarity(queryVector, vec);
1625
+ if (similarity >= minSimilarity) {
1626
+ candidates.push({
1627
+ message,
1628
+ similarity,
1629
+ chunkTextSource: { kind: "chunk-cached", chunkIndex: ci, version }
1630
+ });
1631
+ }
1632
+ }
1633
+ } else if (cached.fallback) {
1634
+ const similarity = cosineSimilarity(queryVector, cached.fallback);
1635
+ if (similarity >= minSimilarity) {
1636
+ candidates.push({ message, similarity, chunkTextSource: { kind: "message" } });
1637
+ }
1638
+ }
1639
+ continue;
1640
+ }
1611
1641
  const chunks = await readJsonField(message, "chunks", ctx.walletAddress);
1612
1642
  if (chunks && chunks.length > 0) {
1613
- for (const chunk of chunks) {
1614
- if (!chunk.vector || chunk.vector.length === 0) continue;
1615
- const similarity = cosineSimilarity(queryVector, chunk.vector);
1643
+ const vectors = chunks.map(
1644
+ (chunk) => chunk.vector && chunk.vector.length > 0 ? Float32Array.from(chunk.vector) : new Float32Array(0)
1645
+ );
1646
+ chunkCache?.set(message.id, { version, chunks: vectors });
1647
+ for (let ci = 0; ci < chunks.length; ci++) {
1648
+ const vec = vectors[ci];
1649
+ if (vec.length === 0) continue;
1650
+ const similarity = cosineSimilarity(queryVector, vec);
1616
1651
  if (similarity >= minSimilarity) {
1617
1652
  candidates.push({
1618
1653
  message,
1619
1654
  similarity,
1620
- chunkTextSource: { kind: "chunk", text: chunk.text }
1655
+ chunkTextSource: { kind: "chunk", text: chunks[ci].text }
1621
1656
  });
1622
1657
  }
1623
1658
  }
1624
1659
  } else {
1625
1660
  const messageVector = await readJsonField(message, "vector", ctx.walletAddress);
1626
1661
  if (!messageVector || messageVector.length === 0) continue;
1627
- const similarity = cosineSimilarity(queryVector, messageVector);
1662
+ const fallback = Float32Array.from(messageVector);
1663
+ chunkCache?.set(message.id, { version, chunks: [], fallback });
1664
+ const similarity = cosineSimilarity(queryVector, fallback);
1628
1665
  if (similarity >= minSimilarity) {
1629
1666
  candidates.push({ message, similarity, chunkTextSource: { kind: "message" } });
1630
1667
  }
@@ -1651,9 +1688,31 @@ async function searchChunksOp(ctx, queryVector, options) {
1651
1688
  })
1652
1689
  )
1653
1690
  );
1691
+ const chunkStateByMsgId = /* @__PURE__ */ new Map();
1692
+ const needsChunkText = /* @__PURE__ */ new Set();
1693
+ for (const c of topK) {
1694
+ if (c.chunkTextSource.kind === "chunk-cached") needsChunkText.add(c.message.id);
1695
+ }
1696
+ await Promise.all(
1697
+ Array.from(needsChunkText, async (id) => {
1698
+ const m = uniqueMessages.get(id);
1699
+ const parsed = await readJsonField(m, "chunks", ctx.walletAddress);
1700
+ const version = Number(m._getRaw("updated_at")) || 0;
1701
+ if (parsed) chunkStateByMsgId.set(id, { version, chunks: parsed });
1702
+ })
1703
+ );
1654
1704
  return topK.map(({ message, similarity, chunkTextSource }) => {
1655
1705
  const stored = { ...storedById.get(message.id) };
1656
- const chunkText2 = chunkTextSource.kind === "chunk" ? chunkTextSource.text : stored.content;
1706
+ let chunkText2;
1707
+ if (chunkTextSource.kind === "chunk") {
1708
+ chunkText2 = chunkTextSource.text;
1709
+ } else if (chunkTextSource.kind === "chunk-cached") {
1710
+ const state = chunkStateByMsgId.get(message.id);
1711
+ const chunk = state && state.version === chunkTextSource.version ? state.chunks[chunkTextSource.chunkIndex] : void 0;
1712
+ chunkText2 = chunk?.text ?? stored.content;
1713
+ } else {
1714
+ chunkText2 = stored.content;
1715
+ }
1657
1716
  return { chunkText: chunkText2, message: stored, similarity };
1658
1717
  });
1659
1718
  }
@@ -4017,9 +4076,9 @@ function recencyMultiplier(updatedAt, opts = {}) {
4017
4076
  const updatedMs = updatedAt.getTime();
4018
4077
  if (!Number.isFinite(updatedMs)) return noDate;
4019
4078
  const now = opts.now ?? /* @__PURE__ */ new Date();
4020
- const nowMs = now.getTime();
4021
- if (!Number.isFinite(nowMs)) return noDate;
4022
- const ageDays = Math.max(0, (nowMs - updatedMs) / DAY_MS);
4079
+ const nowMs2 = now.getTime();
4080
+ if (!Number.isFinite(nowMs2)) return noDate;
4081
+ const ageDays = Math.max(0, (nowMs2 - updatedMs) / DAY_MS);
4023
4082
  const perYearDecay = opts.perYearDecay ?? DEFAULT_PER_YEAR_DECAY;
4024
4083
  const floor = opts.floor ?? DEFAULT_FLOOR;
4025
4084
  const decay = perYearDecay * (ageDays / 365);
@@ -4028,15 +4087,51 @@ function recencyMultiplier(updatedAt, opts = {}) {
4028
4087
 
4029
4088
  // src/lib/memory/reranker.ts
4030
4089
  var MODEL_ID = "Xenova/ms-marco-MiniLM-L-6-v2";
4090
+ var RerankerUnavailableError = class extends Error {
4091
+ constructor(reason) {
4092
+ super("cross-encoder reranker unavailable (@huggingface/transformers not installed)");
4093
+ this.name = "RerankerUnavailableError";
4094
+ this.reason = reason;
4095
+ }
4096
+ };
4097
+ var available = void 0;
4031
4098
  var modelPromise = null;
4099
+ function isRerankerAvailable() {
4100
+ return available;
4101
+ }
4102
+ function isModuleMissing(err) {
4103
+ let e = err;
4104
+ for (let depth = 0; depth < 5 && e !== null && e !== void 0; depth++) {
4105
+ const code = e.code;
4106
+ if (code === "ERR_MODULE_NOT_FOUND" || code === "MODULE_NOT_FOUND") return true;
4107
+ if (e instanceof Error && /cannot find (module|package)|failed to resolve|unable to resolve module|requiring unknown module/i.test(
4108
+ e.message
4109
+ )) {
4110
+ return true;
4111
+ }
4112
+ e = e.cause;
4113
+ }
4114
+ return false;
4115
+ }
4032
4116
  async function getModel() {
4117
+ if (available === false) throw new RerankerUnavailableError(void 0);
4033
4118
  if (!modelPromise) {
4034
4119
  const load = (async () => {
4035
- const transformers = await import("@huggingface/transformers");
4120
+ let transformers;
4121
+ try {
4122
+ transformers = await import("@huggingface/transformers");
4123
+ } catch (err) {
4124
+ if (isModuleMissing(err)) {
4125
+ available = false;
4126
+ throw new RerankerUnavailableError(err);
4127
+ }
4128
+ throw err;
4129
+ }
4036
4130
  const [tokenizer, model] = await Promise.all([
4037
4131
  transformers.AutoTokenizer.from_pretrained(MODEL_ID),
4038
4132
  transformers.AutoModelForSequenceClassification.from_pretrained(MODEL_ID)
4039
4133
  ]);
4134
+ available = true;
4040
4135
  return { tokenizer, model };
4041
4136
  })();
4042
4137
  modelPromise = load;
@@ -4597,6 +4692,9 @@ async function rankFusedVaultMemoriesAsync(query, queryEmbedding, items, options
4597
4692
  bm25AdmissionDivisor: options?.bm25AdmissionDivisor,
4598
4693
  rrfK: options?.rrfK
4599
4694
  });
4695
+ if (options?.v2HeadStats) {
4696
+ options.v2HeadStats.hadResults = v2Ranked.length > 0;
4697
+ }
4600
4698
  let combined;
4601
4699
  let tailSlice = [];
4602
4700
  if (options?.rerank) {
@@ -4617,8 +4715,13 @@ async function rankFusedVaultMemoriesAsync(query, queryEmbedding, items, options
4617
4715
  return { ...r, similarity: v2 * (1 + ceWeight * ce) };
4618
4716
  });
4619
4717
  combined.sort((a, b) => b.similarity - a.similarity);
4718
+ if (headSlice.length > 0 && options.rerankStats) options.rerankStats.applied = true;
4620
4719
  } catch (err) {
4621
- getLogger().warn("[memory/search] cross-encoder rerank failed; using V2 ranking", err);
4720
+ if (err instanceof RerankerUnavailableError) {
4721
+ getLogger().debug("[memory/search] cross-encoder unavailable; using V2 ranking");
4722
+ } else {
4723
+ getLogger().warn("[memory/search] cross-encoder rerank failed; using V2 ranking", err);
4724
+ }
4622
4725
  combined = v2Ranked;
4623
4726
  }
4624
4727
  } else {
@@ -4752,6 +4855,9 @@ async function rankComposite(originalQuery, originalQueryEmbedding, subQueries,
4752
4855
  (r) => r !== null
4753
4856
  );
4754
4857
  combined.sort((a, b) => b.similarity - a.similarity);
4858
+ if (options?.v2HeadStats) {
4859
+ options.v2HeadStats.hadResults = combined.length > 0;
4860
+ }
4755
4861
  if (options?.includeUnrankedTail) {
4756
4862
  const fusedIds = new Set(combined.map((r) => r.uniqueId));
4757
4863
  for (const item of items) {
@@ -4787,11 +4893,16 @@ async function rankComposite(originalQuery, originalQueryEmbedding, subQueries,
4787
4893
  }));
4788
4894
  head.sort((a, b) => b.similarity - a.similarity);
4789
4895
  combined = [...head, ...tailSlice];
4896
+ if (headSlice.length > 0 && options.rerankStats) options.rerankStats.applied = true;
4790
4897
  } catch (err) {
4791
- getLogger().warn(
4792
- "[memory/search] composite cross-encoder rerank failed; using fused ranking",
4793
- err
4794
- );
4898
+ if (err instanceof RerankerUnavailableError) {
4899
+ getLogger().debug("[memory/search] cross-encoder unavailable; using fused ranking");
4900
+ } else {
4901
+ getLogger().warn(
4902
+ "[memory/search] composite cross-encoder rerank failed; using fused ranking",
4903
+ err
4904
+ );
4905
+ }
4795
4906
  }
4796
4907
  }
4797
4908
  if (options?.mmr) {
@@ -4883,7 +4994,7 @@ async function searchVaultMemoriesWithSize(query, vaultCtx, embeddingOptions, ca
4883
4994
  const minSimilarity = searchOptions?.minSimilarity ?? 0.1;
4884
4995
  const scopes = searchOptions?.scopes;
4885
4996
  if (!query || typeof query !== "string") {
4886
- return { results: [], vaultSize: 0 };
4997
+ return { results: [], vaultSize: 0, reranked: false, hadV2Head: false };
4887
4998
  }
4888
4999
  const folderId = searchOptions?.folderId;
4889
5000
  const queryOpts = {};
@@ -4900,7 +5011,7 @@ async function searchVaultMemoriesWithSize(query, vaultCtx, embeddingOptions, ca
4900
5011
  );
4901
5012
  }
4902
5013
  if (memories.length === 0) {
4903
- return { results: [], vaultSize: loaded.length };
5014
+ return { results: [], vaultSize: loaded.length, reranked: false, hadV2Head: false };
4904
5015
  }
4905
5016
  const queryEmbedding = await generateEmbedding(query, embeddingOptions);
4906
5017
  const currentModel = embeddingOptions.model ?? DEFAULT_API_EMBEDDING_MODEL;
@@ -4976,12 +5087,18 @@ async function searchVaultMemoriesWithSize(query, vaultCtx, embeddingOptions, ca
4976
5087
  memories.map((m) => [m.uniqueId, { createdAt: m.createdAt, updatedAt: m.updatedAt }])
4977
5088
  );
4978
5089
  const stampTimestamps = (out) => {
4979
- out.results = out.results.map((r) => {
5090
+ const results2 = out.results.map((r) => {
4980
5091
  const ts = timestampById.get(r.uniqueId);
4981
5092
  return ts ? { ...r, createdAt: ts.createdAt, updatedAt: ts.updatedAt } : r;
4982
5093
  });
4983
- return out;
5094
+ return {
5095
+ results: results2,
5096
+ vaultSize: out.vaultSize,
5097
+ reranked: out.reranked ?? false,
5098
+ hadV2Head: out.hadV2Head ?? false
5099
+ };
4984
5100
  };
5101
+ const rerankStats = { applied: false };
4985
5102
  const useFusion = searchOptions?.useFusion ?? true;
4986
5103
  const tuning = {
4987
5104
  ...searchOptions?.recencyAlpha !== void 0 && { recencyAlpha: searchOptions.recencyAlpha },
@@ -5008,6 +5125,7 @@ async function searchVaultMemoriesWithSize(query, vaultCtx, embeddingOptions, ca
5008
5125
  query: sq,
5009
5126
  embedding: subEmbeddings[i]
5010
5127
  }));
5128
+ const v2HeadStats = { hadResults: false };
5011
5129
  const composite = await rankComposite(query, queryEmbedding, subQueries, embeddedItems, {
5012
5130
  limit,
5013
5131
  minSimilarity,
@@ -5019,12 +5137,20 @@ async function searchVaultMemoriesWithSize(query, vaultCtx, embeddingOptions, ca
5019
5137
  ...searchOptions.mmr !== void 0 && { mmr: searchOptions.mmr },
5020
5138
  ...tuning,
5021
5139
  ...searchOptions.entityRanking && { entityRanking: searchOptions.entityRanking },
5022
- ...searchOptions.temporalRanking && { temporalRanking: searchOptions.temporalRanking }
5140
+ ...searchOptions.temporalRanking && { temporalRanking: searchOptions.temporalRanking },
5141
+ rerankStats,
5142
+ v2HeadStats
5143
+ });
5144
+ return stampTimestamps({
5145
+ results: composite,
5146
+ vaultSize: loaded.length,
5147
+ reranked: rerankStats.applied,
5148
+ hadV2Head: v2HeadStats.hadResults
5023
5149
  });
5024
- return stampTimestamps({ results: composite, vaultSize: loaded.length });
5025
5150
  }
5026
5151
  }
5027
5152
  if (useFusion && searchOptions?.rerank) {
5153
+ const v2HeadStats = { hadResults: false };
5028
5154
  const results2 = await rankFusedVaultMemoriesAsync(query, queryEmbedding, embeddedItems, {
5029
5155
  limit,
5030
5156
  minSimilarity,
@@ -5036,9 +5162,16 @@ async function searchVaultMemoriesWithSize(query, vaultCtx, embeddingOptions, ca
5036
5162
  ...searchOptions.mmr !== void 0 && { mmr: searchOptions.mmr },
5037
5163
  ...tuning,
5038
5164
  ...searchOptions.entityRanking && { entityRanking: searchOptions.entityRanking },
5039
- ...searchOptions.temporalRanking && { temporalRanking: searchOptions.temporalRanking }
5165
+ ...searchOptions.temporalRanking && { temporalRanking: searchOptions.temporalRanking },
5166
+ rerankStats,
5167
+ v2HeadStats
5168
+ });
5169
+ return stampTimestamps({
5170
+ results: results2,
5171
+ vaultSize: loaded.length,
5172
+ reranked: rerankStats.applied,
5173
+ hadV2Head: v2HeadStats.hadResults
5040
5174
  });
5041
- return stampTimestamps({ results: results2, vaultSize: loaded.length });
5042
5175
  }
5043
5176
  if (useFusion) {
5044
5177
  const results2 = rankFusedVaultMemories(query, queryEmbedding, embeddedItems, {
@@ -5048,7 +5181,7 @@ async function searchVaultMemoriesWithSize(query, vaultCtx, embeddingOptions, ca
5048
5181
  ...searchOptions?.entityRanking && { entityRanking: searchOptions.entityRanking },
5049
5182
  ...searchOptions?.temporalRanking && { temporalRanking: searchOptions.temporalRanking }
5050
5183
  });
5051
- return stampTimestamps({ results: results2, vaultSize: loaded.length });
5184
+ return stampTimestamps({ results: results2, vaultSize: loaded.length, hadV2Head: results2.length > 0 });
5052
5185
  }
5053
5186
  const results = rankVaultMemories(query, queryEmbedding, embeddedItems, {
5054
5187
  limit,
@@ -5060,7 +5193,7 @@ async function searchVaultMemoriesWithSize(query, vaultCtx, embeddingOptions, ca
5060
5193
  supersessionWindow: searchOptions.supersessionWindow
5061
5194
  }
5062
5195
  });
5063
- return stampTimestamps({ results, vaultSize: loaded.length });
5196
+ return stampTimestamps({ results, vaultSize: loaded.length, hadV2Head: results.length > 0 });
5064
5197
  }
5065
5198
  async function searchVaultMemories(query, vaultCtx, embeddingOptions, cache, searchOptions) {
5066
5199
  const { results } = await searchVaultMemoriesWithSize(
@@ -5149,7 +5282,7 @@ function createMemoryVaultSearchTool(vaultCtx, embeddingOptions, cache, searchOp
5149
5282
  legacy.map((r) => ({ id: r.uniqueId, content: r.content, score: r.similarity }))
5150
5283
  );
5151
5284
  }
5152
- const { recall: recall2 } = await import("./recall-DSJSBDR4.mjs");
5285
+ const { recall: recall2 } = await import("./recall-G3CS444F.mjs");
5153
5286
  const result = await recall2(
5154
5287
  query,
5155
5288
  { vaultCtx, embeddingOptions, vaultCache: cache },
@@ -5467,6 +5600,7 @@ function scoreEventTimeOverlap(memoryStart, memoryEnd, memoryKind, window2) {
5467
5600
  var DEFAULT_LIMIT = 8;
5468
5601
  var DEFAULT_BUDGET = "low";
5469
5602
  var DEFAULT_FACT_MIN_SCORE = 0.1;
5603
+ var nowMs = () => typeof performance !== "undefined" && typeof performance.now === "function" ? performance.now() : Date.now();
5470
5604
  var DEFAULT_CHUNK_MIN_SCORE = 0.5;
5471
5605
  function flagsForBudget(budget) {
5472
5606
  switch (budget) {
@@ -5499,22 +5633,67 @@ async function recall(query, ctx, options = {}) {
5499
5633
  const flags = flagsForBudget(requestedBudget);
5500
5634
  const decomposeAvailable = flags.decompose && !!options.decomposeOptions;
5501
5635
  const usedBudget = requestedBudget === "high" && !decomposeAvailable ? "mid" : requestedBudget;
5636
+ const t0 = nowMs();
5637
+ let prepMs = 0;
5638
+ let factLaneMs = 0;
5639
+ let chunkLaneMs = 0;
5640
+ let fuseMs = 0;
5641
+ const factResults = [];
5642
+ const chunkResults = [];
5643
+ let vaultSize;
5644
+ let didRerank = false;
5645
+ let hadV2Head = false;
5646
+ const emitDiagnostics = (candidateCount) => {
5647
+ const cb = options.onDiagnostics;
5648
+ if (!cb) return;
5649
+ const degraded = [];
5650
+ if (flags.rerank && factResults.length > 0 && hadV2Head && !didRerank) {
5651
+ degraded.push("rerank-unavailable");
5652
+ }
5653
+ if (flags.decompose && !decomposeAvailable) degraded.push("decompose-unavailable");
5654
+ const diagnostics = {
5655
+ usedBudget,
5656
+ reranked: didRerank,
5657
+ candidateCount,
5658
+ ...vaultSize !== void 0 && { vaultSize },
5659
+ factCount: factResults.length,
5660
+ chunkCount: chunkResults.length,
5661
+ timings: {
5662
+ total: nowMs() - t0,
5663
+ prep: prepMs,
5664
+ factLane: factLaneMs,
5665
+ chunkLane: chunkLaneMs,
5666
+ fuse: fuseMs
5667
+ },
5668
+ degraded
5669
+ };
5670
+ try {
5671
+ cb(diagnostics);
5672
+ } catch {
5673
+ }
5674
+ };
5502
5675
  if (!query || typeof query !== "string" || query.trim().length === 0) {
5676
+ emitDiagnostics(0);
5503
5677
  return { memories: [], usedBudget, reranked: false, candidateCount: 0 };
5504
5678
  }
5505
5679
  const needsChunkEmbedding = types.includes("chunk") && ctx.storageCtx;
5506
5680
  const wantsTemporal = types.includes("fact") && ctx.vaultCtx;
5681
+ const prepStart = nowMs();
5507
5682
  const [queryEmbedding, entityRanking, temporalRanking] = await Promise.all([
5508
5683
  needsChunkEmbedding ? generateEmbedding(query, ctx.embeddingOptions) : Promise.resolve(void 0),
5509
5684
  buildGraphLaneRanking(query, ctx),
5510
5685
  wantsTemporal ? buildTemporalLaneRanking(query, ctx.vaultCtx, options.now) : Promise.resolve([])
5511
5686
  ]);
5512
- const factResults = [];
5513
- const chunkResults = [];
5514
- let vaultSize;
5687
+ prepMs = nowMs() - prepStart;
5515
5688
  if (types.includes("fact") && ctx.vaultCtx && ctx.vaultCache) {
5689
+ const factStart = nowMs();
5516
5690
  const vaultMinScore = options.minScore ?? DEFAULT_FACT_MIN_SCORE;
5517
- const { results, vaultSize: size } = await searchVaultMemoriesWithSize(
5691
+ const {
5692
+ results,
5693
+ vaultSize: size,
5694
+ reranked,
5695
+ hadV2Head: v2Head
5696
+ } = await searchVaultMemoriesWithSize(
5518
5697
  query,
5519
5698
  ctx.vaultCtx,
5520
5699
  ctx.embeddingOptions,
@@ -5565,14 +5744,19 @@ async function recall(query, ctx, options = {}) {
5565
5744
  )
5566
5745
  );
5567
5746
  vaultSize = size;
5747
+ didRerank = reranked;
5748
+ hadV2Head = v2Head;
5749
+ factLaneMs = nowMs() - factStart;
5568
5750
  }
5569
5751
  if (types.includes("chunk") && ctx.storageCtx && queryEmbedding) {
5752
+ const chunkStart = nowMs();
5570
5753
  const chunkMinScore = options.minScore ?? DEFAULT_CHUNK_MIN_SCORE;
5571
5754
  const results = await searchChunksOp(ctx.storageCtx, queryEmbedding, {
5572
5755
  limit: types.includes("fact") ? Math.max(limit * 2, 16) : limit,
5573
5756
  minSimilarity: chunkMinScore,
5574
5757
  embeddingModel: ctx.embeddingOptions.model ?? DEFAULT_API_EMBEDDING_MODEL,
5575
- ...options.conversationId && { conversationId: options.conversationId }
5758
+ ...options.conversationId && { conversationId: options.conversationId },
5759
+ ...ctx.chunkCache && { chunkCache: ctx.chunkCache }
5576
5760
  });
5577
5761
  chunkResults.push(
5578
5762
  ...dedupeBy(
@@ -5582,18 +5766,23 @@ async function recall(query, ctx, options = {}) {
5582
5766
  (r) => r.chunkText.trim()
5583
5767
  )
5584
5768
  );
5769
+ chunkLaneMs = nowMs() - chunkStart;
5585
5770
  }
5771
+ const fuseStart = nowMs();
5586
5772
  if (types.length === 1 || factResults.length === 0 || chunkResults.length === 0) {
5587
5773
  const memories2 = [
5588
5774
  ...factResults.map(toFactMemory),
5589
5775
  ...chunkResults.map(toChunkMemory)
5590
5776
  ];
5591
5777
  memories2.sort((a, b) => b.score - a.score);
5778
+ const candidateCount = factResults.length + chunkResults.length;
5779
+ fuseMs = nowMs() - fuseStart;
5780
+ emitDiagnostics(candidateCount);
5592
5781
  return {
5593
5782
  memories: memories2.slice(0, limit),
5594
5783
  usedBudget,
5595
- reranked: flags.rerank,
5596
- candidateCount: factResults.length + chunkResults.length,
5784
+ reranked: didRerank,
5785
+ candidateCount,
5597
5786
  ...vaultSize !== void 0 && { vaultSize }
5598
5787
  };
5599
5788
  }
@@ -5642,10 +5831,12 @@ async function recall(query, ctx, options = {}) {
5642
5831
  suppressed = next;
5643
5832
  memories = selectWith(suppressed);
5644
5833
  }
5834
+ fuseMs = nowMs() - fuseStart;
5835
+ emitDiagnostics(byId.size);
5645
5836
  return {
5646
5837
  memories,
5647
5838
  usedBudget,
5648
- reranked: flags.rerank,
5839
+ reranked: didRerank,
5649
5840
  candidateCount: byId.size,
5650
5841
  ...vaultSize !== void 0 && { vaultSize }
5651
5842
  };
@@ -5830,7 +6021,10 @@ export {
5830
6021
  stampTopicsExtractedAtOp,
5831
6022
  deleteAllVaultMemoriesForUserOp,
5832
6023
  updateVaultMemoryEmbeddingOp,
6024
+ RerankerUnavailableError,
6025
+ isRerankerAvailable,
5833
6026
  DEFAULT_VAULT_CACHE_SIZE,
6027
+ LRUCache,
5834
6028
  createVaultEmbeddingCache,
5835
6029
  recall,
5836
6030
  preEmbedVaultMemories,