@anuma/sdk 3.3.0 → 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.
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  recall
3
- } from "./chunk-GZRK43CA.mjs";
3
+ } from "./chunk-CGC3UJHM.mjs";
4
4
  import "./chunk-DFVCS3QQ.mjs";
5
5
  import "./chunk-GYKJOWEO.mjs";
6
6
  export {
@@ -17114,6 +17114,9 @@ async function withEmbeddingRetry(call) {
17114
17114
  }
17115
17115
  }
17116
17116
  if (threw) throw lastThrown;
17117
+ if (last?.error instanceof Error && last.response?.status === void 0) {
17118
+ throw last.error;
17119
+ }
17117
17120
  return last;
17118
17121
  }
17119
17122
  var EmbeddingHttpError = class extends Error {
@@ -18493,6 +18496,7 @@ async function searchVaultMemoriesWithSize(query, vaultCtx, embeddingOptions, ca
18493
18496
  createdAt: m.createdAt,
18494
18497
  updatedAt: m.updatedAt,
18495
18498
  proofCount: m.proofCount,
18499
+ lastObservedAt: m.lastObservedAt,
18496
18500
  eventTimeStart: m.eventTimeStart,
18497
18501
  sourceChunkIds: m.sourceChunkIds,
18498
18502
  eventTimeEnd: m.eventTimeEnd,
@@ -18509,13 +18513,27 @@ async function searchVaultMemoriesWithSize(query, vaultCtx, embeddingOptions, ca
18509
18513
  );
18510
18514
  }
18511
18515
  }
18512
- const timestampById = new Map(
18513
- 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
+ ])
18514
18526
  );
18515
18527
  const stampTimestamps = (out) => {
18516
18528
  const results2 = out.results.map((r) => {
18517
- const ts = timestampById.get(r.uniqueId);
18518
- 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;
18519
18537
  });
18520
18538
  return {
18521
18539
  results: results2,
@@ -18709,7 +18727,7 @@ function createMemoryVaultSearchTool(vaultCtx, embeddingOptions, cache, searchOp
18709
18727
  legacy.map((r) => ({ id: r.uniqueId, content: r.content, score: r.similarity }))
18710
18728
  );
18711
18729
  }
18712
- const { recall: recall2 } = await import("./recall-76WPPKLR.mjs");
18730
+ const { recall: recall2 } = await import("./recall-GWRWPGE4.mjs");
18713
18731
  const result = await recall2(
18714
18732
  query,
18715
18733
  { vaultCtx, embeddingOptions, vaultCache: cache },
@@ -18973,6 +18991,42 @@ Which should be expanded?`,
18973
18991
  };
18974
18992
  }
18975
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
+
18976
19030
  // src/lib/memory/queryTemporal.ts
18977
19031
  var RELATIVE_DAY_ENTRIES = [
18978
19032
  [/\btoday\b/, "today", 0],
@@ -19367,7 +19421,7 @@ async function recall(query, ctx, options = {}) {
19367
19421
  const fuseStart = nowMs();
19368
19422
  if (types.length === 1 || factResults.length === 0 || chunkResults.length === 0) {
19369
19423
  const memories2 = [
19370
- ...factResults.map(toFactMemory),
19424
+ ...factResults.map((r) => toFactMemory(r, options.now)),
19371
19425
  ...chunkResults.map(toChunkMemory)
19372
19426
  ];
19373
19427
  memories2.sort((a, b) => b.score - a.score);
@@ -19388,7 +19442,7 @@ async function recall(query, ctx, options = {}) {
19388
19442
  const fused = rrfFuse([factRanking, chunkRanking], options.rrfK);
19389
19443
  const byId = /* @__PURE__ */ new Map();
19390
19444
  for (const r of factResults) {
19391
- const m = toFactMemory(r);
19445
+ const m = toFactMemory(r, options.now);
19392
19446
  m.score = fused.get(`fact:${r.uniqueId}`) ?? 0;
19393
19447
  if (!m.scoreBreakdown) m.scoreBreakdown = {};
19394
19448
  m.scoreBreakdown.fused = r.similarity;
@@ -19437,7 +19491,10 @@ async function recall(query, ctx, options = {}) {
19437
19491
  ...vaultSize !== void 0 && { vaultSize }
19438
19492
  };
19439
19493
  }
19440
- 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;
19441
19498
  return {
19442
19499
  id: r.uniqueId,
19443
19500
  kind: "fact",
@@ -19453,6 +19510,18 @@ function toFactMemory(r) {
19453
19510
  // (and UI reading them) carry the fact's type. Undefined when untyped.
19454
19511
  ...r.factType !== void 0 && { factType: r.factType },
19455
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
+ ),
19456
19525
  // r.similarity from searchVaultMemoriesWithSize is the fused score
19457
19526
  // (cosine + BM25 + RRF + recency + proof) when useFusion=true (the
19458
19527
  // default) and pure cosine when useFusion=false. The breakdown
@@ -19461,7 +19530,7 @@ function toFactMemory(r) {
19461
19530
  content: r.content,
19462
19531
  score: r.similarity,
19463
19532
  scoreBreakdown: { fused: r.similarity },
19464
- createdAt: r.createdAt ?? /* @__PURE__ */ new Date(0),
19533
+ createdAt,
19465
19534
  updatedAt: r.updatedAt ?? /* @__PURE__ */ new Date(0)
19466
19535
  };
19467
19536
  }
@@ -19650,6 +19719,10 @@ export {
19650
19719
  capHopsForDensity,
19651
19720
  traverseGraphLane,
19652
19721
  createLlmNeighborRefiner,
19722
+ TREND_RECENT_WINDOW_DAYS,
19723
+ TREND_STALE_WINDOW_DAYS,
19724
+ classifyObservationTrend,
19725
+ summarizeObservationTrends,
19653
19726
  recall,
19654
19727
  preEmbedVaultMemories,
19655
19728
  eagerEmbedContent,
@@ -17941,6 +17941,9 @@ async function withEmbeddingRetry(call) {
17941
17941
  }
17942
17942
  }
17943
17943
  if (threw) throw lastThrown;
17944
+ if (last?.error instanceof Error && last.response?.status === void 0) {
17945
+ throw last.error;
17946
+ }
17944
17947
  return last;
17945
17948
  }
17946
17949
  function isFatalEmbeddingError(err) {
@@ -19253,6 +19256,48 @@ var init_graphTraversal = __esm({
19253
19256
  }
19254
19257
  });
19255
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
+
19256
19301
  // src/lib/memory/queryTemporal.ts
19257
19302
  function startOfDay(ts) {
19258
19303
  const d = new Date(ts);
@@ -19652,7 +19697,7 @@ async function recall(query, ctx, options = {}) {
19652
19697
  const fuseStart = nowMs();
19653
19698
  if (types.length === 1 || factResults.length === 0 || chunkResults.length === 0) {
19654
19699
  const memories2 = [
19655
- ...factResults.map(toFactMemory),
19700
+ ...factResults.map((r) => toFactMemory(r, options.now)),
19656
19701
  ...chunkResults.map(toChunkMemory)
19657
19702
  ];
19658
19703
  memories2.sort((a, b) => b.score - a.score);
@@ -19673,7 +19718,7 @@ async function recall(query, ctx, options = {}) {
19673
19718
  const fused = rrfFuse([factRanking, chunkRanking], options.rrfK);
19674
19719
  const byId = /* @__PURE__ */ new Map();
19675
19720
  for (const r of factResults) {
19676
- const m = toFactMemory(r);
19721
+ const m = toFactMemory(r, options.now);
19677
19722
  m.score = fused.get(`fact:${r.uniqueId}`) ?? 0;
19678
19723
  if (!m.scoreBreakdown) m.scoreBreakdown = {};
19679
19724
  m.scoreBreakdown.fused = r.similarity;
@@ -19722,7 +19767,10 @@ async function recall(query, ctx, options = {}) {
19722
19767
  ...vaultSize !== void 0 && { vaultSize }
19723
19768
  };
19724
19769
  }
19725
- 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;
19726
19774
  return {
19727
19775
  id: r.uniqueId,
19728
19776
  kind: "fact",
@@ -19738,6 +19786,18 @@ function toFactMemory(r) {
19738
19786
  // (and UI reading them) carry the fact's type. Undefined when untyped.
19739
19787
  ...r.factType !== void 0 && { factType: r.factType },
19740
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
+ ),
19741
19801
  // r.similarity from searchVaultMemoriesWithSize is the fused score
19742
19802
  // (cosine + BM25 + RRF + recency + proof) when useFusion=true (the
19743
19803
  // default) and pure cosine when useFusion=false. The breakdown
@@ -19746,7 +19806,7 @@ function toFactMemory(r) {
19746
19806
  content: r.content,
19747
19807
  score: r.similarity,
19748
19808
  scoreBreakdown: { fused: r.similarity },
19749
- createdAt: r.createdAt ?? /* @__PURE__ */ new Date(0),
19809
+ createdAt,
19750
19810
  updatedAt: r.updatedAt ?? /* @__PURE__ */ new Date(0)
19751
19811
  };
19752
19812
  }
@@ -19829,6 +19889,7 @@ var init_recall = __esm({
19829
19889
  init_embeddings();
19830
19890
  init_searchTool();
19831
19891
  init_graphTraversal();
19892
+ init_observationTrend();
19832
19893
  init_queryEntities();
19833
19894
  init_queryTemporal();
19834
19895
  init_rrf();
@@ -20424,6 +20485,7 @@ async function searchVaultMemoriesWithSize(query, vaultCtx, embeddingOptions, ca
20424
20485
  createdAt: m.createdAt,
20425
20486
  updatedAt: m.updatedAt,
20426
20487
  proofCount: m.proofCount,
20488
+ lastObservedAt: m.lastObservedAt,
20427
20489
  eventTimeStart: m.eventTimeStart,
20428
20490
  sourceChunkIds: m.sourceChunkIds,
20429
20491
  eventTimeEnd: m.eventTimeEnd,
@@ -20440,13 +20502,27 @@ async function searchVaultMemoriesWithSize(query, vaultCtx, embeddingOptions, ca
20440
20502
  );
20441
20503
  }
20442
20504
  }
20443
- const timestampById = new Map(
20444
- 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
+ ])
20445
20515
  );
20446
20516
  const stampTimestamps = (out) => {
20447
20517
  const results2 = out.results.map((r) => {
20448
- const ts = timestampById.get(r.uniqueId);
20449
- 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;
20450
20526
  });
20451
20527
  return {
20452
20528
  results: results2,
@@ -21559,6 +21635,8 @@ __export(index_exports, {
21559
21635
  TOOL_CATALOG: () => TOOL_CATALOG,
21560
21636
  TOPICS_EXTRACTION_VERSION: () => TOPICS_EXTRACTION_VERSION,
21561
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,
21562
21640
  TextProcessor: () => TextProcessor,
21563
21641
  UserPreference: () => UserPreference,
21564
21642
  VAULT_SIZE_HOP_CAP: () => VAULT_SIZE_HOP_CAP,
@@ -21581,6 +21659,7 @@ __export(index_exports, {
21581
21659
  classifyCryptoPriceBatch: () => classifyCryptoPriceBatch,
21582
21660
  classifyDecay: () => classifyDecay,
21583
21661
  classifyInjectionCandidates: () => classifyInjectionCandidates,
21662
+ classifyObservationTrend: () => classifyObservationTrend,
21584
21663
  classifyStockPrice: () => classifyStockPrice,
21585
21664
  classifyStockPriceBatch: () => classifyStockPriceBatch,
21586
21665
  classifyWeather: () => classifyWeather,
@@ -21760,6 +21839,7 @@ __export(index_exports, {
21760
21839
  stampTopicsExtractedAtOp: () => stampTopicsExtractedAtOp,
21761
21840
  streamCancelPath: () => streamCancelPath,
21762
21841
  streamReplayPath: () => streamReplayPath,
21842
+ summarizeObservationTrends: () => summarizeObservationTrends,
21763
21843
  summaryToSystemMessage: () => summaryToSystemMessage,
21764
21844
  supersedeVaultMemoryOp: () => supersedeVaultMemoryOp,
21765
21845
  synthesizeProfile: () => synthesizeProfile,
@@ -27059,12 +27139,12 @@ function createChunkVectorCache(maxSize = DEFAULT_CHUNK_CACHE_SIZE) {
27059
27139
 
27060
27140
  // src/lib/memory/decay.ts
27061
27141
  init_logger();
27062
- var DAY_MS2 = 24 * 60 * 60 * 1e3;
27063
- var SHORT_TTL_MS = 30 * DAY_MS2;
27064
- 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;
27065
27145
  var NEVER_TTL_MS = Number.POSITIVE_INFINITY;
27066
- var HARD_DELETE_WINDOW_MS = 30 * DAY_MS2;
27067
- 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;
27068
27148
  var DEFAULT_DECAY_POLICY = {
27069
27149
  ttlByType: {
27070
27150
  identity: NEVER_TTL_MS,
@@ -27324,6 +27404,7 @@ function createDecaySweeper(options) {
27324
27404
 
27325
27405
  // src/lib/memory/index.ts
27326
27406
  init_graphTraversal();
27407
+ init_observationTrend();
27327
27408
  init_recall();
27328
27409
 
27329
27410
  // src/lib/memory/recallTool.ts
@@ -27690,6 +27771,7 @@ init_logger();
27690
27771
  init_constants();
27691
27772
  init_embeddings();
27692
27773
  init_vector();
27774
+ init_observationTrend();
27693
27775
  var DEFAULT_SYNTHESIS_MODEL = "inclusionai/ling-2.6-flash";
27694
27776
  var DEFAULT_FACET_RECALL_LIMIT = 20;
27695
27777
  var DEFAULT_FACET_MAX_TOKENS = 512;
@@ -27775,6 +27857,13 @@ async function synthesizeProfile(ctx, options = {}) {
27775
27857
  includeSuperseded: true
27776
27858
  });
27777
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
+ );
27778
27867
  const presentIds = new Set(memories.map((m) => m.uniqueId));
27779
27868
  const hasStaleSections = previous?.sections.some((s) => s.stale);
27780
27869
  const citesMissingFact = previous?.sections.some(
@@ -27782,10 +27871,14 @@ async function synthesizeProfile(ctx, options = {}) {
27782
27871
  );
27783
27872
  if (previous && previous.vaultWatermark === watermark && !hasStaleSections && !citesMissingFact) {
27784
27873
  const sameOrder = previous.sections.length === facets.length && facets.every((f, i) => previous.sections[i]?.key === f.key);
27785
- if (sameOrder) return previous;
27874
+ if (sameOrder) {
27875
+ if (trendsEqual(previous.observationTrends, observationTrends)) return previous;
27876
+ return { ...previous, observationTrends };
27877
+ }
27786
27878
  return {
27787
27879
  ...previous,
27788
- 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
27789
27882
  };
27790
27883
  }
27791
27884
  const staleKeys = await computeStaleFacetKeys(ctx, memories, facets, previous, watermark);
@@ -27818,6 +27911,7 @@ async function synthesizeProfile(ctx, options = {}) {
27818
27911
  sections,
27819
27912
  vaultWatermark: watermark,
27820
27913
  config,
27914
+ observationTrends,
27821
27915
  generatedAt: Date.now()
27822
27916
  };
27823
27917
  }
@@ -27828,6 +27922,10 @@ function configMatches(a, b) {
27828
27922
  function facetsSignature(facets) {
27829
27923
  return facets.map((f) => JSON.stringify([f.key, f.label, f.query, f.guidance])).sort().join("\n");
27830
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
+ }
27831
27929
  function changeTime(m) {
27832
27930
  return Math.max(m.updatedAt.getTime(), m.supersededAt ?? 0, m.lastObservedAt ?? 0);
27833
27931
  }
@@ -30179,7 +30277,7 @@ function createCryptoPricePreProcessor(options = {}) {
30179
30277
  init_clientConfig();
30180
30278
 
30181
30279
  // src/client/core/serverSentEvents.gen.ts
30182
- var createSseClient = ({
30280
+ function createSseClient({
30183
30281
  onRequest,
30184
30282
  onSseError,
30185
30283
  onSseEvent,
@@ -30191,7 +30289,7 @@ var createSseClient = ({
30191
30289
  sseSleepFn,
30192
30290
  url,
30193
30291
  ...options
30194
- }) => {
30292
+ }) {
30195
30293
  let lastEventId;
30196
30294
  const sleep4 = sseSleepFn ?? ((ms) => new Promise((resolve) => setTimeout(resolve, ms)));
30197
30295
  const createStream = async function* () {
@@ -30219,10 +30317,7 @@ var createSseClient = ({
30219
30317
  }
30220
30318
  const _fetch = options.fetch ?? globalThis.fetch;
30221
30319
  const response = await _fetch(request);
30222
- if (!response.ok)
30223
- throw new Error(
30224
- `SSE failed: ${response.status} ${response.statusText}`
30225
- );
30320
+ if (!response.ok) throw new Error(`SSE failed: ${response.status} ${response.statusText}`);
30226
30321
  if (!response.body) throw new Error("No body in SSE response");
30227
30322
  const reader = response.body.pipeThrough(new TextDecoderStream()).getReader();
30228
30323
  let buffer = "";
@@ -30238,6 +30333,7 @@ var createSseClient = ({
30238
30333
  const { done, value } = await reader.read();
30239
30334
  if (done) break;
30240
30335
  buffer += value;
30336
+ buffer = buffer.replace(/\r\n?/g, "\n");
30241
30337
  const chunks = buffer.split("\n\n");
30242
30338
  buffer = chunks.pop() ?? "";
30243
30339
  for (const chunk of chunks) {
@@ -30252,10 +30348,7 @@ var createSseClient = ({
30252
30348
  } else if (line.startsWith("id:")) {
30253
30349
  lastEventId = line.replace(/^id:\s*/, "");
30254
30350
  } else if (line.startsWith("retry:")) {
30255
- const parsed = Number.parseInt(
30256
- line.replace(/^retry:\s*/, ""),
30257
- 10
30258
- );
30351
+ const parsed = Number.parseInt(line.replace(/^retry:\s*/, ""), 10);
30259
30352
  if (!Number.isNaN(parsed)) {
30260
30353
  retryDelay = parsed;
30261
30354
  }
@@ -30301,17 +30394,14 @@ var createSseClient = ({
30301
30394
  if (sseMaxRetryAttempts !== void 0 && attempt >= sseMaxRetryAttempts) {
30302
30395
  break;
30303
30396
  }
30304
- const backoff = Math.min(
30305
- retryDelay * 2 ** (attempt - 1),
30306
- sseMaxRetryDelay ?? 3e4
30307
- );
30397
+ const backoff = Math.min(retryDelay * 2 ** (attempt - 1), sseMaxRetryDelay ?? 3e4);
30308
30398
  await sleep4(backoff);
30309
30399
  }
30310
30400
  }
30311
30401
  };
30312
30402
  const stream = createStream();
30313
30403
  return { stream };
30314
- };
30404
+ }
30315
30405
 
30316
30406
  // src/lib/chat/toolLoop.ts
30317
30407
  init_clientConfig();
@@ -33951,6 +34041,8 @@ function buildSystemPrompt(ctx, options) {
33951
34041
  TOOL_CATALOG,
33952
34042
  TOPICS_EXTRACTION_VERSION,
33953
34043
  TOPIC_EXTRACTION_BATCH_SIZE,
34044
+ TREND_RECENT_WINDOW_DAYS,
34045
+ TREND_STALE_WINDOW_DAYS,
33954
34046
  TextProcessor,
33955
34047
  UserPreference,
33956
34048
  VAULT_SIZE_HOP_CAP,
@@ -33973,6 +34065,7 @@ function buildSystemPrompt(ctx, options) {
33973
34065
  classifyCryptoPriceBatch,
33974
34066
  classifyDecay,
33975
34067
  classifyInjectionCandidates,
34068
+ classifyObservationTrend,
33976
34069
  classifyStockPrice,
33977
34070
  classifyStockPriceBatch,
33978
34071
  classifyWeather,
@@ -34152,6 +34245,7 @@ function buildSystemPrompt(ctx, options) {
34152
34245
  stampTopicsExtractedAtOp,
34153
34246
  streamCancelPath,
34154
34247
  streamReplayPath,
34248
+ summarizeObservationTrends,
34155
34249
  summaryToSystemMessage,
34156
34250
  supersedeVaultMemoryOp,
34157
34251
  synthesizeProfile,