@anuma/sdk 6.10.0 → 6.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -19307,9 +19307,9 @@ function recencyMultiplier(updatedAt, opts = {}) {
19307
19307
  const updatedMs = updatedAt.getTime();
19308
19308
  if (!Number.isFinite(updatedMs)) return noDate;
19309
19309
  const now = opts.now ?? /* @__PURE__ */ new Date();
19310
- const nowMs2 = now.getTime();
19311
- if (!Number.isFinite(nowMs2)) return noDate;
19312
- const ageDays = Math.max(0, (nowMs2 - updatedMs) / DAY_MS);
19310
+ const nowMs3 = now.getTime();
19311
+ if (!Number.isFinite(nowMs3)) return noDate;
19312
+ const ageDays = Math.max(0, (nowMs3 - updatedMs) / DAY_MS);
19313
19313
  const perYearDecay = opts.perYearDecay ?? DEFAULT_PER_YEAR_DECAY;
19314
19314
  const floor = opts.floor ?? DEFAULT_FLOOR;
19315
19315
  const decay = perYearDecay * (ageDays / 365);
@@ -19655,6 +19655,7 @@ function createVaultEmbeddingCache(maxSize = DEFAULT_VAULT_CACHE_SIZE) {
19655
19655
  }
19656
19656
 
19657
19657
  // src/lib/memoryVault/searchTool.ts
19658
+ var nowMs = () => typeof performance !== "undefined" && typeof performance.now === "function" ? performance.now() : Date.now();
19658
19659
  var warnedProgrammaticDecomposeIgnored = false;
19659
19660
  function normalizeEventTimeKind(kind) {
19660
19661
  return kind === "point" || kind === "range" || kind === "ongoing" ? kind : null;
@@ -19887,6 +19888,7 @@ async function rankFusedVaultMemoriesAsync(query, queryEmbedding, items, options
19887
19888
  const rerankTopN = options.rerankTopN ?? 30;
19888
19889
  const ceWeight = options.ceWeight ?? 0.1;
19889
19890
  const headSlice = v2Ranked.slice(0, rerankTopN);
19891
+ const ceStart = nowMs();
19890
19892
  try {
19891
19893
  const reranked = await rerankPairs(
19892
19894
  query,
@@ -19914,6 +19916,8 @@ async function rankFusedVaultMemoriesAsync(query, queryEmbedding, items, options
19914
19916
  getLogger().warn("[memory/search] cross-encoder rerank failed; using V2 ranking", err);
19915
19917
  }
19916
19918
  combined = v2Ranked;
19919
+ } finally {
19920
+ if (options.rerankStats) options.rerankStats.ms += nowMs() - ceStart;
19917
19921
  }
19918
19922
  } else {
19919
19923
  combined = v2Ranked;
@@ -20080,6 +20084,7 @@ async function rankComposite(originalQuery, originalQueryEmbedding, subQueries,
20080
20084
  const ceWeight = options.ceWeight ?? 0.1;
20081
20085
  const headSlice = combined.slice(0, rerankTopN);
20082
20086
  const tailSlice = combined.slice(rerankTopN);
20087
+ const ceStart = nowMs();
20083
20088
  try {
20084
20089
  const reranked = await rerankPairs(
20085
20090
  originalQuery,
@@ -20107,6 +20112,8 @@ async function rankComposite(originalQuery, originalQueryEmbedding, subQueries,
20107
20112
  err
20108
20113
  );
20109
20114
  }
20115
+ } finally {
20116
+ if (options.rerankStats) options.rerankStats.ms += nowMs() - ceStart;
20110
20117
  }
20111
20118
  }
20112
20119
  if (options?.mmr) {
@@ -20233,11 +20240,13 @@ async function buildProjectedCorpus(query, vaultCtx, embeddingOptions, cache, qu
20233
20240
  rowsDecrypted: 0
20234
20241
  };
20235
20242
  }
20243
+ const queryEmbedStart = nowMs();
20236
20244
  const queryEmbedding = await embedQueryOrDegrade(
20237
20245
  query,
20238
20246
  embeddingOptions,
20239
20247
  opts.onEmbeddingDegraded
20240
20248
  );
20249
+ if (opts.embedStats) opts.embedStats.queryMs += nowMs() - queryEmbedStart;
20241
20250
  const embeddingsDegraded = queryEmbedding.length === 0;
20242
20251
  const currentModel = embeddingOptions.model ?? DEFAULT_API_EMBEDDING_MODEL;
20243
20252
  const vectored = [];
@@ -20290,6 +20299,7 @@ async function buildProjectedCorpus(query, vaultCtx, embeddingOptions, cache, qu
20290
20299
  const laneRows = laneFetched.filter((m) => !isEncrypted(m.content));
20291
20300
  if (laneRows.length > 0) {
20292
20301
  let laneVecs;
20302
+ if (opts.embedStats) opts.embedStats.rowsEmbedded += laneRows.length;
20293
20303
  try {
20294
20304
  laneVecs = await generateEmbeddings(
20295
20305
  laneRows.map((m) => m.content),
@@ -20368,6 +20378,10 @@ async function buildProjectedCorpus(query, vaultCtx, embeddingOptions, cache, qu
20368
20378
  async function prepareVaultCandidates(query, vaultCtx, embeddingOptions, cache, searchOptions) {
20369
20379
  if (!query || typeof query !== "string") {
20370
20380
  return {
20381
+ // Nothing was read and nothing was embedded — the short-circuit fires
20382
+ // before either.
20383
+ queryEmbedMs: 0,
20384
+ rowsEmbedded: 0,
20371
20385
  memories: [],
20372
20386
  embeddedItems: [],
20373
20387
  queryEmbedding: [],
@@ -20400,6 +20414,7 @@ async function prepareVaultCandidates(query, vaultCtx, embeddingOptions, cache,
20400
20414
  embeddingsUnavailable = true;
20401
20415
  embeddingFailure = true;
20402
20416
  };
20417
+ const embedStats = { queryMs: 0, rowsEmbedded: 0 };
20403
20418
  if (searchOptions?.decryptLast) {
20404
20419
  const forceIncludeIds = [
20405
20420
  ...searchOptions.entityRanking ?? [],
@@ -20411,7 +20426,8 @@ async function prepareVaultCandidates(query, vaultCtx, embeddingOptions, cache,
20411
20426
  admitFloor: ADMIT_FLOOR,
20412
20427
  unembeddedCap: UNEMBEDDED_CAP,
20413
20428
  ...forceIncludeIds.length > 0 && { forceIncludeIds },
20414
- onEmbeddingDegraded
20429
+ onEmbeddingDegraded,
20430
+ embedStats
20415
20431
  });
20416
20432
  if (corpus.vaultSize === 0) {
20417
20433
  return {
@@ -20422,7 +20438,9 @@ async function prepareVaultCandidates(query, vaultCtx, embeddingOptions, cache,
20422
20438
  embeddingsUnavailable: false,
20423
20439
  embeddingFailure: false,
20424
20440
  decryptLast: true,
20425
- rowsDecrypted: corpus.rowsDecrypted
20441
+ rowsDecrypted: corpus.rowsDecrypted,
20442
+ queryEmbedMs: embedStats.queryMs,
20443
+ rowsEmbedded: embedStats.rowsEmbedded
20426
20444
  };
20427
20445
  }
20428
20446
  ({ memories, embeddedItems, queryEmbedding, vaultSize } = corpus);
@@ -20439,7 +20457,9 @@ async function prepareVaultCandidates(query, vaultCtx, embeddingOptions, cache,
20439
20457
  decryptLast: true,
20440
20458
  // Rows WERE decrypt-attempted even though none came back readable — that
20441
20459
  // is the whole point of reporting attempts rather than successes.
20442
- rowsDecrypted: corpus.rowsDecrypted
20460
+ rowsDecrypted: corpus.rowsDecrypted,
20461
+ queryEmbedMs: embedStats.queryMs,
20462
+ rowsEmbedded: embedStats.rowsEmbedded
20443
20463
  };
20444
20464
  }
20445
20465
  } else {
@@ -20464,10 +20484,14 @@ async function prepareVaultCandidates(query, vaultCtx, embeddingOptions, cache,
20464
20484
  embeddingsUnavailable: false,
20465
20485
  embeddingFailure: false,
20466
20486
  decryptLast: false,
20467
- rowsDecrypted: loaded.length
20487
+ rowsDecrypted: loaded.length,
20488
+ queryEmbedMs: embedStats.queryMs,
20489
+ rowsEmbedded: embedStats.rowsEmbedded
20468
20490
  };
20469
20491
  }
20492
+ const legacyEmbedStart = nowMs();
20470
20493
  queryEmbedding = await embedQueryOrDegrade(query, embeddingOptions, onEmbeddingDegraded);
20494
+ embedStats.queryMs += nowMs() - legacyEmbedStart;
20471
20495
  const currentModel = embeddingOptions.model ?? DEFAULT_API_EMBEDDING_MODEL;
20472
20496
  const uncachedTexts = [];
20473
20497
  const uncachedIndices = [];
@@ -20501,6 +20525,7 @@ async function prepareVaultCandidates(query, vaultCtx, embeddingOptions, cache,
20501
20525
  }
20502
20526
  if (uncachedTexts.length > 0) {
20503
20527
  let newEmbeddings;
20528
+ embedStats.rowsEmbedded += uncachedTexts.length;
20504
20529
  try {
20505
20530
  newEmbeddings = await generateEmbeddings(uncachedTexts, embeddingOptions);
20506
20531
  } catch (err) {
@@ -20544,6 +20569,8 @@ async function prepareVaultCandidates(query, vaultCtx, embeddingOptions, cache,
20544
20569
  embeddingsUnavailable = true;
20545
20570
  }
20546
20571
  return {
20572
+ queryEmbedMs: embedStats.queryMs,
20573
+ rowsEmbedded: embedStats.rowsEmbedded,
20547
20574
  memories,
20548
20575
  embeddedItems,
20549
20576
  queryEmbedding,
@@ -20594,11 +20621,15 @@ async function rankPreparedVaultCandidates(query, prepared, embeddingOptions, se
20594
20621
  results: results2,
20595
20622
  vaultSize: out.vaultSize,
20596
20623
  reranked: out.reranked ?? false,
20624
+ // Read straight off the shared stats object rather than being passed in at
20625
+ // each call site: every return in this function funnels through here, so a
20626
+ // path added later reports the CE bill without having to remember to.
20627
+ rerankMs: rerankStats.ms,
20597
20628
  hadV2Head: out.hadV2Head ?? false,
20598
20629
  embeddingsUnavailable
20599
20630
  };
20600
20631
  };
20601
- const rerankStats = { applied: false };
20632
+ const rerankStats = { applied: false, ms: 0 };
20602
20633
  const useFusion = searchOptions?.useFusion ?? true;
20603
20634
  const tuning = {
20604
20635
  ...searchOptions?.recencyAlpha !== void 0 && { recencyAlpha: searchOptions.recencyAlpha },
@@ -20717,13 +20748,16 @@ async function searchVaultMemoriesWithSize(query, vaultCtx, embeddingOptions, ca
20717
20748
  results: [],
20718
20749
  vaultSize: 0,
20719
20750
  reranked: false,
20751
+ rerankMs: 0,
20720
20752
  hadV2Head: false,
20721
20753
  embeddingsUnavailable: false,
20722
20754
  rankedOnCosine: false,
20723
20755
  // No storage read happened, so nothing was decrypted; report the path the
20724
20756
  // caller asked for so this turn is still attributable.
20725
20757
  decryptLast: !!searchOptions?.decryptLast,
20726
- rowsDecrypted: 0
20758
+ rowsDecrypted: 0,
20759
+ queryEmbedMs: 0,
20760
+ rowsEmbedded: 0
20727
20761
  };
20728
20762
  }
20729
20763
  if (searchOptions?.decompose === "llm" && normalizeSubQueries(searchOptions.subQueries).length < 2 && !warnedProgrammaticDecomposeIgnored) {
@@ -20744,11 +20778,14 @@ async function searchVaultMemoriesWithSize(query, vaultCtx, embeddingOptions, ca
20744
20778
  results: [],
20745
20779
  vaultSize: 0,
20746
20780
  reranked: false,
20781
+ rerankMs: 0,
20747
20782
  hadV2Head: false,
20748
20783
  embeddingsUnavailable: prepared.embeddingsUnavailable,
20749
20784
  rankedOnCosine: false,
20750
20785
  decryptLast: prepared.decryptLast,
20751
- rowsDecrypted: prepared.rowsDecrypted
20786
+ rowsDecrypted: prepared.rowsDecrypted,
20787
+ queryEmbedMs: prepared.queryEmbedMs,
20788
+ rowsEmbedded: prepared.rowsEmbedded
20752
20789
  };
20753
20790
  }
20754
20791
  if (prepared.memories.length === 0) {
@@ -20756,11 +20793,14 @@ async function searchVaultMemoriesWithSize(query, vaultCtx, embeddingOptions, ca
20756
20793
  results: [],
20757
20794
  vaultSize: prepared.vaultSize,
20758
20795
  reranked: false,
20796
+ rerankMs: 0,
20759
20797
  hadV2Head: false,
20760
20798
  embeddingsUnavailable: prepared.embeddingsUnavailable,
20761
20799
  rankedOnCosine: false,
20762
20800
  decryptLast: prepared.decryptLast,
20763
- rowsDecrypted: prepared.rowsDecrypted
20801
+ rowsDecrypted: prepared.rowsDecrypted,
20802
+ queryEmbedMs: prepared.queryEmbedMs,
20803
+ rowsEmbedded: prepared.rowsEmbedded
20764
20804
  };
20765
20805
  }
20766
20806
  const ranked = await rankPreparedVaultCandidates(
@@ -20773,7 +20813,9 @@ async function searchVaultMemoriesWithSize(query, vaultCtx, embeddingOptions, ca
20773
20813
  ...ranked,
20774
20814
  rankedOnCosine: !ranked.embeddingsUnavailable,
20775
20815
  decryptLast: prepared.decryptLast,
20776
- rowsDecrypted: prepared.rowsDecrypted
20816
+ rowsDecrypted: prepared.rowsDecrypted,
20817
+ queryEmbedMs: prepared.queryEmbedMs,
20818
+ rowsEmbedded: prepared.rowsEmbedded
20777
20819
  };
20778
20820
  }
20779
20821
  async function searchVaultMemories(query, vaultCtx, embeddingOptions, cache, searchOptions) {
@@ -20878,7 +20920,7 @@ function createMemoryVaultSearchTool(vaultCtx, embeddingOptions, cache, searchOp
20878
20920
  subQueries = decomp.subQueries;
20879
20921
  }
20880
20922
  }
20881
- const { recall: recall2 } = await import("./recall-T7CNXTQ3.mjs");
20923
+ const { recall: recall2 } = await import("./recall-HVIEAH7J.mjs");
20882
20924
  let recallDegraded = [];
20883
20925
  const result = await recall2(
20884
20926
  query,
@@ -21418,7 +21460,7 @@ function scoreEventTimeOverlap(memoryStart, memoryEnd, memoryKind, window2) {
21418
21460
  var DEFAULT_LIMIT = 8;
21419
21461
  var DEFAULT_BUDGET = "low";
21420
21462
  var DEFAULT_FACT_MIN_SCORE = 0.1;
21421
- var nowMs = () => typeof performance !== "undefined" && typeof performance.now === "function" ? performance.now() : Date.now();
21463
+ var nowMs2 = () => typeof performance !== "undefined" && typeof performance.now === "function" ? performance.now() : Date.now();
21422
21464
  var DEFAULT_CHUNK_MIN_SCORE = 0.5;
21423
21465
  function flagsForBudget(budget) {
21424
21466
  switch (budget) {
@@ -21451,7 +21493,7 @@ async function recall(query, ctx, options = {}) {
21451
21493
  const flags = flagsForBudget(usedBudget);
21452
21494
  const normalizedFacets = normalizeSubQueries(options.subQueries);
21453
21495
  const subQueries = normalizedFacets.length >= 2 ? normalizedFacets : void 0;
21454
- const t0 = nowMs();
21496
+ const t0 = nowMs2();
21455
21497
  let prepMs = 0;
21456
21498
  let factLaneMs = 0;
21457
21499
  let chunkLaneMs = 0;
@@ -21460,6 +21502,9 @@ async function recall(query, ctx, options = {}) {
21460
21502
  const chunkResults = [];
21461
21503
  let vaultSize;
21462
21504
  let didRerank = false;
21505
+ let rerankMs = 0;
21506
+ let queryEmbedMs = 0;
21507
+ let vaultRowsEmbedded;
21463
21508
  let hadV2Head = false;
21464
21509
  let embeddingsUnavailable = false;
21465
21510
  let chunkEmbedFailed = false;
@@ -21484,12 +21529,15 @@ async function recall(query, ctx, options = {}) {
21484
21529
  ...vaultSize !== void 0 && { vaultSize },
21485
21530
  ...decryptLastRan !== void 0 && { decryptLast: decryptLastRan },
21486
21531
  ...vaultRowsDecrypted !== void 0 && { vaultRowsDecrypted },
21532
+ ...vaultRowsEmbedded !== void 0 && { vaultRowsEmbedded },
21487
21533
  factCount: factResults.length,
21488
21534
  chunkCount: chunkResults.length,
21489
21535
  timings: {
21490
- total: nowMs() - t0,
21536
+ total: nowMs2() - t0,
21491
21537
  prep: prepMs,
21492
21538
  factLane: factLaneMs,
21539
+ rerank: rerankMs,
21540
+ queryEmbed: queryEmbedMs,
21493
21541
  chunkLane: chunkLaneMs,
21494
21542
  fuse: fuseMs
21495
21543
  },
@@ -21507,7 +21555,7 @@ async function recall(query, ctx, options = {}) {
21507
21555
  const needsChunkEmbedding = types.includes("chunk") && ctx.storageCtx;
21508
21556
  const wantsTemporal = types.includes("fact") && ctx.vaultCtx;
21509
21557
  const graphRefiner = flags.traverse && options.graphRefine && options.decomposeOptions ? createLlmNeighborRefiner(options.decomposeOptions) : void 0;
21510
- const prepStart = nowMs();
21558
+ const prepStart = nowMs2();
21511
21559
  const [queryEmbedding, entityRanking, temporalRanking] = await Promise.all([
21512
21560
  // The chunk lane is cosine-only — `searchChunksOp` needs a real vector, and
21513
21561
  // there is no lexical fallback for it — so an embeddings outage must SKIP the
@@ -21545,14 +21593,17 @@ async function recall(query, ctx, options = {}) {
21545
21593
  ),
21546
21594
  wantsTemporal ? safeLane("temporal", () => buildTemporalLaneRanking(query, ctx.vaultCtx, options.now)) : Promise.resolve([])
21547
21595
  ]);
21548
- prepMs = nowMs() - prepStart;
21596
+ prepMs = nowMs2() - prepStart;
21549
21597
  if (types.includes("fact") && ctx.vaultCtx && ctx.vaultCache) {
21550
- const factStart = nowMs();
21598
+ const factStart = nowMs2();
21551
21599
  const vaultMinScore = options.minScore ?? DEFAULT_FACT_MIN_SCORE;
21552
21600
  const {
21553
21601
  results,
21554
21602
  vaultSize: size,
21555
21603
  reranked,
21604
+ rerankMs: factRerankMs,
21605
+ queryEmbedMs: factQueryEmbedMs,
21606
+ rowsEmbedded: factRowsEmbedded,
21556
21607
  hadV2Head: v2Head,
21557
21608
  embeddingsUnavailable: factEmbeddingsUnavailable,
21558
21609
  rankedOnCosine: factRankedOnCosine,
@@ -21611,16 +21662,19 @@ async function recall(query, ctx, options = {}) {
21611
21662
  );
21612
21663
  vaultSize = size;
21613
21664
  didRerank = reranked;
21665
+ rerankMs = factRerankMs;
21666
+ queryEmbedMs = factQueryEmbedMs;
21667
+ vaultRowsEmbedded = factRowsEmbedded;
21614
21668
  hadV2Head = v2Head;
21615
21669
  if (factEmbeddingsUnavailable) embeddingsUnavailable = true;
21616
21670
  factLaneRankedOnCosine = factRankedOnCosine;
21617
21671
  decryptLastRan = factDecryptLast;
21618
21672
  vaultRowsDecrypted = factRowsDecrypted;
21619
- factLaneMs = nowMs() - factStart;
21673
+ factLaneMs = nowMs2() - factStart;
21620
21674
  }
21621
21675
  if (chunkEmbedFailed && !factLaneRankedOnCosine) embeddingsUnavailable = true;
21622
21676
  if (types.includes("chunk") && ctx.storageCtx && queryEmbedding) {
21623
- const chunkStart = nowMs();
21677
+ const chunkStart = nowMs2();
21624
21678
  const chunkMinScore = options.minScore ?? DEFAULT_CHUNK_MIN_SCORE;
21625
21679
  const results = await searchChunksOp(ctx.storageCtx, queryEmbedding, {
21626
21680
  limit: types.includes("fact") ? Math.max(limit * 2, 16) : limit,
@@ -21637,9 +21691,9 @@ async function recall(query, ctx, options = {}) {
21637
21691
  (r) => r.chunkText.trim()
21638
21692
  )
21639
21693
  );
21640
- chunkLaneMs = nowMs() - chunkStart;
21694
+ chunkLaneMs = nowMs2() - chunkStart;
21641
21695
  }
21642
- const fuseStart = nowMs();
21696
+ const fuseStart = nowMs2();
21643
21697
  if (types.length === 1 || factResults.length === 0 || chunkResults.length === 0) {
21644
21698
  const memories2 = [
21645
21699
  ...factResults.map((r) => toFactMemory(r, options.now)),
@@ -21647,7 +21701,7 @@ async function recall(query, ctx, options = {}) {
21647
21701
  ];
21648
21702
  memories2.sort((a, b) => b.score - a.score);
21649
21703
  const candidateCount = factResults.length + chunkResults.length;
21650
- fuseMs = nowMs() - fuseStart;
21704
+ fuseMs = nowMs2() - fuseStart;
21651
21705
  emitDiagnostics(candidateCount);
21652
21706
  return {
21653
21707
  memories: memories2.slice(0, limit),
@@ -21702,7 +21756,7 @@ async function recall(query, ctx, options = {}) {
21702
21756
  suppressed = next;
21703
21757
  memories = selectWith(suppressed);
21704
21758
  }
21705
- fuseMs = nowMs() - fuseStart;
21759
+ fuseMs = nowMs2() - fuseStart;
21706
21760
  emitDiagnostics(byId.size);
21707
21761
  return {
21708
21762
  memories,
@@ -20236,9 +20236,9 @@ function recencyMultiplier(updatedAt, opts = {}) {
20236
20236
  const updatedMs = updatedAt.getTime();
20237
20237
  if (!Number.isFinite(updatedMs)) return noDate;
20238
20238
  const now = opts.now ?? /* @__PURE__ */ new Date();
20239
- const nowMs2 = now.getTime();
20240
- if (!Number.isFinite(nowMs2)) return noDate;
20241
- const ageDays2 = Math.max(0, (nowMs2 - updatedMs) / DAY_MS2);
20239
+ const nowMs3 = now.getTime();
20240
+ if (!Number.isFinite(nowMs3)) return noDate;
20241
+ const ageDays2 = Math.max(0, (nowMs3 - updatedMs) / DAY_MS2);
20242
20242
  const perYearDecay = opts.perYearDecay ?? DEFAULT_PER_YEAR_DECAY;
20243
20243
  const floor = opts.floor ?? DEFAULT_FLOOR;
20244
20244
  const decay = perYearDecay * (ageDays2 / 365);
@@ -21576,6 +21576,9 @@ async function recall(query, ctx, options = {}) {
21576
21576
  const chunkResults = [];
21577
21577
  let vaultSize;
21578
21578
  let didRerank = false;
21579
+ let rerankMs = 0;
21580
+ let queryEmbedMs = 0;
21581
+ let vaultRowsEmbedded;
21579
21582
  let hadV2Head = false;
21580
21583
  let embeddingsUnavailable = false;
21581
21584
  let chunkEmbedFailed = false;
@@ -21600,12 +21603,15 @@ async function recall(query, ctx, options = {}) {
21600
21603
  ...vaultSize !== void 0 && { vaultSize },
21601
21604
  ...decryptLastRan !== void 0 && { decryptLast: decryptLastRan },
21602
21605
  ...vaultRowsDecrypted !== void 0 && { vaultRowsDecrypted },
21606
+ ...vaultRowsEmbedded !== void 0 && { vaultRowsEmbedded },
21603
21607
  factCount: factResults.length,
21604
21608
  chunkCount: chunkResults.length,
21605
21609
  timings: {
21606
21610
  total: nowMs() - t0,
21607
21611
  prep: prepMs,
21608
21612
  factLane: factLaneMs,
21613
+ rerank: rerankMs,
21614
+ queryEmbed: queryEmbedMs,
21609
21615
  chunkLane: chunkLaneMs,
21610
21616
  fuse: fuseMs
21611
21617
  },
@@ -21669,6 +21675,9 @@ async function recall(query, ctx, options = {}) {
21669
21675
  results,
21670
21676
  vaultSize: size,
21671
21677
  reranked,
21678
+ rerankMs: factRerankMs,
21679
+ queryEmbedMs: factQueryEmbedMs,
21680
+ rowsEmbedded: factRowsEmbedded,
21672
21681
  hadV2Head: v2Head,
21673
21682
  embeddingsUnavailable: factEmbeddingsUnavailable,
21674
21683
  rankedOnCosine: factRankedOnCosine,
@@ -21727,6 +21736,9 @@ async function recall(query, ctx, options = {}) {
21727
21736
  );
21728
21737
  vaultSize = size;
21729
21738
  didRerank = reranked;
21739
+ rerankMs = factRerankMs;
21740
+ queryEmbedMs = factQueryEmbedMs;
21741
+ vaultRowsEmbedded = factRowsEmbedded;
21730
21742
  hadV2Head = v2Head;
21731
21743
  if (factEmbeddingsUnavailable) embeddingsUnavailable = true;
21732
21744
  factLaneRankedOnCosine = factRankedOnCosine;
@@ -22191,6 +22203,7 @@ async function rankFusedVaultMemoriesAsync(query, queryEmbedding, items, options
22191
22203
  const rerankTopN = options.rerankTopN ?? 30;
22192
22204
  const ceWeight = options.ceWeight ?? 0.1;
22193
22205
  const headSlice = v2Ranked.slice(0, rerankTopN);
22206
+ const ceStart = nowMs2();
22194
22207
  try {
22195
22208
  const reranked = await rerankPairs(
22196
22209
  query,
@@ -22218,6 +22231,8 @@ async function rankFusedVaultMemoriesAsync(query, queryEmbedding, items, options
22218
22231
  getLogger().warn("[memory/search] cross-encoder rerank failed; using V2 ranking", err);
22219
22232
  }
22220
22233
  combined = v2Ranked;
22234
+ } finally {
22235
+ if (options.rerankStats) options.rerankStats.ms += nowMs2() - ceStart;
22221
22236
  }
22222
22237
  } else {
22223
22238
  combined = v2Ranked;
@@ -22384,6 +22399,7 @@ async function rankComposite(originalQuery, originalQueryEmbedding, subQueries,
22384
22399
  const ceWeight = options.ceWeight ?? 0.1;
22385
22400
  const headSlice = combined.slice(0, rerankTopN);
22386
22401
  const tailSlice = combined.slice(rerankTopN);
22402
+ const ceStart = nowMs2();
22387
22403
  try {
22388
22404
  const reranked = await rerankPairs(
22389
22405
  originalQuery,
@@ -22411,6 +22427,8 @@ async function rankComposite(originalQuery, originalQueryEmbedding, subQueries,
22411
22427
  err
22412
22428
  );
22413
22429
  }
22430
+ } finally {
22431
+ if (options.rerankStats) options.rerankStats.ms += nowMs2() - ceStart;
22414
22432
  }
22415
22433
  }
22416
22434
  if (options?.mmr) {
@@ -22537,11 +22555,13 @@ async function buildProjectedCorpus(query, vaultCtx, embeddingOptions, cache, qu
22537
22555
  rowsDecrypted: 0
22538
22556
  };
22539
22557
  }
22558
+ const queryEmbedStart = nowMs2();
22540
22559
  const queryEmbedding = await embedQueryOrDegrade(
22541
22560
  query,
22542
22561
  embeddingOptions,
22543
22562
  opts.onEmbeddingDegraded
22544
22563
  );
22564
+ if (opts.embedStats) opts.embedStats.queryMs += nowMs2() - queryEmbedStart;
22545
22565
  const embeddingsDegraded = queryEmbedding.length === 0;
22546
22566
  const currentModel = embeddingOptions.model ?? DEFAULT_API_EMBEDDING_MODEL;
22547
22567
  const vectored = [];
@@ -22594,6 +22614,7 @@ async function buildProjectedCorpus(query, vaultCtx, embeddingOptions, cache, qu
22594
22614
  const laneRows = laneFetched.filter((m) => !isEncrypted(m.content));
22595
22615
  if (laneRows.length > 0) {
22596
22616
  let laneVecs;
22617
+ if (opts.embedStats) opts.embedStats.rowsEmbedded += laneRows.length;
22597
22618
  try {
22598
22619
  laneVecs = await generateEmbeddings(
22599
22620
  laneRows.map((m) => m.content),
@@ -22672,6 +22693,10 @@ async function buildProjectedCorpus(query, vaultCtx, embeddingOptions, cache, qu
22672
22693
  async function prepareVaultCandidates(query, vaultCtx, embeddingOptions, cache, searchOptions) {
22673
22694
  if (!query || typeof query !== "string") {
22674
22695
  return {
22696
+ // Nothing was read and nothing was embedded — the short-circuit fires
22697
+ // before either.
22698
+ queryEmbedMs: 0,
22699
+ rowsEmbedded: 0,
22675
22700
  memories: [],
22676
22701
  embeddedItems: [],
22677
22702
  queryEmbedding: [],
@@ -22704,6 +22729,7 @@ async function prepareVaultCandidates(query, vaultCtx, embeddingOptions, cache,
22704
22729
  embeddingsUnavailable = true;
22705
22730
  embeddingFailure = true;
22706
22731
  };
22732
+ const embedStats = { queryMs: 0, rowsEmbedded: 0 };
22707
22733
  if (searchOptions?.decryptLast) {
22708
22734
  const forceIncludeIds = [
22709
22735
  ...searchOptions.entityRanking ?? [],
@@ -22715,7 +22741,8 @@ async function prepareVaultCandidates(query, vaultCtx, embeddingOptions, cache,
22715
22741
  admitFloor: ADMIT_FLOOR,
22716
22742
  unembeddedCap: UNEMBEDDED_CAP,
22717
22743
  ...forceIncludeIds.length > 0 && { forceIncludeIds },
22718
- onEmbeddingDegraded
22744
+ onEmbeddingDegraded,
22745
+ embedStats
22719
22746
  });
22720
22747
  if (corpus.vaultSize === 0) {
22721
22748
  return {
@@ -22726,7 +22753,9 @@ async function prepareVaultCandidates(query, vaultCtx, embeddingOptions, cache,
22726
22753
  embeddingsUnavailable: false,
22727
22754
  embeddingFailure: false,
22728
22755
  decryptLast: true,
22729
- rowsDecrypted: corpus.rowsDecrypted
22756
+ rowsDecrypted: corpus.rowsDecrypted,
22757
+ queryEmbedMs: embedStats.queryMs,
22758
+ rowsEmbedded: embedStats.rowsEmbedded
22730
22759
  };
22731
22760
  }
22732
22761
  ({ memories, embeddedItems, queryEmbedding, vaultSize } = corpus);
@@ -22743,7 +22772,9 @@ async function prepareVaultCandidates(query, vaultCtx, embeddingOptions, cache,
22743
22772
  decryptLast: true,
22744
22773
  // Rows WERE decrypt-attempted even though none came back readable — that
22745
22774
  // is the whole point of reporting attempts rather than successes.
22746
- rowsDecrypted: corpus.rowsDecrypted
22775
+ rowsDecrypted: corpus.rowsDecrypted,
22776
+ queryEmbedMs: embedStats.queryMs,
22777
+ rowsEmbedded: embedStats.rowsEmbedded
22747
22778
  };
22748
22779
  }
22749
22780
  } else {
@@ -22768,10 +22799,14 @@ async function prepareVaultCandidates(query, vaultCtx, embeddingOptions, cache,
22768
22799
  embeddingsUnavailable: false,
22769
22800
  embeddingFailure: false,
22770
22801
  decryptLast: false,
22771
- rowsDecrypted: loaded.length
22802
+ rowsDecrypted: loaded.length,
22803
+ queryEmbedMs: embedStats.queryMs,
22804
+ rowsEmbedded: embedStats.rowsEmbedded
22772
22805
  };
22773
22806
  }
22807
+ const legacyEmbedStart = nowMs2();
22774
22808
  queryEmbedding = await embedQueryOrDegrade(query, embeddingOptions, onEmbeddingDegraded);
22809
+ embedStats.queryMs += nowMs2() - legacyEmbedStart;
22775
22810
  const currentModel = embeddingOptions.model ?? DEFAULT_API_EMBEDDING_MODEL;
22776
22811
  const uncachedTexts = [];
22777
22812
  const uncachedIndices = [];
@@ -22805,6 +22840,7 @@ async function prepareVaultCandidates(query, vaultCtx, embeddingOptions, cache,
22805
22840
  }
22806
22841
  if (uncachedTexts.length > 0) {
22807
22842
  let newEmbeddings;
22843
+ embedStats.rowsEmbedded += uncachedTexts.length;
22808
22844
  try {
22809
22845
  newEmbeddings = await generateEmbeddings(uncachedTexts, embeddingOptions);
22810
22846
  } catch (err) {
@@ -22848,6 +22884,8 @@ async function prepareVaultCandidates(query, vaultCtx, embeddingOptions, cache,
22848
22884
  embeddingsUnavailable = true;
22849
22885
  }
22850
22886
  return {
22887
+ queryEmbedMs: embedStats.queryMs,
22888
+ rowsEmbedded: embedStats.rowsEmbedded,
22851
22889
  memories,
22852
22890
  embeddedItems,
22853
22891
  queryEmbedding,
@@ -22898,11 +22936,15 @@ async function rankPreparedVaultCandidates(query, prepared, embeddingOptions, se
22898
22936
  results: results2,
22899
22937
  vaultSize: out.vaultSize,
22900
22938
  reranked: out.reranked ?? false,
22939
+ // Read straight off the shared stats object rather than being passed in at
22940
+ // each call site: every return in this function funnels through here, so a
22941
+ // path added later reports the CE bill without having to remember to.
22942
+ rerankMs: rerankStats.ms,
22901
22943
  hadV2Head: out.hadV2Head ?? false,
22902
22944
  embeddingsUnavailable
22903
22945
  };
22904
22946
  };
22905
- const rerankStats = { applied: false };
22947
+ const rerankStats = { applied: false, ms: 0 };
22906
22948
  const useFusion = searchOptions?.useFusion ?? true;
22907
22949
  const tuning = {
22908
22950
  ...searchOptions?.recencyAlpha !== void 0 && { recencyAlpha: searchOptions.recencyAlpha },
@@ -23021,13 +23063,16 @@ async function searchVaultMemoriesWithSize(query, vaultCtx, embeddingOptions, ca
23021
23063
  results: [],
23022
23064
  vaultSize: 0,
23023
23065
  reranked: false,
23066
+ rerankMs: 0,
23024
23067
  hadV2Head: false,
23025
23068
  embeddingsUnavailable: false,
23026
23069
  rankedOnCosine: false,
23027
23070
  // No storage read happened, so nothing was decrypted; report the path the
23028
23071
  // caller asked for so this turn is still attributable.
23029
23072
  decryptLast: !!searchOptions?.decryptLast,
23030
- rowsDecrypted: 0
23073
+ rowsDecrypted: 0,
23074
+ queryEmbedMs: 0,
23075
+ rowsEmbedded: 0
23031
23076
  };
23032
23077
  }
23033
23078
  if (searchOptions?.decompose === "llm" && normalizeSubQueries(searchOptions.subQueries).length < 2 && !warnedProgrammaticDecomposeIgnored) {
@@ -23048,11 +23093,14 @@ async function searchVaultMemoriesWithSize(query, vaultCtx, embeddingOptions, ca
23048
23093
  results: [],
23049
23094
  vaultSize: 0,
23050
23095
  reranked: false,
23096
+ rerankMs: 0,
23051
23097
  hadV2Head: false,
23052
23098
  embeddingsUnavailable: prepared.embeddingsUnavailable,
23053
23099
  rankedOnCosine: false,
23054
23100
  decryptLast: prepared.decryptLast,
23055
- rowsDecrypted: prepared.rowsDecrypted
23101
+ rowsDecrypted: prepared.rowsDecrypted,
23102
+ queryEmbedMs: prepared.queryEmbedMs,
23103
+ rowsEmbedded: prepared.rowsEmbedded
23056
23104
  };
23057
23105
  }
23058
23106
  if (prepared.memories.length === 0) {
@@ -23060,11 +23108,14 @@ async function searchVaultMemoriesWithSize(query, vaultCtx, embeddingOptions, ca
23060
23108
  results: [],
23061
23109
  vaultSize: prepared.vaultSize,
23062
23110
  reranked: false,
23111
+ rerankMs: 0,
23063
23112
  hadV2Head: false,
23064
23113
  embeddingsUnavailable: prepared.embeddingsUnavailable,
23065
23114
  rankedOnCosine: false,
23066
23115
  decryptLast: prepared.decryptLast,
23067
- rowsDecrypted: prepared.rowsDecrypted
23116
+ rowsDecrypted: prepared.rowsDecrypted,
23117
+ queryEmbedMs: prepared.queryEmbedMs,
23118
+ rowsEmbedded: prepared.rowsEmbedded
23068
23119
  };
23069
23120
  }
23070
23121
  const ranked = await rankPreparedVaultCandidates(
@@ -23077,7 +23128,9 @@ async function searchVaultMemoriesWithSize(query, vaultCtx, embeddingOptions, ca
23077
23128
  ...ranked,
23078
23129
  rankedOnCosine: !ranked.embeddingsUnavailable,
23079
23130
  decryptLast: prepared.decryptLast,
23080
- rowsDecrypted: prepared.rowsDecrypted
23131
+ rowsDecrypted: prepared.rowsDecrypted,
23132
+ queryEmbedMs: prepared.queryEmbedMs,
23133
+ rowsEmbedded: prepared.rowsEmbedded
23081
23134
  };
23082
23135
  }
23083
23136
  async function searchVaultMemories(query, vaultCtx, embeddingOptions, cache, searchOptions) {
@@ -23227,7 +23280,7 @@ ${formatted}`;
23227
23280
  }
23228
23281
  };
23229
23282
  }
23230
- var warnedProgrammaticDecomposeIgnored, SUPERSESSION_SIMILARITY_THRESHOLD, SUPERSESSION_MIN_AGE_GAP_MS, SUPERSESSION_BOOST_FACTOR, SUPERSESSION_MAX_WINDOW, EMBEDDINGS_DEGRADED_EMPTY_NO_LEXICAL;
23283
+ var nowMs2, warnedProgrammaticDecomposeIgnored, SUPERSESSION_SIMILARITY_THRESHOLD, SUPERSESSION_MIN_AGE_GAP_MS, SUPERSESSION_BOOST_FACTOR, SUPERSESSION_MAX_WINDOW, EMBEDDINGS_DEGRADED_EMPTY_NO_LEXICAL;
23231
23284
  var init_searchTool = __esm({
23232
23285
  "src/lib/memoryVault/searchTool.ts"() {
23233
23286
  "use strict";
@@ -23245,6 +23298,7 @@ var init_searchTool = __esm({
23245
23298
  init_bm25();
23246
23299
  init_decomposeQuery();
23247
23300
  init_lruCache();
23301
+ nowMs2 = () => typeof performance !== "undefined" && typeof performance.now === "function" ? performance.now() : Date.now();
23248
23302
  warnedProgrammaticDecomposeIgnored = false;
23249
23303
  SUPERSESSION_SIMILARITY_THRESHOLD = 0.7;
23250
23304
  SUPERSESSION_MIN_AGE_GAP_MS = 30 * 24 * 60 * 60 * 1e3;