@anuma/sdk 6.0.0 → 6.1.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.
@@ -5820,6 +5820,7 @@ function admitVaultProjections(queryEmbedding, vectored, k) {
5820
5820
  return vectored.map((it) => ({ it, score: cosineSimilarity(queryEmbedding, it.embedding) })).sort((a, b) => b.score - a.score || b.it.updatedAt.getTime() - a.it.updatedAt.getTime()).slice(0, k).map((s) => s.it.uniqueId);
5821
5821
  }
5822
5822
  async function buildProjectedCorpus(query, vaultCtx, embeddingOptions, cache, queryOpts, opts) {
5823
+ let rowsDecrypted = 0;
5823
5824
  const keys = await getVaultCandidateKeysOp(
5824
5825
  vaultCtx,
5825
5826
  Object.keys(queryOpts).length > 0 ? queryOpts : void 0
@@ -5832,7 +5833,8 @@ async function buildProjectedCorpus(query, vaultCtx, embeddingOptions, cache, qu
5832
5833
  embeddedItems: [],
5833
5834
  queryEmbedding: [],
5834
5835
  vaultSize: 0,
5835
- laneEmbedFailed: false
5836
+ laneEmbedFailed: false,
5837
+ rowsDecrypted: 0
5836
5838
  };
5837
5839
  }
5838
5840
  const queryEmbedding = await embedQueryOrDegrade(
@@ -5878,6 +5880,7 @@ async function buildProjectedCorpus(query, vaultCtx, embeddingOptions, cache, qu
5878
5880
  for (const id of missIds) if (!gotVector.has(id)) noVectorIds.push(id);
5879
5881
  }
5880
5882
  let laneEmbedFailed = false;
5883
+ const laneById = /* @__PURE__ */ new Map();
5881
5884
  if (noVectorIds.length > 0) {
5882
5885
  const laneIds = noVectorIds.slice(0, opts.unembeddedCap);
5883
5886
  if (noVectorIds.length > laneIds.length) {
@@ -5885,9 +5888,10 @@ async function buildProjectedCorpus(query, vaultCtx, embeddingOptions, cache, qu
5885
5888
  `memoryVault: projected search un-embedded lane capped at ${laneIds.length}/${noVectorIds.length}`
5886
5889
  );
5887
5890
  }
5888
- const laneRows = (await getVaultMemoriesByIdsOp(vaultCtx, laneIds, hydrateOpts)).filter(
5889
- (m) => !isEncrypted(m.content)
5890
- );
5891
+ const laneFetched = await getVaultMemoriesByIdsOp(vaultCtx, laneIds, hydrateOpts);
5892
+ rowsDecrypted += laneFetched.length;
5893
+ for (const row of laneFetched) laneById.set(row.uniqueId, row);
5894
+ const laneRows = laneFetched.filter((m) => !isEncrypted(m.content));
5891
5895
  if (laneRows.length > 0) {
5892
5896
  let laneVecs;
5893
5897
  try {
@@ -5933,7 +5937,16 @@ async function buildProjectedCorpus(query, vaultCtx, embeddingOptions, cache, qu
5933
5937
  if (keyById.has(id)) admissionSet.add(id);
5934
5938
  }
5935
5939
  }
5936
- const admittedRows = await getVaultMemoriesByIdsOp(vaultCtx, [...admissionSet], hydrateOpts);
5940
+ const idsToFetch = [...admissionSet].filter((id) => !laneById.has(id));
5941
+ const fetched = idsToFetch.length > 0 ? await getVaultMemoriesByIdsOp(vaultCtx, idsToFetch, hydrateOpts) : [];
5942
+ rowsDecrypted += fetched.length;
5943
+ const admittedRows = [
5944
+ ...fetched,
5945
+ ...[...admissionSet].flatMap((id) => {
5946
+ const reused = laneById.get(id);
5947
+ return reused ? [reused] : [];
5948
+ })
5949
+ ];
5937
5950
  const memories = admittedRows.filter((m) => !isEncrypted(m.content));
5938
5951
  if (memories.length < admittedRows.length) {
5939
5952
  getLogger().warn(
@@ -5954,7 +5967,7 @@ async function buildProjectedCorpus(query, vaultCtx, embeddingOptions, cache, qu
5954
5967
  eventTimeKind: normalizeEventTimeKind(m.eventTimeKind),
5955
5968
  factType: m.factType
5956
5969
  }));
5957
- return { memories, embeddedItems, queryEmbedding, vaultSize, laneEmbedFailed };
5970
+ return { memories, embeddedItems, queryEmbedding, vaultSize, laneEmbedFailed, rowsDecrypted };
5958
5971
  }
5959
5972
  async function prepareVaultCandidates(query, vaultCtx, embeddingOptions, cache, searchOptions) {
5960
5973
  if (!query || typeof query !== "string") {
@@ -5964,7 +5977,9 @@ async function prepareVaultCandidates(query, vaultCtx, embeddingOptions, cache,
5964
5977
  queryEmbedding: [],
5965
5978
  vaultSize: 0,
5966
5979
  embeddingsUnavailable: false,
5967
- embeddingFailure: false
5980
+ embeddingFailure: false,
5981
+ decryptLast: !!searchOptions?.decryptLast,
5982
+ rowsDecrypted: 0
5968
5983
  };
5969
5984
  }
5970
5985
  const limit = searchOptions?.limit ?? 5;
@@ -5982,6 +5997,7 @@ async function prepareVaultCandidates(query, vaultCtx, embeddingOptions, cache,
5982
5997
  let embeddedItems;
5983
5998
  let queryEmbedding;
5984
5999
  let vaultSize;
6000
+ let rowsDecrypted;
5985
6001
  let embeddingsUnavailable = false;
5986
6002
  let embeddingFailure = false;
5987
6003
  const onEmbeddingDegraded = () => {
@@ -6008,10 +6024,13 @@ async function prepareVaultCandidates(query, vaultCtx, embeddingOptions, cache,
6008
6024
  queryEmbedding: [],
6009
6025
  vaultSize: 0,
6010
6026
  embeddingsUnavailable: false,
6011
- embeddingFailure: false
6027
+ embeddingFailure: false,
6028
+ decryptLast: true,
6029
+ rowsDecrypted: corpus.rowsDecrypted
6012
6030
  };
6013
6031
  }
6014
6032
  ({ memories, embeddedItems, queryEmbedding, vaultSize } = corpus);
6033
+ rowsDecrypted = corpus.rowsDecrypted;
6015
6034
  if (corpus.laneEmbedFailed) embeddingFailure = true;
6016
6035
  if (memories.length === 0) {
6017
6036
  return {
@@ -6020,7 +6039,11 @@ async function prepareVaultCandidates(query, vaultCtx, embeddingOptions, cache,
6020
6039
  queryEmbedding: [],
6021
6040
  vaultSize,
6022
6041
  embeddingsUnavailable,
6023
- embeddingFailure
6042
+ embeddingFailure,
6043
+ decryptLast: true,
6044
+ // Rows WERE decrypt-attempted even though none came back readable — that
6045
+ // is the whole point of reporting attempts rather than successes.
6046
+ rowsDecrypted: corpus.rowsDecrypted
6024
6047
  };
6025
6048
  }
6026
6049
  } else {
@@ -6029,6 +6052,7 @@ async function prepareVaultCandidates(query, vaultCtx, embeddingOptions, cache,
6029
6052
  Object.keys(queryOpts).length > 0 ? queryOpts : void 0
6030
6053
  );
6031
6054
  vaultSize = loaded.length;
6055
+ rowsDecrypted = loaded.length;
6032
6056
  memories = loaded.filter((m) => !isEncrypted(m.content));
6033
6057
  if (memories.length < loaded.length) {
6034
6058
  getLogger().warn(
@@ -6042,7 +6066,9 @@ async function prepareVaultCandidates(query, vaultCtx, embeddingOptions, cache,
6042
6066
  queryEmbedding: [],
6043
6067
  vaultSize: loaded.length,
6044
6068
  embeddingsUnavailable: false,
6045
- embeddingFailure: false
6069
+ embeddingFailure: false,
6070
+ decryptLast: false,
6071
+ rowsDecrypted: loaded.length
6046
6072
  };
6047
6073
  }
6048
6074
  queryEmbedding = await embedQueryOrDegrade(query, embeddingOptions, onEmbeddingDegraded);
@@ -6127,7 +6153,9 @@ async function prepareVaultCandidates(query, vaultCtx, embeddingOptions, cache,
6127
6153
  queryEmbedding,
6128
6154
  vaultSize,
6129
6155
  embeddingsUnavailable,
6130
- embeddingFailure
6156
+ embeddingFailure,
6157
+ decryptLast: !!searchOptions?.decryptLast,
6158
+ rowsDecrypted
6131
6159
  };
6132
6160
  }
6133
6161
  async function rankPreparedVaultCandidates(query, prepared, embeddingOptions, searchOptions) {
@@ -6295,7 +6323,11 @@ async function searchVaultMemoriesWithSize(query, vaultCtx, embeddingOptions, ca
6295
6323
  reranked: false,
6296
6324
  hadV2Head: false,
6297
6325
  embeddingsUnavailable: false,
6298
- rankedOnCosine: false
6326
+ rankedOnCosine: false,
6327
+ // No storage read happened, so nothing was decrypted; report the path the
6328
+ // caller asked for so this turn is still attributable.
6329
+ decryptLast: !!searchOptions?.decryptLast,
6330
+ rowsDecrypted: 0
6299
6331
  };
6300
6332
  }
6301
6333
  if (searchOptions?.decompose === "llm" && normalizeSubQueries(searchOptions.subQueries).length < 2 && !warnedProgrammaticDecomposeIgnored) {
@@ -6318,7 +6350,9 @@ async function searchVaultMemoriesWithSize(query, vaultCtx, embeddingOptions, ca
6318
6350
  reranked: false,
6319
6351
  hadV2Head: false,
6320
6352
  embeddingsUnavailable: prepared.embeddingsUnavailable,
6321
- rankedOnCosine: false
6353
+ rankedOnCosine: false,
6354
+ decryptLast: prepared.decryptLast,
6355
+ rowsDecrypted: prepared.rowsDecrypted
6322
6356
  };
6323
6357
  }
6324
6358
  if (prepared.memories.length === 0) {
@@ -6328,7 +6362,9 @@ async function searchVaultMemoriesWithSize(query, vaultCtx, embeddingOptions, ca
6328
6362
  reranked: false,
6329
6363
  hadV2Head: false,
6330
6364
  embeddingsUnavailable: prepared.embeddingsUnavailable,
6331
- rankedOnCosine: false
6365
+ rankedOnCosine: false,
6366
+ decryptLast: prepared.decryptLast,
6367
+ rowsDecrypted: prepared.rowsDecrypted
6332
6368
  };
6333
6369
  }
6334
6370
  const ranked = await rankPreparedVaultCandidates(
@@ -6337,7 +6373,12 @@ async function searchVaultMemoriesWithSize(query, vaultCtx, embeddingOptions, ca
6337
6373
  embeddingOptions,
6338
6374
  searchOptions
6339
6375
  );
6340
- return { ...ranked, rankedOnCosine: !ranked.embeddingsUnavailable };
6376
+ return {
6377
+ ...ranked,
6378
+ rankedOnCosine: !ranked.embeddingsUnavailable,
6379
+ decryptLast: prepared.decryptLast,
6380
+ rowsDecrypted: prepared.rowsDecrypted
6381
+ };
6341
6382
  }
6342
6383
  async function searchVaultMemories(query, vaultCtx, embeddingOptions, cache, searchOptions) {
6343
6384
  const { results } = await searchVaultMemoriesWithSize(
@@ -6441,7 +6482,7 @@ function createMemoryVaultSearchTool(vaultCtx, embeddingOptions, cache, searchOp
6441
6482
  subQueries = decomp.subQueries;
6442
6483
  }
6443
6484
  }
6444
- const { recall: recall2 } = await import("./recall-6CZ7MYHF.mjs");
6485
+ const { recall: recall2 } = await import("./recall-JAV5PSNS.mjs");
6445
6486
  let recallDegraded = [];
6446
6487
  const result = await recall2(
6447
6488
  query,
@@ -7026,6 +7067,8 @@ async function recall(query, ctx, options = {}) {
7026
7067
  let embeddingsUnavailable = false;
7027
7068
  let chunkEmbedFailed = false;
7028
7069
  let factLaneRankedOnCosine = false;
7070
+ let decryptLastRan;
7071
+ let vaultRowsDecrypted;
7029
7072
  const emitDiagnostics = (candidateCount) => {
7030
7073
  const cb = options.onDiagnostics;
7031
7074
  if (!cb) return;
@@ -7042,6 +7085,8 @@ async function recall(query, ctx, options = {}) {
7042
7085
  reranked: didRerank,
7043
7086
  candidateCount,
7044
7087
  ...vaultSize !== void 0 && { vaultSize },
7088
+ ...decryptLastRan !== void 0 && { decryptLast: decryptLastRan },
7089
+ ...vaultRowsDecrypted !== void 0 && { vaultRowsDecrypted },
7045
7090
  factCount: factResults.length,
7046
7091
  chunkCount: chunkResults.length,
7047
7092
  timings: {
@@ -7113,7 +7158,9 @@ async function recall(query, ctx, options = {}) {
7113
7158
  reranked,
7114
7159
  hadV2Head: v2Head,
7115
7160
  embeddingsUnavailable: factEmbeddingsUnavailable,
7116
- rankedOnCosine: factRankedOnCosine
7161
+ rankedOnCosine: factRankedOnCosine,
7162
+ decryptLast: factDecryptLast,
7163
+ rowsDecrypted: factRowsDecrypted
7117
7164
  } = await searchVaultMemoriesWithSize(
7118
7165
  query,
7119
7166
  ctx.vaultCtx,
@@ -7170,6 +7217,8 @@ async function recall(query, ctx, options = {}) {
7170
7217
  hadV2Head = v2Head;
7171
7218
  if (factEmbeddingsUnavailable) embeddingsUnavailable = true;
7172
7219
  factLaneRankedOnCosine = factRankedOnCosine;
7220
+ decryptLastRan = factDecryptLast;
7221
+ vaultRowsDecrypted = factRowsDecrypted;
7173
7222
  factLaneMs = nowMs() - factStart;
7174
7223
  }
7175
7224
  if (chunkEmbedFailed && !factLaneRankedOnCosine) embeddingsUnavailable = true;
@@ -7096,6 +7096,8 @@ async function recall(query, ctx, options = {}) {
7096
7096
  let embeddingsUnavailable = false;
7097
7097
  let chunkEmbedFailed = false;
7098
7098
  let factLaneRankedOnCosine = false;
7099
+ let decryptLastRan;
7100
+ let vaultRowsDecrypted;
7099
7101
  const emitDiagnostics = (candidateCount) => {
7100
7102
  const cb = options.onDiagnostics;
7101
7103
  if (!cb) return;
@@ -7112,6 +7114,8 @@ async function recall(query, ctx, options = {}) {
7112
7114
  reranked: didRerank,
7113
7115
  candidateCount,
7114
7116
  ...vaultSize !== void 0 && { vaultSize },
7117
+ ...decryptLastRan !== void 0 && { decryptLast: decryptLastRan },
7118
+ ...vaultRowsDecrypted !== void 0 && { vaultRowsDecrypted },
7115
7119
  factCount: factResults.length,
7116
7120
  chunkCount: chunkResults.length,
7117
7121
  timings: {
@@ -7183,7 +7187,9 @@ async function recall(query, ctx, options = {}) {
7183
7187
  reranked,
7184
7188
  hadV2Head: v2Head,
7185
7189
  embeddingsUnavailable: factEmbeddingsUnavailable,
7186
- rankedOnCosine: factRankedOnCosine
7190
+ rankedOnCosine: factRankedOnCosine,
7191
+ decryptLast: factDecryptLast,
7192
+ rowsDecrypted: factRowsDecrypted
7187
7193
  } = await searchVaultMemoriesWithSize(
7188
7194
  query,
7189
7195
  ctx.vaultCtx,
@@ -7240,6 +7246,8 @@ async function recall(query, ctx, options = {}) {
7240
7246
  hadV2Head = v2Head;
7241
7247
  if (factEmbeddingsUnavailable) embeddingsUnavailable = true;
7242
7248
  factLaneRankedOnCosine = factRankedOnCosine;
7249
+ decryptLastRan = factDecryptLast;
7250
+ vaultRowsDecrypted = factRowsDecrypted;
7243
7251
  factLaneMs = nowMs() - factStart;
7244
7252
  }
7245
7253
  if (chunkEmbedFailed && !factLaneRankedOnCosine) embeddingsUnavailable = true;
@@ -8028,6 +8036,7 @@ function admitVaultProjections(queryEmbedding, vectored, k) {
8028
8036
  return vectored.map((it) => ({ it, score: cosineSimilarity(queryEmbedding, it.embedding) })).sort((a, b) => b.score - a.score || b.it.updatedAt.getTime() - a.it.updatedAt.getTime()).slice(0, k).map((s) => s.it.uniqueId);
8029
8037
  }
8030
8038
  async function buildProjectedCorpus(query, vaultCtx, embeddingOptions, cache, queryOpts, opts) {
8039
+ let rowsDecrypted = 0;
8031
8040
  const keys = await getVaultCandidateKeysOp(
8032
8041
  vaultCtx,
8033
8042
  Object.keys(queryOpts).length > 0 ? queryOpts : void 0
@@ -8040,7 +8049,8 @@ async function buildProjectedCorpus(query, vaultCtx, embeddingOptions, cache, qu
8040
8049
  embeddedItems: [],
8041
8050
  queryEmbedding: [],
8042
8051
  vaultSize: 0,
8043
- laneEmbedFailed: false
8052
+ laneEmbedFailed: false,
8053
+ rowsDecrypted: 0
8044
8054
  };
8045
8055
  }
8046
8056
  const queryEmbedding = await embedQueryOrDegrade(
@@ -8086,6 +8096,7 @@ async function buildProjectedCorpus(query, vaultCtx, embeddingOptions, cache, qu
8086
8096
  for (const id of missIds) if (!gotVector.has(id)) noVectorIds.push(id);
8087
8097
  }
8088
8098
  let laneEmbedFailed = false;
8099
+ const laneById = /* @__PURE__ */ new Map();
8089
8100
  if (noVectorIds.length > 0) {
8090
8101
  const laneIds = noVectorIds.slice(0, opts.unembeddedCap);
8091
8102
  if (noVectorIds.length > laneIds.length) {
@@ -8093,9 +8104,10 @@ async function buildProjectedCorpus(query, vaultCtx, embeddingOptions, cache, qu
8093
8104
  `memoryVault: projected search un-embedded lane capped at ${laneIds.length}/${noVectorIds.length}`
8094
8105
  );
8095
8106
  }
8096
- const laneRows = (await getVaultMemoriesByIdsOp(vaultCtx, laneIds, hydrateOpts)).filter(
8097
- (m) => !isEncrypted(m.content)
8098
- );
8107
+ const laneFetched = await getVaultMemoriesByIdsOp(vaultCtx, laneIds, hydrateOpts);
8108
+ rowsDecrypted += laneFetched.length;
8109
+ for (const row of laneFetched) laneById.set(row.uniqueId, row);
8110
+ const laneRows = laneFetched.filter((m) => !isEncrypted(m.content));
8099
8111
  if (laneRows.length > 0) {
8100
8112
  let laneVecs;
8101
8113
  try {
@@ -8141,7 +8153,16 @@ async function buildProjectedCorpus(query, vaultCtx, embeddingOptions, cache, qu
8141
8153
  if (keyById.has(id)) admissionSet.add(id);
8142
8154
  }
8143
8155
  }
8144
- const admittedRows = await getVaultMemoriesByIdsOp(vaultCtx, [...admissionSet], hydrateOpts);
8156
+ const idsToFetch = [...admissionSet].filter((id) => !laneById.has(id));
8157
+ const fetched = idsToFetch.length > 0 ? await getVaultMemoriesByIdsOp(vaultCtx, idsToFetch, hydrateOpts) : [];
8158
+ rowsDecrypted += fetched.length;
8159
+ const admittedRows = [
8160
+ ...fetched,
8161
+ ...[...admissionSet].flatMap((id) => {
8162
+ const reused = laneById.get(id);
8163
+ return reused ? [reused] : [];
8164
+ })
8165
+ ];
8145
8166
  const memories = admittedRows.filter((m) => !isEncrypted(m.content));
8146
8167
  if (memories.length < admittedRows.length) {
8147
8168
  getLogger().warn(
@@ -8162,7 +8183,7 @@ async function buildProjectedCorpus(query, vaultCtx, embeddingOptions, cache, qu
8162
8183
  eventTimeKind: normalizeEventTimeKind(m.eventTimeKind),
8163
8184
  factType: m.factType
8164
8185
  }));
8165
- return { memories, embeddedItems, queryEmbedding, vaultSize, laneEmbedFailed };
8186
+ return { memories, embeddedItems, queryEmbedding, vaultSize, laneEmbedFailed, rowsDecrypted };
8166
8187
  }
8167
8188
  async function prepareVaultCandidates(query, vaultCtx, embeddingOptions, cache, searchOptions) {
8168
8189
  if (!query || typeof query !== "string") {
@@ -8172,7 +8193,9 @@ async function prepareVaultCandidates(query, vaultCtx, embeddingOptions, cache,
8172
8193
  queryEmbedding: [],
8173
8194
  vaultSize: 0,
8174
8195
  embeddingsUnavailable: false,
8175
- embeddingFailure: false
8196
+ embeddingFailure: false,
8197
+ decryptLast: !!searchOptions?.decryptLast,
8198
+ rowsDecrypted: 0
8176
8199
  };
8177
8200
  }
8178
8201
  const limit = searchOptions?.limit ?? 5;
@@ -8190,6 +8213,7 @@ async function prepareVaultCandidates(query, vaultCtx, embeddingOptions, cache,
8190
8213
  let embeddedItems;
8191
8214
  let queryEmbedding;
8192
8215
  let vaultSize;
8216
+ let rowsDecrypted;
8193
8217
  let embeddingsUnavailable = false;
8194
8218
  let embeddingFailure = false;
8195
8219
  const onEmbeddingDegraded = () => {
@@ -8216,10 +8240,13 @@ async function prepareVaultCandidates(query, vaultCtx, embeddingOptions, cache,
8216
8240
  queryEmbedding: [],
8217
8241
  vaultSize: 0,
8218
8242
  embeddingsUnavailable: false,
8219
- embeddingFailure: false
8243
+ embeddingFailure: false,
8244
+ decryptLast: true,
8245
+ rowsDecrypted: corpus.rowsDecrypted
8220
8246
  };
8221
8247
  }
8222
8248
  ({ memories, embeddedItems, queryEmbedding, vaultSize } = corpus);
8249
+ rowsDecrypted = corpus.rowsDecrypted;
8223
8250
  if (corpus.laneEmbedFailed) embeddingFailure = true;
8224
8251
  if (memories.length === 0) {
8225
8252
  return {
@@ -8228,7 +8255,11 @@ async function prepareVaultCandidates(query, vaultCtx, embeddingOptions, cache,
8228
8255
  queryEmbedding: [],
8229
8256
  vaultSize,
8230
8257
  embeddingsUnavailable,
8231
- embeddingFailure
8258
+ embeddingFailure,
8259
+ decryptLast: true,
8260
+ // Rows WERE decrypt-attempted even though none came back readable — that
8261
+ // is the whole point of reporting attempts rather than successes.
8262
+ rowsDecrypted: corpus.rowsDecrypted
8232
8263
  };
8233
8264
  }
8234
8265
  } else {
@@ -8237,6 +8268,7 @@ async function prepareVaultCandidates(query, vaultCtx, embeddingOptions, cache,
8237
8268
  Object.keys(queryOpts).length > 0 ? queryOpts : void 0
8238
8269
  );
8239
8270
  vaultSize = loaded.length;
8271
+ rowsDecrypted = loaded.length;
8240
8272
  memories = loaded.filter((m) => !isEncrypted(m.content));
8241
8273
  if (memories.length < loaded.length) {
8242
8274
  getLogger().warn(
@@ -8250,7 +8282,9 @@ async function prepareVaultCandidates(query, vaultCtx, embeddingOptions, cache,
8250
8282
  queryEmbedding: [],
8251
8283
  vaultSize: loaded.length,
8252
8284
  embeddingsUnavailable: false,
8253
- embeddingFailure: false
8285
+ embeddingFailure: false,
8286
+ decryptLast: false,
8287
+ rowsDecrypted: loaded.length
8254
8288
  };
8255
8289
  }
8256
8290
  queryEmbedding = await embedQueryOrDegrade(query, embeddingOptions, onEmbeddingDegraded);
@@ -8335,7 +8369,9 @@ async function prepareVaultCandidates(query, vaultCtx, embeddingOptions, cache,
8335
8369
  queryEmbedding,
8336
8370
  vaultSize,
8337
8371
  embeddingsUnavailable,
8338
- embeddingFailure
8372
+ embeddingFailure,
8373
+ decryptLast: !!searchOptions?.decryptLast,
8374
+ rowsDecrypted
8339
8375
  };
8340
8376
  }
8341
8377
  async function rankPreparedVaultCandidates(query, prepared, embeddingOptions, searchOptions) {
@@ -8503,7 +8539,11 @@ async function searchVaultMemoriesWithSize(query, vaultCtx, embeddingOptions, ca
8503
8539
  reranked: false,
8504
8540
  hadV2Head: false,
8505
8541
  embeddingsUnavailable: false,
8506
- rankedOnCosine: false
8542
+ rankedOnCosine: false,
8543
+ // No storage read happened, so nothing was decrypted; report the path the
8544
+ // caller asked for so this turn is still attributable.
8545
+ decryptLast: !!searchOptions?.decryptLast,
8546
+ rowsDecrypted: 0
8507
8547
  };
8508
8548
  }
8509
8549
  if (searchOptions?.decompose === "llm" && normalizeSubQueries(searchOptions.subQueries).length < 2 && !warnedProgrammaticDecomposeIgnored) {
@@ -8526,7 +8566,9 @@ async function searchVaultMemoriesWithSize(query, vaultCtx, embeddingOptions, ca
8526
8566
  reranked: false,
8527
8567
  hadV2Head: false,
8528
8568
  embeddingsUnavailable: prepared.embeddingsUnavailable,
8529
- rankedOnCosine: false
8569
+ rankedOnCosine: false,
8570
+ decryptLast: prepared.decryptLast,
8571
+ rowsDecrypted: prepared.rowsDecrypted
8530
8572
  };
8531
8573
  }
8532
8574
  if (prepared.memories.length === 0) {
@@ -8536,7 +8578,9 @@ async function searchVaultMemoriesWithSize(query, vaultCtx, embeddingOptions, ca
8536
8578
  reranked: false,
8537
8579
  hadV2Head: false,
8538
8580
  embeddingsUnavailable: prepared.embeddingsUnavailable,
8539
- rankedOnCosine: false
8581
+ rankedOnCosine: false,
8582
+ decryptLast: prepared.decryptLast,
8583
+ rowsDecrypted: prepared.rowsDecrypted
8540
8584
  };
8541
8585
  }
8542
8586
  const ranked = await rankPreparedVaultCandidates(
@@ -8545,7 +8589,12 @@ async function searchVaultMemoriesWithSize(query, vaultCtx, embeddingOptions, ca
8545
8589
  embeddingOptions,
8546
8590
  searchOptions
8547
8591
  );
8548
- return { ...ranked, rankedOnCosine: !ranked.embeddingsUnavailable };
8592
+ return {
8593
+ ...ranked,
8594
+ rankedOnCosine: !ranked.embeddingsUnavailable,
8595
+ decryptLast: prepared.decryptLast,
8596
+ rowsDecrypted: prepared.rowsDecrypted
8597
+ };
8549
8598
  }
8550
8599
  async function searchVaultMemories(query, vaultCtx, embeddingOptions, cache, searchOptions) {
8551
8600
  const { results } = await searchVaultMemoriesWithSize(
@@ -5505,6 +5505,27 @@ interface RecallDiagnostics {
5505
5505
  candidateCount: number;
5506
5506
  /** Total vault size when the fact lane ran (absent if it didn't). */
5507
5507
  vaultSize?: number;
5508
+ /**
5509
+ * Which vault read path the fact lane actually executed: `true` for the
5510
+ * projected key scan that decrypts only the admission window, `false` for the
5511
+ * legacy whole-vault load. Absent when the fact lane didn't run.
5512
+ *
5513
+ * Reported because "the option was passed" and "the branch ran" are different
5514
+ * facts, and #845 needed the second one: the projected path was enabled in
5515
+ * production and the p50 did not move, with no way to tell a flag that never
5516
+ * reached the bundle from a projection that isn't cheaper at that vault size.
5517
+ */
5518
+ decryptLast?: boolean;
5519
+ /**
5520
+ * Rows the fact lane paid to decrypt. Absent when it didn't run.
5521
+ *
5522
+ * Read against {@link RecallDiagnostics.vaultSize} — that ratio is the whole
5523
+ * point. `decryptLast` true with `vaultRowsDecrypted` ≈ `vaultSize` means the
5524
+ * admission window is admitting the entire vault and the projection is buying
5525
+ * nothing. Far below `vaultSize` with latency unchanged means the decrypt was
5526
+ * never the cost.
5527
+ */
5528
+ vaultRowsDecrypted?: number;
5508
5529
  /** Facts the fact lane returned (post-dedupe, pre-fusion). */
5509
5530
  factCount: number;
5510
5531
  /** Chunks the chunk lane returned (post-dedupe, pre-fusion). */
@@ -5505,6 +5505,27 @@ interface RecallDiagnostics {
5505
5505
  candidateCount: number;
5506
5506
  /** Total vault size when the fact lane ran (absent if it didn't). */
5507
5507
  vaultSize?: number;
5508
+ /**
5509
+ * Which vault read path the fact lane actually executed: `true` for the
5510
+ * projected key scan that decrypts only the admission window, `false` for the
5511
+ * legacy whole-vault load. Absent when the fact lane didn't run.
5512
+ *
5513
+ * Reported because "the option was passed" and "the branch ran" are different
5514
+ * facts, and #845 needed the second one: the projected path was enabled in
5515
+ * production and the p50 did not move, with no way to tell a flag that never
5516
+ * reached the bundle from a projection that isn't cheaper at that vault size.
5517
+ */
5518
+ decryptLast?: boolean;
5519
+ /**
5520
+ * Rows the fact lane paid to decrypt. Absent when it didn't run.
5521
+ *
5522
+ * Read against {@link RecallDiagnostics.vaultSize} — that ratio is the whole
5523
+ * point. `decryptLast` true with `vaultRowsDecrypted` ≈ `vaultSize` means the
5524
+ * admission window is admitting the entire vault and the projection is buying
5525
+ * nothing. Far below `vaultSize` with latency unchanged means the decrypt was
5526
+ * never the cost.
5527
+ */
5528
+ vaultRowsDecrypted?: number;
5508
5529
  /** Facts the fact lane returned (post-dedupe, pre-fusion). */
5509
5530
  factCount: number;
5510
5531
  /** Chunks the chunk lane returned (post-dedupe, pre-fusion). */
@@ -121,7 +121,7 @@ import {
121
121
  upsertMessageOp,
122
122
  useEncryption,
123
123
  vaultMemoryToStored
124
- } from "./chunk-5QINPRGH.mjs";
124
+ } from "./chunk-LMGWHYUM.mjs";
125
125
  import {
126
126
  PII_PATTERNS,
127
127
  PiiRedactor,
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  recall
3
- } from "./chunk-5QINPRGH.mjs";
3
+ } from "./chunk-LMGWHYUM.mjs";
4
4
  import "./chunk-ILAWDQDE.mjs";
5
5
  import "./chunk-GYKJOWEO.mjs";
6
6
  export {