@agentmemory/agentmemory 0.9.27 → 0.9.28

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.
Files changed (122) hide show
  1. package/AGENTS.md +5 -5
  2. package/README.md +97 -37
  3. package/dist/cli.d.mts.map +1 -1
  4. package/dist/cli.mjs +206 -154
  5. package/dist/cli.mjs.map +1 -1
  6. package/dist/config-ChC9EtgV.mjs +259 -0
  7. package/dist/config-ChC9EtgV.mjs.map +1 -0
  8. package/dist/{connect-bmZ5eqYN.mjs → connect-JnsJXc68.mjs} +136 -42
  9. package/dist/connect-JnsJXc68.mjs.map +1 -0
  10. package/dist/hooks/notification.mjs +2 -1
  11. package/dist/hooks/notification.mjs.map +1 -1
  12. package/dist/hooks/post-commit.mjs +2 -1
  13. package/dist/hooks/post-commit.mjs.map +1 -1
  14. package/dist/hooks/post-tool-failure.mjs +2 -1
  15. package/dist/hooks/post-tool-failure.mjs.map +1 -1
  16. package/dist/hooks/post-tool-use.mjs +2 -1
  17. package/dist/hooks/post-tool-use.mjs.map +1 -1
  18. package/dist/hooks/pre-compact.mjs +2 -1
  19. package/dist/hooks/pre-compact.mjs.map +1 -1
  20. package/dist/hooks/pre-tool-use.mjs +2 -1
  21. package/dist/hooks/pre-tool-use.mjs.map +1 -1
  22. package/dist/hooks/prompt-submit.mjs +2 -1
  23. package/dist/hooks/prompt-submit.mjs.map +1 -1
  24. package/dist/hooks/session-end.mjs +2 -1
  25. package/dist/hooks/session-end.mjs.map +1 -1
  26. package/dist/hooks/session-start.mjs +2 -1
  27. package/dist/hooks/session-start.mjs.map +1 -1
  28. package/dist/hooks/stop.mjs +2 -1
  29. package/dist/hooks/stop.mjs.map +1 -1
  30. package/dist/hooks/subagent-start.mjs +2 -1
  31. package/dist/hooks/subagent-start.mjs.map +1 -1
  32. package/dist/hooks/subagent-stop.mjs +2 -1
  33. package/dist/hooks/subagent-stop.mjs.map +1 -1
  34. package/dist/hooks/task-completed.mjs +2 -1
  35. package/dist/hooks/task-completed.mjs.map +1 -1
  36. package/dist/image-refs-BKLmp_sD.mjs +34 -0
  37. package/dist/image-refs-BKLmp_sD.mjs.map +1 -0
  38. package/dist/{image-refs-B5Zf_Djo.mjs → image-refs-C2YU7BIm.mjs} +3 -21
  39. package/dist/image-refs-C2YU7BIm.mjs.map +1 -0
  40. package/dist/index.mjs +118 -150
  41. package/dist/index.mjs.map +1 -1
  42. package/dist/{image-store-Gpo2mgM9.mjs → keyed-mutex-DTHtcZrt.mjs} +14 -11
  43. package/dist/keyed-mutex-DTHtcZrt.mjs.map +1 -0
  44. package/dist/{logger-yHTcEBAI.mjs → logger-BEB7pCI9.mjs} +1 -1
  45. package/dist/{logger-yHTcEBAI.mjs.map → logger-BEB7pCI9.mjs.map} +1 -1
  46. package/dist/{src-MOg2zKJs.mjs → src-CzgoepGU.mjs} +49 -30
  47. package/dist/src-CzgoepGU.mjs.map +1 -0
  48. package/dist/{standalone-BORXC71-.mjs → standalone-YsZFFQBM.mjs} +7 -4
  49. package/dist/standalone-YsZFFQBM.mjs.map +1 -0
  50. package/dist/standalone.d.mts.map +1 -1
  51. package/dist/standalone.mjs +6 -2
  52. package/dist/standalone.mjs.map +1 -1
  53. package/dist/{tools-registry-D8XVVPbJ.mjs → tools-registry-D3NEoe5m.mjs} +4 -256
  54. package/dist/tools-registry-D3NEoe5m.mjs.map +1 -0
  55. package/package.json +4 -1
  56. package/plugin/.claude-plugin/plugin.json +1 -1
  57. package/plugin/.codex-plugin/plugin.json +1 -1
  58. package/plugin/plugin.json +2 -2
  59. package/plugin/scripts/notification.mjs +2 -1
  60. package/plugin/scripts/notification.mjs.map +1 -1
  61. package/plugin/scripts/post-commit.mjs +2 -1
  62. package/plugin/scripts/post-commit.mjs.map +1 -1
  63. package/plugin/scripts/post-tool-failure.mjs +2 -1
  64. package/plugin/scripts/post-tool-failure.mjs.map +1 -1
  65. package/plugin/scripts/post-tool-use.mjs +2 -1
  66. package/plugin/scripts/post-tool-use.mjs.map +1 -1
  67. package/plugin/scripts/pre-compact.mjs +2 -1
  68. package/plugin/scripts/pre-compact.mjs.map +1 -1
  69. package/plugin/scripts/pre-tool-use.mjs +2 -1
  70. package/plugin/scripts/pre-tool-use.mjs.map +1 -1
  71. package/plugin/scripts/prompt-submit.mjs +2 -1
  72. package/plugin/scripts/prompt-submit.mjs.map +1 -1
  73. package/plugin/scripts/session-end.mjs +2 -1
  74. package/plugin/scripts/session-end.mjs.map +1 -1
  75. package/plugin/scripts/session-start.mjs +2 -1
  76. package/plugin/scripts/session-start.mjs.map +1 -1
  77. package/plugin/scripts/stop.mjs +2 -1
  78. package/plugin/scripts/stop.mjs.map +1 -1
  79. package/plugin/scripts/subagent-start.mjs +2 -1
  80. package/plugin/scripts/subagent-start.mjs.map +1 -1
  81. package/plugin/scripts/subagent-stop.mjs +2 -1
  82. package/plugin/scripts/subagent-stop.mjs.map +1 -1
  83. package/plugin/scripts/task-completed.mjs +2 -1
  84. package/plugin/scripts/task-completed.mjs.map +1 -1
  85. package/plugin/skills/_shared/TROUBLESHOOTING.md +38 -0
  86. package/plugin/skills/agentmemory-agents/REFERENCE.md +28 -0
  87. package/plugin/skills/agentmemory-agents/SKILL.md +34 -0
  88. package/plugin/skills/agentmemory-architecture/SKILL.md +33 -0
  89. package/plugin/skills/agentmemory-config/REFERENCE.md +42 -0
  90. package/plugin/skills/agentmemory-config/SKILL.md +37 -0
  91. package/plugin/skills/agentmemory-hooks/REFERENCE.md +20 -0
  92. package/plugin/skills/agentmemory-hooks/SKILL.md +39 -0
  93. package/plugin/skills/agentmemory-mcp-tools/REFERENCE.md +65 -0
  94. package/plugin/skills/agentmemory-mcp-tools/SKILL.md +39 -0
  95. package/plugin/skills/agentmemory-rest-api/REFERENCE.md +129 -0
  96. package/plugin/skills/agentmemory-rest-api/SKILL.md +43 -0
  97. package/plugin/skills/commit-context/EXAMPLES.md +71 -0
  98. package/plugin/skills/commit-context/SKILL.md +53 -8
  99. package/plugin/skills/commit-history/EXAMPLES.md +71 -0
  100. package/plugin/skills/commit-history/SKILL.md +51 -9
  101. package/plugin/skills/forget/EXAMPLES.md +75 -0
  102. package/plugin/skills/forget/SKILL.md +54 -14
  103. package/plugin/skills/handoff/EXAMPLES.md +56 -0
  104. package/plugin/skills/handoff/SKILL.md +56 -9
  105. package/plugin/skills/recall/EXAMPLES.md +74 -0
  106. package/plugin/skills/recall/SKILL.md +50 -11
  107. package/plugin/skills/recap/EXAMPLES.md +60 -0
  108. package/plugin/skills/recap/SKILL.md +51 -13
  109. package/plugin/skills/remember/EXAMPLES.md +67 -0
  110. package/plugin/skills/remember/SKILL.md +53 -17
  111. package/plugin/skills/session-history/EXAMPLES.md +59 -0
  112. package/plugin/skills/session-history/SKILL.md +54 -11
  113. package/plugin/skills/write-agentmemory-skill/SKILL.md +40 -0
  114. package/dist/connect-bmZ5eqYN.mjs.map +0 -1
  115. package/dist/image-refs-B5Zf_Djo.mjs.map +0 -1
  116. package/dist/image-store-Gpo2mgM9.mjs.map +0 -1
  117. package/dist/rolldown-runtime-twds-ZHy.mjs +0 -14
  118. package/dist/src-MOg2zKJs.mjs.map +0 -1
  119. package/dist/standalone-BORXC71-.mjs.map +0 -1
  120. package/dist/tools-registry-D8XVVPbJ.mjs.map +0 -1
  121. package/dist/version-9DNrRyph.mjs +0 -6
  122. package/dist/version-9DNrRyph.mjs.map +0 -1
package/dist/index.mjs CHANGED
@@ -4,6 +4,7 @@ import { TriggerAction, registerWorker } from "iii-sdk";
4
4
  import { constants, existsSync, mkdirSync, readFileSync, unlinkSync, writeFileSync } from "node:fs";
5
5
  import { basename, dirname, extname, join, resolve, sep } from "node:path";
6
6
  import { homedir } from "node:os";
7
+ import pc from "picocolors";
7
8
  import { AsyncLocalStorage } from "node:async_hooks";
8
9
  import Anthropic from "@anthropic-ai/sdk";
9
10
  import { lstat, mkdir, open, readFile, readdir, stat, unlink, utimes, writeFile } from "node:fs/promises";
@@ -15,18 +16,6 @@ import { lookup } from "node:dns/promises";
15
16
  import { isIP } from "node:net";
16
17
  import { fileURLToPath } from "node:url";
17
18
  import { createServer } from "node:http";
18
- //#region \0rolldown/runtime.js
19
- var __defProp = Object.defineProperty;
20
- var __exportAll = (all, no_symbols) => {
21
- let target = {};
22
- for (var name in all) __defProp(target, name, {
23
- get: all[name],
24
- enumerable: true
25
- });
26
- if (!no_symbols) __defProp(target, Symbol.toStringTag, { value: "Module" });
27
- return target;
28
- };
29
- //#endregion
30
19
  //#region src/config.ts
31
20
  function safeParseInt(value, fallback) {
32
21
  if (!value) return fallback;
@@ -102,14 +91,14 @@ function detectProvider(env) {
102
91
  };
103
92
  }
104
93
  if (!(env["AGENTMEMORY_ALLOW_AGENT_SDK"] === "true")) {
105
- process.stderr.write("[agentmemory] No LLM provider key found (ANTHROPIC_API_KEY, GEMINI_API_KEY, OPENROUTER_API_KEY, MINIMAX_API_KEY, OPENAI_API_KEY). LLM-backed compression and summarization are DISABLED — using no-op provider. This is the safe default: the agent-sdk fallback used to spawn Claude Agent SDK child sessions which inherit Claude Code's plugin hooks and cause infinite Stop-hook recursion (#149 follow-up). To opt in to the agent-sdk fallback anyway, set both AGENTMEMORY_AUTO_COMPRESS=true AND AGENTMEMORY_ALLOW_AGENT_SDK=true — but be aware it will burn your Claude Pro allocation and may still recurse if you use it from inside Claude Code itself.\n");
94
+ process.stderr.write(pc.dim("[agentmemory] No LLM provider key set — running zero-LLM (BM25 + on-device embeddings). Set ANTHROPIC_API_KEY (or GEMINI/OPENAI/OPENROUTER/MINIMAX) in ~/.agentmemory/.env for LLM compression and summaries. Agent-SDK fallback stays off by default to avoid a Stop-hook recursion loop; opt in with AGENTMEMORY_AUTO_COMPRESS=true + AGENTMEMORY_ALLOW_AGENT_SDK=true.\n"));
106
95
  return {
107
96
  provider: "noop",
108
97
  model: "noop",
109
98
  maxTokens
110
99
  };
111
100
  }
112
- process.stderr.write("[agentmemory] WARNING: agent-sdk fallback enabled via AGENTMEMORY_ALLOW_AGENT_SDK=true. This spawns @anthropic-ai/claude-agent-sdk child sessions that can trigger the Stop-hook recursion loop (#149 follow-up). A SDK-child env marker is set to block re-entry, but prefer setting a real API key in ~/.agentmemory/.env instead.\n");
101
+ process.stderr.write("[agentmemory] WARNING: agent-sdk fallback enabled via AGENTMEMORY_ALLOW_AGENT_SDK=true. This spawns @anthropic-ai/claude-agent-sdk child sessions that can trigger the Stop-hook recursion loop. A SDK-child env marker is set to block re-entry, but prefer setting a real API key in ~/.agentmemory/.env instead.\n");
113
102
  return {
114
103
  provider: "agent-sdk",
115
104
  model: "claude-sonnet-4-20250514",
@@ -269,7 +258,7 @@ function loadFallbackConfig() {
269
258
  const allowAgentSdk = env["AGENTMEMORY_ALLOW_AGENT_SDK"] === "true";
270
259
  return { providers: raw.split(",").map((p) => p.trim()).filter((p) => Boolean(p) && VALID_PROVIDERS.has(p)).filter((p) => {
271
260
  if (p === "agent-sdk" && !allowAgentSdk) {
272
- process.stderr.write("[agentmemory] Ignoring FALLBACK_PROVIDERS entry 'agent-sdk' (AGENTMEMORY_ALLOW_AGENT_SDK is not 'true'). The agent-sdk fallback can spawn Claude Agent SDK child sessions that trigger the Stop-hook recursion loop (#149 follow-up). Opt in explicitly with AGENTMEMORY_ALLOW_AGENT_SDK=true if this is intentional.\n");
261
+ process.stderr.write("[agentmemory] Ignoring FALLBACK_PROVIDERS entry 'agent-sdk' (AGENTMEMORY_ALLOW_AGENT_SDK is not 'true'). The agent-sdk fallback can spawn Claude Agent SDK child sessions that trigger the Stop-hook recursion loop. Opt in explicitly with AGENTMEMORY_ALLOW_AGENT_SDK=true if this is intentional.\n");
273
262
  return false;
274
263
  }
275
264
  return true;
@@ -3639,6 +3628,74 @@ function registerSearchFunction(sdk, kv) {
3639
3628
  });
3640
3629
  }
3641
3630
  //#endregion
3631
+ //#region src/utils/image-store.ts
3632
+ const IMAGES_DIR = join(homedir(), ".agentmemory", "images");
3633
+ const DEFAULT_MAX_BYTES = 500 * 1024 * 1024;
3634
+ function getMaxBytes() {
3635
+ return Number(process.env.AGENTMEMORY_IMAGE_STORE_MAX_BYTES) || DEFAULT_MAX_BYTES;
3636
+ }
3637
+ function isManagedImagePath(filePath) {
3638
+ const resolved = resolve(filePath);
3639
+ const normalizedImagesDir = resolve(IMAGES_DIR);
3640
+ return resolved.startsWith(normalizedImagesDir + sep) || resolved === normalizedImagesDir;
3641
+ }
3642
+ function contentHash(data) {
3643
+ return createHash("sha256").update(data).digest("hex");
3644
+ }
3645
+ async function saveImageToDisk(base64Data) {
3646
+ if (!base64Data) return {
3647
+ filePath: "",
3648
+ bytesWritten: 0
3649
+ };
3650
+ if (!existsSync(IMAGES_DIR)) await mkdir(IMAGES_DIR, { recursive: true });
3651
+ let cleanBase64 = base64Data;
3652
+ let ext = "png";
3653
+ if (base64Data.startsWith("data:image/")) {
3654
+ const commaIdx = base64Data.indexOf(",");
3655
+ if (commaIdx !== -1) {
3656
+ const meta = base64Data.substring(0, commaIdx);
3657
+ if (meta.includes("jpeg") || meta.includes("jpg")) ext = "jpg";
3658
+ else if (meta.includes("webp")) ext = "webp";
3659
+ else if (meta.includes("gif")) ext = "gif";
3660
+ cleanBase64 = base64Data.substring(commaIdx + 1);
3661
+ }
3662
+ } else if (base64Data.startsWith("/9j/")) ext = "jpg";
3663
+ const filePath = join(IMAGES_DIR, `${contentHash(cleanBase64)}.${ext}`);
3664
+ if (existsSync(filePath)) return {
3665
+ filePath,
3666
+ bytesWritten: 0
3667
+ };
3668
+ await writeFile(filePath, Buffer.from(cleanBase64, "base64"));
3669
+ return {
3670
+ filePath,
3671
+ bytesWritten: (await stat(filePath)).size
3672
+ };
3673
+ }
3674
+ async function deleteImage(filePath) {
3675
+ if (!filePath) return { deletedBytes: 0 };
3676
+ if (!isManagedImagePath(filePath)) return { deletedBytes: 0 };
3677
+ try {
3678
+ if (existsSync(filePath)) {
3679
+ const size = (await stat(filePath)).size;
3680
+ await unlink(filePath);
3681
+ return { deletedBytes: size };
3682
+ }
3683
+ } catch (err) {
3684
+ console.error("[agentmemory] Failed to delete image context:", err);
3685
+ }
3686
+ return { deletedBytes: 0 };
3687
+ }
3688
+ /** Touch an image file to update its mtime (marking it as recently used for LRU eviction) */
3689
+ async function touchImage(filePath) {
3690
+ if (!filePath || !isManagedImagePath(filePath)) return;
3691
+ try {
3692
+ if (existsSync(filePath)) {
3693
+ const now = /* @__PURE__ */ new Date();
3694
+ await utimes(filePath, now, now);
3695
+ }
3696
+ } catch (err) {}
3697
+ }
3698
+ //#endregion
3642
3699
  //#region src/functions/observe.ts
3643
3700
  function extractImage(d) {
3644
3701
  if (!d) return void 0;
@@ -3716,10 +3773,9 @@ function registerObserveFunction(sdk, kv, dedupMap, maxObservationsPerSession) {
3716
3773
  const inheritedAgentId = existingSession ? existingSession.agentId : getAgentId();
3717
3774
  if (inheritedAgentId) raw.agentId = inheritedAgentId;
3718
3775
  if (pendingImageData && (pendingImageData.startsWith("data:image/") || pendingImageData.startsWith("iVBORw0KGgo") || pendingImageData.startsWith("/9j/"))) {
3719
- const { saveImageToDisk } = await Promise.resolve().then(() => image_store_exports);
3720
3776
  const { filePath, bytesWritten } = await saveImageToDisk(pendingImageData);
3721
3777
  raw.imageData = filePath;
3722
- const { incrementImageRef } = await Promise.resolve().then(() => image_refs_exports);
3778
+ const { incrementImageRef } = await import("./image-refs-BKLmp_sD.mjs");
3723
3779
  await incrementImageRef(kv, filePath);
3724
3780
  sdk.trigger({
3725
3781
  function_id: "mem::disk-size-delta",
@@ -3739,13 +3795,13 @@ function registerObserveFunction(sdk, kv, dedupMap, maxObservationsPerSession) {
3739
3795
  try {
3740
3796
  await kv.set(KV.observations(payload.sessionId), obsId, raw);
3741
3797
  } catch (error) {
3742
- if (raw.imageData) {
3743
- const { deleteImage } = await Promise.resolve().then(() => image_store_exports);
3744
- const { deletedBytes } = await deleteImage(raw.imageData);
3745
- if (deletedBytes > 0) sdk.trigger({
3746
- function_id: "mem::disk-size-delta",
3747
- payload: { deltaBytes: -deletedBytes },
3748
- action: TriggerAction.Void()
3798
+ if (raw.imageData) try {
3799
+ const { decrementImageRef } = await import("./image-refs-BKLmp_sD.mjs");
3800
+ await decrementImageRef(kv, sdk, raw.imageData);
3801
+ } catch (rollbackError) {
3802
+ logger.error("Failed to roll back image ref after observation write failure", {
3803
+ imageRef: raw.imageData,
3804
+ error: rollbackError instanceof Error ? rollbackError.message : String(rollbackError)
3749
3805
  });
3750
3806
  }
3751
3807
  throw error;
@@ -3867,115 +3923,6 @@ function registerObserveFunction(sdk, kv, dedupMap, maxObservationsPerSession) {
3867
3923
  });
3868
3924
  }
3869
3925
  //#endregion
3870
- //#region src/utils/image-store.ts
3871
- var image_store_exports = /* @__PURE__ */ __exportAll({
3872
- IMAGES_DIR: () => IMAGES_DIR,
3873
- deleteImage: () => deleteImage,
3874
- getMaxBytes: () => getMaxBytes,
3875
- isManagedImagePath: () => isManagedImagePath,
3876
- saveImageToDisk: () => saveImageToDisk,
3877
- touchImage: () => touchImage
3878
- });
3879
- const IMAGES_DIR = join(homedir(), ".agentmemory", "images");
3880
- const DEFAULT_MAX_BYTES = 500 * 1024 * 1024;
3881
- function getMaxBytes() {
3882
- return Number(process.env.AGENTMEMORY_IMAGE_STORE_MAX_BYTES) || DEFAULT_MAX_BYTES;
3883
- }
3884
- function isManagedImagePath(filePath) {
3885
- const resolved = resolve(filePath);
3886
- const normalizedImagesDir = resolve(IMAGES_DIR);
3887
- return resolved.startsWith(normalizedImagesDir + sep) || resolved === normalizedImagesDir;
3888
- }
3889
- function contentHash(data) {
3890
- return createHash("sha256").update(data).digest("hex");
3891
- }
3892
- async function saveImageToDisk(base64Data) {
3893
- if (!base64Data) return {
3894
- filePath: "",
3895
- bytesWritten: 0
3896
- };
3897
- if (!existsSync(IMAGES_DIR)) await mkdir(IMAGES_DIR, { recursive: true });
3898
- let cleanBase64 = base64Data;
3899
- let ext = "png";
3900
- if (base64Data.startsWith("data:image/")) {
3901
- const commaIdx = base64Data.indexOf(",");
3902
- if (commaIdx !== -1) {
3903
- const meta = base64Data.substring(0, commaIdx);
3904
- if (meta.includes("jpeg") || meta.includes("jpg")) ext = "jpg";
3905
- else if (meta.includes("webp")) ext = "webp";
3906
- else if (meta.includes("gif")) ext = "gif";
3907
- cleanBase64 = base64Data.substring(commaIdx + 1);
3908
- }
3909
- } else if (base64Data.startsWith("/9j/")) ext = "jpg";
3910
- const filePath = join(IMAGES_DIR, `${contentHash(cleanBase64)}.${ext}`);
3911
- if (existsSync(filePath)) return {
3912
- filePath,
3913
- bytesWritten: 0
3914
- };
3915
- await writeFile(filePath, Buffer.from(cleanBase64, "base64"));
3916
- return {
3917
- filePath,
3918
- bytesWritten: (await stat(filePath)).size
3919
- };
3920
- }
3921
- async function deleteImage(filePath) {
3922
- if (!filePath) return { deletedBytes: 0 };
3923
- if (!isManagedImagePath(filePath)) return { deletedBytes: 0 };
3924
- try {
3925
- if (existsSync(filePath)) {
3926
- const size = (await stat(filePath)).size;
3927
- await unlink(filePath);
3928
- return { deletedBytes: size };
3929
- }
3930
- } catch (err) {
3931
- console.error("[agentmemory] Failed to delete image context:", err);
3932
- }
3933
- return { deletedBytes: 0 };
3934
- }
3935
- /** Touch an image file to update its mtime (marking it as recently used for LRU eviction) */
3936
- async function touchImage(filePath) {
3937
- if (!filePath || !isManagedImagePath(filePath)) return;
3938
- try {
3939
- if (existsSync(filePath)) {
3940
- const now = /* @__PURE__ */ new Date();
3941
- await utimes(filePath, now, now);
3942
- }
3943
- } catch (err) {}
3944
- }
3945
- //#endregion
3946
- //#region src/functions/image-refs.ts
3947
- var image_refs_exports = /* @__PURE__ */ __exportAll({
3948
- decrementImageRef: () => decrementImageRef,
3949
- getImageRefCount: () => getImageRefCount,
3950
- incrementImageRef: () => incrementImageRef
3951
- });
3952
- async function getImageRefCount(kv, filePath) {
3953
- const count = await kv.get(KV.imageRefs, filePath);
3954
- return count ? Number(count) : 0;
3955
- }
3956
- async function incrementImageRef(kv, filePath) {
3957
- return withKeyedLock(`imgRef:${filePath}`, async () => {
3958
- const current = await getImageRefCount(kv, filePath);
3959
- await kv.set(KV.imageRefs, filePath, current + 1);
3960
- await touchImage(filePath);
3961
- });
3962
- }
3963
- async function decrementImageRef(kv, sdk, filePath) {
3964
- return withKeyedLock(`imgRef:${filePath}`, async () => {
3965
- const current = await getImageRefCount(kv, filePath);
3966
- if (current <= 1) {
3967
- await kv.delete(KV.imageEmbeddings, filePath);
3968
- await kv.delete(KV.imageRefs, filePath);
3969
- const { deletedBytes } = await deleteImage(filePath);
3970
- if (deletedBytes > 0) sdk.trigger({
3971
- function_id: "mem::disk-size-delta",
3972
- payload: { deltaBytes: -deletedBytes },
3973
- action: TriggerAction.Void()
3974
- });
3975
- } else await kv.set(KV.imageRefs, filePath, current - 1);
3976
- });
3977
- }
3978
- //#endregion
3979
3926
  //#region src/functions/image-quota-cleanup.ts
3980
3927
  const GRACE_PERIOD_MS = 3e4;
3981
3928
  function registerImageQuotaCleanup(sdk, kv) {
@@ -4023,6 +3970,7 @@ function registerImageQuotaCleanup(sdk, kv) {
4023
3970
  await withKeyedLock(`imgRef:${f.filePath}`, async () => {
4024
3971
  let refCount;
4025
3972
  try {
3973
+ const { getImageRefCount } = await import("./image-refs-BKLmp_sD.mjs");
4026
3974
  refCount = await getImageRefCount(kv, f.filePath);
4027
3975
  } catch (err) {
4028
3976
  logger.error("Failed to read refCount; skipping eviction", {
@@ -5113,6 +5061,12 @@ function registerContextFunction(sdk, kv, tokenBudget) {
5113
5061
  sdk.registerFunction("mem::context", async (data) => {
5114
5062
  const budget = data.budget || tokenBudget;
5115
5063
  const blocks = [];
5064
+ const isolated = isAgentScopeIsolated();
5065
+ const explicitAgentId = typeof data.agentId === "string" && data.agentId.trim().length > 0 ? data.agentId.trim() : void 0;
5066
+ const wildcardAgent = explicitAgentId === "*";
5067
+ const envAgentId = isolated ? getAgentId() : void 0;
5068
+ const filterAgentId = wildcardAgent ? void 0 : explicitAgentId ?? envAgentId;
5069
+ if (isolated && !wildcardAgent && !explicitAgentId && !envAgentId) throw new Error("mem::context: AGENTMEMORY_AGENT_SCOPE=isolated is set but no agent id is available (env AGENT_ID unset and no explicit agentId in the call). Refusing to read cross-agent rows. Pass agentId: \"*\" to opt in to a wildcard read.");
5116
5070
  const [pinnedSlots, profile, lessons] = await Promise.all([
5117
5071
  isSlotsEnabled() ? listPinnedSlots(kv).catch(() => []) : Promise.resolve([]),
5118
5072
  kv.get(KV.profiles, data.project).catch(() => null),
@@ -5159,7 +5113,7 @@ function registerContextFunction(sdk, kv, tokenBudget) {
5159
5113
  sourceIds: relevantLessons.map((l) => l.id)
5160
5114
  });
5161
5115
  }
5162
- const sessions = (await kv.list(KV.sessions)).filter((s) => s.project === data.project && s.id !== data.sessionId).sort((a, b) => new Date(b.startedAt).getTime() - new Date(a.startedAt).getTime()).slice(0, 10);
5116
+ const sessions = (await kv.list(KV.sessions)).filter((s) => s.project === data.project && s.id !== data.sessionId && (filterAgentId === void 0 || s.agentId === filterAgentId)).sort((a, b) => new Date(b.startedAt).getTime() - new Date(a.startedAt).getTime()).slice(0, 10);
5163
5117
  const summariesPerSession = await Promise.all(sessions.map((s) => kv.get(KV.summaries, s.id).catch(() => null)));
5164
5118
  const sessionsNeedingObs = [];
5165
5119
  for (let i = 0; i < sessions.length; i++) {
@@ -6149,7 +6103,7 @@ function registerRememberFunction(sdk, kv) {
6149
6103
  const deletedMemoryIds = [];
6150
6104
  const deletedObservationIds = [];
6151
6105
  let deletedSession = false;
6152
- const { decrementImageRef } = await Promise.resolve().then(() => image_refs_exports);
6106
+ const { decrementImageRef } = await import("./image-refs-BKLmp_sD.mjs");
6153
6107
  if (data.memoryId) {
6154
6108
  const mem = await kv.get(KV.memories, data.memoryId);
6155
6109
  await kv.delete(KV.memories, data.memoryId);
@@ -6256,7 +6210,7 @@ async function runRecoveredSessionConsolidation(sdk) {
6256
6210
  function registerEvictFunction(sdk, kv) {
6257
6211
  sdk.registerFunction("mem::evict", async (data) => {
6258
6212
  const dryRun = data?.dryRun ?? false;
6259
- const { decrementImageRef } = await Promise.resolve().then(() => image_refs_exports);
6213
+ const { decrementImageRef } = await import("./image-refs-BKLmp_sD.mjs");
6260
6214
  const configOverride = await kv.get(KV.config, "eviction").catch(() => null);
6261
6215
  const cfg = {
6262
6216
  ...DEFAULTS$1,
@@ -6704,7 +6658,7 @@ async function findByKeyword(kv, keyword, project) {
6704
6658
  }
6705
6659
  //#endregion
6706
6660
  //#region src/version.ts
6707
- const VERSION = "0.9.27";
6661
+ const VERSION = "0.9.28";
6708
6662
  //#endregion
6709
6663
  //#region src/telemetry/setup.ts
6710
6664
  const OTEL_CONFIG = {
@@ -7074,7 +7028,7 @@ function registerAutoForgetFunction(sdk, kv) {
7074
7028
  sdk.registerFunction("mem::auto-forget", async (data) => {
7075
7029
  const dryRun = data?.dryRun ?? false;
7076
7030
  const now = Date.now();
7077
- const { decrementImageRef } = await Promise.resolve().then(() => image_refs_exports);
7031
+ const { decrementImageRef } = await import("./image-refs-BKLmp_sD.mjs");
7078
7032
  const result = {
7079
7033
  ttlExpired: [],
7080
7034
  contradictions: [],
@@ -7334,7 +7288,8 @@ function registerExportImportFunction(sdk, kv) {
7334
7288
  "0.9.24",
7335
7289
  "0.9.25",
7336
7290
  "0.9.26",
7337
- "0.9.27"
7291
+ "0.9.27",
7292
+ "0.9.28"
7338
7293
  ]).has(importData.version)) return {
7339
7294
  success: false,
7340
7295
  error: `Unsupported export version: ${importData.version}`
@@ -14212,7 +14167,7 @@ function registerRetentionFunctions(sdk, kv) {
14212
14167
  const threshold = typeof data?.threshold === "number" && Number.isFinite(data.threshold) ? data.threshold : DEFAULT_DECAY.tierThresholds.cold;
14213
14168
  const maxEvictRaw = typeof data?.maxEvict === "number" && Number.isInteger(data.maxEvict) ? data.maxEvict : 50;
14214
14169
  const maxEvict = Math.min(1e3, Math.max(0, maxEvictRaw));
14215
- const { decrementImageRef } = await Promise.resolve().then(() => image_refs_exports);
14170
+ const { decrementImageRef } = await import("./image-refs-BKLmp_sD.mjs");
14216
14171
  const candidates = (await kv.list(KV.retentionScores)).filter((s) => s.score < threshold).sort((a, b) => a.score - b.score).slice(0, maxEvict);
14217
14172
  if (data?.dryRun) return {
14218
14173
  success: true,
@@ -15680,11 +15635,15 @@ function registerApiTriggers(sdk, kv, secret, metricsStore, provider) {
15680
15635
  status_code: 400,
15681
15636
  body: { error: "budget must be a positive integer" }
15682
15637
  };
15638
+ const queryAgentId = typeof req.query_params?.["agentId"] === "string" ? req.query_params["agentId"] : void 0;
15639
+ const bodyAgentId = typeof body.agentId === "string" && body.agentId.trim().length > 0 ? body.agentId.trim() : void 0;
15683
15640
  const payload = {
15684
15641
  sessionId,
15685
15642
  project
15686
15643
  };
15687
15644
  if (budget !== void 0) payload.budget = budget;
15645
+ const agentId = bodyAgentId ?? queryAgentId;
15646
+ if (agentId !== void 0) payload.agentId = agentId;
15688
15647
  return {
15689
15648
  status_code: 200,
15690
15649
  body: await sdk.trigger({
@@ -15896,7 +15855,8 @@ function registerApiTriggers(sdk, kv, secret, metricsStore, provider) {
15896
15855
  function_id: "mem::context",
15897
15856
  payload: {
15898
15857
  sessionId,
15899
- project
15858
+ project,
15859
+ ...agentId ? { agentId } : {}
15900
15860
  }
15901
15861
  })).context
15902
15862
  }
@@ -16088,9 +16048,14 @@ function registerApiTriggers(sdk, kv, secret, metricsStore, provider) {
16088
16048
  const normalizedAgentId = typeof req.query_params?.["agentId"] === "string" ? req.query_params["agentId"].trim() : void 0;
16089
16049
  const wildcardAgent = normalizedAgentId === "*";
16090
16050
  const filterAgentId = wildcardAgent ? void 0 : (normalizedAgentId && !wildcardAgent ? normalizedAgentId : void 0) ?? (isAgentScopeIsolated() ? getAgentId() : void 0);
16051
+ const filtered = filterAgentId ? sessions.filter((s) => s.agentId === filterAgentId) : sessions;
16052
+ const summaries = await Promise.all(filtered.map((s) => kv.get(KV.summaries, s.id).catch(() => null)));
16091
16053
  return {
16092
16054
  status_code: 200,
16093
- body: { sessions: filterAgentId ? sessions.filter((s) => s.agentId === filterAgentId) : sessions }
16055
+ body: { sessions: filtered.map((s, i) => summaries[i] ? {
16056
+ ...s,
16057
+ summary: summaries[i]
16058
+ } : s) }
16094
16059
  };
16095
16060
  });
16096
16061
  sdk.registerTrigger({
@@ -18970,13 +18935,15 @@ function registerApiTriggers(sdk, kv, secret, metricsStore, provider) {
18970
18935
  //#region src/triggers/events.ts
18971
18936
  function registerEventTriggers(sdk, kv) {
18972
18937
  sdk.registerFunction("event::session::started", async (data) => {
18938
+ const agentId = (typeof data.agentId === "string" && data.agentId.trim().length > 0 ? data.agentId.trim().slice(0, 128) : void 0) ?? getAgentId();
18973
18939
  const session = {
18974
18940
  id: data.sessionId,
18975
18941
  project: data.project,
18976
18942
  cwd: data.cwd,
18977
18943
  startedAt: (/* @__PURE__ */ new Date()).toISOString(),
18978
18944
  status: "active",
18979
- observationCount: 0
18945
+ observationCount: 0,
18946
+ ...agentId ? { agentId } : {}
18980
18947
  };
18981
18948
  await kv.set(KV.sessions, data.sessionId, session);
18982
18949
  return {
@@ -18985,7 +18952,8 @@ function registerEventTriggers(sdk, kv) {
18985
18952
  function_id: "mem::context",
18986
18953
  payload: {
18987
18954
  sessionId: data.sessionId,
18988
- project: data.project
18955
+ project: data.project,
18956
+ ...agentId ? { agentId } : {}
18989
18957
  }
18990
18958
  })).context
18991
18959
  };
@@ -22019,10 +21987,10 @@ async function main() {
22019
21987
  }
22020
21988
  registerConsolidationPipelineFunction(sdk, kv, provider);
22021
21989
  bootLog(`Consolidation pipeline: registered (CONSOLIDATION_ENABLED=${isConsolidationEnabled() ? "true" : "false"})`);
22022
- 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.`);
22023
- 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).`);
22024
- 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.`);
22025
- 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).`);
21990
+ 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. Set AGENTMEMORY_AUTO_COMPRESS=false to disable.`);
21991
+ else bootLog(`Auto-compress: OFF (default) — observations indexed via zero-LLM synthetic compression. Set AGENTMEMORY_AUTO_COMPRESS=true to opt-in to LLM-powered summaries (uses your API key).`);
21992
+ 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. Set AGENTMEMORY_INJECT_CONTEXT=false to disable.`);
21993
+ else bootLog(`Context injection: OFF (default) — 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).`);
22026
21994
  const teamConfig = loadTeamConfig();
22027
21995
  if (teamConfig) {
22028
21996
  registerTeamFunction(sdk, kv, teamConfig);
@@ -22129,7 +22097,7 @@ async function main() {
22129
22097
  backfilled++;
22130
22098
  }
22131
22099
  if (backfilled > 0) {
22132
- bootLog(`Backfilled ${backfilled} memories into BM25 (legacy gap before #257)`);
22100
+ bootLog(`Backfilled ${backfilled} memories into BM25 (legacy index gap)`);
22133
22101
  indexPersistence.scheduleSave();
22134
22102
  }
22135
22103
  } catch (err) {
@@ -22211,6 +22179,6 @@ main().catch((err) => {
22211
22179
  process.exit(1);
22212
22180
  });
22213
22181
  //#endregion
22214
- export {};
22182
+ export { KV as i, touchImage as n, withKeyedLock as r, deleteImage as t };
22215
22183
 
22216
22184
  //# sourceMappingURL=index.mjs.map