@agentmemory/agentmemory 0.9.30 → 0.9.32
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/.env.example +57 -48
- package/AGENTS.md +8 -8
- package/README.md +256 -819
- package/dist/.env.example +57 -48
- package/dist/cli.d.mts.map +1 -1
- package/dist/cli.mjs +2257 -1027
- package/dist/cli.mjs.map +1 -1
- package/dist/compression-recovery-CZh63Jmz.mjs +5997 -0
- package/dist/compression-recovery-CZh63Jmz.mjs.map +1 -0
- package/dist/{connect-B4_ca6BD.mjs → connect-BX3njQ3Y.mjs} +897 -276
- package/dist/connect-BX3njQ3Y.mjs.map +1 -0
- package/dist/hooks/_capture.d.mts +5 -1
- package/dist/hooks/_capture.d.mts.map +1 -1
- package/dist/hooks/_capture.mjs +141 -26
- package/dist/hooks/_capture.mjs.map +1 -1
- package/dist/hooks/notification.mjs +20 -6
- package/dist/hooks/notification.mjs.map +1 -1
- package/dist/hooks/post-commit.mjs +83 -10
- package/dist/hooks/post-commit.mjs.map +1 -1
- package/dist/hooks/post-tool-failure.mjs +19 -6
- package/dist/hooks/post-tool-failure.mjs.map +1 -1
- package/dist/hooks/post-tool-use.mjs +19 -6
- package/dist/hooks/post-tool-use.mjs.map +1 -1
- package/dist/hooks/pre-compact.mjs +104 -22
- package/dist/hooks/pre-compact.mjs.map +1 -1
- package/dist/hooks/pre-tool-use.mjs +83 -10
- package/dist/hooks/pre-tool-use.mjs.map +1 -1
- package/dist/hooks/prompt-submit.mjs +12 -4
- package/dist/hooks/prompt-submit.mjs.map +1 -1
- package/dist/hooks/session-end.mjs +59 -17
- package/dist/hooks/session-end.mjs.map +1 -1
- package/dist/hooks/session-start.mjs +95 -15
- package/dist/hooks/session-start.mjs.map +1 -1
- package/dist/hooks/stop.mjs +75 -72
- package/dist/hooks/stop.mjs.map +1 -1
- package/dist/hooks/subagent-start.mjs +13 -5
- package/dist/hooks/subagent-start.mjs.map +1 -1
- package/dist/hooks/subagent-stop.mjs +32 -10
- package/dist/hooks/subagent-stop.mjs.map +1 -1
- package/dist/hooks/task-completed.mjs +21 -6
- package/dist/hooks/task-completed.mjs.map +1 -1
- package/dist/{image-refs-T_urbwHM.mjs → image-refs-Cyta4Lf9.mjs} +2 -2
- package/dist/{image-refs-T_urbwHM.mjs.map → image-refs-Cyta4Lf9.mjs.map} +1 -1
- package/dist/index.mjs +16390 -11530
- package/dist/index.mjs.map +1 -1
- package/dist/integrations/dsh.d.mts +55 -0
- package/dist/integrations/dsh.d.mts.map +1 -0
- package/dist/integrations/dsh.mjs +1172 -0
- package/dist/integrations/dsh.mjs.map +1 -0
- package/dist/{keyed-mutex-DchXsyfP.mjs → keyed-mutex-DCUh7PG-.mjs} +58 -9
- package/dist/keyed-mutex-DCUh7PG-.mjs.map +1 -0
- package/dist/{secret-store-BnY3A50C.mjs → secret-store-iYXRcrO8.mjs} +717 -474
- package/dist/secret-store-iYXRcrO8.mjs.map +1 -0
- package/dist/session-arguments-zxsbbd8y.mjs +113 -0
- package/dist/session-arguments-zxsbbd8y.mjs.map +1 -0
- package/dist/{src-Jsq9LCeH.mjs → src-C23nMpda.mjs} +5263 -4667
- package/dist/src-C23nMpda.mjs.map +1 -0
- package/dist/{standalone-DKCdrf1d.mjs → standalone-BYo5USDb.mjs} +379 -63
- package/dist/standalone-BYo5USDb.mjs.map +1 -0
- package/dist/standalone.d.mts +1 -1
- package/dist/standalone.d.mts.map +1 -1
- package/dist/standalone.mjs +864 -81
- package/dist/standalone.mjs.map +1 -1
- package/dist/viewer/index.html +337 -168
- package/integrations/hermes/README.md +94 -0
- package/integrations/hermes/__init__.py +670 -0
- package/integrations/hermes/plugin.yaml +27 -0
- package/integrations/omp/LICENSE +190 -0
- package/integrations/omp/README.md +76 -0
- package/integrations/omp/capture.ts +1 -0
- package/integrations/omp/dist/index.mjs +1477 -0
- package/integrations/omp/index.ts +488 -0
- package/integrations/omp/package.json +13 -0
- package/integrations/omp/security.ts +67 -0
- package/integrations/omp/skills/agentmemory-agents/REFERENCE.md +32 -0
- package/integrations/omp/skills/agentmemory-agents/SKILL.md +48 -0
- package/integrations/omp/skills/agentmemory-agents/TROUBLESHOOTING.md +70 -0
- package/integrations/omp/skills/agentmemory-architecture/SKILL.md +37 -0
- package/integrations/omp/skills/agentmemory-architecture/TROUBLESHOOTING.md +70 -0
- package/integrations/omp/skills/agentmemory-config/REFERENCE.md +91 -0
- package/integrations/omp/skills/agentmemory-config/SKILL.md +98 -0
- package/integrations/omp/skills/agentmemory-config/TROUBLESHOOTING.md +70 -0
- package/integrations/omp/skills/agentmemory-hooks/REFERENCE.md +20 -0
- package/integrations/omp/skills/agentmemory-hooks/SKILL.md +60 -0
- package/integrations/omp/skills/agentmemory-hooks/TROUBLESHOOTING.md +70 -0
- package/integrations/omp/skills/agentmemory-mcp-tools/REFERENCE.md +66 -0
- package/integrations/omp/skills/agentmemory-mcp-tools/SKILL.md +52 -0
- package/integrations/omp/skills/agentmemory-mcp-tools/TROUBLESHOOTING.md +70 -0
- package/integrations/omp/skills/agentmemory-rest-api/REFERENCE.md +159 -0
- package/integrations/omp/skills/agentmemory-rest-api/SKILL.md +49 -0
- package/integrations/omp/skills/agentmemory-rest-api/TROUBLESHOOTING.md +70 -0
- package/integrations/omp/skills/commit-context/EXAMPLES.md +71 -0
- package/integrations/omp/skills/commit-context/SKILL.md +64 -0
- package/integrations/omp/skills/commit-context/TROUBLESHOOTING.md +70 -0
- package/integrations/omp/skills/commit-history/EXAMPLES.md +71 -0
- package/integrations/omp/skills/commit-history/SKILL.md +62 -0
- package/integrations/omp/skills/commit-history/TROUBLESHOOTING.md +70 -0
- package/integrations/omp/skills/forget/EXAMPLES.md +40 -0
- package/integrations/omp/skills/forget/SKILL.md +73 -0
- package/integrations/omp/skills/forget/TROUBLESHOOTING.md +70 -0
- package/integrations/omp/skills/handoff/EXAMPLES.md +57 -0
- package/integrations/omp/skills/handoff/SKILL.md +75 -0
- package/integrations/omp/skills/handoff/TROUBLESHOOTING.md +70 -0
- package/integrations/omp/skills/lesson/SKILL.md +64 -0
- package/integrations/omp/skills/lesson/TROUBLESHOOTING.md +70 -0
- package/integrations/omp/skills/memory-discipline/SKILL.md +65 -0
- package/integrations/omp/skills/memory-discipline/TROUBLESHOOTING.md +70 -0
- package/integrations/omp/skills/recall/EXAMPLES.md +74 -0
- package/integrations/omp/skills/recall/SKILL.md +74 -0
- package/integrations/omp/skills/recall/TROUBLESHOOTING.md +70 -0
- package/integrations/omp/skills/recap/EXAMPLES.md +62 -0
- package/integrations/omp/skills/recap/SKILL.md +68 -0
- package/integrations/omp/skills/recap/TROUBLESHOOTING.md +70 -0
- package/integrations/omp/skills/remember/EXAMPLES.md +67 -0
- package/integrations/omp/skills/remember/SKILL.md +66 -0
- package/integrations/omp/skills/remember/TROUBLESHOOTING.md +70 -0
- package/integrations/omp/skills/session-history/EXAMPLES.md +59 -0
- package/integrations/omp/skills/session-history/SKILL.md +67 -0
- package/integrations/omp/skills/session-history/TROUBLESHOOTING.md +70 -0
- package/integrations/omp/skills/write-agentmemory-skill/SKILL.md +41 -0
- package/integrations/omp/skills/write-agentmemory-skill/TROUBLESHOOTING.md +70 -0
- package/integrations/openclaw/LICENSE +190 -0
- package/integrations/openclaw/README.md +98 -0
- package/integrations/openclaw/openclaw.plugin.json +71 -0
- package/integrations/openclaw/package.json +38 -0
- package/integrations/openclaw/plugin.mjs +425 -0
- package/integrations/openclaw/plugin.yaml +26 -0
- package/integrations/openclaw/skills/agentmemory-agents/REFERENCE.md +32 -0
- package/integrations/openclaw/skills/agentmemory-agents/SKILL.md +48 -0
- package/integrations/openclaw/skills/agentmemory-agents/TROUBLESHOOTING.md +70 -0
- package/integrations/openclaw/skills/agentmemory-architecture/SKILL.md +37 -0
- package/integrations/openclaw/skills/agentmemory-architecture/TROUBLESHOOTING.md +70 -0
- package/integrations/openclaw/skills/agentmemory-config/REFERENCE.md +91 -0
- package/integrations/openclaw/skills/agentmemory-config/SKILL.md +98 -0
- package/integrations/openclaw/skills/agentmemory-config/TROUBLESHOOTING.md +70 -0
- package/integrations/openclaw/skills/agentmemory-hooks/REFERENCE.md +20 -0
- package/integrations/openclaw/skills/agentmemory-hooks/SKILL.md +60 -0
- package/integrations/openclaw/skills/agentmemory-hooks/TROUBLESHOOTING.md +70 -0
- package/integrations/openclaw/skills/agentmemory-mcp-tools/REFERENCE.md +66 -0
- package/integrations/openclaw/skills/agentmemory-mcp-tools/SKILL.md +52 -0
- package/integrations/openclaw/skills/agentmemory-mcp-tools/TROUBLESHOOTING.md +70 -0
- package/integrations/openclaw/skills/agentmemory-rest-api/REFERENCE.md +159 -0
- package/integrations/openclaw/skills/agentmemory-rest-api/SKILL.md +49 -0
- package/integrations/openclaw/skills/agentmemory-rest-api/TROUBLESHOOTING.md +70 -0
- package/integrations/openclaw/skills/commit-context/EXAMPLES.md +71 -0
- package/integrations/openclaw/skills/commit-context/SKILL.md +64 -0
- package/integrations/openclaw/skills/commit-context/TROUBLESHOOTING.md +70 -0
- package/integrations/openclaw/skills/commit-history/EXAMPLES.md +71 -0
- package/integrations/openclaw/skills/commit-history/SKILL.md +62 -0
- package/integrations/openclaw/skills/commit-history/TROUBLESHOOTING.md +70 -0
- package/integrations/openclaw/skills/forget/EXAMPLES.md +40 -0
- package/integrations/openclaw/skills/forget/SKILL.md +73 -0
- package/integrations/openclaw/skills/forget/TROUBLESHOOTING.md +70 -0
- package/integrations/openclaw/skills/handoff/EXAMPLES.md +57 -0
- package/integrations/openclaw/skills/handoff/SKILL.md +75 -0
- package/integrations/openclaw/skills/handoff/TROUBLESHOOTING.md +70 -0
- package/integrations/openclaw/skills/lesson/SKILL.md +64 -0
- package/integrations/openclaw/skills/lesson/TROUBLESHOOTING.md +70 -0
- package/integrations/openclaw/skills/memory-discipline/SKILL.md +65 -0
- package/integrations/openclaw/skills/memory-discipline/TROUBLESHOOTING.md +70 -0
- package/integrations/openclaw/skills/recall/EXAMPLES.md +74 -0
- package/integrations/openclaw/skills/recall/SKILL.md +74 -0
- package/integrations/openclaw/skills/recall/TROUBLESHOOTING.md +70 -0
- package/integrations/openclaw/skills/recap/EXAMPLES.md +62 -0
- package/integrations/openclaw/skills/recap/SKILL.md +68 -0
- package/integrations/openclaw/skills/recap/TROUBLESHOOTING.md +70 -0
- package/integrations/openclaw/skills/remember/EXAMPLES.md +67 -0
- package/integrations/openclaw/skills/remember/SKILL.md +66 -0
- package/integrations/openclaw/skills/remember/TROUBLESHOOTING.md +70 -0
- package/integrations/openclaw/skills/session-history/EXAMPLES.md +59 -0
- package/integrations/openclaw/skills/session-history/SKILL.md +67 -0
- package/integrations/openclaw/skills/session-history/TROUBLESHOOTING.md +70 -0
- package/integrations/openclaw/skills/write-agentmemory-skill/SKILL.md +41 -0
- package/integrations/openclaw/skills/write-agentmemory-skill/TROUBLESHOOTING.md +70 -0
- package/integrations/pi/LICENSE +190 -0
- package/integrations/pi/README.md +46 -51
- package/integrations/pi/dist/index.mjs +1460 -0
- package/integrations/pi/index.ts +192 -175
- package/integrations/pi/package.json +17 -7
- package/integrations/pi/security.ts +6 -26
- package/integrations/pi/skills/agentmemory-agents/REFERENCE.md +32 -0
- package/integrations/pi/skills/agentmemory-agents/SKILL.md +48 -0
- package/integrations/pi/skills/agentmemory-agents/TROUBLESHOOTING.md +70 -0
- package/integrations/pi/skills/agentmemory-architecture/SKILL.md +37 -0
- package/integrations/pi/skills/agentmemory-architecture/TROUBLESHOOTING.md +70 -0
- package/integrations/pi/skills/agentmemory-config/REFERENCE.md +91 -0
- package/integrations/pi/skills/agentmemory-config/SKILL.md +98 -0
- package/integrations/pi/skills/agentmemory-config/TROUBLESHOOTING.md +70 -0
- package/integrations/pi/skills/agentmemory-hooks/REFERENCE.md +20 -0
- package/integrations/pi/skills/agentmemory-hooks/SKILL.md +60 -0
- package/integrations/pi/skills/agentmemory-hooks/TROUBLESHOOTING.md +70 -0
- package/integrations/pi/skills/agentmemory-mcp-tools/REFERENCE.md +66 -0
- package/integrations/pi/skills/agentmemory-mcp-tools/SKILL.md +52 -0
- package/integrations/pi/skills/agentmemory-mcp-tools/TROUBLESHOOTING.md +70 -0
- package/integrations/pi/skills/agentmemory-rest-api/REFERENCE.md +159 -0
- package/integrations/pi/skills/agentmemory-rest-api/SKILL.md +49 -0
- package/integrations/pi/skills/agentmemory-rest-api/TROUBLESHOOTING.md +70 -0
- package/integrations/pi/skills/commit-context/EXAMPLES.md +71 -0
- package/integrations/pi/skills/commit-context/SKILL.md +64 -0
- package/integrations/pi/skills/commit-context/TROUBLESHOOTING.md +70 -0
- package/integrations/pi/skills/commit-history/EXAMPLES.md +71 -0
- package/integrations/pi/skills/commit-history/SKILL.md +62 -0
- package/integrations/pi/skills/commit-history/TROUBLESHOOTING.md +70 -0
- package/integrations/pi/skills/forget/EXAMPLES.md +40 -0
- package/integrations/pi/skills/forget/SKILL.md +73 -0
- package/integrations/pi/skills/forget/TROUBLESHOOTING.md +70 -0
- package/integrations/pi/skills/handoff/EXAMPLES.md +57 -0
- package/integrations/pi/skills/handoff/SKILL.md +75 -0
- package/integrations/pi/skills/handoff/TROUBLESHOOTING.md +70 -0
- package/integrations/pi/skills/lesson/SKILL.md +64 -0
- package/integrations/pi/skills/lesson/TROUBLESHOOTING.md +70 -0
- package/integrations/pi/skills/memory-discipline/SKILL.md +65 -0
- package/integrations/pi/skills/memory-discipline/TROUBLESHOOTING.md +70 -0
- package/integrations/pi/skills/recall/EXAMPLES.md +74 -0
- package/integrations/pi/skills/recall/SKILL.md +74 -0
- package/integrations/pi/skills/recall/TROUBLESHOOTING.md +70 -0
- package/integrations/pi/skills/recap/EXAMPLES.md +62 -0
- package/integrations/pi/skills/recap/SKILL.md +68 -0
- package/integrations/pi/skills/recap/TROUBLESHOOTING.md +70 -0
- package/integrations/pi/skills/remember/EXAMPLES.md +67 -0
- package/integrations/pi/skills/remember/SKILL.md +66 -0
- package/integrations/pi/skills/remember/TROUBLESHOOTING.md +70 -0
- package/integrations/pi/skills/session-history/EXAMPLES.md +59 -0
- package/integrations/pi/skills/session-history/SKILL.md +67 -0
- package/integrations/pi/skills/session-history/TROUBLESHOOTING.md +70 -0
- package/integrations/pi/skills/write-agentmemory-skill/SKILL.md +41 -0
- package/integrations/pi/skills/write-agentmemory-skill/TROUBLESHOOTING.md +70 -0
- package/package.json +33 -11
- package/plugin/.claude-plugin/plugin.json +16 -3
- package/plugin/.codex-plugin/plugin.json +4 -3
- package/plugin/.devin-plugin/plugin.json +6 -5
- package/plugin/.mcp.json +5 -1
- package/plugin/README.md +71 -0
- package/plugin/cursor/hooks.json +23 -8
- package/plugin/hooks/hooks.json +24 -12
- package/plugin/hooks.json +67 -0
- package/plugin/opencode/README.md +1 -1
- package/plugin/opencode/agentmemory-capture.ts +25 -11
- package/plugin/opencode/plugin.json +1 -1
- package/plugin/plugin.json +1 -1
- package/plugin/scripts/_capture.d.mts +5 -1
- package/plugin/scripts/_capture.d.mts.map +1 -1
- package/plugin/scripts/_capture.mjs +141 -26
- package/plugin/scripts/_capture.mjs.map +1 -1
- package/plugin/scripts/cursor/run-detached.mjs +786 -0
- package/plugin/scripts/cursor/run-detached.mjs.map +1 -0
- package/plugin/scripts/cursor/run-hook.d.mts +1 -0
- package/plugin/scripts/cursor/run-hook.mjs +704 -0
- package/plugin/scripts/cursor/run-hook.mjs.map +1 -0
- package/plugin/scripts/notification.mjs +20 -6
- package/plugin/scripts/notification.mjs.map +1 -1
- package/plugin/scripts/plugin-bridge.mjs +61 -11
- package/plugin/scripts/post-tool-failure.mjs +19 -6
- package/plugin/scripts/post-tool-failure.mjs.map +1 -1
- package/plugin/scripts/post-tool-use.mjs +19 -6
- package/plugin/scripts/post-tool-use.mjs.map +1 -1
- package/plugin/scripts/pre-compact.mjs +104 -22
- package/plugin/scripts/pre-compact.mjs.map +1 -1
- package/plugin/scripts/pre-tool-use.mjs +83 -10
- package/plugin/scripts/pre-tool-use.mjs.map +1 -1
- package/plugin/scripts/prompt-submit.mjs +12 -4
- package/plugin/scripts/prompt-submit.mjs.map +1 -1
- package/plugin/scripts/session-end.mjs +59 -17
- package/plugin/scripts/session-end.mjs.map +1 -1
- package/plugin/scripts/session-start.mjs +95 -15
- package/plugin/scripts/session-start.mjs.map +1 -1
- package/plugin/scripts/stop.mjs +75 -72
- package/plugin/scripts/stop.mjs.map +1 -1
- package/plugin/scripts/subagent-start.mjs +13 -5
- package/plugin/scripts/subagent-start.mjs.map +1 -1
- package/plugin/scripts/subagent-stop.mjs +32 -10
- package/plugin/scripts/subagent-stop.mjs.map +1 -1
- package/plugin/scripts/task-completed.mjs +21 -6
- package/plugin/scripts/task-completed.mjs.map +1 -1
- package/plugin/skills/_shared/TROUBLESHOOTING.md +21 -7
- package/plugin/skills/agentmemory-agents/REFERENCE.md +8 -7
- package/plugin/skills/agentmemory-agents/SKILL.md +19 -5
- package/plugin/skills/agentmemory-agents/TROUBLESHOOTING.md +70 -0
- package/plugin/skills/agentmemory-architecture/SKILL.md +8 -4
- package/plugin/skills/agentmemory-architecture/TROUBLESHOOTING.md +70 -0
- package/plugin/skills/agentmemory-config/REFERENCE.md +13 -15
- package/plugin/skills/agentmemory-config/SKILL.md +34 -10
- package/plugin/skills/agentmemory-config/TROUBLESHOOTING.md +70 -0
- package/plugin/skills/agentmemory-hooks/SKILL.md +31 -10
- package/plugin/skills/agentmemory-hooks/TROUBLESHOOTING.md +70 -0
- package/plugin/skills/agentmemory-mcp-tools/REFERENCE.md +5 -5
- package/plugin/skills/agentmemory-mcp-tools/SKILL.md +16 -3
- package/plugin/skills/agentmemory-mcp-tools/TROUBLESHOOTING.md +70 -0
- package/plugin/skills/agentmemory-rest-api/REFERENCE.md +10 -1
- package/plugin/skills/agentmemory-rest-api/SKILL.md +12 -6
- package/plugin/skills/agentmemory-rest-api/TROUBLESHOOTING.md +70 -0
- package/plugin/skills/commit-context/SKILL.md +1 -1
- package/plugin/skills/commit-context/TROUBLESHOOTING.md +70 -0
- package/plugin/skills/commit-history/SKILL.md +1 -1
- package/plugin/skills/commit-history/TROUBLESHOOTING.md +70 -0
- package/plugin/skills/forget/EXAMPLES.md +19 -54
- package/plugin/skills/forget/SKILL.md +16 -12
- package/plugin/skills/forget/TROUBLESHOOTING.md +70 -0
- package/plugin/skills/handoff/EXAMPLES.md +5 -4
- package/plugin/skills/handoff/SKILL.md +10 -5
- package/plugin/skills/handoff/TROUBLESHOOTING.md +70 -0
- package/plugin/skills/lesson/SKILL.md +1 -1
- package/plugin/skills/lesson/TROUBLESHOOTING.md +70 -0
- package/plugin/skills/memory-discipline/SKILL.md +1 -1
- package/plugin/skills/memory-discipline/TROUBLESHOOTING.md +70 -0
- package/plugin/skills/recall/SKILL.md +18 -7
- package/plugin/skills/recall/TROUBLESHOOTING.md +70 -0
- package/plugin/skills/recap/EXAMPLES.md +5 -3
- package/plugin/skills/recap/SKILL.md +11 -6
- package/plugin/skills/recap/TROUBLESHOOTING.md +70 -0
- package/plugin/skills/remember/EXAMPLES.md +3 -3
- package/plugin/skills/remember/SKILL.md +1 -1
- package/plugin/skills/remember/TROUBLESHOOTING.md +70 -0
- package/plugin/skills/session-history/EXAMPLES.md +2 -2
- package/plugin/skills/session-history/SKILL.md +10 -4
- package/plugin/skills/session-history/TROUBLESHOOTING.md +70 -0
- package/plugin/skills/write-agentmemory-skill/SKILL.md +2 -1
- package/plugin/skills/write-agentmemory-skill/TROUBLESHOOTING.md +70 -0
- package/dist/connect-B4_ca6BD.mjs.map +0 -1
- package/dist/docker-compose.yml +0 -73
- package/dist/iii-config.docker.yaml +0 -53
- package/dist/iii-config.yaml +0 -63
- package/dist/keyed-mutex-DchXsyfP.mjs.map +0 -1
- package/dist/secret-store-BnY3A50C.mjs.map +0 -1
- package/dist/src-Jsq9LCeH.mjs.map +0 -1
- package/dist/standalone-DKCdrf1d.mjs.map +0 -1
- package/dist/status-IRz7ta8-.mjs +0 -2344
- package/dist/status-IRz7ta8-.mjs.map +0 -1
- package/docker-compose.yml +0 -73
- package/iii-config.docker.yaml +0 -53
- package/iii-config.yaml +0 -63
- package/plugin/scripts/post-commit.mjs +0 -184
- package/plugin/scripts/post-commit.mjs.map +0 -1
- /package/plugin/scripts/{post-commit.d.mts → cursor/run-detached.d.mts} +0 -0
|
@@ -1,373 +1,22 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { chmodSync, closeSync, existsSync, linkSync, mkdirSync, openSync, readFileSync,
|
|
3
|
-
import {
|
|
1
|
+
import { a as KV, r as withKeyedLock, s as generateId } from "./keyed-mutex-DCUh7PG-.mjs";
|
|
2
|
+
import { chmodSync, closeSync, existsSync, linkSync, mkdirSync, openSync, readFileSync, renameSync, unlinkSync, writeSync } from "node:fs";
|
|
3
|
+
import { join } from "node:path";
|
|
4
4
|
import { homedir } from "node:os";
|
|
5
5
|
import pc from "picocolors";
|
|
6
6
|
import { randomBytes } from "node:crypto";
|
|
7
7
|
import { readFile, stat } from "node:fs/promises";
|
|
8
|
-
//#region src/cli/engine-config.ts
|
|
9
|
-
const SEEDED_BUILTIN_WORKERS = [
|
|
10
|
-
"http",
|
|
11
|
-
"iii-http",
|
|
12
|
-
"state",
|
|
13
|
-
"iii-state",
|
|
14
|
-
"queue",
|
|
15
|
-
"iii-queue",
|
|
16
|
-
"pubsub",
|
|
17
|
-
"iii-pubsub",
|
|
18
|
-
"cron",
|
|
19
|
-
"iii-cron",
|
|
20
|
-
"iii-stream",
|
|
21
|
-
"iii-observability",
|
|
22
|
-
"iii-worker-manager"
|
|
23
|
-
];
|
|
24
|
-
function configuredPersistDir(renderedConfig) {
|
|
25
|
-
const lines = renderedConfig.split("\n");
|
|
26
|
-
const block = workerBlock(lines, "configuration");
|
|
27
|
-
if (!block) return null;
|
|
28
|
-
for (let i = block.start + 1; i < block.end; i++) {
|
|
29
|
-
const match = lines[i].trim().match(/^directory:\s*(.+?)\s*$/);
|
|
30
|
-
if (match) return match[1].replace(/^(['"])(.*)\1$/, "$2");
|
|
31
|
-
}
|
|
32
|
-
return null;
|
|
33
|
-
}
|
|
34
|
-
const ENGINE_DEFAULT_SAVE_INTERVAL_MS = 5e3;
|
|
35
|
-
const ENGINE_FLUSH_MARGIN_MS = 1500;
|
|
36
|
-
function engineFlushWaitMs(stateBackend, configTexts) {
|
|
37
|
-
if (stateBackend === "redis") return 0;
|
|
38
|
-
return engineSaveIntervalMs(configTexts) + ENGINE_FLUSH_MARGIN_MS;
|
|
39
|
-
}
|
|
40
|
-
function captureDurableAfterMs(stateBackend, configTexts) {
|
|
41
|
-
if (stateBackend === "redis") return ENGINE_FLUSH_MARGIN_MS;
|
|
42
|
-
return engineSaveIntervalMs(configTexts) + ENGINE_FLUSH_MARGIN_MS;
|
|
43
|
-
}
|
|
44
|
-
function engineSaveIntervalMs(configTexts) {
|
|
45
|
-
const intervals = [];
|
|
46
|
-
for (const text of configTexts) {
|
|
47
|
-
const explicit = [...text.matchAll(/save_interval_ms:\s*(\d+)/g)].map((m) => parseInt(m[1], 10));
|
|
48
|
-
intervals.push(...explicit);
|
|
49
|
-
if ((text.match(/store_method:\s*file_based/g)?.length ?? 0) > explicit.length) intervals.push(ENGINE_DEFAULT_SAVE_INTERVAL_MS);
|
|
50
|
-
}
|
|
51
|
-
return intervals.length > 0 ? Math.max(...intervals) : ENGINE_DEFAULT_SAVE_INTERVAL_MS;
|
|
52
|
-
}
|
|
53
|
-
function engineStateConfigPaths(engineCwd, runtimePath) {
|
|
54
|
-
return [...persistedBuiltinConfigDirs(engineCwd, runtimePath).map((dir) => join(dir, "iii-state.yaml")), runtimePath];
|
|
55
|
-
}
|
|
56
|
-
function persistedBuiltinConfigDirs(engineCwd, configPath, renderedConfig) {
|
|
57
|
-
const dirs = [
|
|
58
|
-
join(engineCwd, "config"),
|
|
59
|
-
join(dirname(configPath), "config"),
|
|
60
|
-
join(engineCwd, "data", "configuration")
|
|
61
|
-
];
|
|
62
|
-
const custom = renderedConfig ? configuredPersistDir(renderedConfig) : null;
|
|
63
|
-
if (custom) dirs.unshift(resolve(engineCwd, custom));
|
|
64
|
-
return [...new Set(dirs)];
|
|
65
|
-
}
|
|
66
|
-
function persistedBuiltinConfigPaths(engineCwd, configPath, renderedConfig) {
|
|
67
|
-
return persistedBuiltinConfigDirs(engineCwd, configPath, renderedConfig).flatMap((dir) => SEEDED_BUILTIN_WORKERS.map((id) => join(dir, `${id}.yaml`)));
|
|
68
|
-
}
|
|
69
|
-
function isPersistedBuiltinEntry(content, id) {
|
|
70
|
-
return content.split("\n").find((line) => line.trim() !== "")?.trim() === `id: ${id}`;
|
|
71
|
-
}
|
|
72
|
-
function clearPersistedBuiltinConfig(engineCwd, configPath, renderedConfig) {
|
|
73
|
-
const cleared = [];
|
|
74
|
-
for (const path of persistedBuiltinConfigPaths(engineCwd, configPath, renderedConfig)) try {
|
|
75
|
-
if (!isPersistedBuiltinEntry(readFileSync(path, "utf8"), basename(path, ".yaml"))) continue;
|
|
76
|
-
rmSync(path);
|
|
77
|
-
cleared.push(path);
|
|
78
|
-
} catch (err) {
|
|
79
|
-
if (err.code === "ENOENT") continue;
|
|
80
|
-
throw new Error(`could not remove persisted engine config ${path}: ${String(err)}`);
|
|
81
|
-
}
|
|
82
|
-
return cleared;
|
|
83
|
-
}
|
|
84
|
-
function yamlSingleQuote(value) {
|
|
85
|
-
return `'${value.replace(/'/g, "''")}'`;
|
|
86
|
-
}
|
|
87
|
-
function workerBlock(lines, name) {
|
|
88
|
-
const marker = `- name: ${name}`;
|
|
89
|
-
const start = lines.findIndex((line) => line.trim() === marker);
|
|
90
|
-
if (start === -1) return null;
|
|
91
|
-
const indent = lines[start].match(/^\s*/)?.[0] ?? "";
|
|
92
|
-
let end = lines.length;
|
|
93
|
-
for (let i = start + 1; i < lines.length; i++) {
|
|
94
|
-
const line = lines[i];
|
|
95
|
-
if (line.startsWith(indent) && line.trim().startsWith("- name: ")) {
|
|
96
|
-
end = i;
|
|
97
|
-
break;
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
return {
|
|
101
|
-
start,
|
|
102
|
-
end,
|
|
103
|
-
indent
|
|
104
|
-
};
|
|
105
|
-
}
|
|
106
|
-
function setWorkerPort(lines, name, port) {
|
|
107
|
-
let block = workerBlock(lines, name);
|
|
108
|
-
if (!block && name === "iii-worker-manager") {
|
|
109
|
-
const workersIndex = lines.findIndex((line) => line.trim() === "workers:");
|
|
110
|
-
if (workersIndex === -1) return;
|
|
111
|
-
lines.splice(workersIndex + 1, 0, " - name: iii-worker-manager", " config:", ` port: ${port}`, " host: 127.0.0.1");
|
|
112
|
-
return;
|
|
113
|
-
}
|
|
114
|
-
if (!block) return;
|
|
115
|
-
const portIndex = lines.findIndex((line, index) => index > block.start && index < block.end && line.trim().startsWith("port:"));
|
|
116
|
-
if (portIndex !== -1) {
|
|
117
|
-
lines[portIndex] = `${lines[portIndex].match(/^\s*/)?.[0] ?? `${block.indent} `}port: ${port}`;
|
|
118
|
-
return;
|
|
119
|
-
}
|
|
120
|
-
const configIndex = lines.findIndex((line, index) => index > block.start && index < block.end && line.trim() === "config:");
|
|
121
|
-
if (configIndex !== -1) {
|
|
122
|
-
const configIndent = lines[configIndex].match(/^\s*/)?.[0] ?? `${block.indent} `;
|
|
123
|
-
lines.splice(configIndex + 1, 0, `${configIndent} port: ${port}`);
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
function setFileStoreSaveInterval(lines, workerName, override) {
|
|
127
|
-
const block = workerBlock(lines, workerName);
|
|
128
|
-
if (!block) return;
|
|
129
|
-
const methodIndex = lines.findIndex((line, index) => index > block.start && index < block.end && line.trim() === "store_method: file_based");
|
|
130
|
-
if (methodIndex === -1) return;
|
|
131
|
-
const indent = lines[methodIndex].match(/^\s*/)?.[0] ?? "";
|
|
132
|
-
const intervalIndex = lines.findIndex((line, index) => index > block.start && index < block.end && line.trim().startsWith("save_interval_ms:"));
|
|
133
|
-
if (intervalIndex !== -1) {
|
|
134
|
-
if (override === void 0) return;
|
|
135
|
-
lines[intervalIndex] = `${lines[intervalIndex].match(/^\s*/)?.[0] ?? indent}save_interval_ms: ${override}`;
|
|
136
|
-
return;
|
|
137
|
-
}
|
|
138
|
-
lines.splice(methodIndex + 1, 0, `${indent}save_interval_ms: ${override ?? 2e3}`);
|
|
139
|
-
}
|
|
140
|
-
const REDIS_URL_ENV_REF = "${AGENTMEMORY_REDIS_URL}";
|
|
141
|
-
const UNSAFE_REDIS_URL_CHARS = /['\u0000-\u001f\u007f]/;
|
|
142
|
-
function replaceKvAdapterWithRedis(lines, workerName) {
|
|
143
|
-
const block = workerBlock(lines, workerName);
|
|
144
|
-
if (!block) throw new Error(`AGENTMEMORY_STATE_BACKEND=redis requires a "${workerName}" worker in the engine config, but none was found.`);
|
|
145
|
-
const adapterIndex = lines.findIndex((line, index) => index > block.start && index < block.end && line.trim() === "adapter:");
|
|
146
|
-
if (adapterIndex === -1) throw new Error(`AGENTMEMORY_STATE_BACKEND=redis requires an "adapter:" block under the "${workerName}" worker in the engine config, but none was found.`);
|
|
147
|
-
const adapterIndent = lines[adapterIndex].match(/^\s*/)?.[0] ?? "";
|
|
148
|
-
let end = block.end;
|
|
149
|
-
for (let i = adapterIndex + 1; i < block.end; i++) {
|
|
150
|
-
const line = lines[i];
|
|
151
|
-
if (line.trim() === "") continue;
|
|
152
|
-
if ((line.match(/^\s*/)?.[0] ?? "").length <= adapterIndent.length) {
|
|
153
|
-
end = i;
|
|
154
|
-
break;
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
const childIndent = `${adapterIndent} `;
|
|
158
|
-
const grandchildIndent = `${adapterIndent} `;
|
|
159
|
-
lines.splice(adapterIndex + 1, end - (adapterIndex + 1), `${childIndent}name: redis`, `${childIndent}config:`, `${grandchildIndent}redis_url: ${yamlSingleQuote(REDIS_URL_ENV_REF)}`);
|
|
160
|
-
}
|
|
161
|
-
function setManagedCorsOrigins(lines, restPort, viewerPort) {
|
|
162
|
-
const block = workerBlock(lines, "iii-http");
|
|
163
|
-
if (!block) return;
|
|
164
|
-
const originsIndex = lines.findIndex((line, index) => index > block.start && index < block.end && line.trim().startsWith("allowed_origins:"));
|
|
165
|
-
if (originsIndex === -1) return;
|
|
166
|
-
lines[originsIndex] = `${lines[originsIndex].match(/^\s*/)?.[0] ?? " "}allowed_origins: ["http://localhost:${restPort}", "http://localhost:${viewerPort}", "http://127.0.0.1:${restPort}", "http://127.0.0.1:${viewerPort}"]`;
|
|
167
|
-
}
|
|
168
|
-
function renderEngineConfig(template, options) {
|
|
169
|
-
if (options.stateBackend?.kind === "redis" && !options.stateBackend.redisUrl) throw new Error("AGENTMEMORY_STATE_BACKEND=redis requires AGENTMEMORY_REDIS_URL to be set (e.g. redis://localhost:6379).");
|
|
170
|
-
if (options.stateBackend?.kind === "redis" && UNSAFE_REDIS_URL_CHARS.test(options.stateBackend.redisUrl ?? "")) throw new Error("AGENTMEMORY_REDIS_URL contains a single quote or a control character, which breaks the engine config once the engine expands it. Percent-encode those characters in the URL (for example a single quote as %27).");
|
|
171
|
-
const rendered = template.replace("file_path: ./data/state_store.db", `file_path: ${yamlSingleQuote(join(options.dataDir, "state_store.db"))}`).replace("file_path: ./data/stream_store", `file_path: ${yamlSingleQuote(join(options.dataDir, "stream_store"))}`);
|
|
172
|
-
const usesRedis = options.stateBackend?.kind === "redis";
|
|
173
|
-
const lines = rendered.split("\n");
|
|
174
|
-
setFileStoreSaveInterval(lines, "iii-state", options.saveIntervalMs);
|
|
175
|
-
setFileStoreSaveInterval(lines, "iii-stream", options.saveIntervalMs);
|
|
176
|
-
if (options.ports) {
|
|
177
|
-
setWorkerPort(lines, "iii-http", options.ports.restPort);
|
|
178
|
-
setWorkerPort(lines, "iii-stream", options.ports.streamPort);
|
|
179
|
-
setWorkerPort(lines, "iii-worker-manager", options.ports.enginePort);
|
|
180
|
-
setManagedCorsOrigins(lines, options.ports.restPort, options.ports.viewerPort);
|
|
181
|
-
}
|
|
182
|
-
if (usesRedis) {
|
|
183
|
-
replaceKvAdapterWithRedis(lines, "iii-state");
|
|
184
|
-
replaceKvAdapterWithRedis(lines, "iii-stream");
|
|
185
|
-
}
|
|
186
|
-
return lines.join("\n");
|
|
187
|
-
}
|
|
188
|
-
//#endregion
|
|
189
|
-
//#region src/cli/engine-launch.ts
|
|
190
|
-
function agentmemoryHome(home) {
|
|
191
|
-
return join(home, ".agentmemory");
|
|
192
|
-
}
|
|
193
|
-
function runtimeConfigPath(dataDir) {
|
|
194
|
-
return join(dataDir, "iii-config.runtime.yaml");
|
|
195
|
-
}
|
|
196
|
-
function dockerProjectName(restPort) {
|
|
197
|
-
return `agentmemory-${restPort}`;
|
|
198
|
-
}
|
|
199
|
-
function dockerComposeArgs(composeFile, projectName, command) {
|
|
200
|
-
return [
|
|
201
|
-
"compose",
|
|
202
|
-
...projectName ? ["-p", projectName] : [],
|
|
203
|
-
"-f",
|
|
204
|
-
composeFile,
|
|
205
|
-
...command
|
|
206
|
-
];
|
|
207
|
-
}
|
|
208
|
-
function isBundledConfig(configPath, packageDir) {
|
|
209
|
-
const resolved = resolve(configPath);
|
|
210
|
-
return resolved === resolve(join(packageDir, "iii-config.yaml")) || resolved === resolve(join(packageDir, "..", "iii-config.yaml"));
|
|
211
|
-
}
|
|
212
|
-
function resolveEngineCwd(configPath, invocationCwd, home, bundledConfig = false) {
|
|
213
|
-
if (bundledConfig) return agentmemoryHome(home);
|
|
214
|
-
return dirname(isAbsolute(configPath) ? configPath : resolve(invocationCwd, configPath));
|
|
215
|
-
}
|
|
216
|
-
function indentation(line) {
|
|
217
|
-
return line.length - line.trimStart().length;
|
|
218
|
-
}
|
|
219
|
-
function yamlScalar(value) {
|
|
220
|
-
const trimmed = value.trim();
|
|
221
|
-
const first = trimmed[0];
|
|
222
|
-
const last = trimmed.at(-1);
|
|
223
|
-
if (first === "\"" && last === "\"" || first === "'" && last === "'") return trimmed.slice(1, -1);
|
|
224
|
-
return trimmed;
|
|
225
|
-
}
|
|
226
|
-
function isAgentmemoryExecCommand(line, nodeBin, workerEntry) {
|
|
227
|
-
const match = line.match(/^\s*-\s+(.+?)\s*$/);
|
|
228
|
-
if (!match) return false;
|
|
229
|
-
const command = yamlScalar(match[1]).replaceAll("\\", "/");
|
|
230
|
-
return command === `${nodeBin} ${workerEntry}`.replaceAll("\\", "/") || /^(?:node|node\.exe)\s+\.\/dist\/index\.mjs$/.test(command) || /^(?:node|node\.exe)\s+dist\/index\.mjs$/.test(command);
|
|
231
|
-
}
|
|
232
|
-
function removeAgentmemoryExecCommand(raw, nodeBin, workerEntry) {
|
|
233
|
-
const lines = raw.split("\n");
|
|
234
|
-
const output = [];
|
|
235
|
-
let index = 0;
|
|
236
|
-
while (index < lines.length) {
|
|
237
|
-
const line = lines[index];
|
|
238
|
-
if (line.trim() !== "- name: iii-exec") {
|
|
239
|
-
output.push(line);
|
|
240
|
-
index++;
|
|
241
|
-
continue;
|
|
242
|
-
}
|
|
243
|
-
const blockIndent = indentation(line);
|
|
244
|
-
let blockEnd = index + 1;
|
|
245
|
-
while (blockEnd < lines.length) {
|
|
246
|
-
const candidate = lines[blockEnd];
|
|
247
|
-
if (candidate.trim() !== "") {
|
|
248
|
-
const candidateIndent = indentation(candidate);
|
|
249
|
-
if (candidateIndent < blockIndent || candidateIndent === blockIndent && candidate.trim().startsWith("- name: ")) break;
|
|
250
|
-
}
|
|
251
|
-
blockEnd++;
|
|
252
|
-
}
|
|
253
|
-
const block = lines.slice(index, blockEnd);
|
|
254
|
-
const execIndex = block.findIndex((candidate) => candidate.trim() === "exec:");
|
|
255
|
-
if (execIndex === -1) {
|
|
256
|
-
output.push(...block);
|
|
257
|
-
index = blockEnd;
|
|
258
|
-
continue;
|
|
259
|
-
}
|
|
260
|
-
const execIndent = indentation(block[execIndex]);
|
|
261
|
-
let execEnd = execIndex + 1;
|
|
262
|
-
while (execEnd < block.length) {
|
|
263
|
-
const candidate = block[execEnd];
|
|
264
|
-
if (candidate.trim() !== "" && indentation(candidate) <= execIndent) break;
|
|
265
|
-
execEnd++;
|
|
266
|
-
}
|
|
267
|
-
const beforeExec = block.slice(0, execIndex + 1);
|
|
268
|
-
const execLines = block.slice(execIndex + 1, execEnd);
|
|
269
|
-
const afterExec = block.slice(execEnd);
|
|
270
|
-
const remainingExecLines = execLines.filter((candidate) => !isAgentmemoryExecCommand(candidate, nodeBin, workerEntry));
|
|
271
|
-
const removed = remainingExecLines.length !== execLines.length;
|
|
272
|
-
const hasExecCommand = remainingExecLines.some((candidate) => /^\s*-\s+/.test(candidate) && indentation(candidate) > execIndent);
|
|
273
|
-
if (!removed) output.push(...block);
|
|
274
|
-
else if (hasExecCommand) output.push(...beforeExec, ...remainingExecLines, ...afterExec);
|
|
275
|
-
index = blockEnd;
|
|
276
|
-
}
|
|
277
|
-
return output.join("\n");
|
|
278
|
-
}
|
|
279
|
-
function rewriteBundledConfig(raw, home, nodeBin, workerEntry, options) {
|
|
280
|
-
return removeAgentmemoryExecCommand(renderEngineConfig(raw, {
|
|
281
|
-
dataDir: options?.dataDir ?? join(agentmemoryHome(home), "data"),
|
|
282
|
-
...options?.ports ? { ports: options.ports } : {},
|
|
283
|
-
...options?.stateBackend ? { stateBackend: options.stateBackend } : {},
|
|
284
|
-
...options?.saveIntervalMs !== void 0 ? { saveIntervalMs: options.saveIntervalMs } : {}
|
|
285
|
-
}), nodeBin, workerEntry);
|
|
286
|
-
}
|
|
287
|
-
function legacyDataMigrations(invocationCwd, home, resolvedDataDir = join(agentmemoryHome(home), "data")) {
|
|
288
|
-
return [{
|
|
289
|
-
from: join(invocationCwd, "data", "state_store.db"),
|
|
290
|
-
to: join(resolvedDataDir, "state_store.db")
|
|
291
|
-
}, {
|
|
292
|
-
from: join(invocationCwd, "data", "stream_store"),
|
|
293
|
-
to: join(resolvedDataDir, "stream_store")
|
|
294
|
-
}];
|
|
295
|
-
}
|
|
296
|
-
function engineChildEnv(base, platform = process.platform) {
|
|
297
|
-
const env = {
|
|
298
|
-
...base,
|
|
299
|
-
III_TELEMETRY_ENABLED: base["III_TELEMETRY_ENABLED"] ?? "false"
|
|
300
|
-
};
|
|
301
|
-
if (platform === "linux" && !base.MALLOC_ARENA_MAX) env.MALLOC_ARENA_MAX = "2";
|
|
302
|
-
return env;
|
|
303
|
-
}
|
|
304
|
-
function resolveLaunchRenderFailure(stateBackendKind, err) {
|
|
305
|
-
if (stateBackendKind !== "redis") return { fatal: false };
|
|
306
|
-
return {
|
|
307
|
-
fatal: true,
|
|
308
|
-
message: `Failed to render the Redis state backend into the engine config: ${err instanceof Error ? err.message : String(err)} Refusing to start the engine, since it would silently fall back to the file (or in-memory) store instead of Redis. Fix the config or unset AGENTMEMORY_STATE_BACKEND to use the default file store.`
|
|
309
|
-
};
|
|
310
|
-
}
|
|
311
|
-
const CREDENTIAL_URL_PATTERN = /:\/\/[^@\s/]*@/g;
|
|
312
|
-
function redactCredentialUrls(text) {
|
|
313
|
-
return text.replace(CREDENTIAL_URL_PATTERN, "://***@");
|
|
314
|
-
}
|
|
315
|
-
//#endregion
|
|
316
|
-
//#region src/logger.ts
|
|
317
|
-
function fmt(level, msg, fields) {
|
|
318
|
-
if (!fields || Object.keys(fields).length === 0) return `[agentmemory] ${level} ${msg}`;
|
|
319
|
-
try {
|
|
320
|
-
return `[agentmemory] ${level} ${msg} ${JSON.stringify(fields)}`;
|
|
321
|
-
} catch {
|
|
322
|
-
return `[agentmemory] ${level} ${msg}`;
|
|
323
|
-
}
|
|
324
|
-
}
|
|
325
|
-
function emit(level, msg, fields) {
|
|
326
|
-
try {
|
|
327
|
-
process.stderr.write(fmt(level, msg, fields) + "\n");
|
|
328
|
-
} catch {}
|
|
329
|
-
}
|
|
330
|
-
const logger = {
|
|
331
|
-
info(msg, fields) {
|
|
332
|
-
emit("info", msg, fields);
|
|
333
|
-
},
|
|
334
|
-
warn(msg, fields) {
|
|
335
|
-
emit("warn", msg, fields);
|
|
336
|
-
},
|
|
337
|
-
error(msg, fields) {
|
|
338
|
-
emit("error", msg, fields);
|
|
339
|
-
}
|
|
340
|
-
};
|
|
341
|
-
let bootVerbose = process.env["AGENTMEMORY_VERBOSE"] === "1" || process.env["AGENTMEMORY_VERBOSE"] === "true";
|
|
342
|
-
const bootBuffer = [];
|
|
343
|
-
function setBootVerbose(enabled) {
|
|
344
|
-
bootVerbose = enabled;
|
|
345
|
-
}
|
|
346
|
-
function bootLog(msg) {
|
|
347
|
-
if (bootVerbose) {
|
|
348
|
-
try {
|
|
349
|
-
process.stderr.write(`[agentmemory] ${msg}\n`);
|
|
350
|
-
} catch {}
|
|
351
|
-
return;
|
|
352
|
-
}
|
|
353
|
-
if (bootBuffer.length < 500) bootBuffer.push(msg);
|
|
354
|
-
}
|
|
355
|
-
function bootWarn(msg) {
|
|
356
|
-
try {
|
|
357
|
-
process.stderr.write(`[agentmemory] warn ${msg}\n`);
|
|
358
|
-
} catch {}
|
|
359
|
-
}
|
|
360
|
-
//#endregion
|
|
361
8
|
//#region src/config.ts
|
|
9
|
+
const MAX_IMPORT_OBS_PER_SESSION = 5e3;
|
|
362
10
|
function safeParseInt(value, fallback) {
|
|
363
11
|
if (!value) return fallback;
|
|
364
12
|
const parsed = parseInt(value, 10);
|
|
365
13
|
return Number.isNaN(parsed) ? fallback : parsed;
|
|
366
14
|
}
|
|
367
|
-
const DATA_DIR = join(homedir(), ".agentmemory");
|
|
368
|
-
const ENV_FILE = join(
|
|
15
|
+
const DATA_DIR = process.env["AGENTMEMORY_DATA_DIR"] || join(homedir(), ".agentmemory");
|
|
16
|
+
const ENV_FILE = process.env["AGENTMEMORY_ENV_FILE"] || join(homedir(), ".agentmemory", ".env");
|
|
369
17
|
let warnPremiumModelShown = false;
|
|
370
18
|
let providerNoticeShown = false;
|
|
19
|
+
let obsCapImportCeilingWarned = false;
|
|
371
20
|
function writeProviderNoticeOnce(text) {
|
|
372
21
|
if (providerNoticeShown) return;
|
|
373
22
|
providerNoticeShown = true;
|
|
@@ -380,7 +29,10 @@ function loadEnvFile() {
|
|
|
380
29
|
envFileCache = {};
|
|
381
30
|
return envFileCache;
|
|
382
31
|
}
|
|
383
|
-
|
|
32
|
+
envFileCache = parseEnvContent(readFileSync(ENV_FILE, "utf-8"));
|
|
33
|
+
return envFileCache;
|
|
34
|
+
}
|
|
35
|
+
function parseEnvContent(content) {
|
|
384
36
|
const vars = {};
|
|
385
37
|
for (const line of content.split("\n")) {
|
|
386
38
|
const trimmed = line.trim();
|
|
@@ -399,61 +51,135 @@ function loadEnvFile() {
|
|
|
399
51
|
}
|
|
400
52
|
vars[key] = val;
|
|
401
53
|
}
|
|
402
|
-
|
|
403
|
-
return envFileCache;
|
|
54
|
+
return vars;
|
|
404
55
|
}
|
|
405
56
|
function hasRealValue(v) {
|
|
406
57
|
return typeof v === "string" && v.trim().length > 0;
|
|
407
58
|
}
|
|
408
59
|
function hydrateProcessEnvFromFile() {
|
|
60
|
+
const beforeHydration = { ...process.env };
|
|
409
61
|
for (const [k, v] of Object.entries(loadEnvFile())) if (process.env[k] === void 0) process.env[k] = v;
|
|
62
|
+
return beforeHydration;
|
|
63
|
+
}
|
|
64
|
+
function warnIfPremiumModel(env, envName, model) {
|
|
65
|
+
if (warnPremiumModelShown || !/sonnet|opus|gpt-5\.\d+-sol|gpt-4o(?!.*mini)|gpt-4-turbo/i.test(model) || env["AGENTMEMORY_SUPPRESS_COST_WARNING"] === "1" || env["AGENTMEMORY_SUPPRESS_COST_WARNING"] === "true") return;
|
|
66
|
+
warnPremiumModelShown = true;
|
|
67
|
+
process.stderr.write(`[agentmemory] ${envName}=${model} is in the premium tier. Background compression on this model can cost $5+/day under active use. Cheaper alternatives with comparable quality for memory compression: deepseek/deepseek-v4-flash-0731, deepseek/deepseek-v4-pro, qwen/qwen3-coder. See README "Cost-aware model selection" for the full table. Set AGENTMEMORY_SUPPRESS_COST_WARNING=1 to silence.\n`);
|
|
68
|
+
}
|
|
69
|
+
const LLM_PROVIDER_NAMES = [
|
|
70
|
+
"anthropic",
|
|
71
|
+
"openai",
|
|
72
|
+
"gemini",
|
|
73
|
+
"openrouter",
|
|
74
|
+
"minimax"
|
|
75
|
+
];
|
|
76
|
+
const LLM_PROVIDER_KEYS = {
|
|
77
|
+
anthropic: ["ANTHROPIC_API_KEY"],
|
|
78
|
+
openai: ["OPENAI_API_KEY"],
|
|
79
|
+
gemini: ["GEMINI_API_KEY", "GOOGLE_API_KEY"],
|
|
80
|
+
openrouter: ["OPENROUTER_API_KEY"],
|
|
81
|
+
minimax: ["MINIMAX_API_KEY"]
|
|
82
|
+
};
|
|
83
|
+
const REMOTE_EMBEDDING_PROVIDER_KEYS = {
|
|
84
|
+
gemini: ["GEMINI_API_KEY"],
|
|
85
|
+
openai: ["OPENAI_API_KEY", "OPENAI_EMBEDDING_API_KEY"],
|
|
86
|
+
voyage: ["VOYAGE_API_KEY"],
|
|
87
|
+
cohere: ["COHERE_API_KEY"],
|
|
88
|
+
openrouter: ["OPENROUTER_API_KEY"]
|
|
89
|
+
};
|
|
90
|
+
function isLlmProviderName(value) {
|
|
91
|
+
return LLM_PROVIDER_NAMES.includes(value);
|
|
92
|
+
}
|
|
93
|
+
function selectedLlmProviderValue(env) {
|
|
94
|
+
return (env["AGENTMEMORY_LLM_PROVIDER"] || "").trim().toLowerCase();
|
|
95
|
+
}
|
|
96
|
+
function llmProviderHasKey(env, name) {
|
|
97
|
+
return LLM_PROVIDER_KEYS[name].some((k) => hasRealValue(env[k]));
|
|
98
|
+
}
|
|
99
|
+
function envFileLabel(path = ENV_FILE) {
|
|
100
|
+
const home = homedir();
|
|
101
|
+
return path.startsWith(`${home}/`) ? `~${path.slice(home.length)}` : path;
|
|
102
|
+
}
|
|
103
|
+
function llmOptInHint(env = getMergedEnv()) {
|
|
104
|
+
const selected = selectedLlmProviderValue(env);
|
|
105
|
+
if (selected) {
|
|
106
|
+
if (!isLlmProviderName(selected)) return `AGENTMEMORY_LLM_PROVIDER=${selected} is not a known provider. Use one of: ${LLM_PROVIDER_NAMES.join(", ")}.`;
|
|
107
|
+
if (!llmProviderHasKey(env, selected)) return `AGENTMEMORY_LLM_PROVIDER=${selected} is set, but ${LLM_PROVIDER_KEYS[selected].join(" or ")} is not. Add the key to ${envFileLabel()}.`;
|
|
108
|
+
return null;
|
|
109
|
+
}
|
|
110
|
+
if (env["AGENTMEMORY_ALLOW_AGENT_SDK"] === "true") return null;
|
|
111
|
+
const withKey = LLM_PROVIDER_NAMES.filter((name) => llmProviderHasKey(env, name));
|
|
112
|
+
if (withKey.length === 0) return null;
|
|
113
|
+
return `Found ${withKey.flatMap((name) => LLM_PROVIDER_KEYS[name].filter((k) => hasRealValue(env[k]))).join(", ")}, but agentmemory sends nothing to an LLM provider until you choose one for it. To turn on LLM summaries and compression, add AGENTMEMORY_LLM_PROVIDER=${withKey[0]} to ${envFileLabel()}.`;
|
|
114
|
+
}
|
|
115
|
+
function embeddingOptInHint(env = getMergedEnv()) {
|
|
116
|
+
const chosen = (env["EMBEDDING_PROVIDER"] || "").trim().toLowerCase();
|
|
117
|
+
if (chosen) {
|
|
118
|
+
const keys = REMOTE_EMBEDDING_PROVIDER_KEYS[chosen];
|
|
119
|
+
if (keys && !keys.some((k) => hasRealValue(env[k]))) return `EMBEDDING_PROVIDER=${chosen} is set, but ${keys.join(" or ")} is not. Add the key to ${envFileLabel()}, or set EMBEDDING_PROVIDER=local for on-device embeddings.`;
|
|
120
|
+
return null;
|
|
121
|
+
}
|
|
122
|
+
const withKey = Object.keys(REMOTE_EMBEDDING_PROVIDER_KEYS).filter((name) => REMOTE_EMBEDDING_PROVIDER_KEYS[name].some((k) => hasRealValue(env[k])));
|
|
123
|
+
if (withKey.length === 0) return null;
|
|
124
|
+
return `A ${withKey.join("/")} key is present, but cloud embeddings stay off until you choose them. Add EMBEDDING_PROVIDER=${withKey[0]} to ${envFileLabel()}, or EMBEDDING_PROVIDER=local for on-device embeddings.`;
|
|
410
125
|
}
|
|
411
126
|
function detectProvider(env) {
|
|
412
127
|
const maxTokens = parseInt(env["MAX_TOKENS"] || "4096", 10);
|
|
413
|
-
|
|
414
|
-
provider: "
|
|
415
|
-
model:
|
|
416
|
-
maxTokens,
|
|
417
|
-
baseURL: env["OPENAI_BASE_URL"]
|
|
418
|
-
};
|
|
419
|
-
if (hasRealValue(env["MINIMAX_API_KEY"])) return {
|
|
420
|
-
provider: "minimax",
|
|
421
|
-
model: env["MINIMAX_MODEL"] || "MiniMax-M3",
|
|
128
|
+
const noop = {
|
|
129
|
+
provider: "noop",
|
|
130
|
+
model: "noop",
|
|
422
131
|
maxTokens
|
|
423
132
|
};
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
133
|
+
const selected = selectedLlmProviderValue(env);
|
|
134
|
+
if (selected) {
|
|
135
|
+
if (!isLlmProviderName(selected) || !llmProviderHasKey(env, selected)) {
|
|
136
|
+
writeProviderNoticeOnce(`[agentmemory] ${llmOptInHint(env)} Running zero-LLM.\n`);
|
|
137
|
+
return noop;
|
|
138
|
+
}
|
|
139
|
+
switch (selected) {
|
|
140
|
+
case "openai": {
|
|
141
|
+
const model = env["OPENAI_MODEL"] || "gpt-5.6-luna";
|
|
142
|
+
warnIfPremiumModel(env, "OPENAI_MODEL", model);
|
|
143
|
+
return {
|
|
144
|
+
provider: "openai",
|
|
145
|
+
model,
|
|
146
|
+
maxTokens,
|
|
147
|
+
baseURL: env["OPENAI_BASE_URL"]
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
case "minimax": return {
|
|
151
|
+
provider: "minimax",
|
|
152
|
+
model: env["MINIMAX_MODEL"] || "MiniMax-M3",
|
|
153
|
+
maxTokens
|
|
154
|
+
};
|
|
155
|
+
case "anthropic": return {
|
|
156
|
+
provider: "anthropic",
|
|
157
|
+
model: env["ANTHROPIC_MODEL"] || "claude-sonnet-5",
|
|
158
|
+
maxTokens,
|
|
159
|
+
baseURL: env["ANTHROPIC_BASE_URL"]
|
|
160
|
+
};
|
|
161
|
+
case "gemini":
|
|
162
|
+
if (!hasRealValue(env["GEMINI_API_KEY"])) process.stderr.write("[agentmemory] GOOGLE_API_KEY detected — treating as GEMINI_API_KEY. Set GEMINI_API_KEY in ~/.agentmemory/.env to silence this warning.\n");
|
|
163
|
+
return {
|
|
164
|
+
provider: "gemini",
|
|
165
|
+
model: env["GEMINI_MODEL"] || "gemini-3.7-flash",
|
|
166
|
+
maxTokens
|
|
167
|
+
};
|
|
168
|
+
case "openrouter": {
|
|
169
|
+
const model = env["OPENROUTER_MODEL"] || "anthropic/claude-sonnet-5";
|
|
170
|
+
warnIfPremiumModel(env, "OPENROUTER_MODEL", model);
|
|
171
|
+
return {
|
|
172
|
+
provider: "openrouter",
|
|
173
|
+
model,
|
|
174
|
+
maxTokens
|
|
175
|
+
};
|
|
176
|
+
}
|
|
443
177
|
}
|
|
444
|
-
return {
|
|
445
|
-
provider: "openrouter",
|
|
446
|
-
model,
|
|
447
|
-
maxTokens
|
|
448
|
-
};
|
|
449
178
|
}
|
|
450
179
|
if (!(env["AGENTMEMORY_ALLOW_AGENT_SDK"] === "true")) {
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
model: "noop",
|
|
455
|
-
maxTokens
|
|
456
|
-
};
|
|
180
|
+
const hint = llmOptInHint(env);
|
|
181
|
+
writeProviderNoticeOnce(hint ? `[agentmemory] ${hint}\n` : pc.dim("[agentmemory] No LLM provider chosen, so agentmemory runs zero-LLM: no LLM compression or summaries, and no session content leaves this machine for an LLM. Search uses BM25 plus any embedding provider you set with EMBEDDING_PROVIDER (EMBEDDING_PROVIDER=local runs on-device). To turn on LLM summaries, set AGENTMEMORY_LLM_PROVIDER (anthropic, openai, gemini, openrouter or minimax) and that provider's key in ~/.agentmemory/.env.\n"));
|
|
182
|
+
return noop;
|
|
457
183
|
}
|
|
458
184
|
writeProviderNoticeOnce("[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");
|
|
459
185
|
return {
|
|
@@ -466,16 +192,21 @@ function loadConfig() {
|
|
|
466
192
|
const env = getMergedEnv();
|
|
467
193
|
const provider = detectProvider(env);
|
|
468
194
|
const restPort = parseInt(env["III_REST_PORT"] || "3111", 10) || 3111;
|
|
469
|
-
const streamsPort = parseInt(env["III_STREAM_PORT"] || env["III_STREAMS_PORT"] || "", 10) || restPort + 1;
|
|
470
195
|
const viewerPort = parseInt(env["III_VIEWER_PORT"] || "", 10) || restPort + 2;
|
|
196
|
+
const engineUrl = env["III_ENGINE_URL"] || env["III_URL"] || `ws://localhost:${parseInt(env["III_ENGINE_PORT"] || "", 10) || restPort + 46023}`;
|
|
197
|
+
const maxObservationsPerSession = safeParseInt(env["MAX_OBS_PER_SESSION"], 500);
|
|
198
|
+
if (!obsCapImportCeilingWarned && (maxObservationsPerSession === 0 || maxObservationsPerSession > 5e3)) {
|
|
199
|
+
obsCapImportCeilingWarned = true;
|
|
200
|
+
const capDesc = maxObservationsPerSession === 0 ? "uncapped (0)" : String(maxObservationsPerSession);
|
|
201
|
+
process.stderr.write(`[agentmemory] WARNING: MAX_OBS_PER_SESSION is ${capDesc}, above the ${MAX_IMPORT_OBS_PER_SESSION}-per-session import ceiling (MAX_IMPORT_OBS_PER_SESSION). Sessions past that ceiling make every mem::export -> mem::import restore fail wholesale. Keep MAX_OBS_PER_SESSION at or below ${MAX_IMPORT_OBS_PER_SESSION} if you rely on export/import backups.\n`);
|
|
202
|
+
}
|
|
471
203
|
return {
|
|
472
|
-
engineUrl
|
|
204
|
+
engineUrl,
|
|
473
205
|
restPort,
|
|
474
|
-
streamsPort,
|
|
475
206
|
viewerPort,
|
|
476
207
|
provider,
|
|
477
208
|
tokenBudget: safeParseInt(env["TOKEN_BUDGET"], 2e3),
|
|
478
|
-
maxObservationsPerSession
|
|
209
|
+
maxObservationsPerSession,
|
|
479
210
|
compressionModel: provider.model,
|
|
480
211
|
dataDir: DATA_DIR
|
|
481
212
|
};
|
|
@@ -499,6 +230,11 @@ function getSessionSweepStaleHours() {
|
|
|
499
230
|
const parsed = parseInt(raw.trim(), 10);
|
|
500
231
|
return parsed > 0 ? parsed : 24;
|
|
501
232
|
}
|
|
233
|
+
function getFinalizeIdleMs() {
|
|
234
|
+
const raw = getMergedEnv()["AGENTMEMORY_FINALIZE_IDLE_MS"];
|
|
235
|
+
if (!raw || !/^\d+$/.test(raw.trim())) return 12e4;
|
|
236
|
+
return parseInt(raw.trim(), 10);
|
|
237
|
+
}
|
|
502
238
|
function isGraphCompactOnBootEnabled() {
|
|
503
239
|
return getMergedEnv()["AGENTMEMORY_GRAPH_COMPACT_ON_BOOT"] !== "false";
|
|
504
240
|
}
|
|
@@ -523,9 +259,21 @@ function getAuditMigrateMaxBytes() {
|
|
|
523
259
|
return safeParseInt(getMergedEnv()["AGENTMEMORY_AUDIT_MIGRATE_MAX_BYTES"], 32 * 1024 * 1024);
|
|
524
260
|
}
|
|
525
261
|
function detectLlmProviderKind(env = getMergedEnv()) {
|
|
526
|
-
|
|
262
|
+
const selected = selectedLlmProviderValue(env);
|
|
263
|
+
if (selected && isLlmProviderName(selected) && llmProviderHasKey(env, selected)) return "llm";
|
|
264
|
+
if (!selected && env["AGENTMEMORY_ALLOW_AGENT_SDK"] === "true") return "llm";
|
|
527
265
|
return "noop";
|
|
528
266
|
}
|
|
267
|
+
function describeLlmRoute(provider) {
|
|
268
|
+
if (provider.provider === "noop") return null;
|
|
269
|
+
const parts = [provider.provider, provider.model];
|
|
270
|
+
if (provider.baseURL) try {
|
|
271
|
+
parts.push(new URL(provider.baseURL).host);
|
|
272
|
+
} catch {
|
|
273
|
+
parts.push("custom base URL");
|
|
274
|
+
}
|
|
275
|
+
return parts.join(" · ");
|
|
276
|
+
}
|
|
529
277
|
function loadEmbeddingConfig() {
|
|
530
278
|
const env = getMergedEnv();
|
|
531
279
|
let bm25Weight = parseFloat(env["BM25_WEIGHT"] || "0.4");
|
|
@@ -539,15 +287,8 @@ function loadEmbeddingConfig() {
|
|
|
539
287
|
};
|
|
540
288
|
}
|
|
541
289
|
function detectEmbeddingProvider(env) {
|
|
542
|
-
const
|
|
543
|
-
|
|
544
|
-
if (forced) return forced;
|
|
545
|
-
if (source["GEMINI_API_KEY"]) return "gemini";
|
|
546
|
-
if (source["OPENAI_API_KEY"] || source["OPENAI_EMBEDDING_API_KEY"]) return "openai";
|
|
547
|
-
if (source["VOYAGE_API_KEY"]) return "voyage";
|
|
548
|
-
if (source["COHERE_API_KEY"]) return "cohere";
|
|
549
|
-
if (source["OPENROUTER_API_KEY"]) return "openrouter";
|
|
550
|
-
return null;
|
|
290
|
+
const forced = ((env ?? getMergedEnv())["EMBEDDING_PROVIDER"] || "").trim();
|
|
291
|
+
return forced ? forced : null;
|
|
551
292
|
}
|
|
552
293
|
function loadClaudeBridgeConfig() {
|
|
553
294
|
const env = getMergedEnv();
|
|
@@ -613,20 +354,6 @@ const FOLLOWUP_WINDOW_DEFAULT_SECONDS = 30;
|
|
|
613
354
|
function getFollowupWindowSeconds() {
|
|
614
355
|
return safeParseInt(getMergedEnv()["AGENTMEMORY_FOLLOWUP_WINDOW_SECONDS"], FOLLOWUP_WINDOW_DEFAULT_SECONDS);
|
|
615
356
|
}
|
|
616
|
-
const VIEWER_STREAM_MAX_DEFAULT = 500;
|
|
617
|
-
const VIEWER_STREAM_MAX_FLOOR = 200;
|
|
618
|
-
function parseExactInt(value, fallback) {
|
|
619
|
-
if (!value) return fallback;
|
|
620
|
-
const trimmed = value.trim();
|
|
621
|
-
if (!/^-?\d+$/.test(trimmed)) return fallback;
|
|
622
|
-
const parsed = Number(trimmed);
|
|
623
|
-
return Number.isSafeInteger(parsed) ? parsed : fallback;
|
|
624
|
-
}
|
|
625
|
-
function getViewerStreamMax() {
|
|
626
|
-
const parsed = parseExactInt(getMergedEnv()["AGENTMEMORY_VIEWER_STREAM_MAX"], VIEWER_STREAM_MAX_DEFAULT);
|
|
627
|
-
if (parsed < 0) return VIEWER_STREAM_MAX_DEFAULT;
|
|
628
|
-
return Math.max(parsed, VIEWER_STREAM_MAX_FLOOR);
|
|
629
|
-
}
|
|
630
357
|
function isConsolidationEnabled() {
|
|
631
358
|
const env = getMergedEnv();
|
|
632
359
|
const explicit = env["CONSOLIDATION_ENABLED"];
|
|
@@ -659,9 +386,13 @@ function getIndexSaveIntervalMs() {
|
|
|
659
386
|
const raw = safeParseInt(getMergedEnv()["AGENTMEMORY_INDEX_SAVE_INTERVAL_MS"], INDEX_SAVE_INTERVAL_DEFAULT_MS);
|
|
660
387
|
return raw > 0 ? raw : INDEX_SAVE_INTERVAL_DEFAULT_MS;
|
|
661
388
|
}
|
|
389
|
+
const STATE_SAVE_INTERVAL_DEFAULT_MS = 2e3;
|
|
662
390
|
function getStateSaveIntervalMs() {
|
|
663
|
-
const
|
|
664
|
-
|
|
391
|
+
const value = getMergedEnv()["AGENTMEMORY_STATE_SAVE_INTERVAL_MS"];
|
|
392
|
+
if (value === void 0 || value.trim() === "") return STATE_SAVE_INTERVAL_DEFAULT_MS;
|
|
393
|
+
if (!/^\d+$/.test(value.trim())) return STATE_SAVE_INTERVAL_DEFAULT_MS;
|
|
394
|
+
const raw = Number(value);
|
|
395
|
+
return Number.isSafeInteger(raw) && raw >= 100 && raw <= 36e5 ? raw : STATE_SAVE_INTERVAL_DEFAULT_MS;
|
|
665
396
|
}
|
|
666
397
|
function getVectorBucketSize() {
|
|
667
398
|
const raw = safeParseInt(getMergedEnv()["AGENTMEMORY_VECTOR_BUCKET_SIZE"], 500);
|
|
@@ -698,15 +429,158 @@ function loadFallbackConfig() {
|
|
|
698
429
|
}) };
|
|
699
430
|
}
|
|
700
431
|
//#endregion
|
|
432
|
+
//#region src/cli/engine-launch.ts
|
|
433
|
+
function runtimeConfigPath(dataDir) {
|
|
434
|
+
return join(dataDir, "iii-config.runtime.yaml");
|
|
435
|
+
}
|
|
436
|
+
const CREDENTIAL_URL_PATTERN = /:\/\/[^@\s/]*@/g;
|
|
437
|
+
function redactCredentialUrls(text) {
|
|
438
|
+
return text.replace(CREDENTIAL_URL_PATTERN, "://***@");
|
|
439
|
+
}
|
|
440
|
+
//#endregion
|
|
441
|
+
//#region src/cli/engine-config.ts
|
|
442
|
+
const ENGINE_DEFAULT_SAVE_INTERVAL_MS = 5e3;
|
|
443
|
+
const ENGINE_FLUSH_MARGIN_MS = 1500;
|
|
444
|
+
function engineFlushWaitMs(stateBackend, configTexts) {
|
|
445
|
+
if (stateBackend === "redis") return 0;
|
|
446
|
+
return engineSaveIntervalMs(configTexts) + ENGINE_FLUSH_MARGIN_MS;
|
|
447
|
+
}
|
|
448
|
+
function captureDurableAfterMs(stateBackend, configTexts) {
|
|
449
|
+
if (stateBackend === "redis") return ENGINE_FLUSH_MARGIN_MS;
|
|
450
|
+
return engineSaveIntervalMs(configTexts) + ENGINE_FLUSH_MARGIN_MS;
|
|
451
|
+
}
|
|
452
|
+
function engineSaveIntervalMs(configTexts, env = process.env) {
|
|
453
|
+
const intervals = [];
|
|
454
|
+
for (const text of configTexts) {
|
|
455
|
+
const explicit = [];
|
|
456
|
+
for (const match of text.matchAll(/save_interval_ms:\s*["']?(\d+|\$\{([A-Za-z_][A-Za-z0-9_]*)(?::-(\d+))?\})/g)) {
|
|
457
|
+
const raw = match[2] ? env[match[2]] || match[3] : match[1];
|
|
458
|
+
if (raw && /^\d+$/.test(raw) && Number.isSafeInteger(Number(raw))) explicit.push(Number(raw));
|
|
459
|
+
}
|
|
460
|
+
intervals.push(...explicit);
|
|
461
|
+
if ((text.match(/store_method:\s*file_based/g)?.length ?? 0) > explicit.length) intervals.push(ENGINE_DEFAULT_SAVE_INTERVAL_MS);
|
|
462
|
+
}
|
|
463
|
+
return intervals.length > 0 ? Math.max(...intervals) : ENGINE_DEFAULT_SAVE_INTERVAL_MS;
|
|
464
|
+
}
|
|
465
|
+
function engineStateConfigPaths(engineCwd, runtimePath) {
|
|
466
|
+
return [...new Set([
|
|
467
|
+
join(engineCwd, "compose", "worker-compose.yaml"),
|
|
468
|
+
join(engineCwd, "compose", "config", "state.yaml"),
|
|
469
|
+
join(engineCwd, "worker-compose.runtime.yaml"),
|
|
470
|
+
join(engineCwd, "config", "state.yaml"),
|
|
471
|
+
runtimePath
|
|
472
|
+
])];
|
|
473
|
+
}
|
|
474
|
+
//#endregion
|
|
475
|
+
//#region src/logger.ts
|
|
476
|
+
function fmt(level, msg, fields) {
|
|
477
|
+
if (!fields || Object.keys(fields).length === 0) return `[agentmemory] ${level} ${msg}`;
|
|
478
|
+
try {
|
|
479
|
+
return `[agentmemory] ${level} ${msg} ${JSON.stringify(fields)}`;
|
|
480
|
+
} catch {
|
|
481
|
+
return `[agentmemory] ${level} ${msg}`;
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
function emit(level, msg, fields) {
|
|
485
|
+
try {
|
|
486
|
+
const line = fmt(level, msg, fields) + "\n";
|
|
487
|
+
if (level === "error" || process.env["AGENTMEMORY_MCP_STDIO__"] === "1") process.stderr.write(line);
|
|
488
|
+
else process.stdout.write(line);
|
|
489
|
+
} catch {}
|
|
490
|
+
}
|
|
491
|
+
const logger = {
|
|
492
|
+
info(msg, fields) {
|
|
493
|
+
emit("info", msg, fields);
|
|
494
|
+
},
|
|
495
|
+
warn(msg, fields) {
|
|
496
|
+
emit("warn", msg, fields);
|
|
497
|
+
},
|
|
498
|
+
error(msg, fields) {
|
|
499
|
+
emit("error", msg, fields);
|
|
500
|
+
}
|
|
501
|
+
};
|
|
502
|
+
let bootVerbose = process.env["AGENTMEMORY_VERBOSE"] === "1" || process.env["AGENTMEMORY_VERBOSE"] === "true";
|
|
503
|
+
const bootBuffer = [];
|
|
504
|
+
function setBootVerbose(enabled) {
|
|
505
|
+
bootVerbose = enabled;
|
|
506
|
+
}
|
|
507
|
+
function bootLog(msg) {
|
|
508
|
+
if (bootVerbose) {
|
|
509
|
+
try {
|
|
510
|
+
process.stderr.write(`[agentmemory] ${msg}\n`);
|
|
511
|
+
} catch {}
|
|
512
|
+
return;
|
|
513
|
+
}
|
|
514
|
+
if (bootBuffer.length < 500) bootBuffer.push(msg);
|
|
515
|
+
}
|
|
516
|
+
function bootWarn(msg) {
|
|
517
|
+
try {
|
|
518
|
+
process.stderr.write(`[agentmemory] warn ${msg}\n`);
|
|
519
|
+
} catch {}
|
|
520
|
+
}
|
|
521
|
+
//#endregion
|
|
701
522
|
//#region src/version.ts
|
|
702
|
-
const VERSION = "0.9.
|
|
703
|
-
const III_PINNED_VERSION = "0.
|
|
523
|
+
const VERSION = "0.9.32";
|
|
524
|
+
const III_PINNED_VERSION = "0.25.0";
|
|
704
525
|
//#endregion
|
|
705
526
|
//#region src/mcp/tools-registry.ts
|
|
527
|
+
const READ_ONLY_TOOLS = new Set([
|
|
528
|
+
"memory_recall",
|
|
529
|
+
"memory_file_history",
|
|
530
|
+
"memory_patterns",
|
|
531
|
+
"memory_sessions",
|
|
532
|
+
"memory_smart_search",
|
|
533
|
+
"memory_vision_search",
|
|
534
|
+
"memory_timeline",
|
|
535
|
+
"memory_export",
|
|
536
|
+
"memory_relations",
|
|
537
|
+
"memory_commit_lookup",
|
|
538
|
+
"memory_commits",
|
|
539
|
+
"memory_graph_query",
|
|
540
|
+
"memory_team_feed",
|
|
541
|
+
"memory_audit",
|
|
542
|
+
"memory_frontier",
|
|
543
|
+
"memory_next",
|
|
544
|
+
"memory_diagnose",
|
|
545
|
+
"memory_facet_query",
|
|
546
|
+
"memory_verify",
|
|
547
|
+
"memory_lesson_recall",
|
|
548
|
+
"memory_insight_list",
|
|
549
|
+
"memory_slot_list",
|
|
550
|
+
"memory_slot_get"
|
|
551
|
+
]);
|
|
552
|
+
const DESTRUCTIVE_TOOLS = new Set([
|
|
553
|
+
"memory_action_update",
|
|
554
|
+
"memory_compress_file",
|
|
555
|
+
"memory_claude_bridge_sync",
|
|
556
|
+
"memory_governance_delete",
|
|
557
|
+
"memory_heal",
|
|
558
|
+
"memory_lesson_delete",
|
|
559
|
+
"memory_obsidian_export",
|
|
560
|
+
"memory_slot_replace",
|
|
561
|
+
"memory_slot_delete"
|
|
562
|
+
]);
|
|
563
|
+
const IDEMPOTENT_WRITE_TOOLS = new Set([
|
|
564
|
+
"memory_governance_delete",
|
|
565
|
+
"memory_lesson_delete",
|
|
566
|
+
"memory_slot_replace",
|
|
567
|
+
"memory_slot_delete",
|
|
568
|
+
"memory_claude_bridge_sync"
|
|
569
|
+
]);
|
|
570
|
+
const OPEN_WORLD_TOOLS = new Set(["memory_mesh_sync"]);
|
|
571
|
+
function toolAnnotations(name) {
|
|
572
|
+
const readOnly = READ_ONLY_TOOLS.has(name);
|
|
573
|
+
return {
|
|
574
|
+
readOnlyHint: readOnly,
|
|
575
|
+
destructiveHint: !readOnly && DESTRUCTIVE_TOOLS.has(name),
|
|
576
|
+
idempotentHint: readOnly || IDEMPOTENT_WRITE_TOOLS.has(name),
|
|
577
|
+
openWorldHint: OPEN_WORLD_TOOLS.has(name)
|
|
578
|
+
};
|
|
579
|
+
}
|
|
706
580
|
const CORE_TOOLS = [
|
|
707
581
|
{
|
|
708
582
|
name: "memory_recall",
|
|
709
|
-
description: "Search
|
|
583
|
+
description: "Search stored memories and session observations for relevant context. Use when you need to recall what happened in previous sessions, find past decisions, or look up how a file was modified before.",
|
|
710
584
|
inputSchema: {
|
|
711
585
|
type: "object",
|
|
712
586
|
properties: {
|
|
@@ -724,7 +598,28 @@ const CORE_TOOLS = [
|
|
|
724
598
|
},
|
|
725
599
|
token_budget: {
|
|
726
600
|
type: "number",
|
|
727
|
-
description: "Optional token budget
|
|
601
|
+
description: "Optional estimated content token budget; response includes truncation and recovery metadata"
|
|
602
|
+
},
|
|
603
|
+
targetLayer: {
|
|
604
|
+
type: "string",
|
|
605
|
+
enum: [
|
|
606
|
+
"all",
|
|
607
|
+
"memory",
|
|
608
|
+
"observation"
|
|
609
|
+
],
|
|
610
|
+
description: "Search all indexed layers (default), durable memories, or raw observations before ranking"
|
|
611
|
+
},
|
|
612
|
+
project: {
|
|
613
|
+
type: "string",
|
|
614
|
+
description: "Filter by project path"
|
|
615
|
+
},
|
|
616
|
+
cwd: {
|
|
617
|
+
type: "string",
|
|
618
|
+
description: "Filter by session working directory"
|
|
619
|
+
},
|
|
620
|
+
agentId: {
|
|
621
|
+
type: "string",
|
|
622
|
+
description: "Filter by owning agent; '*' reads across agents"
|
|
728
623
|
}
|
|
729
624
|
},
|
|
730
625
|
required: ["query"]
|
|
@@ -813,15 +708,32 @@ const CORE_TOOLS = [
|
|
|
813
708
|
},
|
|
814
709
|
{
|
|
815
710
|
name: "memory_sessions",
|
|
816
|
-
description: "List recent sessions with
|
|
711
|
+
description: "List recent sessions with status, observation counts, summaries and a continuation cursor. Filters apply before pagination; retain them when requesting the next page.",
|
|
817
712
|
inputSchema: {
|
|
818
713
|
type: "object",
|
|
819
|
-
properties: {
|
|
714
|
+
properties: {
|
|
715
|
+
project: {
|
|
716
|
+
type: "string",
|
|
717
|
+
description: "Exact project identifier used when sessions were started"
|
|
718
|
+
},
|
|
719
|
+
agentId: {
|
|
720
|
+
type: "string",
|
|
721
|
+
description: "Filter by owning agent; '*' reads across agents"
|
|
722
|
+
},
|
|
723
|
+
limit: {
|
|
724
|
+
type: "integer",
|
|
725
|
+
description: "Page size (default 20, max 100)"
|
|
726
|
+
},
|
|
727
|
+
cursor: {
|
|
728
|
+
type: "string",
|
|
729
|
+
description: "nextCursor from the previous page; omit for the first page"
|
|
730
|
+
}
|
|
731
|
+
}
|
|
820
732
|
}
|
|
821
733
|
},
|
|
822
734
|
{
|
|
823
735
|
name: "memory_smart_search",
|
|
824
|
-
description: "Hybrid semantic+keyword search with progressive disclosure.",
|
|
736
|
+
description: "Hybrid semantic+keyword search with progressive disclosure. Pass query to search, or expandIds to recover full results.",
|
|
825
737
|
inputSchema: {
|
|
826
738
|
type: "object",
|
|
827
739
|
properties: {
|
|
@@ -831,14 +743,34 @@ const CORE_TOOLS = [
|
|
|
831
743
|
},
|
|
832
744
|
expandIds: {
|
|
833
745
|
type: "string",
|
|
834
|
-
description: "Comma-separated observation IDs to expand"
|
|
746
|
+
description: "Comma-separated memory or observation IDs to expand; query is optional when provided"
|
|
835
747
|
},
|
|
836
748
|
limit: {
|
|
837
749
|
type: "number",
|
|
838
750
|
description: "Max results (default 10)"
|
|
751
|
+
},
|
|
752
|
+
targetLayer: {
|
|
753
|
+
type: "string",
|
|
754
|
+
enum: [
|
|
755
|
+
"all",
|
|
756
|
+
"memory",
|
|
757
|
+
"observation"
|
|
758
|
+
],
|
|
759
|
+
description: "Search all indexed layers (default), durable memories, or raw observations before ranking"
|
|
760
|
+
},
|
|
761
|
+
project: {
|
|
762
|
+
type: "string",
|
|
763
|
+
description: "Filter by project path"
|
|
764
|
+
},
|
|
765
|
+
agentId: {
|
|
766
|
+
type: "string",
|
|
767
|
+
description: "Filter by owning agent; '*' reads across agents"
|
|
768
|
+
},
|
|
769
|
+
includeLessons: {
|
|
770
|
+
type: "boolean",
|
|
771
|
+
description: "Include lesson matches when targetLayer is all (default true)"
|
|
839
772
|
}
|
|
840
|
-
}
|
|
841
|
-
required: ["query"]
|
|
773
|
+
}
|
|
842
774
|
}
|
|
843
775
|
},
|
|
844
776
|
{
|
|
@@ -916,10 +848,31 @@ const CORE_TOOLS = [
|
|
|
916
848
|
},
|
|
917
849
|
{
|
|
918
850
|
name: "memory_export",
|
|
919
|
-
description: "Export
|
|
851
|
+
description: "Export memory data as JSON. Past the transport size limit the export is refused, so use the paging arguments on a large store.",
|
|
920
852
|
inputSchema: {
|
|
921
853
|
type: "object",
|
|
922
|
-
properties: {
|
|
854
|
+
properties: {
|
|
855
|
+
maxSessions: {
|
|
856
|
+
type: "number",
|
|
857
|
+
description: "Sessions per page (with their observations)"
|
|
858
|
+
},
|
|
859
|
+
offset: {
|
|
860
|
+
type: "number",
|
|
861
|
+
description: "Session offset"
|
|
862
|
+
},
|
|
863
|
+
collectionLimit: {
|
|
864
|
+
type: "number",
|
|
865
|
+
description: "Rows per page for memories, summaries, graphNodes, lessons and the other top-level collections; access logs follow the memories on the page. Sessions and their observations are paged only by maxSessions and offset, so pass collections to leave them out of each page"
|
|
866
|
+
},
|
|
867
|
+
collectionOffset: {
|
|
868
|
+
type: "number",
|
|
869
|
+
description: "Row offset for the top-level collections"
|
|
870
|
+
},
|
|
871
|
+
collections: {
|
|
872
|
+
type: "string",
|
|
873
|
+
description: "Comma-separated collections to return, e.g. memories,lessons. Sessions and their observations come back only when the list names sessions, access logs only together with memories. Unknown names are ignored. Omit for everything. A paged or selected export cannot be imported with strategy replace."
|
|
874
|
+
}
|
|
875
|
+
}
|
|
923
876
|
}
|
|
924
877
|
},
|
|
925
878
|
{
|
|
@@ -1604,6 +1557,11 @@ const V070_TOOLS = [
|
|
|
1604
1557
|
tags: {
|
|
1605
1558
|
type: "string",
|
|
1606
1559
|
description: "Comma-separated tags"
|
|
1560
|
+
},
|
|
1561
|
+
sourceIds: {
|
|
1562
|
+
type: "array",
|
|
1563
|
+
items: { type: "string" },
|
|
1564
|
+
description: "Ids of the session, memory, observation or crystal this lesson came from (max 50)"
|
|
1607
1565
|
}
|
|
1608
1566
|
},
|
|
1609
1567
|
required: ["content"]
|
|
@@ -1826,7 +1784,10 @@ function getAllTools() {
|
|
|
1826
1784
|
...V070_TOOLS,
|
|
1827
1785
|
...V073_TOOLS,
|
|
1828
1786
|
...V010_SLOTS_TOOLS
|
|
1829
|
-
]
|
|
1787
|
+
].map((tool) => ({
|
|
1788
|
+
...tool,
|
|
1789
|
+
annotations: toolAnnotations(tool.name)
|
|
1790
|
+
}));
|
|
1830
1791
|
}
|
|
1831
1792
|
function getVisibleTools() {
|
|
1832
1793
|
if ((process.env["AGENTMEMORY_TOOLS"] || "all") === "core") return getAllTools().filter((t) => ESSENTIAL_TOOLS.has(t.name));
|
|
@@ -1925,7 +1886,7 @@ async function auditMigrationDeleteDelayMs() {
|
|
|
1925
1886
|
const dataDir = getEnvVar("AGENTMEMORY_DATA_DIR");
|
|
1926
1887
|
if (!dataDir) return ENGINE_DEFAULT_SAVE_INTERVAL_MS * AUDIT_MIGRATION_DELETE_WAIT_INTERVALS;
|
|
1927
1888
|
const configTexts = [];
|
|
1928
|
-
for (const path of engineStateConfigPaths(
|
|
1889
|
+
for (const path of engineStateConfigPaths(dataDir, runtimeConfigPath(dataDir))) try {
|
|
1929
1890
|
configTexts.push(await readFile(path, "utf-8"));
|
|
1930
1891
|
} catch {}
|
|
1931
1892
|
return engineSaveIntervalMs(configTexts) * AUDIT_MIGRATION_DELETE_WAIT_INTERVALS;
|
|
@@ -2224,10 +2185,244 @@ async function runAuditRetentionSweep(kv, retentionMonths) {
|
|
|
2224
2185
|
};
|
|
2225
2186
|
}
|
|
2226
2187
|
//#endregion
|
|
2188
|
+
//#region src/state/search-layer.ts
|
|
2189
|
+
function isSearchLayer(value) {
|
|
2190
|
+
return value === "all" || value === "memory" || value === "observation";
|
|
2191
|
+
}
|
|
2192
|
+
function isSearchResultLayer(value) {
|
|
2193
|
+
return value === "memory" || value === "observation" || value === "lesson" || value === "insight";
|
|
2194
|
+
}
|
|
2195
|
+
function getSearchResultLayer(obsId, sessionId) {
|
|
2196
|
+
if (obsId.startsWith("mem_")) return "memory";
|
|
2197
|
+
if (sessionId === "lesson" || obsId.startsWith("lsn_")) return "lesson";
|
|
2198
|
+
if (sessionId === "insight" || obsId.startsWith("ins_")) return "insight";
|
|
2199
|
+
return "observation";
|
|
2200
|
+
}
|
|
2201
|
+
function matchesSearchLayer(obsId, sessionId, targetLayer = "all", layer) {
|
|
2202
|
+
return targetLayer === "all" || (layer ?? getSearchResultLayer(obsId, sessionId)) === targetLayer;
|
|
2203
|
+
}
|
|
2204
|
+
//#endregion
|
|
2205
|
+
//#region src/state/memory-utils.ts
|
|
2206
|
+
const MAX_DATE_MS = 864e13;
|
|
2207
|
+
function supersededAt(previous, now) {
|
|
2208
|
+
const prior = previous ? Date.parse(previous) : NaN;
|
|
2209
|
+
const current = Date.parse(now);
|
|
2210
|
+
if (Number.isNaN(prior) || current > prior) return now;
|
|
2211
|
+
return new Date(Math.min(prior + 1, MAX_DATE_MS)).toISOString();
|
|
2212
|
+
}
|
|
2213
|
+
function memoryToObservation(memory) {
|
|
2214
|
+
return {
|
|
2215
|
+
id: memory.id,
|
|
2216
|
+
sessionId: memory.sessionIds?.[0] ?? "memory",
|
|
2217
|
+
timestamp: memory.createdAt,
|
|
2218
|
+
type: "decision",
|
|
2219
|
+
memoryType: memory.type,
|
|
2220
|
+
title: memory.title,
|
|
2221
|
+
facts: [memory.content],
|
|
2222
|
+
narrative: memory.content,
|
|
2223
|
+
concepts: memory.concepts,
|
|
2224
|
+
files: memory.files,
|
|
2225
|
+
importance: memory.strength,
|
|
2226
|
+
...memory.agentId ? { agentId: memory.agentId } : {}
|
|
2227
|
+
};
|
|
2228
|
+
}
|
|
2229
|
+
function lessonToObservation(l) {
|
|
2230
|
+
return {
|
|
2231
|
+
id: l.id,
|
|
2232
|
+
sessionId: "lesson",
|
|
2233
|
+
timestamp: l.createdAt,
|
|
2234
|
+
type: "decision",
|
|
2235
|
+
title: l.content.slice(0, 120),
|
|
2236
|
+
facts: [l.content],
|
|
2237
|
+
narrative: l.context || "",
|
|
2238
|
+
concepts: l.tags,
|
|
2239
|
+
files: [],
|
|
2240
|
+
importance: l.confidence
|
|
2241
|
+
};
|
|
2242
|
+
}
|
|
2243
|
+
function observationEmbedText(record) {
|
|
2244
|
+
return [
|
|
2245
|
+
record.title,
|
|
2246
|
+
...record.concepts || [],
|
|
2247
|
+
record.narrative || ""
|
|
2248
|
+
].filter((part) => part && part.trim()).join(" ").trim();
|
|
2249
|
+
}
|
|
2250
|
+
//#endregion
|
|
2251
|
+
//#region src/functions/recall-response.ts
|
|
2252
|
+
function estimateTokens(value) {
|
|
2253
|
+
return Math.max(1, Math.ceil(JSON.stringify(value).length / 3));
|
|
2254
|
+
}
|
|
2255
|
+
function prefix(text, length) {
|
|
2256
|
+
let end = Math.min(length, text.length);
|
|
2257
|
+
if (end > 0 && end < text.length && /[\uD800-\uDBFF]/.test(text[end - 1])) end--;
|
|
2258
|
+
return text.slice(0, end);
|
|
2259
|
+
}
|
|
2260
|
+
function fitText(text, budget, makeResult) {
|
|
2261
|
+
let low = 0;
|
|
2262
|
+
let high = text.length;
|
|
2263
|
+
while (low < high) {
|
|
2264
|
+
const middle = Math.ceil((low + high) / 2);
|
|
2265
|
+
if (estimateTokens(makeResult(prefix(text, middle))) <= budget) low = middle;
|
|
2266
|
+
else high = middle - 1;
|
|
2267
|
+
}
|
|
2268
|
+
return makeResult(prefix(text, low));
|
|
2269
|
+
}
|
|
2270
|
+
function formatResult(result, format) {
|
|
2271
|
+
if (format === "full") return result;
|
|
2272
|
+
const observation = result.observation;
|
|
2273
|
+
const compact = {
|
|
2274
|
+
obsId: observation.id,
|
|
2275
|
+
sessionId: result.sessionId,
|
|
2276
|
+
title: observation.title,
|
|
2277
|
+
type: observation.type,
|
|
2278
|
+
...observation.memoryType !== void 0 && { memoryType: observation.memoryType },
|
|
2279
|
+
score: result.score,
|
|
2280
|
+
timestamp: observation.timestamp,
|
|
2281
|
+
...result.layer !== void 0 && { layer: result.layer }
|
|
2282
|
+
};
|
|
2283
|
+
if (format === "compact") return compact;
|
|
2284
|
+
const { type: _type, ...narrative } = compact;
|
|
2285
|
+
return {
|
|
2286
|
+
...narrative,
|
|
2287
|
+
narrative: observation.narrative
|
|
2288
|
+
};
|
|
2289
|
+
}
|
|
2290
|
+
function clipResult(result, format, budget) {
|
|
2291
|
+
const observation = result.observation;
|
|
2292
|
+
const layer = result.layer !== void 0 ? { layer: result.layer } : {};
|
|
2293
|
+
if (format === "compact") {
|
|
2294
|
+
const base = {
|
|
2295
|
+
obsId: observation.id,
|
|
2296
|
+
sessionId: result.sessionId,
|
|
2297
|
+
title: "",
|
|
2298
|
+
type: observation.type,
|
|
2299
|
+
...observation.memoryType !== void 0 && { memoryType: observation.memoryType },
|
|
2300
|
+
score: result.score,
|
|
2301
|
+
timestamp: observation.timestamp,
|
|
2302
|
+
...layer,
|
|
2303
|
+
content_truncated: true
|
|
2304
|
+
};
|
|
2305
|
+
const minimum = estimateTokens(base);
|
|
2306
|
+
if (minimum > budget) return { minimum };
|
|
2307
|
+
return {
|
|
2308
|
+
result: fitText(observation.title, budget, (title) => ({
|
|
2309
|
+
...base,
|
|
2310
|
+
title
|
|
2311
|
+
})),
|
|
2312
|
+
minimum
|
|
2313
|
+
};
|
|
2314
|
+
}
|
|
2315
|
+
const makeResult = (title, narrative) => {
|
|
2316
|
+
if (format === "narrative") return {
|
|
2317
|
+
obsId: observation.id,
|
|
2318
|
+
sessionId: result.sessionId,
|
|
2319
|
+
title,
|
|
2320
|
+
narrative,
|
|
2321
|
+
...observation.memoryType !== void 0 && { memoryType: observation.memoryType },
|
|
2322
|
+
score: result.score,
|
|
2323
|
+
timestamp: observation.timestamp,
|
|
2324
|
+
...layer,
|
|
2325
|
+
content_truncated: true
|
|
2326
|
+
};
|
|
2327
|
+
return {
|
|
2328
|
+
observation: {
|
|
2329
|
+
id: observation.id,
|
|
2330
|
+
sessionId: observation.sessionId,
|
|
2331
|
+
timestamp: observation.timestamp,
|
|
2332
|
+
type: observation.type,
|
|
2333
|
+
...observation.memoryType !== void 0 && { memoryType: observation.memoryType },
|
|
2334
|
+
title,
|
|
2335
|
+
facts: [],
|
|
2336
|
+
narrative,
|
|
2337
|
+
concepts: [],
|
|
2338
|
+
files: [],
|
|
2339
|
+
importance: observation.importance,
|
|
2340
|
+
...observation.confidence !== void 0 && { confidence: observation.confidence },
|
|
2341
|
+
...observation.agentId !== void 0 && { agentId: observation.agentId },
|
|
2342
|
+
...observation.origin && { origin: {
|
|
2343
|
+
channel: observation.origin.channel,
|
|
2344
|
+
capturedAt: observation.origin.capturedAt
|
|
2345
|
+
} }
|
|
2346
|
+
},
|
|
2347
|
+
score: result.score,
|
|
2348
|
+
sessionId: result.sessionId,
|
|
2349
|
+
...layer,
|
|
2350
|
+
content_truncated: true
|
|
2351
|
+
};
|
|
2352
|
+
};
|
|
2353
|
+
const minimum = estimateTokens(makeResult("", ""));
|
|
2354
|
+
if (minimum > budget) return { minimum };
|
|
2355
|
+
const titleResult = fitText(prefix(observation.title, 120), budget, (title) => makeResult(title, ""));
|
|
2356
|
+
const title = "observation" in titleResult ? titleResult.observation.title : titleResult.title;
|
|
2357
|
+
return {
|
|
2358
|
+
result: fitText(observation.narrative || observation.facts.join("\n"), budget, (text) => makeResult(title, text)),
|
|
2359
|
+
minimum
|
|
2360
|
+
};
|
|
2361
|
+
}
|
|
2362
|
+
function buildRecallResponse(results, format, tokenBudget) {
|
|
2363
|
+
const selected = [];
|
|
2364
|
+
let used = 0;
|
|
2365
|
+
let clipped = false;
|
|
2366
|
+
let minimumBudget;
|
|
2367
|
+
for (const result of results) {
|
|
2368
|
+
const formatted = formatResult(result, format);
|
|
2369
|
+
const tokens = estimateTokens(formatted);
|
|
2370
|
+
if (tokenBudget === void 0 || used + tokens <= tokenBudget) {
|
|
2371
|
+
selected.push(formatted);
|
|
2372
|
+
used += tokens;
|
|
2373
|
+
continue;
|
|
2374
|
+
}
|
|
2375
|
+
if (selected.length === 0) {
|
|
2376
|
+
const preview = clipResult(result, format, tokenBudget);
|
|
2377
|
+
if (preview.result) {
|
|
2378
|
+
selected.push(preview.result);
|
|
2379
|
+
used = estimateTokens(preview.result);
|
|
2380
|
+
clipped = true;
|
|
2381
|
+
continue;
|
|
2382
|
+
} else minimumBudget = Math.min(preview.minimum, tokens);
|
|
2383
|
+
}
|
|
2384
|
+
break;
|
|
2385
|
+
}
|
|
2386
|
+
const excluded = results.slice(selected.length);
|
|
2387
|
+
const metadata = {
|
|
2388
|
+
tokens_used: used,
|
|
2389
|
+
tokens_budget: tokenBudget,
|
|
2390
|
+
truncated: clipped || excluded.length > 0,
|
|
2391
|
+
matched_count: results.length,
|
|
2392
|
+
excluded_by_budget: excluded.length,
|
|
2393
|
+
excluded_results: excluded.slice(0, 10).map((result) => ({
|
|
2394
|
+
obsId: result.observation.id,
|
|
2395
|
+
sessionId: result.sessionId,
|
|
2396
|
+
title: prefix(result.observation.title, 120)
|
|
2397
|
+
})),
|
|
2398
|
+
excluded_results_truncated: excluded.length > 10,
|
|
2399
|
+
...minimumBudget !== void 0 && { minimum_budget: minimumBudget }
|
|
2400
|
+
};
|
|
2401
|
+
if (format === "narrative") {
|
|
2402
|
+
const narrativeResults = selected;
|
|
2403
|
+
return {
|
|
2404
|
+
...metadata,
|
|
2405
|
+
format,
|
|
2406
|
+
results: narrativeResults,
|
|
2407
|
+
text: narrativeResults.map((result, index) => `${index + 1}. ${result.title}\n${result.narrative}`).join("\n\n")
|
|
2408
|
+
};
|
|
2409
|
+
}
|
|
2410
|
+
if (format === "compact") return {
|
|
2411
|
+
...metadata,
|
|
2412
|
+
format,
|
|
2413
|
+
results: selected
|
|
2414
|
+
};
|
|
2415
|
+
return {
|
|
2416
|
+
...metadata,
|
|
2417
|
+
format,
|
|
2418
|
+
results: selected
|
|
2419
|
+
};
|
|
2420
|
+
}
|
|
2421
|
+
//#endregion
|
|
2227
2422
|
//#region src/secret-store.ts
|
|
2228
2423
|
const SECRET_KEY = "AGENTMEMORY_SECRET";
|
|
2229
2424
|
function agentmemoryHomeDir() {
|
|
2230
|
-
return join(homedir(), ".agentmemory");
|
|
2425
|
+
return process.env["AGENTMEMORY_DATA_DIR"] || join(homedir(), ".agentmemory");
|
|
2231
2426
|
}
|
|
2232
2427
|
function secretFilePath() {
|
|
2233
2428
|
return join(agentmemoryHomeDir(), "secret");
|
|
@@ -2251,7 +2446,7 @@ function unquote(value) {
|
|
|
2251
2446
|
function readEnvFileSecret() {
|
|
2252
2447
|
let content;
|
|
2253
2448
|
try {
|
|
2254
|
-
content = readFileSync(join(
|
|
2449
|
+
content = readFileSync(process.env["AGENTMEMORY_ENV_FILE"] || join(homedir(), ".agentmemory", ".env"), "utf-8");
|
|
2255
2450
|
} catch {
|
|
2256
2451
|
return "";
|
|
2257
2452
|
}
|
|
@@ -2267,13 +2462,29 @@ function readEnvFileSecret() {
|
|
|
2267
2462
|
}
|
|
2268
2463
|
return found;
|
|
2269
2464
|
}
|
|
2270
|
-
function
|
|
2465
|
+
function readSecretFile(path) {
|
|
2271
2466
|
try {
|
|
2272
|
-
return usable(readFileSync(
|
|
2467
|
+
return usable(readFileSync(path, "utf-8"));
|
|
2273
2468
|
} catch {
|
|
2274
2469
|
return "";
|
|
2275
2470
|
}
|
|
2276
2471
|
}
|
|
2472
|
+
function legacyDataDirSecretPaths(env = process.env) {
|
|
2473
|
+
const dataDir = env["AGENTMEMORY_DATA_DIR"];
|
|
2474
|
+
if (!dataDir) return [];
|
|
2475
|
+
const paths = [
|
|
2476
|
+
join(dataDir, "secret"),
|
|
2477
|
+
join(dataDir, ".hmac"),
|
|
2478
|
+
join(dataDir, "..", ".hmac")
|
|
2479
|
+
];
|
|
2480
|
+
return [...new Set(paths.filter((path) => path !== secretFilePath()))];
|
|
2481
|
+
}
|
|
2482
|
+
function readStoredSecret(env = process.env) {
|
|
2483
|
+
const canonicalPath = canonicalSecretPath();
|
|
2484
|
+
const localPath = secretFilePath();
|
|
2485
|
+
const legacyPaths = legacyDataDirSecretPaths(env);
|
|
2486
|
+
return readSecretFile(canonicalPath) || (localPath === canonicalPath ? "" : readSecretFile(localPath)) || legacyPaths.map(readSecretFile).find(Boolean) || "";
|
|
2487
|
+
}
|
|
2277
2488
|
function explicitSecret(env = process.env) {
|
|
2278
2489
|
return usable(env[SECRET_KEY]) || readEnvFileSecret();
|
|
2279
2490
|
}
|
|
@@ -2290,30 +2501,44 @@ function isLoopbackUrl(url) {
|
|
|
2290
2501
|
function resolveClientSecret(baseUrl, env = process.env) {
|
|
2291
2502
|
const fromEnv = usable(env[SECRET_KEY]);
|
|
2292
2503
|
if (fromEnv) return fromEnv;
|
|
2504
|
+
if (env.AGENTMEMORY_CREDENTIAL_MODE === "explicit") return "";
|
|
2293
2505
|
if (!isLoopbackUrl(baseUrl)) return "";
|
|
2294
|
-
return readEnvFileSecret() || readStoredSecret();
|
|
2506
|
+
return readEnvFileSecret() || readStoredSecret(env);
|
|
2295
2507
|
}
|
|
2296
|
-
function
|
|
2297
|
-
|
|
2298
|
-
|
|
2299
|
-
|
|
2300
|
-
|
|
2301
|
-
};
|
|
2302
|
-
const stored = readStoredSecret();
|
|
2303
|
-
if (stored) return {
|
|
2304
|
-
secret: stored,
|
|
2305
|
-
source: "file"
|
|
2306
|
-
};
|
|
2307
|
-
const generated = randomBytes(32).toString("hex");
|
|
2308
|
-
const path = secretFilePath();
|
|
2309
|
-
mkdirSync(agentmemoryHomeDir(), {
|
|
2508
|
+
function canonicalSecretPath() {
|
|
2509
|
+
return join(homedir(), ".agentmemory", "secret");
|
|
2510
|
+
}
|
|
2511
|
+
function writeSecretFile(path, secret) {
|
|
2512
|
+
mkdirSync(join(path, ".."), {
|
|
2310
2513
|
recursive: true,
|
|
2311
2514
|
mode: 448
|
|
2312
2515
|
});
|
|
2313
2516
|
const staging = `${path}.${process.pid}.${randomBytes(4).toString("hex")}.tmp`;
|
|
2314
2517
|
const fd = openSync(staging, "wx", 384);
|
|
2315
2518
|
try {
|
|
2316
|
-
writeSync(fd, `${
|
|
2519
|
+
writeSync(fd, `${secret}\n`);
|
|
2520
|
+
} finally {
|
|
2521
|
+
closeSync(fd);
|
|
2522
|
+
}
|
|
2523
|
+
try {
|
|
2524
|
+
chmodSync(staging, 384);
|
|
2525
|
+
renameSync(staging, path);
|
|
2526
|
+
chmodSync(path, 384);
|
|
2527
|
+
} finally {
|
|
2528
|
+
try {
|
|
2529
|
+
unlinkSync(staging);
|
|
2530
|
+
} catch {}
|
|
2531
|
+
}
|
|
2532
|
+
}
|
|
2533
|
+
function writeSecretIfAbsent(path, secret) {
|
|
2534
|
+
mkdirSync(join(path, ".."), {
|
|
2535
|
+
recursive: true,
|
|
2536
|
+
mode: 448
|
|
2537
|
+
});
|
|
2538
|
+
const staging = `${path}.${process.pid}.${randomBytes(4).toString("hex")}.tmp`;
|
|
2539
|
+
const fd = openSync(staging, "wx", 384);
|
|
2540
|
+
try {
|
|
2541
|
+
writeSync(fd, `${secret}\n`);
|
|
2317
2542
|
} finally {
|
|
2318
2543
|
closeSync(fd);
|
|
2319
2544
|
}
|
|
@@ -2322,20 +2547,38 @@ function ensureServerSecret(env = process.env) {
|
|
|
2322
2547
|
linkSync(staging, path);
|
|
2323
2548
|
} catch (err) {
|
|
2324
2549
|
if (err.code !== "EEXIST") throw err;
|
|
2325
|
-
const raced = readStoredSecret();
|
|
2326
|
-
if (!raced) throw err;
|
|
2327
|
-
return {
|
|
2328
|
-
secret: raced,
|
|
2329
|
-
source: "file"
|
|
2330
|
-
};
|
|
2331
2550
|
} finally {
|
|
2332
2551
|
try {
|
|
2333
2552
|
unlinkSync(staging);
|
|
2334
2553
|
} catch {}
|
|
2335
2554
|
}
|
|
2555
|
+
const stored = readSecretFile(path);
|
|
2556
|
+
if (!stored) throw new Error(`Could not read stored API secret at ${path}.`);
|
|
2557
|
+
return stored;
|
|
2558
|
+
}
|
|
2559
|
+
function ensureServerSecret(env = process.env) {
|
|
2560
|
+
const configured = explicitSecret(env);
|
|
2561
|
+
if (configured) return {
|
|
2562
|
+
secret: configured,
|
|
2563
|
+
source: "env"
|
|
2564
|
+
};
|
|
2565
|
+
const localPath = secretFilePath();
|
|
2566
|
+
const canonicalPath = canonicalSecretPath();
|
|
2567
|
+
const canonical = localPath === canonicalPath ? "" : readSecretFile(canonicalPath);
|
|
2568
|
+
if (canonical) {
|
|
2569
|
+
if (localPath !== canonicalPath && readSecretFile(localPath) !== canonical) writeSecretFile(localPath, canonical);
|
|
2570
|
+
return {
|
|
2571
|
+
secret: canonical,
|
|
2572
|
+
source: "file"
|
|
2573
|
+
};
|
|
2574
|
+
}
|
|
2575
|
+
const legacy = readSecretFile(localPath) || legacyDataDirSecretPaths(env).map(readSecretFile).find(Boolean) || "";
|
|
2576
|
+
const localSecret = writeSecretIfAbsent(localPath, legacy || randomBytes(32).toString("hex"));
|
|
2577
|
+
const secret = localPath === canonicalPath ? localSecret : writeSecretIfAbsent(canonicalPath, localSecret);
|
|
2578
|
+
if (localPath !== canonicalPath && localSecret !== secret) writeSecretFile(localPath, secret);
|
|
2336
2579
|
return {
|
|
2337
|
-
secret
|
|
2338
|
-
source: "generated"
|
|
2580
|
+
secret,
|
|
2581
|
+
source: legacy ? "file" : "generated"
|
|
2339
2582
|
};
|
|
2340
2583
|
}
|
|
2341
2584
|
function bearerHeaders(baseUrl, env = process.env) {
|
|
@@ -2343,6 +2586,6 @@ function bearerHeaders(baseUrl, env = process.env) {
|
|
|
2343
2586
|
return secret ? { Authorization: `Bearer ${secret}` } : {};
|
|
2344
2587
|
}
|
|
2345
2588
|
//#endregion
|
|
2346
|
-
export {
|
|
2589
|
+
export { getStandalonePersistPath as $, setBootVerbose as A, detectLlmProviderKind as B, getAllTools as C, bootLog as D, VERSION as E, runtimeConfigPath as F, getConsolidationDecayDays as G, getAgentId as H, LLM_PROVIDER_KEYS as I, getFinalizeIdleMs as J, getConsolidationIntervalMs as K, MAX_IMPORT_OBS_PER_SESSION as L, engineFlushWaitMs as M, engineStateConfigPaths as N, bootWarn as O, redactCredentialUrls as P, getSessionSweepStaleHours as Q, describeLlmRoute as R, ESSENTIAL_TOOLS as S, III_PINNED_VERSION as T, getAuditRetentionMonths as U, embeddingOptInHint as V, getConsolidationCooldownMs as W, getIndexSaveIntervalMs as X, getFollowupWindowSeconds as Y, getRedisUrl as Z, recordAudit as _, loadEmbeddingConfig as _t, secretFilePath as a, isAgentScopeIsolated as at, setAuditRecordedListener as b, loadTeamConfig as bt, memoryToObservation as c, isContextInjectionEnabled as ct, getSearchResultLayer as d, isGraphExtractionEnabled as dt, getStateBackend as et, isSearchLayer as f, isSessionSweepEnabled as ft, queryAudit as g, loadConfig as gt, AUDIT_MIGRATION_STATE_KEY as h, loadClaudeBridgeConfig as ht, resolveClientSecret as i, hydrateProcessEnvFromFile as it, captureDurableAfterMs as j, logger as k, observationEmbedText as l, isDropStaleIndexEnabled as lt, matchesSearchLayer as m, llmOptInHint as mt, ensureServerSecret as n, getVectorBackfillMax as nt, buildRecallResponse as o, isAutoCompressEnabled as ot, isSearchResultLayer as p, isVectorBackfillAllEnabled as pt, getEnvVar as q, explicitSecret as r, getVectorBucketSize as rt, lessonToObservation as s, isConsolidationEnabled as st, bearerHeaders as t, getStateSaveIntervalMs as tt, supersededAt as u, isGraphCompactOnBootEnabled as ut, runAuditRetentionSweep as v, loadFallbackConfig as vt, getVisibleTools as w, startAuditMigration as x, parseEnvContent as xt, safeAudit as y, loadSnapshotConfig as yt, detectEmbeddingProvider as z };
|
|
2347
2590
|
|
|
2348
|
-
//# sourceMappingURL=secret-store-
|
|
2591
|
+
//# sourceMappingURL=secret-store-iYXRcrO8.mjs.map
|