@anuma/sdk 7.1.1 → 7.3.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.
@@ -16713,10 +16713,18 @@ function admitVaultProjections(queryEmbedding, vectored, k) {
16713
16713
  }
16714
16714
  async function buildProjectedCorpus(query, vaultCtx, embeddingOptions, cache, queryOpts, opts) {
16715
16715
  let rowsDecrypted = 0;
16716
+ const keysStart = nowMs();
16716
16717
  const keys = await getVaultCandidateKeysOp(
16717
16718
  vaultCtx,
16718
16719
  Object.keys(queryOpts).length > 0 ? queryOpts : void 0
16719
16720
  );
16721
+ const corpusStats = {
16722
+ keysMs: nowMs() - keysStart,
16723
+ embeddingsFetchMs: 0,
16724
+ rowsFetchMs: 0,
16725
+ cacheHits: 0,
16726
+ cacheMisses: 0
16727
+ };
16720
16728
  const hydrateOpts = queryOpts.includeArchived ? { includeArchived: true } : void 0;
16721
16729
  const vaultSize = keys.length;
16722
16730
  if (keys.length === 0) {
@@ -16726,7 +16734,8 @@ async function buildProjectedCorpus(query, vaultCtx, embeddingOptions, cache, qu
16726
16734
  queryEmbedding: [],
16727
16735
  vaultSize: 0,
16728
16736
  laneEmbedFailed: false,
16729
- rowsDecrypted: 0
16737
+ rowsDecrypted: 0,
16738
+ corpusStats
16730
16739
  };
16731
16740
  }
16732
16741
  const queryEmbedStart = nowMs();
@@ -16748,16 +16757,20 @@ async function buildProjectedCorpus(query, vaultCtx, embeddingOptions, cache, qu
16748
16757
  for (const k2 of keys) {
16749
16758
  const cached = cachedRowVector(cache, k2.uniqueId, k2.updatedAt);
16750
16759
  if (cached && cached.length === queryEmbedding.length) {
16760
+ corpusStats.cacheHits++;
16751
16761
  vectored.push({ uniqueId: k2.uniqueId, embedding: cached, updatedAt: k2.updatedAt });
16752
16762
  continue;
16753
16763
  }
16764
+ corpusStats.cacheMisses++;
16754
16765
  const modelCompatible = (k2.embeddingModel ?? currentModel) === currentModel;
16755
16766
  if (modelCompatible) missIds.push(k2.uniqueId);
16756
16767
  else noVectorIds.push(k2.uniqueId);
16757
16768
  }
16758
16769
  }
16759
16770
  if (missIds.length > 0) {
16771
+ const embeddingsStart = nowMs();
16760
16772
  const rows = await getVaultEmbeddingsByIdsOp(vaultCtx, missIds, hydrateOpts);
16773
+ corpusStats.embeddingsFetchMs += nowMs() - embeddingsStart;
16761
16774
  const gotVector = /* @__PURE__ */ new Set();
16762
16775
  for (const r of rows) {
16763
16776
  if (!r.embedding) continue;
@@ -16785,7 +16798,9 @@ async function buildProjectedCorpus(query, vaultCtx, embeddingOptions, cache, qu
16785
16798
  `memoryVault: projected search un-embedded lane capped at ${laneIds.length}/${noVectorIds.length}`
16786
16799
  );
16787
16800
  }
16801
+ const laneStart = nowMs();
16788
16802
  const laneFetched = await getVaultMemoriesByIdsOp(vaultCtx, laneIds, hydrateOpts);
16803
+ corpusStats.rowsFetchMs += nowMs() - laneStart;
16789
16804
  rowsDecrypted += laneFetched.length;
16790
16805
  for (const row of laneFetched) laneById.set(row.uniqueId, row);
16791
16806
  const laneRows = laneFetched.filter((m) => !isEncrypted(m.content));
@@ -16837,7 +16852,9 @@ async function buildProjectedCorpus(query, vaultCtx, embeddingOptions, cache, qu
16837
16852
  }
16838
16853
  }
16839
16854
  const idsToFetch = [...admissionSet].filter((id) => !laneById.has(id));
16855
+ const admittedStart = nowMs();
16840
16856
  const fetched = idsToFetch.length > 0 ? await getVaultMemoriesByIdsOp(vaultCtx, idsToFetch, hydrateOpts) : [];
16857
+ corpusStats.rowsFetchMs += nowMs() - admittedStart;
16841
16858
  rowsDecrypted += fetched.length;
16842
16859
  const admittedRows = [
16843
16860
  ...fetched,
@@ -16866,7 +16883,10 @@ async function buildProjectedCorpus(query, vaultCtx, embeddingOptions, cache, qu
16866
16883
  }
16867
16884
  if (staleIds.length > 0) {
16868
16885
  const contentById = new Map(memories.map((m) => [m.uniqueId, m]));
16869
- for (const r of await getVaultEmbeddingsByIdsOp(vaultCtx, staleIds, hydrateOpts)) {
16886
+ const staleStart = nowMs();
16887
+ const staleRows = await getVaultEmbeddingsByIdsOp(vaultCtx, staleIds, hydrateOpts);
16888
+ corpusStats.embeddingsFetchMs += nowMs() - staleStart;
16889
+ for (const r of staleRows) {
16870
16890
  if (!r.embedding) continue;
16871
16891
  try {
16872
16892
  const parsed = JSON.parse(r.embedding);
@@ -16898,7 +16918,15 @@ async function buildProjectedCorpus(query, vaultCtx, embeddingOptions, cache, qu
16898
16918
  eventTimeKind: normalizeEventTimeKind(m.eventTimeKind),
16899
16919
  factType: m.factType
16900
16920
  }));
16901
- return { memories, embeddedItems, queryEmbedding, vaultSize, laneEmbedFailed, rowsDecrypted };
16921
+ return {
16922
+ memories,
16923
+ embeddedItems,
16924
+ queryEmbedding,
16925
+ vaultSize,
16926
+ laneEmbedFailed,
16927
+ rowsDecrypted,
16928
+ corpusStats
16929
+ };
16902
16930
  }
16903
16931
  async function prepareVaultCandidates(query, vaultCtx, embeddingOptions, cache, searchOptions) {
16904
16932
  if (!query || typeof query !== "string") {
@@ -16939,6 +16967,7 @@ async function prepareVaultCandidates(query, vaultCtx, embeddingOptions, cache,
16939
16967
  embeddingFailure = true;
16940
16968
  };
16941
16969
  const embedStats = { queryMs: 0, rowsEmbedded: 0 };
16970
+ let corpusStats;
16942
16971
  if (searchOptions?.decryptLast) {
16943
16972
  const forceIncludeIds = [
16944
16973
  ...searchOptions.entityRanking ?? [],
@@ -16959,6 +16988,7 @@ async function prepareVaultCandidates(query, vaultCtx, embeddingOptions, cache,
16959
16988
  onEmbeddingDegraded,
16960
16989
  embedStats
16961
16990
  });
16991
+ corpusStats = corpus.corpusStats;
16962
16992
  if (corpus.vaultSize === 0) {
16963
16993
  return {
16964
16994
  memories: [],
@@ -16970,7 +17000,8 @@ async function prepareVaultCandidates(query, vaultCtx, embeddingOptions, cache,
16970
17000
  decryptLast: true,
16971
17001
  rowsDecrypted: corpus.rowsDecrypted,
16972
17002
  queryEmbedMs: embedStats.queryMs,
16973
- rowsEmbedded: embedStats.rowsEmbedded
17003
+ rowsEmbedded: embedStats.rowsEmbedded,
17004
+ corpusStats
16974
17005
  };
16975
17006
  }
16976
17007
  ({ memories, embeddedItems, queryEmbedding, vaultSize } = corpus);
@@ -16987,7 +17018,8 @@ async function prepareVaultCandidates(query, vaultCtx, embeddingOptions, cache,
16987
17018
  decryptLast: true,
16988
17019
  rowsDecrypted: corpus.rowsDecrypted,
16989
17020
  queryEmbedMs: embedStats.queryMs,
16990
- rowsEmbedded: embedStats.rowsEmbedded
17021
+ rowsEmbedded: embedStats.rowsEmbedded,
17022
+ corpusStats
16991
17023
  };
16992
17024
  }
16993
17025
  } else {
@@ -17120,7 +17152,8 @@ async function prepareVaultCandidates(query, vaultCtx, embeddingOptions, cache,
17120
17152
  embeddingsUnavailable,
17121
17153
  embeddingFailure,
17122
17154
  decryptLast: !!searchOptions?.decryptLast,
17123
- rowsDecrypted
17155
+ rowsDecrypted,
17156
+ ...corpusStats && { corpusStats }
17124
17157
  };
17125
17158
  }
17126
17159
  async function rankPreparedVaultCandidates(query, prepared, embeddingOptions, searchOptions) {
@@ -17337,7 +17370,8 @@ async function searchVaultMemoriesWithSize(query, vaultCtx, embeddingOptions, ca
17337
17370
  decryptLast: prepared.decryptLast,
17338
17371
  rowsDecrypted: prepared.rowsDecrypted,
17339
17372
  queryEmbedMs: prepared.queryEmbedMs,
17340
- rowsEmbedded: prepared.rowsEmbedded
17373
+ rowsEmbedded: prepared.rowsEmbedded,
17374
+ ...prepared.corpusStats && { corpusStats: prepared.corpusStats }
17341
17375
  };
17342
17376
  }
17343
17377
  if (prepared.memories.length === 0) {
@@ -17352,7 +17386,8 @@ async function searchVaultMemoriesWithSize(query, vaultCtx, embeddingOptions, ca
17352
17386
  decryptLast: prepared.decryptLast,
17353
17387
  rowsDecrypted: prepared.rowsDecrypted,
17354
17388
  queryEmbedMs: prepared.queryEmbedMs,
17355
- rowsEmbedded: prepared.rowsEmbedded
17389
+ rowsEmbedded: prepared.rowsEmbedded,
17390
+ ...prepared.corpusStats && { corpusStats: prepared.corpusStats }
17356
17391
  };
17357
17392
  }
17358
17393
  const ranked = await rankPreparedVaultCandidates(
@@ -17367,7 +17402,8 @@ async function searchVaultMemoriesWithSize(query, vaultCtx, embeddingOptions, ca
17367
17402
  decryptLast: prepared.decryptLast,
17368
17403
  rowsDecrypted: prepared.rowsDecrypted,
17369
17404
  queryEmbedMs: prepared.queryEmbedMs,
17370
- rowsEmbedded: prepared.rowsEmbedded
17405
+ rowsEmbedded: prepared.rowsEmbedded,
17406
+ ...prepared.corpusStats && { corpusStats: prepared.corpusStats }
17371
17407
  };
17372
17408
  }
17373
17409
  async function searchVaultMemories(query, vaultCtx, embeddingOptions, cache, searchOptions) {
@@ -19356,6 +19392,7 @@ async function recall(query, ctx, options = {}) {
19356
19392
  let factLaneRankedOnCosine = false;
19357
19393
  let decryptLastRan;
19358
19394
  let vaultRowsDecrypted;
19395
+ let corpusStats;
19359
19396
  let graphLaneCount = 0;
19360
19397
  let temporalLaneCount = 0;
19361
19398
  let graphLaneFailed = false;
@@ -19396,6 +19433,10 @@ async function recall(query, ctx, options = {}) {
19396
19433
  ...decryptLastRan !== void 0 && { decryptLast: decryptLastRan },
19397
19434
  ...vaultRowsDecrypted !== void 0 && { vaultRowsDecrypted },
19398
19435
  ...vaultRowsEmbedded !== void 0 && { vaultRowsEmbedded },
19436
+ ...corpusStats && {
19437
+ vaultCacheHits: corpusStats.cacheHits,
19438
+ vaultCacheMisses: corpusStats.cacheMisses
19439
+ },
19399
19440
  ...chunkStats && {
19400
19441
  chunkRowsScanned: chunkStats.rowsScanned,
19401
19442
  chunkRowsFetched: chunkStats.rowsFetched,
@@ -19418,7 +19459,12 @@ async function recall(query, ctx, options = {}) {
19418
19459
  rerank: rerankMs,
19419
19460
  queryEmbed: queryEmbedMs,
19420
19461
  chunkLane: chunkLaneMs,
19421
- fuse: fuseMs
19462
+ fuse: fuseMs,
19463
+ ...corpusStats && {
19464
+ corpusKeys: corpusStats.keysMs,
19465
+ corpusEmbeddingsFetch: corpusStats.embeddingsFetchMs,
19466
+ corpusRowsFetch: corpusStats.rowsFetchMs
19467
+ }
19422
19468
  },
19423
19469
  degraded
19424
19470
  };
@@ -19492,7 +19538,8 @@ async function recall(query, ctx, options = {}) {
19492
19538
  embeddingsUnavailable: factEmbeddingsUnavailable,
19493
19539
  rankedOnCosine: factRankedOnCosine,
19494
19540
  decryptLast: factDecryptLast,
19495
- rowsDecrypted: factRowsDecrypted
19541
+ rowsDecrypted: factRowsDecrypted,
19542
+ corpusStats: factCorpusStats
19496
19543
  } = await (ctx.factSource?.search.bind(ctx.factSource) ?? ((searchQuery, searchOptions) => searchVaultMemoriesWithSize(
19497
19544
  searchQuery,
19498
19545
  ctx.vaultCtx,
@@ -19558,6 +19605,7 @@ async function recall(query, ctx, options = {}) {
19558
19605
  factLaneRankedOnCosine = factRankedOnCosine;
19559
19606
  decryptLastRan = factDecryptLast;
19560
19607
  vaultRowsDecrypted = factRowsDecrypted;
19608
+ corpusStats = factCorpusStats;
19561
19609
  factLaneMs = nowMs() - factStart;
19562
19610
  }
19563
19611
  if (chunkEmbedFailed && !factLaneRankedOnCosine) embeddingsUnavailable = true;
@@ -20914,6 +20962,7 @@ var queryFields = [
20914
20962
  "updated_after",
20915
20963
  "topics_due",
20916
20964
  "topics_extracted",
20965
+ "event_time_overlaps",
20917
20966
  "order",
20918
20967
  "cursor",
20919
20968
  "limit",
@@ -22163,6 +22212,7 @@ var MAX_QUERY_IDS = 1e3;
22163
22212
  var MAX_QUERY_TOPICS = 100;
22164
22213
  var MAX_QUERY_FILTER = 20;
22165
22214
  var GRAPH_LANE_ROWS = 256;
22215
+ var TEMPORAL_LANE_ROWS = 256;
22166
22216
  var RemoteMemoryPartialCreateError = class extends Error {
22167
22217
  constructor(created, cause) {
22168
22218
  super(`createMany stored ${created.length} memories before a batch failed`);
@@ -22261,7 +22311,7 @@ function createRemoteMemoryStore(options) {
22261
22311
  const pipeline = createRemoteMemoryPipeline({
22262
22312
  ...options,
22263
22313
  graphRanking: options.graphRanking ?? ((query, _traverse, recallOptions) => topicGraphRanking(query, recallOptions)),
22264
- temporalRanking: options.temporalRanking ?? (() => Promise.resolve([]))
22314
+ temporalRanking: options.temporalRanking ?? ((query, now) => eventTimeRanking(query, now))
22265
22315
  });
22266
22316
  const subscribers = /* @__PURE__ */ new Set();
22267
22317
  const seen = /* @__PURE__ */ new Map();
@@ -22324,6 +22374,24 @@ function createRemoteMemoryStore(options) {
22324
22374
  matched: [...canonicalTopics(memory)].filter((name) => wanted.has(name)).length
22325
22375
  })).filter((row) => row.matched > 0).sort((a, b) => b.matched - a.matched).slice(0, NODE_BUDGET).map((row) => row.memoryId);
22326
22376
  };
22377
+ const eventTimeRanking = async (query, now) => {
22378
+ const window2 = parseQueryTimeWindow(query, now);
22379
+ if (!window2) return [];
22380
+ const rows = await pages(
22381
+ metadata2,
22382
+ { event_time_overlaps: { start: window2.start, end: window2.end } },
22383
+ TEMPORAL_LANE_ROWS
22384
+ );
22385
+ return rows.map(({ memory }) => ({
22386
+ memoryId: memory.memory_id,
22387
+ score: scoreEventTimeOverlap(
22388
+ memory.event_time_start ?? null,
22389
+ memory.event_time_end ?? null,
22390
+ memory.event_time_kind ?? null,
22391
+ window2
22392
+ )
22393
+ })).filter((row) => row.score > 0).sort((a, b) => b.score - a.score).map((row) => row.memoryId);
22394
+ };
22327
22395
  const enumerateIds = async (read, ids, filters) => (await Promise.all(
22328
22396
  chunks2([...new Set(ids)], MAX_QUERY_IDS).map(
22329
22397
  (memory_ids) => pages(read, { ...filters, memory_ids })
@@ -4011,6 +4011,13 @@ declare function eagerEmbedContent(content: string, embeddingOptions: EmbeddingO
4011
4011
  * trusting it (see `vectorVersion.ts`).
4012
4012
  */
4013
4013
  updatedAt?: Date): Promise<void>;
4014
+ interface CorpusStats {
4015
+ keysMs: number;
4016
+ embeddingsFetchMs: number;
4017
+ rowsFetchMs: number;
4018
+ cacheHits: number;
4019
+ cacheMisses: number;
4020
+ }
4014
4021
  /**
4015
4022
  * A single vault search result with its similarity score.
4016
4023
  */
@@ -4089,6 +4096,7 @@ declare function searchVaultMemoriesWithSize(query: string, vaultCtx: VaultMemor
4089
4096
  */
4090
4097
  queryEmbedMs: number;
4091
4098
  rowsEmbedded: number;
4099
+ corpusStats?: CorpusStats;
4092
4100
  }>;
4093
4101
  /**
4094
4102
  * Search vault memories by semantic similarity. Returns structured results
@@ -4653,6 +4661,8 @@ interface RecallDiagnostics {
4653
4661
  * LEGACY read path this batch is uncapped, so it can be the whole vault.
4654
4662
  */
4655
4663
  vaultRowsEmbedded?: number;
4664
+ vaultCacheHits?: number;
4665
+ vaultCacheMisses?: number;
4656
4666
  /** Embedded messages the chunk lane considered; absent when the lane did not run. */
4657
4667
  chunkRowsScanned?: number;
4658
4668
  /** Messages whose vectors the chunk lane read from storage on a cache miss. */
@@ -4755,6 +4765,9 @@ interface RecallDiagnostics {
4755
4765
  chunkLane: number;
4756
4766
  /** Cross-lane RRF fusion + provenance dedup after both lanes. */
4757
4767
  fuse: number;
4768
+ corpusKeys?: number;
4769
+ corpusEmbeddingsFetch?: number;
4770
+ corpusRowsFetch?: number;
4758
4771
  };
4759
4772
  /** Soft-degradation signals that fired this call (empty when clean). */
4760
4773
  degraded: RecallDegradation[];
@@ -9641,6 +9654,10 @@ interface RemoteMemoryQueryOptions extends RemoteMemoryReadFilters {
9641
9654
  updated_after?: number;
9642
9655
  topics_due?: number;
9643
9656
  topics_extracted?: boolean;
9657
+ event_time_overlaps?: {
9658
+ start: number;
9659
+ end: number;
9660
+ };
9644
9661
  order?: "created" | "updated" | "archived" | "changed";
9645
9662
  cursor?: string;
9646
9663
  limit?: number;
@@ -9819,7 +9836,6 @@ interface RemoteMemoryStoreOptions {
9819
9836
  embeddingOptions: EmbeddingOptions;
9820
9837
  /** Defaults to ranking memories by how many query entities their topics name. */
9821
9838
  graphRanking?: RecallFactSource["graphRanking"];
9822
- /** Defaults to no temporal lane: nearby has no event-time filter yet. */
9823
9839
  temporalRanking?: RecallFactSource["temporalRanking"];
9824
9840
  pollIntervalMs?: number;
9825
9841
  }
@@ -4011,6 +4011,13 @@ declare function eagerEmbedContent(content: string, embeddingOptions: EmbeddingO
4011
4011
  * trusting it (see `vectorVersion.ts`).
4012
4012
  */
4013
4013
  updatedAt?: Date): Promise<void>;
4014
+ interface CorpusStats {
4015
+ keysMs: number;
4016
+ embeddingsFetchMs: number;
4017
+ rowsFetchMs: number;
4018
+ cacheHits: number;
4019
+ cacheMisses: number;
4020
+ }
4014
4021
  /**
4015
4022
  * A single vault search result with its similarity score.
4016
4023
  */
@@ -4089,6 +4096,7 @@ declare function searchVaultMemoriesWithSize(query: string, vaultCtx: VaultMemor
4089
4096
  */
4090
4097
  queryEmbedMs: number;
4091
4098
  rowsEmbedded: number;
4099
+ corpusStats?: CorpusStats;
4092
4100
  }>;
4093
4101
  /**
4094
4102
  * Search vault memories by semantic similarity. Returns structured results
@@ -4653,6 +4661,8 @@ interface RecallDiagnostics {
4653
4661
  * LEGACY read path this batch is uncapped, so it can be the whole vault.
4654
4662
  */
4655
4663
  vaultRowsEmbedded?: number;
4664
+ vaultCacheHits?: number;
4665
+ vaultCacheMisses?: number;
4656
4666
  /** Embedded messages the chunk lane considered; absent when the lane did not run. */
4657
4667
  chunkRowsScanned?: number;
4658
4668
  /** Messages whose vectors the chunk lane read from storage on a cache miss. */
@@ -4755,6 +4765,9 @@ interface RecallDiagnostics {
4755
4765
  chunkLane: number;
4756
4766
  /** Cross-lane RRF fusion + provenance dedup after both lanes. */
4757
4767
  fuse: number;
4768
+ corpusKeys?: number;
4769
+ corpusEmbeddingsFetch?: number;
4770
+ corpusRowsFetch?: number;
4758
4771
  };
4759
4772
  /** Soft-degradation signals that fired this call (empty when clean). */
4760
4773
  degraded: RecallDegradation[];
@@ -9641,6 +9654,10 @@ interface RemoteMemoryQueryOptions extends RemoteMemoryReadFilters {
9641
9654
  updated_after?: number;
9642
9655
  topics_due?: number;
9643
9656
  topics_extracted?: boolean;
9657
+ event_time_overlaps?: {
9658
+ start: number;
9659
+ end: number;
9660
+ };
9644
9661
  order?: "created" | "updated" | "archived" | "changed";
9645
9662
  cursor?: string;
9646
9663
  limit?: number;
@@ -9819,7 +9836,6 @@ interface RemoteMemoryStoreOptions {
9819
9836
  embeddingOptions: EmbeddingOptions;
9820
9837
  /** Defaults to ranking memories by how many query entities their topics name. */
9821
9838
  graphRanking?: RecallFactSource["graphRanking"];
9822
- /** Defaults to no temporal lane: nearby has no event-time filter yet. */
9823
9839
  temporalRanking?: RecallFactSource["temporalRanking"];
9824
9840
  pollIntervalMs?: number;
9825
9841
  }
@@ -15098,10 +15098,18 @@ function admitVaultProjections(queryEmbedding, vectored, k) {
15098
15098
  }
15099
15099
  async function buildProjectedCorpus(query, vaultCtx, embeddingOptions, cache, queryOpts, opts) {
15100
15100
  let rowsDecrypted = 0;
15101
+ const keysStart = nowMs();
15101
15102
  const keys = await getVaultCandidateKeysOp(
15102
15103
  vaultCtx,
15103
15104
  Object.keys(queryOpts).length > 0 ? queryOpts : void 0
15104
15105
  );
15106
+ const corpusStats = {
15107
+ keysMs: nowMs() - keysStart,
15108
+ embeddingsFetchMs: 0,
15109
+ rowsFetchMs: 0,
15110
+ cacheHits: 0,
15111
+ cacheMisses: 0
15112
+ };
15105
15113
  const hydrateOpts = queryOpts.includeArchived ? { includeArchived: true } : void 0;
15106
15114
  const vaultSize = keys.length;
15107
15115
  if (keys.length === 0) {
@@ -15111,7 +15119,8 @@ async function buildProjectedCorpus(query, vaultCtx, embeddingOptions, cache, qu
15111
15119
  queryEmbedding: [],
15112
15120
  vaultSize: 0,
15113
15121
  laneEmbedFailed: false,
15114
- rowsDecrypted: 0
15122
+ rowsDecrypted: 0,
15123
+ corpusStats
15115
15124
  };
15116
15125
  }
15117
15126
  const queryEmbedStart = nowMs();
@@ -15133,16 +15142,20 @@ async function buildProjectedCorpus(query, vaultCtx, embeddingOptions, cache, qu
15133
15142
  for (const k2 of keys) {
15134
15143
  const cached = cachedRowVector(cache, k2.uniqueId, k2.updatedAt);
15135
15144
  if (cached && cached.length === queryEmbedding.length) {
15145
+ corpusStats.cacheHits++;
15136
15146
  vectored.push({ uniqueId: k2.uniqueId, embedding: cached, updatedAt: k2.updatedAt });
15137
15147
  continue;
15138
15148
  }
15149
+ corpusStats.cacheMisses++;
15139
15150
  const modelCompatible = (k2.embeddingModel ?? currentModel) === currentModel;
15140
15151
  if (modelCompatible) missIds.push(k2.uniqueId);
15141
15152
  else noVectorIds.push(k2.uniqueId);
15142
15153
  }
15143
15154
  }
15144
15155
  if (missIds.length > 0) {
15156
+ const embeddingsStart = nowMs();
15145
15157
  const rows = await getVaultEmbeddingsByIdsOp(vaultCtx, missIds, hydrateOpts);
15158
+ corpusStats.embeddingsFetchMs += nowMs() - embeddingsStart;
15146
15159
  const gotVector = /* @__PURE__ */ new Set();
15147
15160
  for (const r of rows) {
15148
15161
  if (!r.embedding) continue;
@@ -15170,7 +15183,9 @@ async function buildProjectedCorpus(query, vaultCtx, embeddingOptions, cache, qu
15170
15183
  `memoryVault: projected search un-embedded lane capped at ${laneIds.length}/${noVectorIds.length}`
15171
15184
  );
15172
15185
  }
15186
+ const laneStart = nowMs();
15173
15187
  const laneFetched = await getVaultMemoriesByIdsOp(vaultCtx, laneIds, hydrateOpts);
15188
+ corpusStats.rowsFetchMs += nowMs() - laneStart;
15174
15189
  rowsDecrypted += laneFetched.length;
15175
15190
  for (const row of laneFetched) laneById.set(row.uniqueId, row);
15176
15191
  const laneRows = laneFetched.filter((m) => !isEncrypted(m.content));
@@ -15222,7 +15237,9 @@ async function buildProjectedCorpus(query, vaultCtx, embeddingOptions, cache, qu
15222
15237
  }
15223
15238
  }
15224
15239
  const idsToFetch = [...admissionSet].filter((id) => !laneById.has(id));
15240
+ const admittedStart = nowMs();
15225
15241
  const fetched = idsToFetch.length > 0 ? await getVaultMemoriesByIdsOp(vaultCtx, idsToFetch, hydrateOpts) : [];
15242
+ corpusStats.rowsFetchMs += nowMs() - admittedStart;
15226
15243
  rowsDecrypted += fetched.length;
15227
15244
  const admittedRows = [
15228
15245
  ...fetched,
@@ -15251,7 +15268,10 @@ async function buildProjectedCorpus(query, vaultCtx, embeddingOptions, cache, qu
15251
15268
  }
15252
15269
  if (staleIds.length > 0) {
15253
15270
  const contentById = new Map(memories.map((m) => [m.uniqueId, m]));
15254
- for (const r of await getVaultEmbeddingsByIdsOp(vaultCtx, staleIds, hydrateOpts)) {
15271
+ const staleStart = nowMs();
15272
+ const staleRows = await getVaultEmbeddingsByIdsOp(vaultCtx, staleIds, hydrateOpts);
15273
+ corpusStats.embeddingsFetchMs += nowMs() - staleStart;
15274
+ for (const r of staleRows) {
15255
15275
  if (!r.embedding) continue;
15256
15276
  try {
15257
15277
  const parsed = JSON.parse(r.embedding);
@@ -15283,7 +15303,15 @@ async function buildProjectedCorpus(query, vaultCtx, embeddingOptions, cache, qu
15283
15303
  eventTimeKind: normalizeEventTimeKind(m.eventTimeKind),
15284
15304
  factType: m.factType
15285
15305
  }));
15286
- return { memories, embeddedItems, queryEmbedding, vaultSize, laneEmbedFailed, rowsDecrypted };
15306
+ return {
15307
+ memories,
15308
+ embeddedItems,
15309
+ queryEmbedding,
15310
+ vaultSize,
15311
+ laneEmbedFailed,
15312
+ rowsDecrypted,
15313
+ corpusStats
15314
+ };
15287
15315
  }
15288
15316
  async function prepareVaultCandidates(query, vaultCtx, embeddingOptions, cache, searchOptions) {
15289
15317
  if (!query || typeof query !== "string") {
@@ -15324,6 +15352,7 @@ async function prepareVaultCandidates(query, vaultCtx, embeddingOptions, cache,
15324
15352
  embeddingFailure = true;
15325
15353
  };
15326
15354
  const embedStats = { queryMs: 0, rowsEmbedded: 0 };
15355
+ let corpusStats;
15327
15356
  if (searchOptions?.decryptLast) {
15328
15357
  const forceIncludeIds = [
15329
15358
  ...searchOptions.entityRanking ?? [],
@@ -15344,6 +15373,7 @@ async function prepareVaultCandidates(query, vaultCtx, embeddingOptions, cache,
15344
15373
  onEmbeddingDegraded,
15345
15374
  embedStats
15346
15375
  });
15376
+ corpusStats = corpus.corpusStats;
15347
15377
  if (corpus.vaultSize === 0) {
15348
15378
  return {
15349
15379
  memories: [],
@@ -15355,7 +15385,8 @@ async function prepareVaultCandidates(query, vaultCtx, embeddingOptions, cache,
15355
15385
  decryptLast: true,
15356
15386
  rowsDecrypted: corpus.rowsDecrypted,
15357
15387
  queryEmbedMs: embedStats.queryMs,
15358
- rowsEmbedded: embedStats.rowsEmbedded
15388
+ rowsEmbedded: embedStats.rowsEmbedded,
15389
+ corpusStats
15359
15390
  };
15360
15391
  }
15361
15392
  ({ memories, embeddedItems, queryEmbedding, vaultSize } = corpus);
@@ -15372,7 +15403,8 @@ async function prepareVaultCandidates(query, vaultCtx, embeddingOptions, cache,
15372
15403
  decryptLast: true,
15373
15404
  rowsDecrypted: corpus.rowsDecrypted,
15374
15405
  queryEmbedMs: embedStats.queryMs,
15375
- rowsEmbedded: embedStats.rowsEmbedded
15406
+ rowsEmbedded: embedStats.rowsEmbedded,
15407
+ corpusStats
15376
15408
  };
15377
15409
  }
15378
15410
  } else {
@@ -15505,7 +15537,8 @@ async function prepareVaultCandidates(query, vaultCtx, embeddingOptions, cache,
15505
15537
  embeddingsUnavailable,
15506
15538
  embeddingFailure,
15507
15539
  decryptLast: !!searchOptions?.decryptLast,
15508
- rowsDecrypted
15540
+ rowsDecrypted,
15541
+ ...corpusStats && { corpusStats }
15509
15542
  };
15510
15543
  }
15511
15544
  async function rankPreparedVaultCandidates(query, prepared, embeddingOptions, searchOptions) {
@@ -15722,7 +15755,8 @@ async function searchVaultMemoriesWithSize(query, vaultCtx, embeddingOptions, ca
15722
15755
  decryptLast: prepared.decryptLast,
15723
15756
  rowsDecrypted: prepared.rowsDecrypted,
15724
15757
  queryEmbedMs: prepared.queryEmbedMs,
15725
- rowsEmbedded: prepared.rowsEmbedded
15758
+ rowsEmbedded: prepared.rowsEmbedded,
15759
+ ...prepared.corpusStats && { corpusStats: prepared.corpusStats }
15726
15760
  };
15727
15761
  }
15728
15762
  if (prepared.memories.length === 0) {
@@ -15737,7 +15771,8 @@ async function searchVaultMemoriesWithSize(query, vaultCtx, embeddingOptions, ca
15737
15771
  decryptLast: prepared.decryptLast,
15738
15772
  rowsDecrypted: prepared.rowsDecrypted,
15739
15773
  queryEmbedMs: prepared.queryEmbedMs,
15740
- rowsEmbedded: prepared.rowsEmbedded
15774
+ rowsEmbedded: prepared.rowsEmbedded,
15775
+ ...prepared.corpusStats && { corpusStats: prepared.corpusStats }
15741
15776
  };
15742
15777
  }
15743
15778
  const ranked = await rankPreparedVaultCandidates(
@@ -15752,7 +15787,8 @@ async function searchVaultMemoriesWithSize(query, vaultCtx, embeddingOptions, ca
15752
15787
  decryptLast: prepared.decryptLast,
15753
15788
  rowsDecrypted: prepared.rowsDecrypted,
15754
15789
  queryEmbedMs: prepared.queryEmbedMs,
15755
- rowsEmbedded: prepared.rowsEmbedded
15790
+ rowsEmbedded: prepared.rowsEmbedded,
15791
+ ...prepared.corpusStats && { corpusStats: prepared.corpusStats }
15756
15792
  };
15757
15793
  }
15758
15794
  async function searchVaultMemories(query, vaultCtx, embeddingOptions, cache, searchOptions) {
@@ -17727,6 +17763,7 @@ async function recall(query, ctx, options = {}) {
17727
17763
  let factLaneRankedOnCosine = false;
17728
17764
  let decryptLastRan;
17729
17765
  let vaultRowsDecrypted;
17766
+ let corpusStats;
17730
17767
  let graphLaneCount = 0;
17731
17768
  let temporalLaneCount = 0;
17732
17769
  let graphLaneFailed = false;
@@ -17767,6 +17804,10 @@ async function recall(query, ctx, options = {}) {
17767
17804
  ...decryptLastRan !== void 0 && { decryptLast: decryptLastRan },
17768
17805
  ...vaultRowsDecrypted !== void 0 && { vaultRowsDecrypted },
17769
17806
  ...vaultRowsEmbedded !== void 0 && { vaultRowsEmbedded },
17807
+ ...corpusStats && {
17808
+ vaultCacheHits: corpusStats.cacheHits,
17809
+ vaultCacheMisses: corpusStats.cacheMisses
17810
+ },
17770
17811
  ...chunkStats && {
17771
17812
  chunkRowsScanned: chunkStats.rowsScanned,
17772
17813
  chunkRowsFetched: chunkStats.rowsFetched,
@@ -17789,7 +17830,12 @@ async function recall(query, ctx, options = {}) {
17789
17830
  rerank: rerankMs,
17790
17831
  queryEmbed: queryEmbedMs,
17791
17832
  chunkLane: chunkLaneMs,
17792
- fuse: fuseMs
17833
+ fuse: fuseMs,
17834
+ ...corpusStats && {
17835
+ corpusKeys: corpusStats.keysMs,
17836
+ corpusEmbeddingsFetch: corpusStats.embeddingsFetchMs,
17837
+ corpusRowsFetch: corpusStats.rowsFetchMs
17838
+ }
17793
17839
  },
17794
17840
  degraded
17795
17841
  };
@@ -17863,7 +17909,8 @@ async function recall(query, ctx, options = {}) {
17863
17909
  embeddingsUnavailable: factEmbeddingsUnavailable,
17864
17910
  rankedOnCosine: factRankedOnCosine,
17865
17911
  decryptLast: factDecryptLast,
17866
- rowsDecrypted: factRowsDecrypted
17912
+ rowsDecrypted: factRowsDecrypted,
17913
+ corpusStats: factCorpusStats
17867
17914
  } = await (ctx.factSource?.search.bind(ctx.factSource) ?? ((searchQuery, searchOptions) => searchVaultMemoriesWithSize(
17868
17915
  searchQuery,
17869
17916
  ctx.vaultCtx,
@@ -17929,6 +17976,7 @@ async function recall(query, ctx, options = {}) {
17929
17976
  factLaneRankedOnCosine = factRankedOnCosine;
17930
17977
  decryptLastRan = factDecryptLast;
17931
17978
  vaultRowsDecrypted = factRowsDecrypted;
17979
+ corpusStats = factCorpusStats;
17932
17980
  factLaneMs = nowMs() - factStart;
17933
17981
  }
17934
17982
  if (chunkEmbedFailed && !factLaneRankedOnCosine) embeddingsUnavailable = true;
@@ -19273,6 +19321,7 @@ var queryFields = [
19273
19321
  "updated_after",
19274
19322
  "topics_due",
19275
19323
  "topics_extracted",
19324
+ "event_time_overlaps",
19276
19325
  "order",
19277
19326
  "cursor",
19278
19327
  "limit",
@@ -20520,6 +20569,7 @@ var MAX_QUERY_IDS = 1e3;
20520
20569
  var MAX_QUERY_TOPICS = 100;
20521
20570
  var MAX_QUERY_FILTER = 20;
20522
20571
  var GRAPH_LANE_ROWS = 256;
20572
+ var TEMPORAL_LANE_ROWS = 256;
20523
20573
  var RemoteMemoryPartialCreateError = class extends Error {
20524
20574
  constructor(created, cause) {
20525
20575
  super(`createMany stored ${created.length} memories before a batch failed`);
@@ -20618,7 +20668,7 @@ function createRemoteMemoryStore(options) {
20618
20668
  const pipeline = createRemoteMemoryPipeline({
20619
20669
  ...options,
20620
20670
  graphRanking: options.graphRanking ?? ((query, _traverse, recallOptions) => topicGraphRanking(query, recallOptions)),
20621
- temporalRanking: options.temporalRanking ?? (() => Promise.resolve([]))
20671
+ temporalRanking: options.temporalRanking ?? ((query, now) => eventTimeRanking(query, now))
20622
20672
  });
20623
20673
  const subscribers = /* @__PURE__ */ new Set();
20624
20674
  const seen = /* @__PURE__ */ new Map();
@@ -20681,6 +20731,24 @@ function createRemoteMemoryStore(options) {
20681
20731
  matched: [...canonicalTopics(memory)].filter((name) => wanted.has(name)).length
20682
20732
  })).filter((row) => row.matched > 0).sort((a, b) => b.matched - a.matched).slice(0, NODE_BUDGET).map((row) => row.memoryId);
20683
20733
  };
20734
+ const eventTimeRanking = async (query, now) => {
20735
+ const window2 = parseQueryTimeWindow(query, now);
20736
+ if (!window2) return [];
20737
+ const rows = await pages(
20738
+ metadata2,
20739
+ { event_time_overlaps: { start: window2.start, end: window2.end } },
20740
+ TEMPORAL_LANE_ROWS
20741
+ );
20742
+ return rows.map(({ memory }) => ({
20743
+ memoryId: memory.memory_id,
20744
+ score: scoreEventTimeOverlap(
20745
+ memory.event_time_start ?? null,
20746
+ memory.event_time_end ?? null,
20747
+ memory.event_time_kind ?? null,
20748
+ window2
20749
+ )
20750
+ })).filter((row) => row.score > 0).sort((a, b) => b.score - a.score).map((row) => row.memoryId);
20751
+ };
20684
20752
  const enumerateIds = async (read, ids, filters) => (await Promise.all(
20685
20753
  chunks2([...new Set(ids)], MAX_QUERY_IDS).map(
20686
20754
  (memory_ids) => pages(read, { ...filters, memory_ids })
@@ -557,6 +557,8 @@ interface RecallDiagnostics {
557
557
  * LEGACY read path this batch is uncapped, so it can be the whole vault.
558
558
  */
559
559
  vaultRowsEmbedded?: number;
560
+ vaultCacheHits?: number;
561
+ vaultCacheMisses?: number;
560
562
  /** Embedded messages the chunk lane considered; absent when the lane did not run. */
561
563
  chunkRowsScanned?: number;
562
564
  /** Messages whose vectors the chunk lane read from storage on a cache miss. */
@@ -659,6 +661,9 @@ interface RecallDiagnostics {
659
661
  chunkLane: number;
660
662
  /** Cross-lane RRF fusion + provenance dedup after both lanes. */
661
663
  fuse: number;
664
+ corpusKeys?: number;
665
+ corpusEmbeddingsFetch?: number;
666
+ corpusRowsFetch?: number;
662
667
  };
663
668
  /** Soft-degradation signals that fired this call (empty when clean). */
664
669
  degraded: RecallDegradation[];