@agentmemory/agentmemory 0.9.2 → 0.9.4

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,5 +1,5 @@
1
1
  import { a as jaccardSimilarity, i as generateId, n as STREAM, r as fingerprintId, t as KV } from "./cli.mjs";
2
- import { _ as loadTeamConfig, a as getConsolidationDecayDays, c as isAutoCompressEnabled, d as isGraphExtractionEnabled, f as loadClaudeBridgeConfig, g as loadSnapshotConfig, h as loadFallbackConfig, i as detectEmbeddingProvider, l as isConsolidationEnabled, m as loadEmbeddingConfig, n as getVisibleTools, o as getEnvVar, p as loadConfig, r as VERSION, t as getAllTools, u as isContextInjectionEnabled } from "./tools-registry-CHH84gIQ.mjs";
2
+ import { _ as loadSnapshotConfig, a as detectLlmProviderKind, d as isContextInjectionEnabled, f as isGraphExtractionEnabled, g as loadFallbackConfig, h as loadEmbeddingConfig, i as detectEmbeddingProvider, l as isAutoCompressEnabled, m as loadConfig, n as getVisibleTools, o as getConsolidationDecayDays, p as loadClaudeBridgeConfig, r as VERSION, s as getEnvVar, t as getAllTools, u as isConsolidationEnabled, v as loadTeamConfig } from "./tools-registry-Co8VIL4t.mjs";
3
3
  import { execFile } from "node:child_process";
4
4
  import { constants, existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
5
5
  import { basename, dirname, extname, join, resolve, sep } from "node:path";
@@ -2018,8 +2018,10 @@ var SearchIndex = class SearchIndex {
2018
2018
  //#endregion
2019
2019
  //#region src/state/index-persistence.ts
2020
2020
  const DEBOUNCE_MS = 5e3;
2021
+ const FAILURE_LOG_THROTTLE_MS = 6e4;
2021
2022
  var IndexPersistence = class {
2022
2023
  timer = null;
2024
+ lastFailureLogAt = 0;
2023
2025
  constructor(kv, bm25, vector) {
2024
2026
  this.kv = kv;
2025
2027
  this.bm25 = bm25;
@@ -2027,15 +2029,21 @@ var IndexPersistence = class {
2027
2029
  }
2028
2030
  scheduleSave() {
2029
2031
  if (this.timer) clearTimeout(this.timer);
2030
- this.timer = setTimeout(() => this.save(), DEBOUNCE_MS);
2032
+ this.timer = setTimeout(() => {
2033
+ this.save().catch((err) => this.logFailure(err));
2034
+ }, DEBOUNCE_MS);
2031
2035
  }
2032
2036
  async save() {
2033
2037
  if (this.timer) {
2034
2038
  clearTimeout(this.timer);
2035
2039
  this.timer = null;
2036
2040
  }
2037
- await this.kv.set(KV.bm25Index, "data", this.bm25.serialize());
2038
- if (this.vector && this.vector.size > 0) await this.kv.set(KV.bm25Index, "vectors", this.vector.serialize());
2041
+ try {
2042
+ await this.kv.set(KV.bm25Index, "data", this.bm25.serialize());
2043
+ if (this.vector && this.vector.size > 0) await this.kv.set(KV.bm25Index, "vectors", this.vector.serialize());
2044
+ } catch (err) {
2045
+ this.logFailure(err);
2046
+ }
2039
2047
  }
2040
2048
  async load() {
2041
2049
  let bm25 = null;
@@ -2055,6 +2063,18 @@ var IndexPersistence = class {
2055
2063
  this.timer = null;
2056
2064
  }
2057
2065
  }
2066
+ logFailure(err) {
2067
+ const now = Date.now();
2068
+ if (now - this.lastFailureLogAt < FAILURE_LOG_THROTTLE_MS) return;
2069
+ this.lastFailureLogAt = now;
2070
+ const code = err?.code;
2071
+ const message = err instanceof Error ? err.message : String(err);
2072
+ logger.warn("index persistence: failed to save BM25/vector index", {
2073
+ code,
2074
+ message,
2075
+ hint: code === "TIMEOUT" ? "iii-engine state::set timed out; recent index updates remain in memory and will retry on the next debounce flush" : void 0
2076
+ });
2077
+ }
2058
2078
  };
2059
2079
 
2060
2080
  //#endregion
@@ -2507,10 +2527,10 @@ function registerObserveFunction(sdk, kv, dedupMap, maxObservationsPerSession) {
2507
2527
  };
2508
2528
  }
2509
2529
  if (pendingImageData && (pendingImageData.startsWith("data:image/") || pendingImageData.startsWith("iVBORw0KGgo") || pendingImageData.startsWith("/9j/"))) {
2510
- const { saveImageToDisk } = await import("./image-store-BLOkD0xV.mjs");
2530
+ const { saveImageToDisk } = await import("./image-store-Cn9eD-7D.mjs");
2511
2531
  const { filePath, bytesWritten } = await saveImageToDisk(pendingImageData);
2512
2532
  raw.imageData = filePath;
2513
- const { incrementImageRef } = await import("./image-refs-Dq5wcV-a.mjs");
2533
+ const { incrementImageRef } = await import("./image-refs-BfT7XAa-.mjs");
2514
2534
  await incrementImageRef(kv, filePath);
2515
2535
  sdk.triggerVoid("mem::disk-size-delta", { deltaBytes: bytesWritten });
2516
2536
  if (process.env["AGENTMEMORY_IMAGE_EMBEDDINGS"] === "true") sdk.triggerVoid("mem::vision-embed", {
@@ -2523,7 +2543,7 @@ function registerObserveFunction(sdk, kv, dedupMap, maxObservationsPerSession) {
2523
2543
  await kv.set(KV.observations(payload.sessionId), obsId, raw);
2524
2544
  } catch (error) {
2525
2545
  if (raw.imageData) {
2526
- const { deleteImage } = await import("./image-store-BLOkD0xV.mjs");
2546
+ const { deleteImage } = await import("./image-store-Cn9eD-7D.mjs");
2527
2547
  const { deletedBytes } = await deleteImage(raw.imageData);
2528
2548
  if (deletedBytes > 0) sdk.triggerVoid("mem::disk-size-delta", { deltaBytes: -deletedBytes });
2529
2549
  }
@@ -4556,7 +4576,7 @@ function registerRememberFunction(sdk, kv) {
4556
4576
  const deletedMemoryIds = [];
4557
4577
  const deletedObservationIds = [];
4558
4578
  let deletedSession = false;
4559
- const { decrementImageRef } = await import("./image-refs-Dq5wcV-a.mjs");
4579
+ const { decrementImageRef } = await import("./image-refs-BfT7XAa-.mjs");
4560
4580
  if (data.memoryId) {
4561
4581
  const mem = await kv.get(KV.memories, data.memoryId);
4562
4582
  await kv.delete(KV.memories, data.memoryId);
@@ -4615,7 +4635,7 @@ const DEFAULTS$1 = {
4615
4635
  function registerEvictFunction(sdk, kv) {
4616
4636
  sdk.registerFunction("mem::evict", async (data) => {
4617
4637
  const dryRun = data?.dryRun ?? false;
4618
- const { decrementImageRef } = await import("./image-refs-Dq5wcV-a.mjs");
4638
+ const { decrementImageRef } = await import("./image-refs-BfT7XAa-.mjs");
4619
4639
  const configOverride = await kv.get(KV.config, "eviction").catch(() => null);
4620
4640
  const cfg = {
4621
4641
  ...DEFAULTS$1,
@@ -5218,7 +5238,7 @@ function registerAutoForgetFunction(sdk, kv) {
5218
5238
  sdk.registerFunction("mem::auto-forget", async (data) => {
5219
5239
  const dryRun = data?.dryRun ?? false;
5220
5240
  const now = Date.now();
5221
- const { decrementImageRef } = await import("./image-refs-Dq5wcV-a.mjs");
5241
+ const { decrementImageRef } = await import("./image-refs-BfT7XAa-.mjs");
5222
5242
  const result = {
5223
5243
  ttlExpired: [],
5224
5244
  contradictions: [],
@@ -5449,7 +5469,9 @@ function registerExportImportFunction(sdk, kv) {
5449
5469
  "0.8.13",
5450
5470
  "0.9.0",
5451
5471
  "0.9.1",
5452
- "0.9.2"
5472
+ "0.9.2",
5473
+ "0.9.3",
5474
+ "0.9.4"
5453
5475
  ]).has(importData.version)) return {
5454
5476
  success: false,
5455
5477
  error: `Unsupported export version: ${importData.version}`
@@ -11806,7 +11828,7 @@ function registerRetentionFunctions(sdk, kv) {
11806
11828
  const threshold = typeof data?.threshold === "number" && Number.isFinite(data.threshold) ? data.threshold : DEFAULT_DECAY.tierThresholds.cold;
11807
11829
  const maxEvictRaw = typeof data?.maxEvict === "number" && Number.isInteger(data.maxEvict) ? data.maxEvict : 50;
11808
11830
  const maxEvict = Math.min(1e3, Math.max(0, maxEvictRaw));
11809
- const { decrementImageRef } = await import("./image-refs-Dq5wcV-a.mjs");
11831
+ const { decrementImageRef } = await import("./image-refs-BfT7XAa-.mjs");
11810
11832
  const candidates = (await kv.list(KV.retentionScores)).filter((s) => s.score < threshold).sort((a, b) => a.score - b.score).slice(0, maxEvict);
11811
11833
  if (data?.dryRun) return {
11812
11834
  success: true,
@@ -12067,7 +12089,7 @@ function parseJsonlText(text, fallbackSessionId) {
12067
12089
  const parsed = JSON.parse(line);
12068
12090
  if (parsed && typeof parsed === "object") entries.push(parsed);
12069
12091
  } catch {}
12070
- let sessionId = fallbackSessionId || "";
12092
+ let sessionId = "";
12071
12093
  let cwd = "";
12072
12094
  let firstTs = "";
12073
12095
  let lastTs = "";
@@ -12128,7 +12150,7 @@ function parseJsonlText(text, fallbackSessionId) {
12128
12150
  });
12129
12151
  } else if (entry.type === "summary" || entry.type === "system") {}
12130
12152
  }
12131
- const effectiveSessionId = sessionId || generateId("sess");
12153
+ const effectiveSessionId = sessionId || fallbackSessionId || generateId("sess");
12132
12154
  for (const obs of observations) if (obs.sessionId === "imported") obs.sessionId = effectiveSessionId;
12133
12155
  const nowIso = (/* @__PURE__ */ new Date()).toISOString();
12134
12156
  return {
@@ -12238,6 +12260,8 @@ function projectTimeline(observations) {
12238
12260
 
12239
12261
  //#endregion
12240
12262
  //#region src/functions/replay.ts
12263
+ const MAX_FILES_DEFAULT = 200;
12264
+ const MAX_FILES_UPPER_BOUND = 1e3;
12241
12265
  const SENSITIVE_PATH_PATTERNS = [
12242
12266
  /(^|[\\/_.-])secret([\\/_.-]|s?$)/i,
12243
12267
  /(^|[\\/_.-])credentials?([\\/_.-]|$)/i,
@@ -12372,8 +12396,11 @@ async function loadObservations(kv, sessionId) {
12372
12396
  }
12373
12397
  async function findJsonlFiles(root, limit = 200) {
12374
12398
  const out = [];
12399
+ let discovered = 0;
12400
+ let walked = 0;
12401
+ const traversalCap = Math.max(limit * 50, 5e4);
12375
12402
  async function walk(dir) {
12376
- if (out.length >= limit) return;
12403
+ if (walked >= traversalCap) return;
12377
12404
  let names;
12378
12405
  try {
12379
12406
  names = await readdir(dir);
@@ -12381,7 +12408,8 @@ async function findJsonlFiles(root, limit = 200) {
12381
12408
  return;
12382
12409
  }
12383
12410
  for (const name of names) {
12384
- if (out.length >= limit) return;
12411
+ if (walked >= traversalCap) return;
12412
+ walked++;
12385
12413
  const full = join(dir, name);
12386
12414
  let st;
12387
12415
  try {
@@ -12391,11 +12419,20 @@ async function findJsonlFiles(root, limit = 200) {
12391
12419
  }
12392
12420
  if (st.isSymbolicLink()) continue;
12393
12421
  if (st.isDirectory()) await walk(full);
12394
- else if (st.isFile() && name.endsWith(".jsonl")) out.push(full);
12422
+ else if (st.isFile() && name.endsWith(".jsonl")) {
12423
+ discovered++;
12424
+ if (out.length < limit) out.push(full);
12425
+ }
12395
12426
  }
12396
12427
  }
12397
12428
  await walk(root);
12398
- return out;
12429
+ const traversalCapped = walked >= traversalCap;
12430
+ return {
12431
+ files: out,
12432
+ truncated: discovered > out.length || traversalCapped,
12433
+ discovered,
12434
+ traversalCapped
12435
+ };
12399
12436
  }
12400
12437
  function registerReplayFunctions(sdk, kv) {
12401
12438
  sdk.registerFunction("mem::replay::load", async (data) => {
@@ -12443,10 +12480,21 @@ function registerReplayFunctions(sdk, kv) {
12443
12480
  error: "path not found"
12444
12481
  };
12445
12482
  }
12483
+ const maxFiles = Number.isInteger(data.maxFiles) && data.maxFiles > 0 ? Math.min(data.maxFiles, MAX_FILES_UPPER_BOUND) : MAX_FILES_DEFAULT;
12446
12484
  let files = [];
12447
- if (stat.isDirectory()) files = await findJsonlFiles(abs, data.maxFiles || 200);
12448
- else if (stat.isFile() && abs.endsWith(".jsonl")) files = [abs];
12449
- else return {
12485
+ let truncated = false;
12486
+ let discovered = 0;
12487
+ let traversalCapped = false;
12488
+ if (stat.isDirectory()) {
12489
+ const found = await findJsonlFiles(abs, maxFiles);
12490
+ files = found.files;
12491
+ truncated = found.truncated;
12492
+ discovered = found.discovered;
12493
+ traversalCapped = found.traversalCapped;
12494
+ } else if (stat.isFile() && abs.endsWith(".jsonl")) {
12495
+ files = [abs];
12496
+ discovered = 1;
12497
+ } else return {
12450
12498
  success: false,
12451
12499
  error: "path must be a .jsonl file or directory"
12452
12500
  };
@@ -12454,7 +12502,12 @@ function registerReplayFunctions(sdk, kv) {
12454
12502
  success: true,
12455
12503
  imported: 0,
12456
12504
  sessionIds: [],
12457
- observations: 0
12505
+ observations: 0,
12506
+ discovered,
12507
+ truncated,
12508
+ traversalCapped,
12509
+ maxFiles,
12510
+ maxFilesUpperBound: MAX_FILES_UPPER_BOUND
12458
12511
  };
12459
12512
  const sessionIds = [];
12460
12513
  let observationCount = 0;
@@ -12520,7 +12573,12 @@ function registerReplayFunctions(sdk, kv) {
12520
12573
  success: true,
12521
12574
  imported: files.length,
12522
12575
  sessionIds,
12523
- observations: observationCount
12576
+ observations: observationCount,
12577
+ discovered,
12578
+ truncated,
12579
+ traversalCapped,
12580
+ maxFiles,
12581
+ maxFilesUpperBound: MAX_FILES_UPPER_BOUND
12524
12582
  };
12525
12583
  });
12526
12584
  }
@@ -12747,6 +12805,28 @@ function requireConfiguredSecret(secret, feature) {
12747
12805
  body: { error: `${feature} requires AGENTMEMORY_SECRET` }
12748
12806
  };
12749
12807
  }
12808
+ function flagDisabledResponse(opts) {
12809
+ return {
12810
+ status_code: 503,
12811
+ body: opts
12812
+ };
12813
+ }
12814
+ function graphDisabledResponse() {
12815
+ return flagDisabledResponse({
12816
+ error: "Knowledge graph not enabled",
12817
+ flag: "GRAPH_EXTRACTION_ENABLED",
12818
+ enableHow: "Set GRAPH_EXTRACTION_ENABLED=true and restart. Requires an LLM provider key.",
12819
+ docsHref: "https://github.com/rohitg00/agentmemory#knowledge-graph"
12820
+ });
12821
+ }
12822
+ function consolidationDisabledResponse() {
12823
+ return flagDisabledResponse({
12824
+ error: "Consolidation pipeline not enabled",
12825
+ flag: "CONSOLIDATION_ENABLED",
12826
+ enableHow: "Set CONSOLIDATION_ENABLED=true and restart. Requires an LLM provider key.",
12827
+ docsHref: "https://github.com/rohitg00/agentmemory#consolidation"
12828
+ });
12829
+ }
12750
12830
  function asNonEmptyString$1(value) {
12751
12831
  if (typeof value !== "string") return null;
12752
12832
  const trimmed = value.trim();
@@ -12798,6 +12878,77 @@ function registerApiTriggers(sdk, kv, secret, metricsStore, provider) {
12798
12878
  http_method: "GET"
12799
12879
  }
12800
12880
  });
12881
+ sdk.registerFunction("api::config-flags", async (req) => {
12882
+ const authErr = checkAuth(req, secret);
12883
+ if (authErr) return authErr;
12884
+ return {
12885
+ status_code: 200,
12886
+ body: {
12887
+ version: VERSION,
12888
+ provider: detectLlmProviderKind(),
12889
+ embeddingProvider: detectEmbeddingProvider() ? "embeddings" : "none",
12890
+ flags: [
12891
+ {
12892
+ key: "GRAPH_EXTRACTION_ENABLED",
12893
+ label: "Knowledge graph extraction",
12894
+ enabled: isGraphExtractionEnabled(),
12895
+ default: false,
12896
+ affects: ["Graph", "Dashboard"],
12897
+ needsLlm: true,
12898
+ description: "Extracts entities and relations from observations into a knowledge graph.",
12899
+ enableHow: "Set GRAPH_EXTRACTION_ENABLED=true and provide an LLM key, then restart.",
12900
+ docsHref: "https://github.com/rohitg00/agentmemory#knowledge-graph"
12901
+ },
12902
+ {
12903
+ key: "CONSOLIDATION_ENABLED",
12904
+ label: "Memory consolidation",
12905
+ enabled: isConsolidationEnabled(),
12906
+ default: false,
12907
+ affects: [
12908
+ "Dashboard",
12909
+ "Memories",
12910
+ "Crystals"
12911
+ ],
12912
+ needsLlm: true,
12913
+ description: "Periodically summarizes sessions into semantic facts + procedures.",
12914
+ enableHow: "Set CONSOLIDATION_ENABLED=true and provide an LLM key, then restart.",
12915
+ docsHref: "https://github.com/rohitg00/agentmemory#consolidation"
12916
+ },
12917
+ {
12918
+ key: "AGENTMEMORY_AUTO_COMPRESS",
12919
+ label: "LLM-powered observation compression",
12920
+ enabled: isAutoCompressEnabled(),
12921
+ default: false,
12922
+ affects: ["Memories", "Timeline"],
12923
+ needsLlm: true,
12924
+ description: "Every observation is compressed by the LLM for richer summaries (costs tokens). OFF uses zero-LLM synthetic compression.",
12925
+ enableHow: "Set AGENTMEMORY_AUTO_COMPRESS=true and provide an LLM key.",
12926
+ docsHref: "https://github.com/rohitg00/agentmemory/issues/138"
12927
+ },
12928
+ {
12929
+ key: "AGENTMEMORY_INJECT_CONTEXT",
12930
+ label: "In-conversation context injection",
12931
+ enabled: isContextInjectionEnabled(),
12932
+ default: false,
12933
+ affects: ["Hooks"],
12934
+ needsLlm: false,
12935
+ description: "Hooks write recalled context into Claude Code's conversation. OFF captures in the background without injecting.",
12936
+ enableHow: "Set AGENTMEMORY_INJECT_CONTEXT=true and restart.",
12937
+ docsHref: "https://github.com/rohitg00/agentmemory/issues/143"
12938
+ }
12939
+ ]
12940
+ }
12941
+ };
12942
+ });
12943
+ sdk.registerTrigger({
12944
+ type: "http",
12945
+ function_id: "api::config-flags",
12946
+ config: {
12947
+ api_path: "/agentmemory/config/flags",
12948
+ http_method: "GET",
12949
+ middleware_function_ids: ["middleware::api-auth"]
12950
+ }
12951
+ });
12801
12952
  sdk.registerFunction("api::health", async (req) => {
12802
12953
  const health = await getLatestHealth(kv);
12803
12954
  const functionMetrics = metricsStore ? await metricsStore.getAll() : [];
@@ -13032,11 +13183,12 @@ function registerApiTriggers(sdk, kv, secret, metricsStore, provider) {
13032
13183
  payload.path = body.path.trim();
13033
13184
  }
13034
13185
  if (body.maxFiles !== void 0) {
13035
- if (!Number.isInteger(body.maxFiles) || body.maxFiles < 1) return {
13186
+ const n = body.maxFiles;
13187
+ if (!Number.isInteger(n) || n < 1 || n > MAX_FILES_UPPER_BOUND) return {
13036
13188
  status_code: 400,
13037
- body: { error: "maxFiles must be a positive integer" }
13189
+ body: { error: `maxFiles must be an integer between 1 and ${MAX_FILES_UPPER_BOUND}` }
13038
13190
  };
13039
- payload.maxFiles = body.maxFiles;
13191
+ payload.maxFiles = n;
13040
13192
  }
13041
13193
  return {
13042
13194
  status_code: 202,
@@ -13618,10 +13770,7 @@ function registerApiTriggers(sdk, kv, secret, metricsStore, provider) {
13618
13770
  })
13619
13771
  };
13620
13772
  } catch {
13621
- return {
13622
- status_code: 404,
13623
- body: { error: "Knowledge graph not enabled" }
13624
- };
13773
+ return graphDisabledResponse();
13625
13774
  }
13626
13775
  });
13627
13776
  sdk.registerTrigger({
@@ -13644,10 +13793,7 @@ function registerApiTriggers(sdk, kv, secret, metricsStore, provider) {
13644
13793
  })
13645
13794
  };
13646
13795
  } catch {
13647
- return {
13648
- status_code: 404,
13649
- body: { error: "Knowledge graph not enabled" }
13650
- };
13796
+ return graphDisabledResponse();
13651
13797
  }
13652
13798
  });
13653
13799
  sdk.registerTrigger({
@@ -13674,10 +13820,7 @@ function registerApiTriggers(sdk, kv, secret, metricsStore, provider) {
13674
13820
  })
13675
13821
  };
13676
13822
  } catch {
13677
- return {
13678
- status_code: 404,
13679
- body: { error: "Knowledge graph not enabled" }
13680
- };
13823
+ return graphDisabledResponse();
13681
13824
  }
13682
13825
  });
13683
13826
  sdk.registerTrigger({
@@ -13700,10 +13843,7 @@ function registerApiTriggers(sdk, kv, secret, metricsStore, provider) {
13700
13843
  })
13701
13844
  };
13702
13845
  } catch {
13703
- return {
13704
- status_code: 404,
13705
- body: { error: "Consolidation pipeline not enabled" }
13706
- };
13846
+ return consolidationDisabledResponse();
13707
13847
  }
13708
13848
  });
13709
13849
  sdk.registerTrigger({
@@ -13964,6 +14104,32 @@ function registerApiTriggers(sdk, kv, secret, metricsStore, provider) {
13964
14104
  http_method: "GET"
13965
14105
  }
13966
14106
  });
14107
+ sdk.registerFunction("api::memory-by-id", async (req) => {
14108
+ const authErr = checkAuth(req, secret);
14109
+ if (authErr) return authErr;
14110
+ const id = req.path_params?.["id"];
14111
+ if (!id || typeof id !== "string") return {
14112
+ status_code: 400,
14113
+ body: { error: "id path parameter is required" }
14114
+ };
14115
+ const memory = await kv.get(KV.memories, id);
14116
+ if (!memory) return {
14117
+ status_code: 404,
14118
+ body: { error: `memory not found: ${id}` }
14119
+ };
14120
+ return {
14121
+ status_code: 200,
14122
+ body: { memory }
14123
+ };
14124
+ });
14125
+ sdk.registerTrigger({
14126
+ type: "http",
14127
+ function_id: "api::memory-by-id",
14128
+ config: {
14129
+ api_path: "/agentmemory/memories/:id",
14130
+ http_method: "GET"
14131
+ }
14132
+ });
13967
14133
  sdk.registerFunction("api::semantic-list", async (req) => {
13968
14134
  const authErr = checkAuth(req, secret);
13969
14135
  if (authErr) return authErr;
@@ -15842,6 +16008,15 @@ function registerEventTriggers(sdk, kv) {
15842
16008
  error: err instanceof Error ? err.message : String(err)
15843
16009
  });
15844
16010
  }
16011
+ if (isGraphExtractionEnabled()) try {
16012
+ const compressed = (await kv.list(KV.observations(data.sessionId))).filter((o) => o.title);
16013
+ if (compressed.length > 0) sdk.triggerVoid("mem::graph-extract", { observations: compressed });
16014
+ } catch (err) {
16015
+ logger.warn("graph-extract triggerVoid failed", {
16016
+ sessionId: data.sessionId,
16017
+ error: err instanceof Error ? err.message : String(err)
16018
+ });
16019
+ }
15845
16020
  return summary;
15846
16021
  });
15847
16022
  sdk.registerTrigger({
@@ -17753,6 +17928,14 @@ function initMetrics(getMeter) {
17753
17928
  function hasGetMeter(sdk) {
17754
17929
  return typeof sdk === "object" && sdk !== null && "getMeter" in sdk && typeof sdk.getMeter === "function";
17755
17930
  }
17931
+ let lastUnhandledLogAt = 0;
17932
+ process.on("unhandledRejection", (reason) => {
17933
+ const now = Date.now();
17934
+ if (now - lastUnhandledLogAt < 6e4) return;
17935
+ lastUnhandledLogAt = now;
17936
+ const r = reason;
17937
+ console.warn(`[agentmemory] unhandledRejection (suppressed):`, r?.code ? `${r.code} ${r.function_id ?? ""} ${r.message ?? ""}`.trim() : reason);
17938
+ });
17756
17939
  async function main() {
17757
17940
  const config = loadConfig();
17758
17941
  const embeddingConfig = loadEmbeddingConfig();
@@ -17959,4 +18142,4 @@ main().catch((err) => {
17959
18142
 
17960
18143
  //#endregion
17961
18144
  export { deleteImage as a, saveImageToDisk as c, IMAGES_DIR as i, touchImage as l, getImageRefCount as n, getMaxBytes as o, incrementImageRef as r, isManagedImagePath as s, decrementImageRef as t };
17962
- //# sourceMappingURL=src-tmuZyobT.mjs.map
18145
+ //# sourceMappingURL=src-uDy2jLO-.mjs.map