@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.
@@ -5269,9 +5269,9 @@ function recencyMultiplier(updatedAt, opts = {}) {
5269
5269
  const updatedMs = updatedAt.getTime();
5270
5270
  if (!Number.isFinite(updatedMs)) return noDate;
5271
5271
  const now = opts.now ?? /* @__PURE__ */ new Date();
5272
- const nowMs2 = now.getTime();
5273
- if (!Number.isFinite(nowMs2)) return noDate;
5274
- const ageDays = Math.max(0, (nowMs2 - updatedMs) / DAY_MS);
5272
+ const nowMs3 = now.getTime();
5273
+ if (!Number.isFinite(nowMs3)) return noDate;
5274
+ const ageDays = Math.max(0, (nowMs3 - updatedMs) / DAY_MS);
5275
5275
  const perYearDecay = opts.perYearDecay ?? DEFAULT_PER_YEAR_DECAY;
5276
5276
  const floor = opts.floor ?? DEFAULT_FLOOR;
5277
5277
  const decay = perYearDecay * (ageDays / 365);
@@ -5617,6 +5617,7 @@ function createVaultEmbeddingCache(maxSize = DEFAULT_VAULT_CACHE_SIZE) {
5617
5617
  }
5618
5618
 
5619
5619
  // src/lib/memoryVault/searchTool.ts
5620
+ var nowMs = () => typeof performance !== "undefined" && typeof performance.now === "function" ? performance.now() : Date.now();
5620
5621
  var warnedProgrammaticDecomposeIgnored = false;
5621
5622
  function normalizeEventTimeKind(kind) {
5622
5623
  return kind === "point" || kind === "range" || kind === "ongoing" ? kind : null;
@@ -5849,6 +5850,7 @@ async function rankFusedVaultMemoriesAsync(query, queryEmbedding, items, options
5849
5850
  const rerankTopN = options.rerankTopN ?? 30;
5850
5851
  const ceWeight = options.ceWeight ?? 0.1;
5851
5852
  const headSlice = v2Ranked.slice(0, rerankTopN);
5853
+ const ceStart = nowMs();
5852
5854
  try {
5853
5855
  const reranked = await rerankPairs(
5854
5856
  query,
@@ -5876,6 +5878,8 @@ async function rankFusedVaultMemoriesAsync(query, queryEmbedding, items, options
5876
5878
  getLogger().warn("[memory/search] cross-encoder rerank failed; using V2 ranking", err);
5877
5879
  }
5878
5880
  combined = v2Ranked;
5881
+ } finally {
5882
+ if (options.rerankStats) options.rerankStats.ms += nowMs() - ceStart;
5879
5883
  }
5880
5884
  } else {
5881
5885
  combined = v2Ranked;
@@ -6042,6 +6046,7 @@ async function rankComposite(originalQuery, originalQueryEmbedding, subQueries,
6042
6046
  const ceWeight = options.ceWeight ?? 0.1;
6043
6047
  const headSlice = combined.slice(0, rerankTopN);
6044
6048
  const tailSlice = combined.slice(rerankTopN);
6049
+ const ceStart = nowMs();
6045
6050
  try {
6046
6051
  const reranked = await rerankPairs(
6047
6052
  originalQuery,
@@ -6069,6 +6074,8 @@ async function rankComposite(originalQuery, originalQueryEmbedding, subQueries,
6069
6074
  err
6070
6075
  );
6071
6076
  }
6077
+ } finally {
6078
+ if (options.rerankStats) options.rerankStats.ms += nowMs() - ceStart;
6072
6079
  }
6073
6080
  }
6074
6081
  if (options?.mmr) {
@@ -6195,11 +6202,13 @@ async function buildProjectedCorpus(query, vaultCtx, embeddingOptions, cache, qu
6195
6202
  rowsDecrypted: 0
6196
6203
  };
6197
6204
  }
6205
+ const queryEmbedStart = nowMs();
6198
6206
  const queryEmbedding = await embedQueryOrDegrade(
6199
6207
  query,
6200
6208
  embeddingOptions,
6201
6209
  opts.onEmbeddingDegraded
6202
6210
  );
6211
+ if (opts.embedStats) opts.embedStats.queryMs += nowMs() - queryEmbedStart;
6203
6212
  const embeddingsDegraded = queryEmbedding.length === 0;
6204
6213
  const currentModel = embeddingOptions.model ?? DEFAULT_API_EMBEDDING_MODEL;
6205
6214
  const vectored = [];
@@ -6252,6 +6261,7 @@ async function buildProjectedCorpus(query, vaultCtx, embeddingOptions, cache, qu
6252
6261
  const laneRows = laneFetched.filter((m) => !isEncrypted(m.content));
6253
6262
  if (laneRows.length > 0) {
6254
6263
  let laneVecs;
6264
+ if (opts.embedStats) opts.embedStats.rowsEmbedded += laneRows.length;
6255
6265
  try {
6256
6266
  laneVecs = await generateEmbeddings(
6257
6267
  laneRows.map((m) => m.content),
@@ -6330,6 +6340,10 @@ async function buildProjectedCorpus(query, vaultCtx, embeddingOptions, cache, qu
6330
6340
  async function prepareVaultCandidates(query, vaultCtx, embeddingOptions, cache, searchOptions) {
6331
6341
  if (!query || typeof query !== "string") {
6332
6342
  return {
6343
+ // Nothing was read and nothing was embedded — the short-circuit fires
6344
+ // before either.
6345
+ queryEmbedMs: 0,
6346
+ rowsEmbedded: 0,
6333
6347
  memories: [],
6334
6348
  embeddedItems: [],
6335
6349
  queryEmbedding: [],
@@ -6362,6 +6376,7 @@ async function prepareVaultCandidates(query, vaultCtx, embeddingOptions, cache,
6362
6376
  embeddingsUnavailable = true;
6363
6377
  embeddingFailure = true;
6364
6378
  };
6379
+ const embedStats = { queryMs: 0, rowsEmbedded: 0 };
6365
6380
  if (searchOptions?.decryptLast) {
6366
6381
  const forceIncludeIds = [
6367
6382
  ...searchOptions.entityRanking ?? [],
@@ -6373,7 +6388,8 @@ async function prepareVaultCandidates(query, vaultCtx, embeddingOptions, cache,
6373
6388
  admitFloor: ADMIT_FLOOR,
6374
6389
  unembeddedCap: UNEMBEDDED_CAP,
6375
6390
  ...forceIncludeIds.length > 0 && { forceIncludeIds },
6376
- onEmbeddingDegraded
6391
+ onEmbeddingDegraded,
6392
+ embedStats
6377
6393
  });
6378
6394
  if (corpus.vaultSize === 0) {
6379
6395
  return {
@@ -6384,7 +6400,9 @@ async function prepareVaultCandidates(query, vaultCtx, embeddingOptions, cache,
6384
6400
  embeddingsUnavailable: false,
6385
6401
  embeddingFailure: false,
6386
6402
  decryptLast: true,
6387
- rowsDecrypted: corpus.rowsDecrypted
6403
+ rowsDecrypted: corpus.rowsDecrypted,
6404
+ queryEmbedMs: embedStats.queryMs,
6405
+ rowsEmbedded: embedStats.rowsEmbedded
6388
6406
  };
6389
6407
  }
6390
6408
  ({ memories, embeddedItems, queryEmbedding, vaultSize } = corpus);
@@ -6401,7 +6419,9 @@ async function prepareVaultCandidates(query, vaultCtx, embeddingOptions, cache,
6401
6419
  decryptLast: true,
6402
6420
  // Rows WERE decrypt-attempted even though none came back readable — that
6403
6421
  // is the whole point of reporting attempts rather than successes.
6404
- rowsDecrypted: corpus.rowsDecrypted
6422
+ rowsDecrypted: corpus.rowsDecrypted,
6423
+ queryEmbedMs: embedStats.queryMs,
6424
+ rowsEmbedded: embedStats.rowsEmbedded
6405
6425
  };
6406
6426
  }
6407
6427
  } else {
@@ -6426,10 +6446,14 @@ async function prepareVaultCandidates(query, vaultCtx, embeddingOptions, cache,
6426
6446
  embeddingsUnavailable: false,
6427
6447
  embeddingFailure: false,
6428
6448
  decryptLast: false,
6429
- rowsDecrypted: loaded.length
6449
+ rowsDecrypted: loaded.length,
6450
+ queryEmbedMs: embedStats.queryMs,
6451
+ rowsEmbedded: embedStats.rowsEmbedded
6430
6452
  };
6431
6453
  }
6454
+ const legacyEmbedStart = nowMs();
6432
6455
  queryEmbedding = await embedQueryOrDegrade(query, embeddingOptions, onEmbeddingDegraded);
6456
+ embedStats.queryMs += nowMs() - legacyEmbedStart;
6433
6457
  const currentModel = embeddingOptions.model ?? DEFAULT_API_EMBEDDING_MODEL;
6434
6458
  const uncachedTexts = [];
6435
6459
  const uncachedIndices = [];
@@ -6463,6 +6487,7 @@ async function prepareVaultCandidates(query, vaultCtx, embeddingOptions, cache,
6463
6487
  }
6464
6488
  if (uncachedTexts.length > 0) {
6465
6489
  let newEmbeddings;
6490
+ embedStats.rowsEmbedded += uncachedTexts.length;
6466
6491
  try {
6467
6492
  newEmbeddings = await generateEmbeddings(uncachedTexts, embeddingOptions);
6468
6493
  } catch (err) {
@@ -6506,6 +6531,8 @@ async function prepareVaultCandidates(query, vaultCtx, embeddingOptions, cache,
6506
6531
  embeddingsUnavailable = true;
6507
6532
  }
6508
6533
  return {
6534
+ queryEmbedMs: embedStats.queryMs,
6535
+ rowsEmbedded: embedStats.rowsEmbedded,
6509
6536
  memories,
6510
6537
  embeddedItems,
6511
6538
  queryEmbedding,
@@ -6556,11 +6583,15 @@ async function rankPreparedVaultCandidates(query, prepared, embeddingOptions, se
6556
6583
  results: results2,
6557
6584
  vaultSize: out.vaultSize,
6558
6585
  reranked: out.reranked ?? false,
6586
+ // Read straight off the shared stats object rather than being passed in at
6587
+ // each call site: every return in this function funnels through here, so a
6588
+ // path added later reports the CE bill without having to remember to.
6589
+ rerankMs: rerankStats.ms,
6559
6590
  hadV2Head: out.hadV2Head ?? false,
6560
6591
  embeddingsUnavailable
6561
6592
  };
6562
6593
  };
6563
- const rerankStats = { applied: false };
6594
+ const rerankStats = { applied: false, ms: 0 };
6564
6595
  const useFusion = searchOptions?.useFusion ?? true;
6565
6596
  const tuning = {
6566
6597
  ...searchOptions?.recencyAlpha !== void 0 && { recencyAlpha: searchOptions.recencyAlpha },
@@ -6679,13 +6710,16 @@ async function searchVaultMemoriesWithSize(query, vaultCtx, embeddingOptions, ca
6679
6710
  results: [],
6680
6711
  vaultSize: 0,
6681
6712
  reranked: false,
6713
+ rerankMs: 0,
6682
6714
  hadV2Head: false,
6683
6715
  embeddingsUnavailable: false,
6684
6716
  rankedOnCosine: false,
6685
6717
  // No storage read happened, so nothing was decrypted; report the path the
6686
6718
  // caller asked for so this turn is still attributable.
6687
6719
  decryptLast: !!searchOptions?.decryptLast,
6688
- rowsDecrypted: 0
6720
+ rowsDecrypted: 0,
6721
+ queryEmbedMs: 0,
6722
+ rowsEmbedded: 0
6689
6723
  };
6690
6724
  }
6691
6725
  if (searchOptions?.decompose === "llm" && normalizeSubQueries(searchOptions.subQueries).length < 2 && !warnedProgrammaticDecomposeIgnored) {
@@ -6706,11 +6740,14 @@ async function searchVaultMemoriesWithSize(query, vaultCtx, embeddingOptions, ca
6706
6740
  results: [],
6707
6741
  vaultSize: 0,
6708
6742
  reranked: false,
6743
+ rerankMs: 0,
6709
6744
  hadV2Head: false,
6710
6745
  embeddingsUnavailable: prepared.embeddingsUnavailable,
6711
6746
  rankedOnCosine: false,
6712
6747
  decryptLast: prepared.decryptLast,
6713
- rowsDecrypted: prepared.rowsDecrypted
6748
+ rowsDecrypted: prepared.rowsDecrypted,
6749
+ queryEmbedMs: prepared.queryEmbedMs,
6750
+ rowsEmbedded: prepared.rowsEmbedded
6714
6751
  };
6715
6752
  }
6716
6753
  if (prepared.memories.length === 0) {
@@ -6718,11 +6755,14 @@ async function searchVaultMemoriesWithSize(query, vaultCtx, embeddingOptions, ca
6718
6755
  results: [],
6719
6756
  vaultSize: prepared.vaultSize,
6720
6757
  reranked: false,
6758
+ rerankMs: 0,
6721
6759
  hadV2Head: false,
6722
6760
  embeddingsUnavailable: prepared.embeddingsUnavailable,
6723
6761
  rankedOnCosine: false,
6724
6762
  decryptLast: prepared.decryptLast,
6725
- rowsDecrypted: prepared.rowsDecrypted
6763
+ rowsDecrypted: prepared.rowsDecrypted,
6764
+ queryEmbedMs: prepared.queryEmbedMs,
6765
+ rowsEmbedded: prepared.rowsEmbedded
6726
6766
  };
6727
6767
  }
6728
6768
  const ranked = await rankPreparedVaultCandidates(
@@ -6735,7 +6775,9 @@ async function searchVaultMemoriesWithSize(query, vaultCtx, embeddingOptions, ca
6735
6775
  ...ranked,
6736
6776
  rankedOnCosine: !ranked.embeddingsUnavailable,
6737
6777
  decryptLast: prepared.decryptLast,
6738
- rowsDecrypted: prepared.rowsDecrypted
6778
+ rowsDecrypted: prepared.rowsDecrypted,
6779
+ queryEmbedMs: prepared.queryEmbedMs,
6780
+ rowsEmbedded: prepared.rowsEmbedded
6739
6781
  };
6740
6782
  }
6741
6783
  async function searchVaultMemories(query, vaultCtx, embeddingOptions, cache, searchOptions) {
@@ -6840,7 +6882,7 @@ function createMemoryVaultSearchTool(vaultCtx, embeddingOptions, cache, searchOp
6840
6882
  subQueries = decomp.subQueries;
6841
6883
  }
6842
6884
  }
6843
- const { recall: recall2 } = await import("./recall-WIB7RQQZ.mjs");
6885
+ const { recall: recall2 } = await import("./recall-OALPGL3H.mjs");
6844
6886
  let recallDegraded = [];
6845
6887
  const result = await recall2(
6846
6888
  query,
@@ -7380,7 +7422,7 @@ function scoreEventTimeOverlap(memoryStart, memoryEnd, memoryKind, window2) {
7380
7422
  var DEFAULT_LIMIT = 8;
7381
7423
  var DEFAULT_BUDGET = "low";
7382
7424
  var DEFAULT_FACT_MIN_SCORE = 0.1;
7383
- var nowMs = () => typeof performance !== "undefined" && typeof performance.now === "function" ? performance.now() : Date.now();
7425
+ var nowMs2 = () => typeof performance !== "undefined" && typeof performance.now === "function" ? performance.now() : Date.now();
7384
7426
  var DEFAULT_CHUNK_MIN_SCORE = 0.5;
7385
7427
  function flagsForBudget(budget) {
7386
7428
  switch (budget) {
@@ -7413,7 +7455,7 @@ async function recall(query, ctx, options = {}) {
7413
7455
  const flags = flagsForBudget(usedBudget);
7414
7456
  const normalizedFacets = normalizeSubQueries(options.subQueries);
7415
7457
  const subQueries = normalizedFacets.length >= 2 ? normalizedFacets : void 0;
7416
- const t0 = nowMs();
7458
+ const t0 = nowMs2();
7417
7459
  let prepMs = 0;
7418
7460
  let factLaneMs = 0;
7419
7461
  let chunkLaneMs = 0;
@@ -7422,6 +7464,9 @@ async function recall(query, ctx, options = {}) {
7422
7464
  const chunkResults = [];
7423
7465
  let vaultSize;
7424
7466
  let didRerank = false;
7467
+ let rerankMs = 0;
7468
+ let queryEmbedMs = 0;
7469
+ let vaultRowsEmbedded;
7425
7470
  let hadV2Head = false;
7426
7471
  let embeddingsUnavailable = false;
7427
7472
  let chunkEmbedFailed = false;
@@ -7446,12 +7491,15 @@ async function recall(query, ctx, options = {}) {
7446
7491
  ...vaultSize !== void 0 && { vaultSize },
7447
7492
  ...decryptLastRan !== void 0 && { decryptLast: decryptLastRan },
7448
7493
  ...vaultRowsDecrypted !== void 0 && { vaultRowsDecrypted },
7494
+ ...vaultRowsEmbedded !== void 0 && { vaultRowsEmbedded },
7449
7495
  factCount: factResults.length,
7450
7496
  chunkCount: chunkResults.length,
7451
7497
  timings: {
7452
- total: nowMs() - t0,
7498
+ total: nowMs2() - t0,
7453
7499
  prep: prepMs,
7454
7500
  factLane: factLaneMs,
7501
+ rerank: rerankMs,
7502
+ queryEmbed: queryEmbedMs,
7455
7503
  chunkLane: chunkLaneMs,
7456
7504
  fuse: fuseMs
7457
7505
  },
@@ -7469,7 +7517,7 @@ async function recall(query, ctx, options = {}) {
7469
7517
  const needsChunkEmbedding = types.includes("chunk") && ctx.storageCtx;
7470
7518
  const wantsTemporal = types.includes("fact") && ctx.vaultCtx;
7471
7519
  const graphRefiner = flags.traverse && options.graphRefine && options.decomposeOptions ? createLlmNeighborRefiner(options.decomposeOptions) : void 0;
7472
- const prepStart = nowMs();
7520
+ const prepStart = nowMs2();
7473
7521
  const [queryEmbedding, entityRanking, temporalRanking] = await Promise.all([
7474
7522
  // The chunk lane is cosine-only — `searchChunksOp` needs a real vector, and
7475
7523
  // there is no lexical fallback for it — so an embeddings outage must SKIP the
@@ -7507,14 +7555,17 @@ async function recall(query, ctx, options = {}) {
7507
7555
  ),
7508
7556
  wantsTemporal ? safeLane("temporal", () => buildTemporalLaneRanking(query, ctx.vaultCtx, options.now)) : Promise.resolve([])
7509
7557
  ]);
7510
- prepMs = nowMs() - prepStart;
7558
+ prepMs = nowMs2() - prepStart;
7511
7559
  if (types.includes("fact") && ctx.vaultCtx && ctx.vaultCache) {
7512
- const factStart = nowMs();
7560
+ const factStart = nowMs2();
7513
7561
  const vaultMinScore = options.minScore ?? DEFAULT_FACT_MIN_SCORE;
7514
7562
  const {
7515
7563
  results,
7516
7564
  vaultSize: size,
7517
7565
  reranked,
7566
+ rerankMs: factRerankMs,
7567
+ queryEmbedMs: factQueryEmbedMs,
7568
+ rowsEmbedded: factRowsEmbedded,
7518
7569
  hadV2Head: v2Head,
7519
7570
  embeddingsUnavailable: factEmbeddingsUnavailable,
7520
7571
  rankedOnCosine: factRankedOnCosine,
@@ -7573,16 +7624,19 @@ async function recall(query, ctx, options = {}) {
7573
7624
  );
7574
7625
  vaultSize = size;
7575
7626
  didRerank = reranked;
7627
+ rerankMs = factRerankMs;
7628
+ queryEmbedMs = factQueryEmbedMs;
7629
+ vaultRowsEmbedded = factRowsEmbedded;
7576
7630
  hadV2Head = v2Head;
7577
7631
  if (factEmbeddingsUnavailable) embeddingsUnavailable = true;
7578
7632
  factLaneRankedOnCosine = factRankedOnCosine;
7579
7633
  decryptLastRan = factDecryptLast;
7580
7634
  vaultRowsDecrypted = factRowsDecrypted;
7581
- factLaneMs = nowMs() - factStart;
7635
+ factLaneMs = nowMs2() - factStart;
7582
7636
  }
7583
7637
  if (chunkEmbedFailed && !factLaneRankedOnCosine) embeddingsUnavailable = true;
7584
7638
  if (types.includes("chunk") && ctx.storageCtx && queryEmbedding) {
7585
- const chunkStart = nowMs();
7639
+ const chunkStart = nowMs2();
7586
7640
  const chunkMinScore = options.minScore ?? DEFAULT_CHUNK_MIN_SCORE;
7587
7641
  const results = await searchChunksOp(ctx.storageCtx, queryEmbedding, {
7588
7642
  limit: types.includes("fact") ? Math.max(limit * 2, 16) : limit,
@@ -7599,9 +7653,9 @@ async function recall(query, ctx, options = {}) {
7599
7653
  (r) => r.chunkText.trim()
7600
7654
  )
7601
7655
  );
7602
- chunkLaneMs = nowMs() - chunkStart;
7656
+ chunkLaneMs = nowMs2() - chunkStart;
7603
7657
  }
7604
- const fuseStart = nowMs();
7658
+ const fuseStart = nowMs2();
7605
7659
  if (types.length === 1 || factResults.length === 0 || chunkResults.length === 0) {
7606
7660
  const memories2 = [
7607
7661
  ...factResults.map((r) => toFactMemory(r, options.now)),
@@ -7609,7 +7663,7 @@ async function recall(query, ctx, options = {}) {
7609
7663
  ];
7610
7664
  memories2.sort((a, b) => b.score - a.score);
7611
7665
  const candidateCount = factResults.length + chunkResults.length;
7612
- fuseMs = nowMs() - fuseStart;
7666
+ fuseMs = nowMs2() - fuseStart;
7613
7667
  emitDiagnostics(candidateCount);
7614
7668
  return {
7615
7669
  memories: memories2.slice(0, limit),
@@ -7664,7 +7718,7 @@ async function recall(query, ctx, options = {}) {
7664
7718
  suppressed = next;
7665
7719
  memories = selectWith(suppressed);
7666
7720
  }
7667
- fuseMs = nowMs() - fuseStart;
7721
+ fuseMs = nowMs2() - fuseStart;
7668
7722
  emitDiagnostics(byId.size);
7669
7723
  return {
7670
7724
  memories,
@@ -6507,9 +6507,9 @@ function recencyMultiplier(updatedAt, opts = {}) {
6507
6507
  const updatedMs = updatedAt.getTime();
6508
6508
  if (!Number.isFinite(updatedMs)) return noDate;
6509
6509
  const now = opts.now ?? /* @__PURE__ */ new Date();
6510
- const nowMs2 = now.getTime();
6511
- if (!Number.isFinite(nowMs2)) return noDate;
6512
- const ageDays2 = Math.max(0, (nowMs2 - updatedMs) / DAY_MS2);
6510
+ const nowMs3 = now.getTime();
6511
+ if (!Number.isFinite(nowMs3)) return noDate;
6512
+ const ageDays2 = Math.max(0, (nowMs3 - updatedMs) / DAY_MS2);
6513
6513
  const perYearDecay = opts.perYearDecay ?? DEFAULT_PER_YEAR_DECAY;
6514
6514
  const floor = opts.floor ?? DEFAULT_FLOOR;
6515
6515
  const decay = perYearDecay * (ageDays2 / 365);
@@ -7563,6 +7563,9 @@ async function recall(query, ctx, options = {}) {
7563
7563
  const chunkResults = [];
7564
7564
  let vaultSize;
7565
7565
  let didRerank = false;
7566
+ let rerankMs = 0;
7567
+ let queryEmbedMs = 0;
7568
+ let vaultRowsEmbedded;
7566
7569
  let hadV2Head = false;
7567
7570
  let embeddingsUnavailable = false;
7568
7571
  let chunkEmbedFailed = false;
@@ -7587,12 +7590,15 @@ async function recall(query, ctx, options = {}) {
7587
7590
  ...vaultSize !== void 0 && { vaultSize },
7588
7591
  ...decryptLastRan !== void 0 && { decryptLast: decryptLastRan },
7589
7592
  ...vaultRowsDecrypted !== void 0 && { vaultRowsDecrypted },
7593
+ ...vaultRowsEmbedded !== void 0 && { vaultRowsEmbedded },
7590
7594
  factCount: factResults.length,
7591
7595
  chunkCount: chunkResults.length,
7592
7596
  timings: {
7593
7597
  total: nowMs() - t0,
7594
7598
  prep: prepMs,
7595
7599
  factLane: factLaneMs,
7600
+ rerank: rerankMs,
7601
+ queryEmbed: queryEmbedMs,
7596
7602
  chunkLane: chunkLaneMs,
7597
7603
  fuse: fuseMs
7598
7604
  },
@@ -7656,6 +7662,9 @@ async function recall(query, ctx, options = {}) {
7656
7662
  results,
7657
7663
  vaultSize: size,
7658
7664
  reranked,
7665
+ rerankMs: factRerankMs,
7666
+ queryEmbedMs: factQueryEmbedMs,
7667
+ rowsEmbedded: factRowsEmbedded,
7659
7668
  hadV2Head: v2Head,
7660
7669
  embeddingsUnavailable: factEmbeddingsUnavailable,
7661
7670
  rankedOnCosine: factRankedOnCosine,
@@ -7714,6 +7723,9 @@ async function recall(query, ctx, options = {}) {
7714
7723
  );
7715
7724
  vaultSize = size;
7716
7725
  didRerank = reranked;
7726
+ rerankMs = factRerankMs;
7727
+ queryEmbedMs = factQueryEmbedMs;
7728
+ vaultRowsEmbedded = factRowsEmbedded;
7717
7729
  hadV2Head = v2Head;
7718
7730
  if (factEmbeddingsUnavailable) embeddingsUnavailable = true;
7719
7731
  factLaneRankedOnCosine = factRankedOnCosine;
@@ -8178,6 +8190,7 @@ async function rankFusedVaultMemoriesAsync(query, queryEmbedding, items, options
8178
8190
  const rerankTopN = options.rerankTopN ?? 30;
8179
8191
  const ceWeight = options.ceWeight ?? 0.1;
8180
8192
  const headSlice = v2Ranked.slice(0, rerankTopN);
8193
+ const ceStart = nowMs2();
8181
8194
  try {
8182
8195
  const reranked = await rerankPairs(
8183
8196
  query,
@@ -8205,6 +8218,8 @@ async function rankFusedVaultMemoriesAsync(query, queryEmbedding, items, options
8205
8218
  getLogger().warn("[memory/search] cross-encoder rerank failed; using V2 ranking", err);
8206
8219
  }
8207
8220
  combined = v2Ranked;
8221
+ } finally {
8222
+ if (options.rerankStats) options.rerankStats.ms += nowMs2() - ceStart;
8208
8223
  }
8209
8224
  } else {
8210
8225
  combined = v2Ranked;
@@ -8371,6 +8386,7 @@ async function rankComposite(originalQuery, originalQueryEmbedding, subQueries,
8371
8386
  const ceWeight = options.ceWeight ?? 0.1;
8372
8387
  const headSlice = combined.slice(0, rerankTopN);
8373
8388
  const tailSlice = combined.slice(rerankTopN);
8389
+ const ceStart = nowMs2();
8374
8390
  try {
8375
8391
  const reranked = await rerankPairs(
8376
8392
  originalQuery,
@@ -8398,6 +8414,8 @@ async function rankComposite(originalQuery, originalQueryEmbedding, subQueries,
8398
8414
  err
8399
8415
  );
8400
8416
  }
8417
+ } finally {
8418
+ if (options.rerankStats) options.rerankStats.ms += nowMs2() - ceStart;
8401
8419
  }
8402
8420
  }
8403
8421
  if (options?.mmr) {
@@ -8524,11 +8542,13 @@ async function buildProjectedCorpus(query, vaultCtx, embeddingOptions, cache, qu
8524
8542
  rowsDecrypted: 0
8525
8543
  };
8526
8544
  }
8545
+ const queryEmbedStart = nowMs2();
8527
8546
  const queryEmbedding = await embedQueryOrDegrade(
8528
8547
  query,
8529
8548
  embeddingOptions,
8530
8549
  opts.onEmbeddingDegraded
8531
8550
  );
8551
+ if (opts.embedStats) opts.embedStats.queryMs += nowMs2() - queryEmbedStart;
8532
8552
  const embeddingsDegraded = queryEmbedding.length === 0;
8533
8553
  const currentModel = embeddingOptions.model ?? DEFAULT_API_EMBEDDING_MODEL;
8534
8554
  const vectored = [];
@@ -8581,6 +8601,7 @@ async function buildProjectedCorpus(query, vaultCtx, embeddingOptions, cache, qu
8581
8601
  const laneRows = laneFetched.filter((m) => !isEncrypted(m.content));
8582
8602
  if (laneRows.length > 0) {
8583
8603
  let laneVecs;
8604
+ if (opts.embedStats) opts.embedStats.rowsEmbedded += laneRows.length;
8584
8605
  try {
8585
8606
  laneVecs = await generateEmbeddings(
8586
8607
  laneRows.map((m) => m.content),
@@ -8659,6 +8680,10 @@ async function buildProjectedCorpus(query, vaultCtx, embeddingOptions, cache, qu
8659
8680
  async function prepareVaultCandidates(query, vaultCtx, embeddingOptions, cache, searchOptions) {
8660
8681
  if (!query || typeof query !== "string") {
8661
8682
  return {
8683
+ // Nothing was read and nothing was embedded — the short-circuit fires
8684
+ // before either.
8685
+ queryEmbedMs: 0,
8686
+ rowsEmbedded: 0,
8662
8687
  memories: [],
8663
8688
  embeddedItems: [],
8664
8689
  queryEmbedding: [],
@@ -8691,6 +8716,7 @@ async function prepareVaultCandidates(query, vaultCtx, embeddingOptions, cache,
8691
8716
  embeddingsUnavailable = true;
8692
8717
  embeddingFailure = true;
8693
8718
  };
8719
+ const embedStats = { queryMs: 0, rowsEmbedded: 0 };
8694
8720
  if (searchOptions?.decryptLast) {
8695
8721
  const forceIncludeIds = [
8696
8722
  ...searchOptions.entityRanking ?? [],
@@ -8702,7 +8728,8 @@ async function prepareVaultCandidates(query, vaultCtx, embeddingOptions, cache,
8702
8728
  admitFloor: ADMIT_FLOOR,
8703
8729
  unembeddedCap: UNEMBEDDED_CAP,
8704
8730
  ...forceIncludeIds.length > 0 && { forceIncludeIds },
8705
- onEmbeddingDegraded
8731
+ onEmbeddingDegraded,
8732
+ embedStats
8706
8733
  });
8707
8734
  if (corpus.vaultSize === 0) {
8708
8735
  return {
@@ -8713,7 +8740,9 @@ async function prepareVaultCandidates(query, vaultCtx, embeddingOptions, cache,
8713
8740
  embeddingsUnavailable: false,
8714
8741
  embeddingFailure: false,
8715
8742
  decryptLast: true,
8716
- rowsDecrypted: corpus.rowsDecrypted
8743
+ rowsDecrypted: corpus.rowsDecrypted,
8744
+ queryEmbedMs: embedStats.queryMs,
8745
+ rowsEmbedded: embedStats.rowsEmbedded
8717
8746
  };
8718
8747
  }
8719
8748
  ({ memories, embeddedItems, queryEmbedding, vaultSize } = corpus);
@@ -8730,7 +8759,9 @@ async function prepareVaultCandidates(query, vaultCtx, embeddingOptions, cache,
8730
8759
  decryptLast: true,
8731
8760
  // Rows WERE decrypt-attempted even though none came back readable — that
8732
8761
  // is the whole point of reporting attempts rather than successes.
8733
- rowsDecrypted: corpus.rowsDecrypted
8762
+ rowsDecrypted: corpus.rowsDecrypted,
8763
+ queryEmbedMs: embedStats.queryMs,
8764
+ rowsEmbedded: embedStats.rowsEmbedded
8734
8765
  };
8735
8766
  }
8736
8767
  } else {
@@ -8755,10 +8786,14 @@ async function prepareVaultCandidates(query, vaultCtx, embeddingOptions, cache,
8755
8786
  embeddingsUnavailable: false,
8756
8787
  embeddingFailure: false,
8757
8788
  decryptLast: false,
8758
- rowsDecrypted: loaded.length
8789
+ rowsDecrypted: loaded.length,
8790
+ queryEmbedMs: embedStats.queryMs,
8791
+ rowsEmbedded: embedStats.rowsEmbedded
8759
8792
  };
8760
8793
  }
8794
+ const legacyEmbedStart = nowMs2();
8761
8795
  queryEmbedding = await embedQueryOrDegrade(query, embeddingOptions, onEmbeddingDegraded);
8796
+ embedStats.queryMs += nowMs2() - legacyEmbedStart;
8762
8797
  const currentModel = embeddingOptions.model ?? DEFAULT_API_EMBEDDING_MODEL;
8763
8798
  const uncachedTexts = [];
8764
8799
  const uncachedIndices = [];
@@ -8792,6 +8827,7 @@ async function prepareVaultCandidates(query, vaultCtx, embeddingOptions, cache,
8792
8827
  }
8793
8828
  if (uncachedTexts.length > 0) {
8794
8829
  let newEmbeddings;
8830
+ embedStats.rowsEmbedded += uncachedTexts.length;
8795
8831
  try {
8796
8832
  newEmbeddings = await generateEmbeddings(uncachedTexts, embeddingOptions);
8797
8833
  } catch (err) {
@@ -8835,6 +8871,8 @@ async function prepareVaultCandidates(query, vaultCtx, embeddingOptions, cache,
8835
8871
  embeddingsUnavailable = true;
8836
8872
  }
8837
8873
  return {
8874
+ queryEmbedMs: embedStats.queryMs,
8875
+ rowsEmbedded: embedStats.rowsEmbedded,
8838
8876
  memories,
8839
8877
  embeddedItems,
8840
8878
  queryEmbedding,
@@ -8885,11 +8923,15 @@ async function rankPreparedVaultCandidates(query, prepared, embeddingOptions, se
8885
8923
  results: results2,
8886
8924
  vaultSize: out.vaultSize,
8887
8925
  reranked: out.reranked ?? false,
8926
+ // Read straight off the shared stats object rather than being passed in at
8927
+ // each call site: every return in this function funnels through here, so a
8928
+ // path added later reports the CE bill without having to remember to.
8929
+ rerankMs: rerankStats.ms,
8888
8930
  hadV2Head: out.hadV2Head ?? false,
8889
8931
  embeddingsUnavailable
8890
8932
  };
8891
8933
  };
8892
- const rerankStats = { applied: false };
8934
+ const rerankStats = { applied: false, ms: 0 };
8893
8935
  const useFusion = searchOptions?.useFusion ?? true;
8894
8936
  const tuning = {
8895
8937
  ...searchOptions?.recencyAlpha !== void 0 && { recencyAlpha: searchOptions.recencyAlpha },
@@ -9008,13 +9050,16 @@ async function searchVaultMemoriesWithSize(query, vaultCtx, embeddingOptions, ca
9008
9050
  results: [],
9009
9051
  vaultSize: 0,
9010
9052
  reranked: false,
9053
+ rerankMs: 0,
9011
9054
  hadV2Head: false,
9012
9055
  embeddingsUnavailable: false,
9013
9056
  rankedOnCosine: false,
9014
9057
  // No storage read happened, so nothing was decrypted; report the path the
9015
9058
  // caller asked for so this turn is still attributable.
9016
9059
  decryptLast: !!searchOptions?.decryptLast,
9017
- rowsDecrypted: 0
9060
+ rowsDecrypted: 0,
9061
+ queryEmbedMs: 0,
9062
+ rowsEmbedded: 0
9018
9063
  };
9019
9064
  }
9020
9065
  if (searchOptions?.decompose === "llm" && normalizeSubQueries(searchOptions.subQueries).length < 2 && !warnedProgrammaticDecomposeIgnored) {
@@ -9035,11 +9080,14 @@ async function searchVaultMemoriesWithSize(query, vaultCtx, embeddingOptions, ca
9035
9080
  results: [],
9036
9081
  vaultSize: 0,
9037
9082
  reranked: false,
9083
+ rerankMs: 0,
9038
9084
  hadV2Head: false,
9039
9085
  embeddingsUnavailable: prepared.embeddingsUnavailable,
9040
9086
  rankedOnCosine: false,
9041
9087
  decryptLast: prepared.decryptLast,
9042
- rowsDecrypted: prepared.rowsDecrypted
9088
+ rowsDecrypted: prepared.rowsDecrypted,
9089
+ queryEmbedMs: prepared.queryEmbedMs,
9090
+ rowsEmbedded: prepared.rowsEmbedded
9043
9091
  };
9044
9092
  }
9045
9093
  if (prepared.memories.length === 0) {
@@ -9047,11 +9095,14 @@ async function searchVaultMemoriesWithSize(query, vaultCtx, embeddingOptions, ca
9047
9095
  results: [],
9048
9096
  vaultSize: prepared.vaultSize,
9049
9097
  reranked: false,
9098
+ rerankMs: 0,
9050
9099
  hadV2Head: false,
9051
9100
  embeddingsUnavailable: prepared.embeddingsUnavailable,
9052
9101
  rankedOnCosine: false,
9053
9102
  decryptLast: prepared.decryptLast,
9054
- rowsDecrypted: prepared.rowsDecrypted
9103
+ rowsDecrypted: prepared.rowsDecrypted,
9104
+ queryEmbedMs: prepared.queryEmbedMs,
9105
+ rowsEmbedded: prepared.rowsEmbedded
9055
9106
  };
9056
9107
  }
9057
9108
  const ranked = await rankPreparedVaultCandidates(
@@ -9064,7 +9115,9 @@ async function searchVaultMemoriesWithSize(query, vaultCtx, embeddingOptions, ca
9064
9115
  ...ranked,
9065
9116
  rankedOnCosine: !ranked.embeddingsUnavailable,
9066
9117
  decryptLast: prepared.decryptLast,
9067
- rowsDecrypted: prepared.rowsDecrypted
9118
+ rowsDecrypted: prepared.rowsDecrypted,
9119
+ queryEmbedMs: prepared.queryEmbedMs,
9120
+ rowsEmbedded: prepared.rowsEmbedded
9068
9121
  };
9069
9122
  }
9070
9123
  async function searchVaultMemories(query, vaultCtx, embeddingOptions, cache, searchOptions) {
@@ -9214,7 +9267,7 @@ ${formatted}`;
9214
9267
  }
9215
9268
  };
9216
9269
  }
9217
- var warnedProgrammaticDecomposeIgnored, SUPERSESSION_SIMILARITY_THRESHOLD, SUPERSESSION_MIN_AGE_GAP_MS, SUPERSESSION_BOOST_FACTOR, SUPERSESSION_MAX_WINDOW, EMBEDDINGS_DEGRADED_EMPTY_NO_LEXICAL;
9270
+ var nowMs2, warnedProgrammaticDecomposeIgnored, SUPERSESSION_SIMILARITY_THRESHOLD, SUPERSESSION_MIN_AGE_GAP_MS, SUPERSESSION_BOOST_FACTOR, SUPERSESSION_MAX_WINDOW, EMBEDDINGS_DEGRADED_EMPTY_NO_LEXICAL;
9218
9271
  var init_searchTool = __esm({
9219
9272
  "src/lib/memoryVault/searchTool.ts"() {
9220
9273
  "use strict";
@@ -9232,6 +9285,7 @@ var init_searchTool = __esm({
9232
9285
  init_bm25();
9233
9286
  init_decomposeQuery();
9234
9287
  init_lruCache();
9288
+ nowMs2 = () => typeof performance !== "undefined" && typeof performance.now === "function" ? performance.now() : Date.now();
9235
9289
  warnedProgrammaticDecomposeIgnored = false;
9236
9290
  SUPERSESSION_SIMILARITY_THRESHOLD = 0.7;
9237
9291
  SUPERSESSION_MIN_AGE_GAP_MS = 30 * 24 * 60 * 60 * 1e3;