@anuma/sdk 3.3.1 → 3.4.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.
@@ -12,6 +12,8 @@ import {
12
12
  NODE_BUDGET,
13
13
  RerankerUnavailableError,
14
14
  TOPICS_EXTRACTION_VERSION,
15
+ TREND_RECENT_WINDOW_DAYS,
16
+ TREND_STALE_WINDOW_DAYS,
15
17
  VAULT_SIZE_HOP_CAP,
16
18
  archiveVaultMemoryOp,
17
19
  assertVaultScopeForSweep,
@@ -20,6 +22,7 @@ import {
20
22
  chunkAndEmbedAllMessages,
21
23
  chunkAndEmbedMessage,
22
24
  chunkText,
25
+ classifyObservationTrend,
23
26
  clearAllEncryptionKeys,
24
27
  clearAllEncryptionState,
25
28
  clearAllKeyPairs,
@@ -111,6 +114,7 @@ import {
111
114
  shouldChunkMessage,
112
115
  stampTopicsExtractedAtOp,
113
116
  stripToolCalls,
117
+ summarizeObservationTrends,
114
118
  supersedeVaultMemoryOp,
115
119
  traverseGraphLane,
116
120
  updateConversationPinnedOp,
@@ -125,7 +129,7 @@ import {
125
129
  updateVaultMemoryOp,
126
130
  useEncryption,
127
131
  vaultMemoryToStored
128
- } from "./chunk-PWTWECXY.mjs";
132
+ } from "./chunk-CGC3UJHM.mjs";
129
133
  import {
130
134
  PiiRedactor,
131
135
  createStreamingDeAnonymizer,
@@ -8734,6 +8738,13 @@ async function synthesizeProfile(ctx, options = {}) {
8734
8738
  includeSuperseded: true
8735
8739
  });
8736
8740
  const watermark = computeVaultWatermark(memories);
8741
+ const observationTrends = summarizeObservationTrends(
8742
+ memories.filter((m) => !m.isDeleted && m.supersededBy === null).map((m) => ({
8743
+ createdAt: m.createdAt,
8744
+ lastObservedAt: m.lastObservedAt,
8745
+ proofCount: m.proofCount
8746
+ }))
8747
+ );
8737
8748
  const presentIds = new Set(memories.map((m) => m.uniqueId));
8738
8749
  const hasStaleSections = previous?.sections.some((s) => s.stale);
8739
8750
  const citesMissingFact = previous?.sections.some(
@@ -8741,10 +8752,14 @@ async function synthesizeProfile(ctx, options = {}) {
8741
8752
  );
8742
8753
  if (previous && previous.vaultWatermark === watermark && !hasStaleSections && !citesMissingFact) {
8743
8754
  const sameOrder = previous.sections.length === facets.length && facets.every((f, i) => previous.sections[i]?.key === f.key);
8744
- if (sameOrder) return previous;
8755
+ if (sameOrder) {
8756
+ if (trendsEqual(previous.observationTrends, observationTrends)) return previous;
8757
+ return { ...previous, observationTrends };
8758
+ }
8745
8759
  return {
8746
8760
  ...previous,
8747
- sections: facets.map((f) => previous.sections.find((s) => s.key === f.key))
8761
+ sections: facets.map((f) => previous.sections.find((s) => s.key === f.key)),
8762
+ observationTrends
8748
8763
  };
8749
8764
  }
8750
8765
  const staleKeys = await computeStaleFacetKeys(ctx, memories, facets, previous, watermark);
@@ -8777,6 +8792,7 @@ async function synthesizeProfile(ctx, options = {}) {
8777
8792
  sections,
8778
8793
  vaultWatermark: watermark,
8779
8794
  config,
8795
+ observationTrends,
8780
8796
  generatedAt: Date.now()
8781
8797
  };
8782
8798
  }
@@ -8787,6 +8803,10 @@ function configMatches(a, b) {
8787
8803
  function facetsSignature(facets) {
8788
8804
  return facets.map((f) => JSON.stringify([f.key, f.label, f.query, f.guidance])).sort().join("\n");
8789
8805
  }
8806
+ function trendsEqual(a, b) {
8807
+ if (!a) return false;
8808
+ return a.new === b.new && a.strengthening === b.strengthening && a.stable === b.stable && a.weakening === b.weakening && a.stale === b.stale;
8809
+ }
8790
8810
  function changeTime(m) {
8791
8811
  return Math.max(m.updatedAt.getTime(), m.supersededAt ?? 0, m.lastObservedAt ?? 0);
8792
8812
  }
@@ -24794,6 +24814,8 @@ export {
24794
24814
  THEME_ATTRS,
24795
24815
  TOPICS_EXTRACTION_VERSION,
24796
24816
  TOPIC_EXTRACTION_BATCH_SIZE,
24817
+ TREND_RECENT_WINDOW_DAYS,
24818
+ TREND_STALE_WINDOW_DAYS,
24797
24819
  TextProcessor,
24798
24820
  UIInteractionProvider,
24799
24821
  VAULT_SIZE_HOP_CAP,
@@ -24815,6 +24837,7 @@ export {
24815
24837
  classifyCryptoPriceBatch,
24816
24838
  classifyDecay,
24817
24839
  classifyInjectionCandidates,
24840
+ classifyObservationTrend,
24818
24841
  classifyStockPrice,
24819
24842
  classifyStockPriceBatch,
24820
24843
  classifyWeather,
@@ -25084,6 +25107,7 @@ export {
25084
25107
  storeNotionReturnUrl,
25085
25108
  streamCancelPath,
25086
25109
  streamReplayPath,
25110
+ summarizeObservationTrends,
25087
25111
  supersedeVaultMemoryOp,
25088
25112
  synthesizeProfile,
25089
25113
  traverseGraphLane,
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  recall
3
- } from "./chunk-PWTWECXY.mjs";
3
+ } from "./chunk-CGC3UJHM.mjs";
4
4
  import "./chunk-DFVCS3QQ.mjs";
5
5
  import "./chunk-GYKJOWEO.mjs";
6
6
  export {
@@ -18496,6 +18496,7 @@ async function searchVaultMemoriesWithSize(query, vaultCtx, embeddingOptions, ca
18496
18496
  createdAt: m.createdAt,
18497
18497
  updatedAt: m.updatedAt,
18498
18498
  proofCount: m.proofCount,
18499
+ lastObservedAt: m.lastObservedAt,
18499
18500
  eventTimeStart: m.eventTimeStart,
18500
18501
  sourceChunkIds: m.sourceChunkIds,
18501
18502
  eventTimeEnd: m.eventTimeEnd,
@@ -18512,13 +18513,27 @@ async function searchVaultMemoriesWithSize(query, vaultCtx, embeddingOptions, ca
18512
18513
  );
18513
18514
  }
18514
18515
  }
18515
- const timestampById = new Map(
18516
- memories.map((m) => [m.uniqueId, { createdAt: m.createdAt, updatedAt: m.updatedAt }])
18516
+ const metaById = new Map(
18517
+ memories.map((m) => [
18518
+ m.uniqueId,
18519
+ {
18520
+ createdAt: m.createdAt,
18521
+ updatedAt: m.updatedAt,
18522
+ proofCount: m.proofCount,
18523
+ lastObservedAt: m.lastObservedAt
18524
+ }
18525
+ ])
18517
18526
  );
18518
18527
  const stampTimestamps = (out) => {
18519
18528
  const results2 = out.results.map((r) => {
18520
- const ts = timestampById.get(r.uniqueId);
18521
- return ts ? { ...r, createdAt: ts.createdAt, updatedAt: ts.updatedAt } : r;
18529
+ const meta = metaById.get(r.uniqueId);
18530
+ return meta ? {
18531
+ ...r,
18532
+ createdAt: meta.createdAt,
18533
+ updatedAt: meta.updatedAt,
18534
+ proofCount: meta.proofCount,
18535
+ lastObservedAt: meta.lastObservedAt
18536
+ } : r;
18522
18537
  });
18523
18538
  return {
18524
18539
  results: results2,
@@ -18712,7 +18727,7 @@ function createMemoryVaultSearchTool(vaultCtx, embeddingOptions, cache, searchOp
18712
18727
  legacy.map((r) => ({ id: r.uniqueId, content: r.content, score: r.similarity }))
18713
18728
  );
18714
18729
  }
18715
- const { recall: recall2 } = await import("./recall-NNBMWRLB.mjs");
18730
+ const { recall: recall2 } = await import("./recall-GWRWPGE4.mjs");
18716
18731
  const result = await recall2(
18717
18732
  query,
18718
18733
  { vaultCtx, embeddingOptions, vaultCache: cache },
@@ -18976,6 +18991,42 @@ Which should be expanded?`,
18976
18991
  };
18977
18992
  }
18978
18993
 
18994
+ // src/lib/memory/observationTrend.ts
18995
+ var DAY_MS2 = 1e3 * 60 * 60 * 24;
18996
+ var TREND_RECENT_WINDOW_DAYS = 30;
18997
+ var TREND_STALE_WINDOW_DAYS = 90;
18998
+ function toMs(value) {
18999
+ return value instanceof Date ? value.getTime() : value;
19000
+ }
19001
+ function classifyObservationTrend(input, now = Date.now()) {
19002
+ const createdMs = toMs(input.createdAt);
19003
+ if (!Number.isFinite(createdMs) || !Number.isFinite(now)) return "stable";
19004
+ const lastMsRaw = input.lastObservedAt;
19005
+ const lastMs = lastMsRaw !== null && lastMsRaw !== void 0 && Number.isFinite(lastMsRaw) ? Math.max(createdMs, lastMsRaw) : createdMs;
19006
+ const proofs = Math.max(1, input.proofCount ?? 1);
19007
+ const ageDays = Math.max(0, (now - createdMs) / DAY_MS2);
19008
+ const daysSinceLast = Math.max(0, (now - lastMs) / DAY_MS2);
19009
+ if (daysSinceLast >= TREND_STALE_WINDOW_DAYS) return "stale";
19010
+ if (daysSinceLast >= TREND_RECENT_WINDOW_DAYS) return "weakening";
19011
+ if (ageDays <= TREND_RECENT_WINDOW_DAYS && proofs <= 2) return "new";
19012
+ if (proofs >= 3) return "strengthening";
19013
+ if (proofs >= 2 && ageDays > TREND_RECENT_WINDOW_DAYS) return "strengthening";
19014
+ return "stable";
19015
+ }
19016
+ function summarizeObservationTrends(inputs, now = Date.now()) {
19017
+ const counts = {
19018
+ new: 0,
19019
+ strengthening: 0,
19020
+ stable: 0,
19021
+ weakening: 0,
19022
+ stale: 0
19023
+ };
19024
+ for (const input of inputs) {
19025
+ counts[classifyObservationTrend(input, now)]++;
19026
+ }
19027
+ return counts;
19028
+ }
19029
+
18979
19030
  // src/lib/memory/queryTemporal.ts
18980
19031
  var RELATIVE_DAY_ENTRIES = [
18981
19032
  [/\btoday\b/, "today", 0],
@@ -19370,7 +19421,7 @@ async function recall(query, ctx, options = {}) {
19370
19421
  const fuseStart = nowMs();
19371
19422
  if (types.length === 1 || factResults.length === 0 || chunkResults.length === 0) {
19372
19423
  const memories2 = [
19373
- ...factResults.map(toFactMemory),
19424
+ ...factResults.map((r) => toFactMemory(r, options.now)),
19374
19425
  ...chunkResults.map(toChunkMemory)
19375
19426
  ];
19376
19427
  memories2.sort((a, b) => b.score - a.score);
@@ -19391,7 +19442,7 @@ async function recall(query, ctx, options = {}) {
19391
19442
  const fused = rrfFuse([factRanking, chunkRanking], options.rrfK);
19392
19443
  const byId = /* @__PURE__ */ new Map();
19393
19444
  for (const r of factResults) {
19394
- const m = toFactMemory(r);
19445
+ const m = toFactMemory(r, options.now);
19395
19446
  m.score = fused.get(`fact:${r.uniqueId}`) ?? 0;
19396
19447
  if (!m.scoreBreakdown) m.scoreBreakdown = {};
19397
19448
  m.scoreBreakdown.fused = r.similarity;
@@ -19440,7 +19491,10 @@ async function recall(query, ctx, options = {}) {
19440
19491
  ...vaultSize !== void 0 && { vaultSize }
19441
19492
  };
19442
19493
  }
19443
- function toFactMemory(r) {
19494
+ function toFactMemory(r, now) {
19495
+ const createdAt = r.createdAt ?? /* @__PURE__ */ new Date(0);
19496
+ const proofCount = r.proofCount ?? void 0;
19497
+ const lastObservedAt = r.lastObservedAt ?? null;
19444
19498
  return {
19445
19499
  id: r.uniqueId,
19446
19500
  kind: "fact",
@@ -19456,6 +19510,18 @@ function toFactMemory(r) {
19456
19510
  // (and UI reading them) carry the fact's type. Undefined when untyped.
19457
19511
  ...r.factType !== void 0 && { factType: r.factType },
19458
19512
  ...r.sourceChunkIds !== void 0 && r.sourceChunkIds !== null && { sourceChunkIds: r.sourceChunkIds },
19513
+ ...proofCount !== void 0 && proofCount !== null && { proofCount },
19514
+ ...lastObservedAt !== null && { lastObservedAt },
19515
+ // C2 — algorithmic trend from evidence timestamps (no LLM). Honor
19516
+ // RecallOptions.now so back-dated eval harnesses get consistent labels.
19517
+ observationTrend: classifyObservationTrend(
19518
+ {
19519
+ createdAt,
19520
+ lastObservedAt,
19521
+ proofCount
19522
+ },
19523
+ now ?? Date.now()
19524
+ ),
19459
19525
  // r.similarity from searchVaultMemoriesWithSize is the fused score
19460
19526
  // (cosine + BM25 + RRF + recency + proof) when useFusion=true (the
19461
19527
  // default) and pure cosine when useFusion=false. The breakdown
@@ -19464,7 +19530,7 @@ function toFactMemory(r) {
19464
19530
  content: r.content,
19465
19531
  score: r.similarity,
19466
19532
  scoreBreakdown: { fused: r.similarity },
19467
- createdAt: r.createdAt ?? /* @__PURE__ */ new Date(0),
19533
+ createdAt,
19468
19534
  updatedAt: r.updatedAt ?? /* @__PURE__ */ new Date(0)
19469
19535
  };
19470
19536
  }
@@ -19653,6 +19719,10 @@ export {
19653
19719
  capHopsForDensity,
19654
19720
  traverseGraphLane,
19655
19721
  createLlmNeighborRefiner,
19722
+ TREND_RECENT_WINDOW_DAYS,
19723
+ TREND_STALE_WINDOW_DAYS,
19724
+ classifyObservationTrend,
19725
+ summarizeObservationTrends,
19656
19726
  recall,
19657
19727
  preEmbedVaultMemories,
19658
19728
  eagerEmbedContent,
@@ -19256,6 +19256,48 @@ var init_graphTraversal = __esm({
19256
19256
  }
19257
19257
  });
19258
19258
 
19259
+ // src/lib/memory/observationTrend.ts
19260
+ function toMs(value) {
19261
+ return value instanceof Date ? value.getTime() : value;
19262
+ }
19263
+ function classifyObservationTrend(input, now = Date.now()) {
19264
+ const createdMs = toMs(input.createdAt);
19265
+ if (!Number.isFinite(createdMs) || !Number.isFinite(now)) return "stable";
19266
+ const lastMsRaw = input.lastObservedAt;
19267
+ const lastMs = lastMsRaw !== null && lastMsRaw !== void 0 && Number.isFinite(lastMsRaw) ? Math.max(createdMs, lastMsRaw) : createdMs;
19268
+ const proofs = Math.max(1, input.proofCount ?? 1);
19269
+ const ageDays2 = Math.max(0, (now - createdMs) / DAY_MS2);
19270
+ const daysSinceLast = Math.max(0, (now - lastMs) / DAY_MS2);
19271
+ if (daysSinceLast >= TREND_STALE_WINDOW_DAYS) return "stale";
19272
+ if (daysSinceLast >= TREND_RECENT_WINDOW_DAYS) return "weakening";
19273
+ if (ageDays2 <= TREND_RECENT_WINDOW_DAYS && proofs <= 2) return "new";
19274
+ if (proofs >= 3) return "strengthening";
19275
+ if (proofs >= 2 && ageDays2 > TREND_RECENT_WINDOW_DAYS) return "strengthening";
19276
+ return "stable";
19277
+ }
19278
+ function summarizeObservationTrends(inputs, now = Date.now()) {
19279
+ const counts = {
19280
+ new: 0,
19281
+ strengthening: 0,
19282
+ stable: 0,
19283
+ weakening: 0,
19284
+ stale: 0
19285
+ };
19286
+ for (const input of inputs) {
19287
+ counts[classifyObservationTrend(input, now)]++;
19288
+ }
19289
+ return counts;
19290
+ }
19291
+ var DAY_MS2, TREND_RECENT_WINDOW_DAYS, TREND_STALE_WINDOW_DAYS;
19292
+ var init_observationTrend = __esm({
19293
+ "src/lib/memory/observationTrend.ts"() {
19294
+ "use strict";
19295
+ DAY_MS2 = 1e3 * 60 * 60 * 24;
19296
+ TREND_RECENT_WINDOW_DAYS = 30;
19297
+ TREND_STALE_WINDOW_DAYS = 90;
19298
+ }
19299
+ });
19300
+
19259
19301
  // src/lib/memory/queryTemporal.ts
19260
19302
  function startOfDay(ts) {
19261
19303
  const d = new Date(ts);
@@ -19655,7 +19697,7 @@ async function recall(query, ctx, options = {}) {
19655
19697
  const fuseStart = nowMs();
19656
19698
  if (types.length === 1 || factResults.length === 0 || chunkResults.length === 0) {
19657
19699
  const memories2 = [
19658
- ...factResults.map(toFactMemory),
19700
+ ...factResults.map((r) => toFactMemory(r, options.now)),
19659
19701
  ...chunkResults.map(toChunkMemory)
19660
19702
  ];
19661
19703
  memories2.sort((a, b) => b.score - a.score);
@@ -19676,7 +19718,7 @@ async function recall(query, ctx, options = {}) {
19676
19718
  const fused = rrfFuse([factRanking, chunkRanking], options.rrfK);
19677
19719
  const byId = /* @__PURE__ */ new Map();
19678
19720
  for (const r of factResults) {
19679
- const m = toFactMemory(r);
19721
+ const m = toFactMemory(r, options.now);
19680
19722
  m.score = fused.get(`fact:${r.uniqueId}`) ?? 0;
19681
19723
  if (!m.scoreBreakdown) m.scoreBreakdown = {};
19682
19724
  m.scoreBreakdown.fused = r.similarity;
@@ -19725,7 +19767,10 @@ async function recall(query, ctx, options = {}) {
19725
19767
  ...vaultSize !== void 0 && { vaultSize }
19726
19768
  };
19727
19769
  }
19728
- function toFactMemory(r) {
19770
+ function toFactMemory(r, now) {
19771
+ const createdAt = r.createdAt ?? /* @__PURE__ */ new Date(0);
19772
+ const proofCount = r.proofCount ?? void 0;
19773
+ const lastObservedAt = r.lastObservedAt ?? null;
19729
19774
  return {
19730
19775
  id: r.uniqueId,
19731
19776
  kind: "fact",
@@ -19741,6 +19786,18 @@ function toFactMemory(r) {
19741
19786
  // (and UI reading them) carry the fact's type. Undefined when untyped.
19742
19787
  ...r.factType !== void 0 && { factType: r.factType },
19743
19788
  ...r.sourceChunkIds !== void 0 && r.sourceChunkIds !== null && { sourceChunkIds: r.sourceChunkIds },
19789
+ ...proofCount !== void 0 && proofCount !== null && { proofCount },
19790
+ ...lastObservedAt !== null && { lastObservedAt },
19791
+ // C2 — algorithmic trend from evidence timestamps (no LLM). Honor
19792
+ // RecallOptions.now so back-dated eval harnesses get consistent labels.
19793
+ observationTrend: classifyObservationTrend(
19794
+ {
19795
+ createdAt,
19796
+ lastObservedAt,
19797
+ proofCount
19798
+ },
19799
+ now ?? Date.now()
19800
+ ),
19744
19801
  // r.similarity from searchVaultMemoriesWithSize is the fused score
19745
19802
  // (cosine + BM25 + RRF + recency + proof) when useFusion=true (the
19746
19803
  // default) and pure cosine when useFusion=false. The breakdown
@@ -19749,7 +19806,7 @@ function toFactMemory(r) {
19749
19806
  content: r.content,
19750
19807
  score: r.similarity,
19751
19808
  scoreBreakdown: { fused: r.similarity },
19752
- createdAt: r.createdAt ?? /* @__PURE__ */ new Date(0),
19809
+ createdAt,
19753
19810
  updatedAt: r.updatedAt ?? /* @__PURE__ */ new Date(0)
19754
19811
  };
19755
19812
  }
@@ -19832,6 +19889,7 @@ var init_recall = __esm({
19832
19889
  init_embeddings();
19833
19890
  init_searchTool();
19834
19891
  init_graphTraversal();
19892
+ init_observationTrend();
19835
19893
  init_queryEntities();
19836
19894
  init_queryTemporal();
19837
19895
  init_rrf();
@@ -20427,6 +20485,7 @@ async function searchVaultMemoriesWithSize(query, vaultCtx, embeddingOptions, ca
20427
20485
  createdAt: m.createdAt,
20428
20486
  updatedAt: m.updatedAt,
20429
20487
  proofCount: m.proofCount,
20488
+ lastObservedAt: m.lastObservedAt,
20430
20489
  eventTimeStart: m.eventTimeStart,
20431
20490
  sourceChunkIds: m.sourceChunkIds,
20432
20491
  eventTimeEnd: m.eventTimeEnd,
@@ -20443,13 +20502,27 @@ async function searchVaultMemoriesWithSize(query, vaultCtx, embeddingOptions, ca
20443
20502
  );
20444
20503
  }
20445
20504
  }
20446
- const timestampById = new Map(
20447
- memories.map((m) => [m.uniqueId, { createdAt: m.createdAt, updatedAt: m.updatedAt }])
20505
+ const metaById = new Map(
20506
+ memories.map((m) => [
20507
+ m.uniqueId,
20508
+ {
20509
+ createdAt: m.createdAt,
20510
+ updatedAt: m.updatedAt,
20511
+ proofCount: m.proofCount,
20512
+ lastObservedAt: m.lastObservedAt
20513
+ }
20514
+ ])
20448
20515
  );
20449
20516
  const stampTimestamps = (out) => {
20450
20517
  const results2 = out.results.map((r) => {
20451
- const ts = timestampById.get(r.uniqueId);
20452
- return ts ? { ...r, createdAt: ts.createdAt, updatedAt: ts.updatedAt } : r;
20518
+ const meta = metaById.get(r.uniqueId);
20519
+ return meta ? {
20520
+ ...r,
20521
+ createdAt: meta.createdAt,
20522
+ updatedAt: meta.updatedAt,
20523
+ proofCount: meta.proofCount,
20524
+ lastObservedAt: meta.lastObservedAt
20525
+ } : r;
20453
20526
  });
20454
20527
  return {
20455
20528
  results: results2,
@@ -21562,6 +21635,8 @@ __export(index_exports, {
21562
21635
  TOOL_CATALOG: () => TOOL_CATALOG,
21563
21636
  TOPICS_EXTRACTION_VERSION: () => TOPICS_EXTRACTION_VERSION,
21564
21637
  TOPIC_EXTRACTION_BATCH_SIZE: () => TOPIC_EXTRACTION_BATCH_SIZE,
21638
+ TREND_RECENT_WINDOW_DAYS: () => TREND_RECENT_WINDOW_DAYS,
21639
+ TREND_STALE_WINDOW_DAYS: () => TREND_STALE_WINDOW_DAYS,
21565
21640
  TextProcessor: () => TextProcessor,
21566
21641
  UserPreference: () => UserPreference,
21567
21642
  VAULT_SIZE_HOP_CAP: () => VAULT_SIZE_HOP_CAP,
@@ -21584,6 +21659,7 @@ __export(index_exports, {
21584
21659
  classifyCryptoPriceBatch: () => classifyCryptoPriceBatch,
21585
21660
  classifyDecay: () => classifyDecay,
21586
21661
  classifyInjectionCandidates: () => classifyInjectionCandidates,
21662
+ classifyObservationTrend: () => classifyObservationTrend,
21587
21663
  classifyStockPrice: () => classifyStockPrice,
21588
21664
  classifyStockPriceBatch: () => classifyStockPriceBatch,
21589
21665
  classifyWeather: () => classifyWeather,
@@ -21763,6 +21839,7 @@ __export(index_exports, {
21763
21839
  stampTopicsExtractedAtOp: () => stampTopicsExtractedAtOp,
21764
21840
  streamCancelPath: () => streamCancelPath,
21765
21841
  streamReplayPath: () => streamReplayPath,
21842
+ summarizeObservationTrends: () => summarizeObservationTrends,
21766
21843
  summaryToSystemMessage: () => summaryToSystemMessage,
21767
21844
  supersedeVaultMemoryOp: () => supersedeVaultMemoryOp,
21768
21845
  synthesizeProfile: () => synthesizeProfile,
@@ -27062,12 +27139,12 @@ function createChunkVectorCache(maxSize = DEFAULT_CHUNK_CACHE_SIZE) {
27062
27139
 
27063
27140
  // src/lib/memory/decay.ts
27064
27141
  init_logger();
27065
- var DAY_MS2 = 24 * 60 * 60 * 1e3;
27066
- var SHORT_TTL_MS = 30 * DAY_MS2;
27067
- var MEDIUM_TTL_MS = 180 * DAY_MS2;
27142
+ var DAY_MS3 = 24 * 60 * 60 * 1e3;
27143
+ var SHORT_TTL_MS = 30 * DAY_MS3;
27144
+ var MEDIUM_TTL_MS = 180 * DAY_MS3;
27068
27145
  var NEVER_TTL_MS = Number.POSITIVE_INFINITY;
27069
- var HARD_DELETE_WINDOW_MS = 30 * DAY_MS2;
27070
- var PAST_EVENT_GRACE_MS = 7 * DAY_MS2;
27146
+ var HARD_DELETE_WINDOW_MS = 30 * DAY_MS3;
27147
+ var PAST_EVENT_GRACE_MS = 7 * DAY_MS3;
27071
27148
  var DEFAULT_DECAY_POLICY = {
27072
27149
  ttlByType: {
27073
27150
  identity: NEVER_TTL_MS,
@@ -27327,6 +27404,7 @@ function createDecaySweeper(options) {
27327
27404
 
27328
27405
  // src/lib/memory/index.ts
27329
27406
  init_graphTraversal();
27407
+ init_observationTrend();
27330
27408
  init_recall();
27331
27409
 
27332
27410
  // src/lib/memory/recallTool.ts
@@ -27693,6 +27771,7 @@ init_logger();
27693
27771
  init_constants();
27694
27772
  init_embeddings();
27695
27773
  init_vector();
27774
+ init_observationTrend();
27696
27775
  var DEFAULT_SYNTHESIS_MODEL = "inclusionai/ling-2.6-flash";
27697
27776
  var DEFAULT_FACET_RECALL_LIMIT = 20;
27698
27777
  var DEFAULT_FACET_MAX_TOKENS = 512;
@@ -27778,6 +27857,13 @@ async function synthesizeProfile(ctx, options = {}) {
27778
27857
  includeSuperseded: true
27779
27858
  });
27780
27859
  const watermark = computeVaultWatermark(memories);
27860
+ const observationTrends = summarizeObservationTrends(
27861
+ memories.filter((m) => !m.isDeleted && m.supersededBy === null).map((m) => ({
27862
+ createdAt: m.createdAt,
27863
+ lastObservedAt: m.lastObservedAt,
27864
+ proofCount: m.proofCount
27865
+ }))
27866
+ );
27781
27867
  const presentIds = new Set(memories.map((m) => m.uniqueId));
27782
27868
  const hasStaleSections = previous?.sections.some((s) => s.stale);
27783
27869
  const citesMissingFact = previous?.sections.some(
@@ -27785,10 +27871,14 @@ async function synthesizeProfile(ctx, options = {}) {
27785
27871
  );
27786
27872
  if (previous && previous.vaultWatermark === watermark && !hasStaleSections && !citesMissingFact) {
27787
27873
  const sameOrder = previous.sections.length === facets.length && facets.every((f, i) => previous.sections[i]?.key === f.key);
27788
- if (sameOrder) return previous;
27874
+ if (sameOrder) {
27875
+ if (trendsEqual(previous.observationTrends, observationTrends)) return previous;
27876
+ return { ...previous, observationTrends };
27877
+ }
27789
27878
  return {
27790
27879
  ...previous,
27791
- sections: facets.map((f) => previous.sections.find((s) => s.key === f.key))
27880
+ sections: facets.map((f) => previous.sections.find((s) => s.key === f.key)),
27881
+ observationTrends
27792
27882
  };
27793
27883
  }
27794
27884
  const staleKeys = await computeStaleFacetKeys(ctx, memories, facets, previous, watermark);
@@ -27821,6 +27911,7 @@ async function synthesizeProfile(ctx, options = {}) {
27821
27911
  sections,
27822
27912
  vaultWatermark: watermark,
27823
27913
  config,
27914
+ observationTrends,
27824
27915
  generatedAt: Date.now()
27825
27916
  };
27826
27917
  }
@@ -27831,6 +27922,10 @@ function configMatches(a, b) {
27831
27922
  function facetsSignature(facets) {
27832
27923
  return facets.map((f) => JSON.stringify([f.key, f.label, f.query, f.guidance])).sort().join("\n");
27833
27924
  }
27925
+ function trendsEqual(a, b) {
27926
+ if (!a) return false;
27927
+ return a.new === b.new && a.strengthening === b.strengthening && a.stable === b.stable && a.weakening === b.weakening && a.stale === b.stale;
27928
+ }
27834
27929
  function changeTime(m) {
27835
27930
  return Math.max(m.updatedAt.getTime(), m.supersededAt ?? 0, m.lastObservedAt ?? 0);
27836
27931
  }
@@ -33946,6 +34041,8 @@ function buildSystemPrompt(ctx, options) {
33946
34041
  TOOL_CATALOG,
33947
34042
  TOPICS_EXTRACTION_VERSION,
33948
34043
  TOPIC_EXTRACTION_BATCH_SIZE,
34044
+ TREND_RECENT_WINDOW_DAYS,
34045
+ TREND_STALE_WINDOW_DAYS,
33949
34046
  TextProcessor,
33950
34047
  UserPreference,
33951
34048
  VAULT_SIZE_HOP_CAP,
@@ -33968,6 +34065,7 @@ function buildSystemPrompt(ctx, options) {
33968
34065
  classifyCryptoPriceBatch,
33969
34066
  classifyDecay,
33970
34067
  classifyInjectionCandidates,
34068
+ classifyObservationTrend,
33971
34069
  classifyStockPrice,
33972
34070
  classifyStockPriceBatch,
33973
34071
  classifyWeather,
@@ -34147,6 +34245,7 @@ function buildSystemPrompt(ctx, options) {
34147
34245
  stampTopicsExtractedAtOp,
34148
34246
  streamCancelPath,
34149
34247
  streamReplayPath,
34248
+ summarizeObservationTrends,
34150
34249
  summaryToSystemMessage,
34151
34250
  supersedeVaultMemoryOp,
34152
34251
  synthesizeProfile,