@agentmemory/agentmemory 0.9.14 → 0.9.15

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.
package/dist/index.mjs CHANGED
@@ -1452,6 +1452,17 @@ const logger = {
1452
1452
  emit("error", msg, fields);
1453
1453
  }
1454
1454
  };
1455
+ let bootVerbose = process.env["AGENTMEMORY_VERBOSE"] === "1" || process.env["AGENTMEMORY_VERBOSE"] === "true";
1456
+ const bootBuffer = [];
1457
+ function bootLog(msg) {
1458
+ if (bootVerbose) {
1459
+ try {
1460
+ process.stderr.write(`[agentmemory] ${msg}\n`);
1461
+ } catch {}
1462
+ return;
1463
+ }
1464
+ if (bootBuffer.length < 500) bootBuffer.push(msg);
1465
+ }
1455
1466
 
1456
1467
  //#endregion
1457
1468
  //#region src/functions/query-expansion.ts
@@ -5956,7 +5967,7 @@ function registerAutoForgetFunction(sdk, kv) {
5956
5967
 
5957
5968
  //#endregion
5958
5969
  //#region src/version.ts
5959
- const VERSION = "0.9.14";
5970
+ const VERSION = "0.9.15";
5960
5971
 
5961
5972
  //#endregion
5962
5973
  //#region src/functions/export-import.ts
@@ -6088,7 +6099,8 @@ function registerExportImportFunction(sdk, kv) {
6088
6099
  "0.9.11",
6089
6100
  "0.9.12",
6090
6101
  "0.9.13",
6091
- "0.9.14"
6102
+ "0.9.14",
6103
+ "0.9.15"
6092
6104
  ]).has(importData.version)) return {
6093
6105
  success: false,
6094
6106
  error: `Unsupported export version: ${importData.version}`
@@ -19395,8 +19407,10 @@ function readBody(req) {
19395
19407
  req.on("error", reject);
19396
19408
  });
19397
19409
  }
19410
+ const MAX_VIEWER_PORT_RETRIES = 10;
19398
19411
  function startViewerServer(port, _kv, _sdk, secret, restPort) {
19399
19412
  const resolvedRestPort = restPort ?? port - 2;
19413
+ const requestedPort = port;
19400
19414
  const server = createServer(async (req, res) => {
19401
19415
  const raw = req.url || "/";
19402
19416
  const qIdx = raw.indexOf("?");
@@ -19433,13 +19447,26 @@ function startViewerServer(port, _kv, _sdk, secret, restPort) {
19433
19447
  json(res, 502, { error: "upstream error" }, req);
19434
19448
  }
19435
19449
  });
19450
+ let attempt = 0;
19451
+ let currentPort = requestedPort;
19452
+ const tryListen = () => {
19453
+ server.listen(currentPort, "127.0.0.1");
19454
+ };
19455
+ server.on("listening", () => {
19456
+ if (currentPort === requestedPort) console.log(`[agentmemory] Viewer: http://localhost:${currentPort}`);
19457
+ else console.log(`[agentmemory] Viewer started on http://localhost:${currentPort} (fallback from ${requestedPort})`);
19458
+ });
19436
19459
  server.on("error", (err) => {
19437
- if (err.code === "EADDRINUSE") console.warn(`[agentmemory] Viewer port ${port} already in use, skipping viewer.`);
19460
+ if (err.code === "EADDRINUSE" && attempt < MAX_VIEWER_PORT_RETRIES) {
19461
+ attempt++;
19462
+ currentPort = requestedPort + attempt;
19463
+ setImmediate(tryListen);
19464
+ return;
19465
+ }
19466
+ if (err.code === "EADDRINUSE") console.warn(`[agentmemory] Viewer ports ${requestedPort}-${requestedPort + MAX_VIEWER_PORT_RETRIES} all in use, skipping viewer.`);
19438
19467
  else console.error(`[agentmemory] Viewer error:`, err.message);
19439
19468
  });
19440
- server.listen(port, "127.0.0.1", () => {
19441
- console.log(`[agentmemory] Viewer: http://localhost:${port}`);
19442
- });
19469
+ tryListen();
19443
19470
  return server;
19444
19471
  }
19445
19472
  async function proxyToRestApi(restPort, pathname, qs, method, req, res, secret) {
@@ -19633,14 +19660,14 @@ async function main() {
19633
19660
  const provider = fallbackConfig.providers.length > 0 ? createFallbackProvider(config.provider, fallbackConfig) : createProvider(config.provider);
19634
19661
  const embeddingProvider = createEmbeddingProvider();
19635
19662
  const imageEmbeddingProvider = createImageEmbeddingProvider();
19636
- console.log(`[agentmemory] Starting worker v${VERSION}...`);
19637
- console.log(`[agentmemory] Engine: ${config.engineUrl}`);
19638
- console.log(`[agentmemory] Provider: ${config.provider.provider} (${config.provider.model})`);
19639
- if (embeddingProvider) console.log(`[agentmemory] Embedding provider: ${embeddingProvider.name} (${embeddingProvider.dimensions} dims)`);
19640
- else console.log(`[agentmemory] Embedding provider: none (BM25-only mode)`);
19641
- if (imageEmbeddingProvider) console.log(`[agentmemory] Image embedding provider: ${imageEmbeddingProvider.name} (${imageEmbeddingProvider.dimensions} dims) — vision-search active`);
19642
- console.log(`[agentmemory] REST API: http://localhost:${config.restPort}/agentmemory/*`);
19643
- console.log(`[agentmemory] Streams: ws://localhost:${config.streamsPort}`);
19663
+ bootLog(`Starting worker v${VERSION}...`);
19664
+ bootLog(`Engine: ${config.engineUrl}`);
19665
+ bootLog(`Provider: ${config.provider.provider} (${config.provider.model})`);
19666
+ if (embeddingProvider) bootLog(`Embedding provider: ${embeddingProvider.name} (${embeddingProvider.dimensions} dims)`);
19667
+ else bootLog(`Embedding provider: none (BM25-only mode)`);
19668
+ if (imageEmbeddingProvider) bootLog(`Image embedding provider: ${imageEmbeddingProvider.name} (${imageEmbeddingProvider.dimensions} dims) — vision-search active`);
19669
+ bootLog(`REST API: http://localhost:${config.restPort}/agentmemory/*`);
19670
+ bootLog(`Streams: ws://localhost:${config.streamsPort}`);
19644
19671
  const sdk = registerWorker(config.engineUrl, {
19645
19672
  workerName: "agentmemory",
19646
19673
  invocationTimeoutMs: 18e4,
@@ -19683,22 +19710,22 @@ async function main() {
19683
19710
  const claudeBridgeConfig = loadClaudeBridgeConfig();
19684
19711
  if (claudeBridgeConfig.enabled) {
19685
19712
  registerClaudeBridgeFunction(sdk, kv, claudeBridgeConfig);
19686
- console.log(`[agentmemory] Claude bridge: syncing to ${claudeBridgeConfig.memoryFilePath}`);
19713
+ bootLog(`Claude bridge: syncing to ${claudeBridgeConfig.memoryFilePath}`);
19687
19714
  }
19688
19715
  if (isGraphExtractionEnabled()) {
19689
19716
  registerGraphFunction(sdk, kv, provider);
19690
- console.log(`[agentmemory] Knowledge graph: extraction enabled`);
19717
+ bootLog(`Knowledge graph: extraction enabled`);
19691
19718
  }
19692
19719
  registerConsolidationPipelineFunction(sdk, kv, provider);
19693
- console.log(`[agentmemory] Consolidation pipeline: registered (CONSOLIDATION_ENABLED=${isConsolidationEnabled() ? "true" : "false"})`);
19694
- if (isAutoCompressEnabled()) console.log(`[agentmemory] WARNING: AGENTMEMORY_AUTO_COMPRESS=true — every PostToolUse observation will be sent to your LLM provider for compression. This spends API tokens proportional to your session tool-use frequency (see #138). Set AGENTMEMORY_AUTO_COMPRESS=false to disable.`);
19695
- else console.log(`[agentmemory] Auto-compress: OFF (default, #138) — observations indexed via zero-LLM synthetic compression. Set AGENTMEMORY_AUTO_COMPRESS=true to opt-in to LLM-powered summaries (uses your API key).`);
19696
- if (isContextInjectionEnabled()) console.log(`[agentmemory] WARNING: AGENTMEMORY_INJECT_CONTEXT=true — the PreToolUse and SessionStart hooks will inject up to ~4000 chars of memory context into every tool turn. On Claude Pro this burns session tokens proportional to your tool-call frequency (see #143). Set AGENTMEMORY_INJECT_CONTEXT=false to disable.`);
19697
- else console.log(`[agentmemory] Context injection: OFF (default, #143) — hooks capture observations but do not inject context into Claude Code's conversation. Set AGENTMEMORY_INJECT_CONTEXT=true to opt-in (warning: expect your Claude Pro allocation to drain faster).`);
19720
+ bootLog(`Consolidation pipeline: registered (CONSOLIDATION_ENABLED=${isConsolidationEnabled() ? "true" : "false"})`);
19721
+ if (isAutoCompressEnabled()) bootLog(`WARNING: AGENTMEMORY_AUTO_COMPRESS=true — every PostToolUse observation will be sent to your LLM provider for compression. This spends API tokens proportional to your session tool-use frequency (see #138). Set AGENTMEMORY_AUTO_COMPRESS=false to disable.`);
19722
+ else bootLog(`Auto-compress: OFF (default, #138) — observations indexed via zero-LLM synthetic compression. Set AGENTMEMORY_AUTO_COMPRESS=true to opt-in to LLM-powered summaries (uses your API key).`);
19723
+ if (isContextInjectionEnabled()) bootLog(`WARNING: AGENTMEMORY_INJECT_CONTEXT=true — the PreToolUse and SessionStart hooks will inject up to ~4000 chars of memory context into every tool turn. On Claude Pro this burns session tokens proportional to your tool-call frequency (see #143). Set AGENTMEMORY_INJECT_CONTEXT=false to disable.`);
19724
+ else bootLog(`Context injection: OFF (default, #143) — hooks capture observations but do not inject context into Claude Code's conversation. Set AGENTMEMORY_INJECT_CONTEXT=true to opt-in (warning: expect your Claude Pro allocation to drain faster).`);
19698
19725
  const teamConfig = loadTeamConfig();
19699
19726
  if (teamConfig) {
19700
19727
  registerTeamFunction(sdk, kv, teamConfig);
19701
- console.log(`[agentmemory] Team memory: ${teamConfig.teamId} (${teamConfig.mode})`);
19728
+ bootLog(`Team memory: ${teamConfig.teamId} (${teamConfig.mode})`);
19702
19729
  }
19703
19730
  registerGovernanceFunction(sdk, kv);
19704
19731
  registerActionsFunction(sdk, kv);
@@ -19728,13 +19755,13 @@ async function main() {
19728
19755
  registerRetentionFunctions(sdk, kv);
19729
19756
  registerCompressFileFunction(sdk, kv, provider);
19730
19757
  registerReplayFunctions(sdk, kv);
19731
- console.log(`[agentmemory] v0.6 advanced retrieval: sliding-window, query-expansion, temporal-graph, retention-scoring`);
19732
- console.log(`[agentmemory] Orchestration layer: actions, frontier, leases, routines, signals, checkpoints, flow-compress, mesh, branch-aware, sentinels, sketches, crystallize, diagnostics, facets`);
19733
- if (isSlotsEnabled()) console.log(`[agentmemory] Slots: enabled (pinned editable memory). Reflect on Stop hook: ${isReflectEnabled() ? "on" : "off"}`);
19758
+ bootLog(`v0.6 advanced retrieval: sliding-window, query-expansion, temporal-graph, retention-scoring`);
19759
+ bootLog(`Orchestration layer: actions, frontier, leases, routines, signals, checkpoints, flow-compress, mesh, branch-aware, sentinels, sketches, crystallize, diagnostics, facets`);
19760
+ if (isSlotsEnabled()) bootLog(`Slots: enabled (pinned editable memory). Reflect on Stop hook: ${isReflectEnabled() ? "on" : "off"}`);
19734
19761
  const snapshotConfig = loadSnapshotConfig();
19735
19762
  if (snapshotConfig.enabled) {
19736
19763
  registerSnapshotFunction(sdk, kv, snapshotConfig.dir);
19737
- console.log(`[agentmemory] Git snapshots: ${snapshotConfig.dir} (every ${snapshotConfig.interval}s)`);
19764
+ bootLog(`Git snapshots: ${snapshotConfig.dir} (every ${snapshotConfig.interval}s)`);
19738
19765
  }
19739
19766
  const bm25Index = getSearchIndex();
19740
19767
  const graphWeight = parseFloat(getEnvVar("AGENTMEMORY_GRAPH_WEIGHT") || "0.3");
@@ -19751,7 +19778,7 @@ async function main() {
19751
19778
  });
19752
19779
  if (loaded?.bm25 && loaded.bm25.size > 0) {
19753
19780
  bm25Index.restoreFrom(loaded.bm25);
19754
- console.log(`[agentmemory] Loaded persisted BM25 index (${bm25Index.size} docs)`);
19781
+ bootLog(`Loaded persisted BM25 index (${bm25Index.size} docs)`);
19755
19782
  }
19756
19783
  if (loaded?.vector && vectorIndex && loaded.vector.size > 0) {
19757
19784
  const activeDim = embeddingProvider?.dimensions ?? 0;
@@ -19766,7 +19793,7 @@ async function main() {
19766
19793
  else throw new Error(`[agentmemory] Refusing to start: persisted vector index has ${mismatches.length} of ${loaded.vector.size} vectors with the wrong dimension. Active provider (${embeddingProvider?.name}) declares ${activeDim}; dimensions seen on disk: ${distinct}. First mismatched obsIds: ${sample}. Loading would silently corrupt search (cross-dimension cosine returns 0). Choose one:\n - Re-embed the existing index against the new provider, then start.\n - Set AGENTMEMORY_DROP_STALE_INDEX=true to discard the persisted vectors and rebuild from live observations.\n - Switch the embedding provider back to the one that wrote the index.`);
19767
19794
  } else {
19768
19795
  vectorIndex.restoreFrom(loaded.vector);
19769
- console.log(`[agentmemory] Loaded persisted vector index (${vectorIndex.size} vectors)`);
19796
+ bootLog(`Loaded persisted vector index (${vectorIndex.size} vectors)`);
19770
19797
  }
19771
19798
  }
19772
19799
  if (bm25Index.size === 0) {
@@ -19775,7 +19802,7 @@ async function main() {
19775
19802
  return 0;
19776
19803
  });
19777
19804
  if (indexCount > 0) {
19778
- console.log(`[agentmemory] Search index rebuilt: ${indexCount} entries`);
19805
+ bootLog(`Search index rebuilt: ${indexCount} entries`);
19779
19806
  indexPersistence.scheduleSave();
19780
19807
  }
19781
19808
  } else try {
@@ -19800,14 +19827,14 @@ async function main() {
19800
19827
  backfilled++;
19801
19828
  }
19802
19829
  if (backfilled > 0) {
19803
- console.log(`[agentmemory] Backfilled ${backfilled} memories into BM25 (legacy gap before #257)`);
19830
+ bootLog(`Backfilled ${backfilled} memories into BM25 (legacy gap before #257)`);
19804
19831
  indexPersistence.scheduleSave();
19805
19832
  }
19806
19833
  } catch (err) {
19807
19834
  console.warn(`[agentmemory] Failed to backfill memories into BM25:`, err);
19808
19835
  }
19809
- console.log(`[agentmemory] Ready. ${embeddingProvider ? "Triple-stream (BM25+Vector+Graph)" : "BM25+Graph"} search active.`);
19810
- console.log(`[agentmemory] Endpoints: 107 REST + ${getAllTools().length} MCP tools + 6 MCP resources + 3 MCP prompts`);
19836
+ bootLog(`Ready. ${embeddingProvider ? "Triple-stream (BM25+Vector+Graph)" : "BM25+Graph"} search active.`);
19837
+ bootLog(`Endpoints: 107 REST + ${getAllTools().length} MCP tools + 6 MCP resources + 3 MCP prompts`);
19811
19838
  const viewerServer = startViewerServer(config.restPort + 2, kv, sdk, secret, config.restPort);
19812
19839
  const autoForgetIntervalMs = parseInt(process.env.AUTO_FORGET_INTERVAL_MS || "3600000", 10);
19813
19840
  const consolidationIntervalMs = parseInt(process.env.CONSOLIDATION_INTERVAL_MS || "7200000", 10);
@@ -19820,7 +19847,7 @@ async function main() {
19820
19847
  });
19821
19848
  } catch {}
19822
19849
  }, autoForgetIntervalMs).unref();
19823
- console.log(`[agentmemory] Auto-forget: enabled (every ${autoForgetIntervalMs / 6e4}m)`);
19850
+ bootLog(`Auto-forget: enabled (every ${autoForgetIntervalMs / 6e4}m)`);
19824
19851
  }
19825
19852
  if (process.env.LESSON_DECAY_ENABLED !== "false") {
19826
19853
  setInterval(async () => {
@@ -19831,7 +19858,7 @@ async function main() {
19831
19858
  });
19832
19859
  } catch {}
19833
19860
  }, 864e5).unref();
19834
- console.log(`[agentmemory] Lesson decay sweep: enabled (every 24h)`);
19861
+ bootLog(`Lesson decay sweep: enabled (every 24h)`);
19835
19862
  }
19836
19863
  if (process.env.INSIGHT_DECAY_ENABLED !== "false") setInterval(async () => {
19837
19864
  try {
@@ -19850,7 +19877,7 @@ async function main() {
19850
19877
  });
19851
19878
  } catch {}
19852
19879
  }, consolidationIntervalMs).unref();
19853
- console.log(`[agentmemory] Auto-consolidation: enabled (every ${consolidationIntervalMs / 6e4}m)`);
19880
+ bootLog(`Auto-consolidation: enabled (every ${consolidationIntervalMs / 6e4}m)`);
19854
19881
  }
19855
19882
  const shutdown = async () => {
19856
19883
  console.log(`\n[agentmemory] Shutting down...`);