@agentmemory/agentmemory 0.9.29 → 0.9.31
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 +102 -35
- package/AGENTS.md +19 -26
- package/README.md +417 -525
- package/dist/.env.example +102 -35
- package/dist/cli.d.mts.map +1 -1
- package/dist/cli.mjs +2316 -655
- package/dist/cli.mjs.map +1 -1
- package/dist/compression-recovery-CnhLQC6N.mjs +5912 -0
- package/dist/compression-recovery-CnhLQC6N.mjs.map +1 -0
- package/dist/{connect-Qaeq15TQ.mjs → connect-BSLIAMpw.mjs} +900 -302
- package/dist/connect-BSLIAMpw.mjs.map +1 -0
- package/dist/hooks/_capture.d.mts +25 -0
- package/dist/hooks/_capture.d.mts.map +1 -0
- package/dist/hooks/_capture.mjs +944 -0
- package/dist/hooks/_capture.mjs.map +1 -0
- package/dist/hooks/antigravity-bridge.d.mts +1 -1
- package/dist/hooks/antigravity-bridge.d.mts.map +1 -1
- package/dist/hooks/antigravity-bridge.mjs +24 -15
- package/dist/hooks/antigravity-bridge.mjs.map +1 -1
- package/dist/hooks/notification.mjs +35 -29
- package/dist/hooks/notification.mjs.map +1 -1
- package/dist/hooks/post-commit.mjs +91 -1
- package/dist/hooks/post-commit.mjs.map +1 -1
- package/dist/hooks/post-tool-failure.mjs +71 -29
- package/dist/hooks/post-tool-failure.mjs.map +1 -1
- package/dist/hooks/post-tool-use.mjs +99 -39
- package/dist/hooks/post-tool-use.mjs.map +1 -1
- package/dist/hooks/pre-compact.mjs +113 -6
- package/dist/hooks/pre-compact.mjs.map +1 -1
- package/dist/hooks/pre-tool-use.mjs +91 -1
- package/dist/hooks/pre-tool-use.mjs.map +1 -1
- package/dist/hooks/prompt-submit.mjs +25 -25
- package/dist/hooks/prompt-submit.mjs.map +1 -1
- package/dist/hooks/session-end.mjs +67 -31
- package/dist/hooks/session-end.mjs.map +1 -1
- package/dist/hooks/session-start.mjs +110 -6
- package/dist/hooks/session-start.mjs.map +1 -1
- package/dist/hooks/stop.mjs +80 -8
- package/dist/hooks/stop.mjs.map +1 -1
- package/dist/hooks/subagent-start.mjs +28 -29
- package/dist/hooks/subagent-start.mjs.map +1 -1
- package/dist/hooks/subagent-stop.mjs +33 -29
- package/dist/hooks/subagent-stop.mjs.map +1 -1
- package/dist/hooks/task-completed.mjs +31 -31
- package/dist/hooks/task-completed.mjs.map +1 -1
- package/dist/{image-refs-BKLmp_sD.mjs → image-refs-BaT-9oMU.mjs} +2 -2
- package/dist/image-refs-BaT-9oMU.mjs.map +1 -0
- package/dist/{image-refs-CJgZmb9X.mjs → image-refs-Cyta4Lf9.mjs} +3 -3
- package/dist/image-refs-Cyta4Lf9.mjs.map +1 -0
- package/dist/{keyed-mutex-DTHtcZrt.mjs → image-store-BsN4vyjr.mjs} +2 -14
- package/dist/image-store-BsN4vyjr.mjs.map +1 -0
- package/dist/index.mjs +15180 -4119
- 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 +1145 -0
- package/dist/integrations/dsh.mjs.map +1 -0
- package/dist/{schema-BFZhNTF7.mjs → keyed-mutex-DCUh7PG-.mjs} +81 -8
- package/dist/keyed-mutex-DCUh7PG-.mjs.map +1 -0
- package/dist/secret-store-D9GwO0xp.mjs +2449 -0
- package/dist/secret-store-D9GwO0xp.mjs.map +1 -0
- package/dist/session-arguments-zxsbbd8y.mjs +113 -0
- package/dist/session-arguments-zxsbbd8y.mjs.map +1 -0
- package/dist/{src-G7yt8gGm.mjs → src-DaMtDzt_.mjs} +8320 -4260
- package/dist/src-DaMtDzt_.mjs.map +1 -0
- package/dist/{standalone-BqNJDJ04.mjs → standalone-BlqshyZ5.mjs} +246 -62
- package/dist/standalone-BlqshyZ5.mjs.map +1 -0
- package/dist/standalone.d.mts +1 -1
- package/dist/standalone.d.mts.map +1 -1
- package/dist/standalone.mjs +866 -78
- package/dist/standalone.mjs.map +1 -1
- package/dist/viewer/index.html +7394 -2816
- package/integrations/hermes/README.md +84 -0
- package/integrations/hermes/__init__.py +669 -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 +1450 -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 +33 -0
- package/integrations/omp/skills/agentmemory-architecture/TROUBLESHOOTING.md +70 -0
- package/integrations/omp/skills/agentmemory-config/REFERENCE.md +90 -0
- package/integrations/omp/skills/agentmemory-config/SKILL.md +78 -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 +49 -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 +42 -0
- package/integrations/omp/skills/agentmemory-mcp-tools/TROUBLESHOOTING.md +70 -0
- package/integrations/omp/skills/agentmemory-rest-api/REFERENCE.md +158 -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 +88 -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 +33 -0
- package/integrations/openclaw/skills/agentmemory-architecture/TROUBLESHOOTING.md +70 -0
- package/integrations/openclaw/skills/agentmemory-config/REFERENCE.md +90 -0
- package/integrations/openclaw/skills/agentmemory-config/SKILL.md +78 -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 +49 -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 +42 -0
- package/integrations/openclaw/skills/agentmemory-mcp-tools/TROUBLESHOOTING.md +70 -0
- package/integrations/openclaw/skills/agentmemory-rest-api/REFERENCE.md +158 -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 +45 -51
- package/integrations/pi/dist/index.mjs +1379 -0
- package/integrations/pi/index.ts +139 -173
- package/integrations/pi/package.json +16 -6
- package/integrations/pi/security.ts +54 -22
- 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 +33 -0
- package/integrations/pi/skills/agentmemory-architecture/TROUBLESHOOTING.md +70 -0
- package/integrations/pi/skills/agentmemory-config/REFERENCE.md +90 -0
- package/integrations/pi/skills/agentmemory-config/SKILL.md +78 -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 +49 -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 +42 -0
- package/integrations/pi/skills/agentmemory-mcp-tools/TROUBLESHOOTING.md +70 -0
- package/integrations/pi/skills/agentmemory-rest-api/REFERENCE.md +158 -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 +42 -12
- package/plugin/.claude-plugin/plugin.json +2 -2
- package/plugin/.codex-plugin/plugin.json +27 -4
- package/plugin/.devin-plugin/plugin.json +5 -3
- package/plugin/.mcp.codex.json +12 -0
- package/plugin/.mcp.copilot.json +2 -7
- package/plugin/.mcp.json +2 -7
- package/plugin/assets/icon.svg +35 -0
- package/plugin/cursor/hooks.json +23 -8
- package/plugin/hooks/hooks.copilot.json +11 -11
- package/plugin/hooks.json +67 -0
- package/plugin/opencode/README.md +267 -31
- package/plugin/opencode/agentmemory-capture.ts +594 -11
- package/plugin/opencode/plugin.json +1 -1
- package/plugin/plugin.json +1 -1
- package/plugin/scripts/_capture.d.mts +25 -0
- package/plugin/scripts/_capture.d.mts.map +1 -0
- package/plugin/scripts/_capture.mjs +944 -0
- package/plugin/scripts/_capture.mjs.map +1 -0
- package/plugin/scripts/antigravity-bridge.d.mts +1 -1
- package/plugin/scripts/antigravity-bridge.d.mts.map +1 -1
- package/plugin/scripts/antigravity-bridge.mjs +24 -15
- package/plugin/scripts/antigravity-bridge.mjs.map +1 -1
- package/plugin/scripts/cursor/run-detached.d.mts +1 -0
- 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 +35 -29
- package/plugin/scripts/notification.mjs.map +1 -1
- package/plugin/scripts/plugin-bridge.mjs +409 -0
- package/plugin/scripts/post-commit.mjs +91 -1
- package/plugin/scripts/post-commit.mjs.map +1 -1
- package/plugin/scripts/post-tool-failure.mjs +71 -29
- package/plugin/scripts/post-tool-failure.mjs.map +1 -1
- package/plugin/scripts/post-tool-use.mjs +99 -39
- package/plugin/scripts/post-tool-use.mjs.map +1 -1
- package/plugin/scripts/pre-compact.mjs +113 -6
- package/plugin/scripts/pre-compact.mjs.map +1 -1
- package/plugin/scripts/pre-tool-use.mjs +91 -1
- package/plugin/scripts/pre-tool-use.mjs.map +1 -1
- package/plugin/scripts/prompt-submit.mjs +25 -25
- package/plugin/scripts/prompt-submit.mjs.map +1 -1
- package/plugin/scripts/session-end.mjs +67 -31
- package/plugin/scripts/session-end.mjs.map +1 -1
- package/plugin/scripts/session-start.mjs +110 -6
- package/plugin/scripts/session-start.mjs.map +1 -1
- package/plugin/scripts/stop.mjs +80 -8
- package/plugin/scripts/stop.mjs.map +1 -1
- package/plugin/scripts/subagent-start.mjs +28 -29
- package/plugin/scripts/subagent-start.mjs.map +1 -1
- package/plugin/scripts/subagent-stop.mjs +33 -29
- package/plugin/scripts/subagent-stop.mjs.map +1 -1
- package/plugin/scripts/task-completed.mjs +31 -31
- package/plugin/scripts/task-completed.mjs.map +1 -1
- package/plugin/skills/_shared/TROUBLESHOOTING.md +42 -12
- package/plugin/skills/agentmemory-agents/REFERENCE.md +10 -9
- 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 +4 -4
- package/plugin/skills/agentmemory-architecture/TROUBLESHOOTING.md +70 -0
- package/plugin/skills/agentmemory-config/REFERENCE.md +48 -3
- package/plugin/skills/agentmemory-config/SKILL.md +51 -10
- package/plugin/skills/agentmemory-config/TROUBLESHOOTING.md +70 -0
- package/plugin/skills/agentmemory-hooks/SKILL.md +15 -5
- 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 +6 -3
- package/plugin/skills/agentmemory-mcp-tools/TROUBLESHOOTING.md +70 -0
- package/plugin/skills/agentmemory-rest-api/REFERENCE.md +18 -2
- 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 +13 -6
- 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 +14 -6
- 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-Qaeq15TQ.mjs.map +0 -1
- package/dist/docker-compose.yml +0 -47
- package/dist/iii-config.docker.yaml +0 -53
- package/dist/iii-config.yaml +0 -61
- package/dist/image-refs-BKLmp_sD.mjs.map +0 -1
- package/dist/image-refs-CJgZmb9X.mjs.map +0 -1
- package/dist/keyed-mutex-DTHtcZrt.mjs.map +0 -1
- package/dist/logger-BEB7pCI9.mjs +0 -43
- package/dist/logger-BEB7pCI9.mjs.map +0 -1
- package/dist/schema-BFZhNTF7.mjs.map +0 -1
- package/dist/src-G7yt8gGm.mjs.map +0 -1
- package/dist/standalone-BqNJDJ04.mjs.map +0 -1
- package/dist/tools-registry-BV_2bu7z.mjs +0 -1405
- package/dist/tools-registry-BV_2bu7z.mjs.map +0 -1
- package/docker-compose.yml +0 -47
- package/iii-config.docker.yaml +0 -53
- package/iii-config.yaml +0 -61
package/dist/standalone.mjs
CHANGED
|
@@ -4,6 +4,7 @@ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
|
4
4
|
import { dirname, join } from "node:path";
|
|
5
5
|
import { homedir } from "node:os";
|
|
6
6
|
import "picocolors";
|
|
7
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
7
8
|
//#region src/mcp/in-memory-kv.ts
|
|
8
9
|
var InMemoryKV = class {
|
|
9
10
|
store = /* @__PURE__ */ new Map();
|
|
@@ -34,20 +35,30 @@ var InMemoryKV = class {
|
|
|
34
35
|
return entries ? Array.from(entries.values()) : [];
|
|
35
36
|
}
|
|
36
37
|
persist() {
|
|
37
|
-
if (!this.persistPath) return;
|
|
38
|
+
if (!this.persistPath) return false;
|
|
38
39
|
try {
|
|
39
40
|
const dir = dirname(this.persistPath);
|
|
40
41
|
if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
|
|
41
42
|
const data = {};
|
|
42
43
|
for (const [scope, entries] of this.store) data[scope] = Object.fromEntries(entries);
|
|
43
44
|
writeFileSync(this.persistPath, JSON.stringify(data), "utf-8");
|
|
45
|
+
return true;
|
|
44
46
|
} catch (err) {
|
|
45
47
|
process.stderr.write(`[@agentmemory/mcp] Persist failed: ${err instanceof Error ? err.message : String(err)}\n`);
|
|
48
|
+
return false;
|
|
46
49
|
}
|
|
47
50
|
}
|
|
48
51
|
};
|
|
49
52
|
//#endregion
|
|
50
53
|
//#region src/mcp/transport.ts
|
|
54
|
+
let activeStdioTransports = 0;
|
|
55
|
+
var JsonRpcError = class extends Error {
|
|
56
|
+
constructor(code, message) {
|
|
57
|
+
super(message);
|
|
58
|
+
this.code = code;
|
|
59
|
+
this.name = "JsonRpcError";
|
|
60
|
+
}
|
|
61
|
+
};
|
|
51
62
|
function isNotification(req) {
|
|
52
63
|
return req.id === void 0 || req.id === null;
|
|
53
64
|
}
|
|
@@ -113,7 +124,7 @@ async function processLine(line, handler, writeOut, writeErr = (msg) => process.
|
|
|
113
124
|
jsonrpc: "2.0",
|
|
114
125
|
id: request.id,
|
|
115
126
|
error: {
|
|
116
|
-
code: -32603,
|
|
127
|
+
code: err instanceof JsonRpcError ? err.code : -32603,
|
|
117
128
|
message: err instanceof Error ? err.message : String(err)
|
|
118
129
|
}
|
|
119
130
|
});
|
|
@@ -193,6 +204,7 @@ function createMessageParser(onMessage, writeErr = (msg) => process.stderr.write
|
|
|
193
204
|
function createStdioTransport(handler) {
|
|
194
205
|
let parser = null;
|
|
195
206
|
let queue = Promise.resolve();
|
|
207
|
+
let active = false;
|
|
196
208
|
const writeResponse = (response) => {
|
|
197
209
|
const formatted = formatResponse(response, parser?.isFramed() ?? false);
|
|
198
210
|
if (typeof formatted === "string") {
|
|
@@ -204,6 +216,10 @@ function createStdioTransport(handler) {
|
|
|
204
216
|
const onData = (chunk) => parser?.push(chunk);
|
|
205
217
|
return {
|
|
206
218
|
start() {
|
|
219
|
+
if (active) return;
|
|
220
|
+
active = true;
|
|
221
|
+
activeStdioTransports += 1;
|
|
222
|
+
process.env["AGENTMEMORY_MCP_STDIO__"] = "1";
|
|
207
223
|
parser = createMessageParser((message) => {
|
|
208
224
|
queue = queue.then(() => processLine(message, handler, writeResponse));
|
|
209
225
|
queue.catch((err) => {
|
|
@@ -214,6 +230,11 @@ function createStdioTransport(handler) {
|
|
|
214
230
|
},
|
|
215
231
|
stop() {
|
|
216
232
|
process.stdin.off("data", onData);
|
|
233
|
+
if (active) {
|
|
234
|
+
active = false;
|
|
235
|
+
activeStdioTransports -= 1;
|
|
236
|
+
if (activeStdioTransports === 0) delete process.env["AGENTMEMORY_MCP_STDIO__"];
|
|
237
|
+
}
|
|
217
238
|
parser = null;
|
|
218
239
|
}
|
|
219
240
|
};
|
|
@@ -223,7 +244,7 @@ function createStdioTransport(handler) {
|
|
|
223
244
|
const CORE_TOOLS = [
|
|
224
245
|
{
|
|
225
246
|
name: "memory_recall",
|
|
226
|
-
description: "Search
|
|
247
|
+
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.",
|
|
227
248
|
inputSchema: {
|
|
228
249
|
type: "object",
|
|
229
250
|
properties: {
|
|
@@ -241,7 +262,28 @@ const CORE_TOOLS = [
|
|
|
241
262
|
},
|
|
242
263
|
token_budget: {
|
|
243
264
|
type: "number",
|
|
244
|
-
description: "Optional token budget
|
|
265
|
+
description: "Optional estimated content token budget; response includes truncation and recovery metadata"
|
|
266
|
+
},
|
|
267
|
+
targetLayer: {
|
|
268
|
+
type: "string",
|
|
269
|
+
enum: [
|
|
270
|
+
"all",
|
|
271
|
+
"memory",
|
|
272
|
+
"observation"
|
|
273
|
+
],
|
|
274
|
+
description: "Search all indexed layers (default), durable memories, or raw observations before ranking"
|
|
275
|
+
},
|
|
276
|
+
project: {
|
|
277
|
+
type: "string",
|
|
278
|
+
description: "Filter by project path"
|
|
279
|
+
},
|
|
280
|
+
cwd: {
|
|
281
|
+
type: "string",
|
|
282
|
+
description: "Filter by session working directory"
|
|
283
|
+
},
|
|
284
|
+
agentId: {
|
|
285
|
+
type: "string",
|
|
286
|
+
description: "Filter by owning agent; '*' reads across agents"
|
|
245
287
|
}
|
|
246
288
|
},
|
|
247
289
|
required: ["query"]
|
|
@@ -316,23 +358,46 @@ const CORE_TOOLS = [
|
|
|
316
358
|
description: "Detect recurring patterns across sessions.",
|
|
317
359
|
inputSchema: {
|
|
318
360
|
type: "object",
|
|
319
|
-
properties: {
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
361
|
+
properties: {
|
|
362
|
+
project: {
|
|
363
|
+
type: "string",
|
|
364
|
+
description: "Project path to analyze"
|
|
365
|
+
},
|
|
366
|
+
limit: {
|
|
367
|
+
type: "integer",
|
|
368
|
+
description: "Most recent sessions to scan (default 50, max 500)"
|
|
369
|
+
}
|
|
370
|
+
}
|
|
323
371
|
}
|
|
324
372
|
},
|
|
325
373
|
{
|
|
326
374
|
name: "memory_sessions",
|
|
327
|
-
description: "List recent sessions with
|
|
375
|
+
description: "List recent sessions with status, observation counts, summaries and a continuation cursor. Filters apply before pagination; retain them when requesting the next page.",
|
|
328
376
|
inputSchema: {
|
|
329
377
|
type: "object",
|
|
330
|
-
properties: {
|
|
378
|
+
properties: {
|
|
379
|
+
project: {
|
|
380
|
+
type: "string",
|
|
381
|
+
description: "Exact project identifier used when sessions were started"
|
|
382
|
+
},
|
|
383
|
+
agentId: {
|
|
384
|
+
type: "string",
|
|
385
|
+
description: "Filter by owning agent; '*' reads across agents"
|
|
386
|
+
},
|
|
387
|
+
limit: {
|
|
388
|
+
type: "integer",
|
|
389
|
+
description: "Page size (default 20, max 100)"
|
|
390
|
+
},
|
|
391
|
+
cursor: {
|
|
392
|
+
type: "string",
|
|
393
|
+
description: "nextCursor from the previous page; omit for the first page"
|
|
394
|
+
}
|
|
395
|
+
}
|
|
331
396
|
}
|
|
332
397
|
},
|
|
333
398
|
{
|
|
334
399
|
name: "memory_smart_search",
|
|
335
|
-
description: "Hybrid semantic+keyword search with progressive disclosure.",
|
|
400
|
+
description: "Hybrid semantic+keyword search with progressive disclosure. Pass query to search, or expandIds to recover full results.",
|
|
336
401
|
inputSchema: {
|
|
337
402
|
type: "object",
|
|
338
403
|
properties: {
|
|
@@ -342,14 +407,34 @@ const CORE_TOOLS = [
|
|
|
342
407
|
},
|
|
343
408
|
expandIds: {
|
|
344
409
|
type: "string",
|
|
345
|
-
description: "Comma-separated observation IDs to expand"
|
|
410
|
+
description: "Comma-separated memory or observation IDs to expand; query is optional when provided"
|
|
346
411
|
},
|
|
347
412
|
limit: {
|
|
348
413
|
type: "number",
|
|
349
414
|
description: "Max results (default 10)"
|
|
415
|
+
},
|
|
416
|
+
targetLayer: {
|
|
417
|
+
type: "string",
|
|
418
|
+
enum: [
|
|
419
|
+
"all",
|
|
420
|
+
"memory",
|
|
421
|
+
"observation"
|
|
422
|
+
],
|
|
423
|
+
description: "Search all indexed layers (default), durable memories, or raw observations before ranking"
|
|
424
|
+
},
|
|
425
|
+
project: {
|
|
426
|
+
type: "string",
|
|
427
|
+
description: "Filter by project path"
|
|
428
|
+
},
|
|
429
|
+
agentId: {
|
|
430
|
+
type: "string",
|
|
431
|
+
description: "Filter by owning agent; '*' reads across agents"
|
|
432
|
+
},
|
|
433
|
+
includeLessons: {
|
|
434
|
+
type: "boolean",
|
|
435
|
+
description: "Include lesson matches when targetLayer is all (default true)"
|
|
350
436
|
}
|
|
351
|
-
}
|
|
352
|
-
required: ["query"]
|
|
437
|
+
}
|
|
353
438
|
}
|
|
354
439
|
},
|
|
355
440
|
{
|
|
@@ -427,10 +512,31 @@ const CORE_TOOLS = [
|
|
|
427
512
|
},
|
|
428
513
|
{
|
|
429
514
|
name: "memory_export",
|
|
430
|
-
description: "Export
|
|
515
|
+
description: "Export memory data as JSON. Past the transport size limit the export is refused, so use the paging arguments on a large store.",
|
|
431
516
|
inputSchema: {
|
|
432
517
|
type: "object",
|
|
433
|
-
properties: {
|
|
518
|
+
properties: {
|
|
519
|
+
maxSessions: {
|
|
520
|
+
type: "number",
|
|
521
|
+
description: "Sessions per page (with their observations)"
|
|
522
|
+
},
|
|
523
|
+
offset: {
|
|
524
|
+
type: "number",
|
|
525
|
+
description: "Session offset"
|
|
526
|
+
},
|
|
527
|
+
collectionLimit: {
|
|
528
|
+
type: "number",
|
|
529
|
+
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"
|
|
530
|
+
},
|
|
531
|
+
collectionOffset: {
|
|
532
|
+
type: "number",
|
|
533
|
+
description: "Row offset for the top-level collections"
|
|
534
|
+
},
|
|
535
|
+
collections: {
|
|
536
|
+
type: "string",
|
|
537
|
+
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."
|
|
538
|
+
}
|
|
539
|
+
}
|
|
434
540
|
}
|
|
435
541
|
},
|
|
436
542
|
{
|
|
@@ -1329,7 +1435,8 @@ function getAllTools() {
|
|
|
1329
1435
|
...V010_SLOTS_TOOLS
|
|
1330
1436
|
];
|
|
1331
1437
|
}
|
|
1332
|
-
|
|
1438
|
+
process.env["AGENTMEMORY_DATA_DIR"] || join(homedir(), ".agentmemory");
|
|
1439
|
+
const ENV_FILE = process.env["AGENTMEMORY_ENV_FILE"] || join(homedir(), ".agentmemory", ".env");
|
|
1333
1440
|
let envFileCache;
|
|
1334
1441
|
function loadEnvFile() {
|
|
1335
1442
|
if (envFileCache) return envFileCache;
|
|
@@ -1337,7 +1444,10 @@ function loadEnvFile() {
|
|
|
1337
1444
|
envFileCache = {};
|
|
1338
1445
|
return envFileCache;
|
|
1339
1446
|
}
|
|
1340
|
-
|
|
1447
|
+
envFileCache = parseEnvContent(readFileSync(ENV_FILE, "utf-8"));
|
|
1448
|
+
return envFileCache;
|
|
1449
|
+
}
|
|
1450
|
+
function parseEnvContent(content) {
|
|
1341
1451
|
const vars = {};
|
|
1342
1452
|
for (const line of content.split("\n")) {
|
|
1343
1453
|
const trimmed = line.trim();
|
|
@@ -1356,8 +1466,7 @@ function loadEnvFile() {
|
|
|
1356
1466
|
}
|
|
1357
1467
|
vars[key] = val;
|
|
1358
1468
|
}
|
|
1359
|
-
|
|
1360
|
-
return envFileCache;
|
|
1469
|
+
return vars;
|
|
1361
1470
|
}
|
|
1362
1471
|
function getMergedEnv(overrides) {
|
|
1363
1472
|
return {
|
|
@@ -1366,18 +1475,534 @@ function getMergedEnv(overrides) {
|
|
|
1366
1475
|
...overrides
|
|
1367
1476
|
};
|
|
1368
1477
|
}
|
|
1478
|
+
function loadAgentScope() {
|
|
1479
|
+
const env = getMergedEnv();
|
|
1480
|
+
const raw = env["AGENT_ID"];
|
|
1481
|
+
if (!raw) return null;
|
|
1482
|
+
const agentId = raw.trim().slice(0, 128);
|
|
1483
|
+
if (!agentId) return null;
|
|
1484
|
+
return {
|
|
1485
|
+
agentId,
|
|
1486
|
+
mode: env["AGENTMEMORY_AGENT_SCOPE"] === "isolated" ? "isolated" : "shared"
|
|
1487
|
+
};
|
|
1488
|
+
}
|
|
1489
|
+
function getAgentId() {
|
|
1490
|
+
return loadAgentScope()?.agentId;
|
|
1491
|
+
}
|
|
1492
|
+
function isAgentScopeIsolated() {
|
|
1493
|
+
return loadAgentScope()?.mode === "isolated";
|
|
1494
|
+
}
|
|
1369
1495
|
function getStandalonePersistPath() {
|
|
1370
1496
|
return getMergedEnv()["STANDALONE_PERSIST_PATH"] || join(homedir(), ".agentmemory", "standalone.json");
|
|
1371
1497
|
}
|
|
1372
1498
|
//#endregion
|
|
1499
|
+
//#region src/state/search-layer.ts
|
|
1500
|
+
function isSearchLayer(value) {
|
|
1501
|
+
return value === "all" || value === "memory" || value === "observation";
|
|
1502
|
+
}
|
|
1503
|
+
//#endregion
|
|
1504
|
+
//#region src/state/memory-utils.ts
|
|
1505
|
+
function memoryToObservation(memory) {
|
|
1506
|
+
return {
|
|
1507
|
+
id: memory.id,
|
|
1508
|
+
sessionId: memory.sessionIds?.[0] ?? "memory",
|
|
1509
|
+
timestamp: memory.createdAt,
|
|
1510
|
+
type: "decision",
|
|
1511
|
+
title: memory.title,
|
|
1512
|
+
facts: [memory.content],
|
|
1513
|
+
narrative: memory.content,
|
|
1514
|
+
concepts: memory.concepts,
|
|
1515
|
+
files: memory.files,
|
|
1516
|
+
importance: memory.strength,
|
|
1517
|
+
...memory.agentId ? { agentId: memory.agentId } : {}
|
|
1518
|
+
};
|
|
1519
|
+
}
|
|
1520
|
+
//#endregion
|
|
1521
|
+
//#region src/functions/recall-response.ts
|
|
1522
|
+
function estimateTokens(value) {
|
|
1523
|
+
return Math.max(1, Math.ceil(JSON.stringify(value).length / 3));
|
|
1524
|
+
}
|
|
1525
|
+
function prefix(text, length) {
|
|
1526
|
+
let end = Math.min(length, text.length);
|
|
1527
|
+
if (end > 0 && end < text.length && /[\uD800-\uDBFF]/.test(text[end - 1])) end--;
|
|
1528
|
+
return text.slice(0, end);
|
|
1529
|
+
}
|
|
1530
|
+
function fitText(text, budget, makeResult) {
|
|
1531
|
+
let low = 0;
|
|
1532
|
+
let high = text.length;
|
|
1533
|
+
while (low < high) {
|
|
1534
|
+
const middle = Math.ceil((low + high) / 2);
|
|
1535
|
+
if (estimateTokens(makeResult(prefix(text, middle))) <= budget) low = middle;
|
|
1536
|
+
else high = middle - 1;
|
|
1537
|
+
}
|
|
1538
|
+
return makeResult(prefix(text, low));
|
|
1539
|
+
}
|
|
1540
|
+
function formatResult(result, format) {
|
|
1541
|
+
if (format === "full") return result;
|
|
1542
|
+
const observation = result.observation;
|
|
1543
|
+
const compact = {
|
|
1544
|
+
obsId: observation.id,
|
|
1545
|
+
sessionId: result.sessionId,
|
|
1546
|
+
title: observation.title,
|
|
1547
|
+
type: observation.type,
|
|
1548
|
+
score: result.score,
|
|
1549
|
+
timestamp: observation.timestamp,
|
|
1550
|
+
...result.layer !== void 0 && { layer: result.layer }
|
|
1551
|
+
};
|
|
1552
|
+
if (format === "compact") return compact;
|
|
1553
|
+
const { type: _type, ...narrative } = compact;
|
|
1554
|
+
return {
|
|
1555
|
+
...narrative,
|
|
1556
|
+
narrative: observation.narrative
|
|
1557
|
+
};
|
|
1558
|
+
}
|
|
1559
|
+
function clipResult(result, format, budget) {
|
|
1560
|
+
const observation = result.observation;
|
|
1561
|
+
const layer = result.layer !== void 0 ? { layer: result.layer } : {};
|
|
1562
|
+
if (format === "compact") {
|
|
1563
|
+
const base = {
|
|
1564
|
+
obsId: observation.id,
|
|
1565
|
+
sessionId: result.sessionId,
|
|
1566
|
+
title: "",
|
|
1567
|
+
type: observation.type,
|
|
1568
|
+
score: result.score,
|
|
1569
|
+
timestamp: observation.timestamp,
|
|
1570
|
+
...layer,
|
|
1571
|
+
content_truncated: true
|
|
1572
|
+
};
|
|
1573
|
+
const minimum = estimateTokens(base);
|
|
1574
|
+
if (minimum > budget) return { minimum };
|
|
1575
|
+
return {
|
|
1576
|
+
result: fitText(observation.title, budget, (title) => ({
|
|
1577
|
+
...base,
|
|
1578
|
+
title
|
|
1579
|
+
})),
|
|
1580
|
+
minimum
|
|
1581
|
+
};
|
|
1582
|
+
}
|
|
1583
|
+
const makeResult = (title, narrative) => {
|
|
1584
|
+
if (format === "narrative") return {
|
|
1585
|
+
obsId: observation.id,
|
|
1586
|
+
sessionId: result.sessionId,
|
|
1587
|
+
title,
|
|
1588
|
+
narrative,
|
|
1589
|
+
score: result.score,
|
|
1590
|
+
timestamp: observation.timestamp,
|
|
1591
|
+
...layer,
|
|
1592
|
+
content_truncated: true
|
|
1593
|
+
};
|
|
1594
|
+
return {
|
|
1595
|
+
observation: {
|
|
1596
|
+
id: observation.id,
|
|
1597
|
+
sessionId: observation.sessionId,
|
|
1598
|
+
timestamp: observation.timestamp,
|
|
1599
|
+
type: observation.type,
|
|
1600
|
+
title,
|
|
1601
|
+
facts: [],
|
|
1602
|
+
narrative,
|
|
1603
|
+
concepts: [],
|
|
1604
|
+
files: [],
|
|
1605
|
+
importance: observation.importance,
|
|
1606
|
+
...observation.confidence !== void 0 && { confidence: observation.confidence },
|
|
1607
|
+
...observation.agentId !== void 0 && { agentId: observation.agentId },
|
|
1608
|
+
...observation.origin && { origin: {
|
|
1609
|
+
channel: observation.origin.channel,
|
|
1610
|
+
capturedAt: observation.origin.capturedAt
|
|
1611
|
+
} }
|
|
1612
|
+
},
|
|
1613
|
+
score: result.score,
|
|
1614
|
+
sessionId: result.sessionId,
|
|
1615
|
+
...layer,
|
|
1616
|
+
content_truncated: true
|
|
1617
|
+
};
|
|
1618
|
+
};
|
|
1619
|
+
const minimum = estimateTokens(makeResult("", ""));
|
|
1620
|
+
if (minimum > budget) return { minimum };
|
|
1621
|
+
const titleResult = fitText(prefix(observation.title, 120), budget, (title) => makeResult(title, ""));
|
|
1622
|
+
const title = "observation" in titleResult ? titleResult.observation.title : titleResult.title;
|
|
1623
|
+
return {
|
|
1624
|
+
result: fitText(observation.narrative || observation.facts.join("\n"), budget, (text) => makeResult(title, text)),
|
|
1625
|
+
minimum
|
|
1626
|
+
};
|
|
1627
|
+
}
|
|
1628
|
+
function buildRecallResponse(results, format, tokenBudget) {
|
|
1629
|
+
const selected = [];
|
|
1630
|
+
let used = 0;
|
|
1631
|
+
let clipped = false;
|
|
1632
|
+
let minimumBudget;
|
|
1633
|
+
for (const result of results) {
|
|
1634
|
+
const formatted = formatResult(result, format);
|
|
1635
|
+
const tokens = estimateTokens(formatted);
|
|
1636
|
+
if (tokenBudget === void 0 || used + tokens <= tokenBudget) {
|
|
1637
|
+
selected.push(formatted);
|
|
1638
|
+
used += tokens;
|
|
1639
|
+
continue;
|
|
1640
|
+
}
|
|
1641
|
+
if (selected.length === 0) {
|
|
1642
|
+
const preview = clipResult(result, format, tokenBudget);
|
|
1643
|
+
if (preview.result) {
|
|
1644
|
+
selected.push(preview.result);
|
|
1645
|
+
used = estimateTokens(preview.result);
|
|
1646
|
+
clipped = true;
|
|
1647
|
+
continue;
|
|
1648
|
+
} else minimumBudget = Math.min(preview.minimum, tokens);
|
|
1649
|
+
}
|
|
1650
|
+
break;
|
|
1651
|
+
}
|
|
1652
|
+
const excluded = results.slice(selected.length);
|
|
1653
|
+
const metadata = {
|
|
1654
|
+
tokens_used: used,
|
|
1655
|
+
tokens_budget: tokenBudget,
|
|
1656
|
+
truncated: clipped || excluded.length > 0,
|
|
1657
|
+
matched_count: results.length,
|
|
1658
|
+
excluded_by_budget: excluded.length,
|
|
1659
|
+
excluded_results: excluded.slice(0, 10).map((result) => ({
|
|
1660
|
+
obsId: result.observation.id,
|
|
1661
|
+
sessionId: result.sessionId,
|
|
1662
|
+
title: prefix(result.observation.title, 120)
|
|
1663
|
+
})),
|
|
1664
|
+
excluded_results_truncated: excluded.length > 10,
|
|
1665
|
+
...minimumBudget !== void 0 && { minimum_budget: minimumBudget }
|
|
1666
|
+
};
|
|
1667
|
+
if (format === "narrative") {
|
|
1668
|
+
const narrativeResults = selected;
|
|
1669
|
+
return {
|
|
1670
|
+
...metadata,
|
|
1671
|
+
format,
|
|
1672
|
+
results: narrativeResults,
|
|
1673
|
+
text: narrativeResults.map((result, index) => `${index + 1}. ${result.title}\n${result.narrative}`).join("\n\n")
|
|
1674
|
+
};
|
|
1675
|
+
}
|
|
1676
|
+
if (format === "compact") return {
|
|
1677
|
+
...metadata,
|
|
1678
|
+
format,
|
|
1679
|
+
results: selected
|
|
1680
|
+
};
|
|
1681
|
+
return {
|
|
1682
|
+
...metadata,
|
|
1683
|
+
format,
|
|
1684
|
+
results: selected
|
|
1685
|
+
};
|
|
1686
|
+
}
|
|
1687
|
+
//#endregion
|
|
1688
|
+
//#region src/mcp/search-arguments.ts
|
|
1689
|
+
function parseSearchExpansionIds(value) {
|
|
1690
|
+
return (typeof value === "string" ? value.split(",") : Array.isArray(value) ? value : []).flatMap((entry) => {
|
|
1691
|
+
if (typeof entry === "string") return entry.trim() ? [entry.trim()] : [];
|
|
1692
|
+
if (!entry || typeof entry !== "object" || typeof entry.obsId !== "string" || !entry.obsId.trim()) return [];
|
|
1693
|
+
const obsId = entry.obsId.trim();
|
|
1694
|
+
return typeof entry.sessionId === "string" && entry.sessionId.trim() ? [{
|
|
1695
|
+
obsId,
|
|
1696
|
+
sessionId: entry.sessionId.trim()
|
|
1697
|
+
}] : [obsId];
|
|
1698
|
+
});
|
|
1699
|
+
}
|
|
1700
|
+
//#endregion
|
|
1701
|
+
//#region src/state/list-query.ts
|
|
1702
|
+
function encodeCursor(position) {
|
|
1703
|
+
return Buffer.from(JSON.stringify(position), "utf-8").toString("base64url");
|
|
1704
|
+
}
|
|
1705
|
+
function decodeCursor(cursor) {
|
|
1706
|
+
if (!cursor) return null;
|
|
1707
|
+
try {
|
|
1708
|
+
const parsed = JSON.parse(Buffer.from(cursor, "base64url").toString("utf-8"));
|
|
1709
|
+
if (!parsed || typeof parsed !== "object") return null;
|
|
1710
|
+
const position = {};
|
|
1711
|
+
if (typeof parsed.key === "string") position.key = parsed.key;
|
|
1712
|
+
if (typeof parsed.id === "string") position.id = parsed.id;
|
|
1713
|
+
if (Number.isInteger(parsed.offset) && parsed.offset >= 0) position.offset = parsed.offset;
|
|
1714
|
+
return position;
|
|
1715
|
+
} catch {
|
|
1716
|
+
return null;
|
|
1717
|
+
}
|
|
1718
|
+
}
|
|
1719
|
+
function compareDesc(aKey, aId, bKey, bId) {
|
|
1720
|
+
if (aKey !== bKey) return aKey < bKey ? 1 : -1;
|
|
1721
|
+
if (aId === bId) return 0;
|
|
1722
|
+
return aId < bId ? 1 : -1;
|
|
1723
|
+
}
|
|
1724
|
+
function sortByKeyDesc(items, keyOf, idOf) {
|
|
1725
|
+
return items.sort((a, b) => compareDesc(keyOf(a), idOf(a), keyOf(b), idOf(b)));
|
|
1726
|
+
}
|
|
1727
|
+
function pageAfterCursor(sortedDesc, keyOf, idOf, cursor, limit) {
|
|
1728
|
+
const position = decodeCursor(cursor);
|
|
1729
|
+
let start = 0;
|
|
1730
|
+
if (position?.key !== void 0 && position.id !== void 0) {
|
|
1731
|
+
const { key, id } = position;
|
|
1732
|
+
start = sortedDesc.findIndex((item) => compareDesc(keyOf(item), idOf(item), key, id) > 0);
|
|
1733
|
+
if (start < 0) start = sortedDesc.length;
|
|
1734
|
+
}
|
|
1735
|
+
const page = sortedDesc.slice(start, start + limit);
|
|
1736
|
+
const last = page[page.length - 1];
|
|
1737
|
+
return {
|
|
1738
|
+
page,
|
|
1739
|
+
nextCursor: last !== void 0 && start + limit < sortedDesc.length ? encodeCursor({
|
|
1740
|
+
key: keyOf(last),
|
|
1741
|
+
id: idOf(last)
|
|
1742
|
+
}) : null
|
|
1743
|
+
};
|
|
1744
|
+
}
|
|
1745
|
+
//#endregion
|
|
1746
|
+
//#region src/mcp/session-arguments.ts
|
|
1747
|
+
function parseSessionArguments(args) {
|
|
1748
|
+
const limit = args.limit === void 0 ? 20 : args.limit;
|
|
1749
|
+
if (typeof limit !== "number" || !Number.isInteger(limit) || limit < 1) throw new Error("limit must be a positive integer");
|
|
1750
|
+
const query = { limit: String(Math.min(limit, 100)) };
|
|
1751
|
+
for (const field of [
|
|
1752
|
+
"project",
|
|
1753
|
+
"agentId",
|
|
1754
|
+
"cursor"
|
|
1755
|
+
]) {
|
|
1756
|
+
if (args[field] === void 0) continue;
|
|
1757
|
+
if (field === "cursor" && typeof args[field] === "string" && !args[field].trim()) continue;
|
|
1758
|
+
if (typeof args[field] !== "string" || !args[field].trim()) throw new Error(`${field} must be a non-empty string`);
|
|
1759
|
+
query[field] = args[field].trim();
|
|
1760
|
+
}
|
|
1761
|
+
if (query.cursor) {
|
|
1762
|
+
const position = decodeCursor(query.cursor);
|
|
1763
|
+
if (!position || typeof position.key !== "string" || typeof position.id !== "string") throw new Error("cursor must be a session continuation token");
|
|
1764
|
+
}
|
|
1765
|
+
return query;
|
|
1766
|
+
}
|
|
1767
|
+
//#endregion
|
|
1373
1768
|
//#region src/version.ts
|
|
1374
|
-
const VERSION = "0.9.
|
|
1769
|
+
const VERSION = "0.9.31";
|
|
1375
1770
|
createRequire(import.meta.url);
|
|
1376
1771
|
//#endregion
|
|
1377
1772
|
//#region src/state/schema.ts
|
|
1773
|
+
const KV = {
|
|
1774
|
+
sessions: "mem:sessions",
|
|
1775
|
+
observations: (sessionId) => `mem:obs:${sessionId}`,
|
|
1776
|
+
memories: "mem:memories",
|
|
1777
|
+
summaries: "mem:summaries",
|
|
1778
|
+
summaryRepairs: "mem:summary:repairs",
|
|
1779
|
+
config: "mem:config",
|
|
1780
|
+
metrics: "mem:metrics",
|
|
1781
|
+
health: "mem:health",
|
|
1782
|
+
embeddings: (obsId) => `mem:emb:${obsId}`,
|
|
1783
|
+
bm25Index: "mem:index:bm25",
|
|
1784
|
+
vectorPendingLog: "mem:index:vec-pending",
|
|
1785
|
+
relations: "mem:relations",
|
|
1786
|
+
profiles: "mem:profiles",
|
|
1787
|
+
claudeBridge: "mem:claude-bridge",
|
|
1788
|
+
graphNodes: "mem:graph:nodes",
|
|
1789
|
+
graphControl: "mem:graph:control",
|
|
1790
|
+
graphEdges: "mem:graph:edges",
|
|
1791
|
+
graphSnapshot: "mem:graph:snapshot",
|
|
1792
|
+
graphNameIndex: "mem:graph:name-index",
|
|
1793
|
+
graphEdgeKey: "mem:graph:edge-key",
|
|
1794
|
+
graphNodeDegree: "mem:graph:node-degree",
|
|
1795
|
+
graphMembership: "mem:graph:membership",
|
|
1796
|
+
graphRetrievalControl: "mem:graph:retrieval-control",
|
|
1797
|
+
graphRetrievalData: "mem:graph:retrieval-data",
|
|
1798
|
+
graphIndexMigration: "mem:graph:index-migration",
|
|
1799
|
+
graphIndexManifest: "mem:graph:index-manifest",
|
|
1800
|
+
semantic: "mem:semantic",
|
|
1801
|
+
procedural: "mem:procedural",
|
|
1802
|
+
teamShared: (teamId) => `mem:team:${teamId}:shared`,
|
|
1803
|
+
teamUsers: (teamId, userId) => `mem:team:${teamId}:users:${userId}`,
|
|
1804
|
+
teamProfile: (teamId) => `mem:team:${teamId}:profile`,
|
|
1805
|
+
audit: "mem:audit",
|
|
1806
|
+
auditMonth: (month) => `mem:audit:${month}`,
|
|
1807
|
+
auditMonths: "mem:audit:months",
|
|
1808
|
+
actions: "mem:actions",
|
|
1809
|
+
actionEdges: "mem:action-edges",
|
|
1810
|
+
leases: "mem:leases",
|
|
1811
|
+
routines: "mem:routines",
|
|
1812
|
+
routineRuns: "mem:routine-runs",
|
|
1813
|
+
signals: "mem:signals",
|
|
1814
|
+
checkpoints: "mem:checkpoints",
|
|
1815
|
+
mesh: "mem:mesh",
|
|
1816
|
+
sketches: "mem:sketches",
|
|
1817
|
+
facets: "mem:facets",
|
|
1818
|
+
sentinels: "mem:sentinels",
|
|
1819
|
+
crystals: "mem:crystals",
|
|
1820
|
+
lessons: "mem:lessons",
|
|
1821
|
+
insights: "mem:insights",
|
|
1822
|
+
graphEdgeHistory: "mem:graph:edge-history",
|
|
1823
|
+
enrichedChunks: (sessionId) => `mem:enriched:${sessionId}`,
|
|
1824
|
+
latentEmbeddings: (obsId) => `mem:latent:${obsId}`,
|
|
1825
|
+
retentionScores: "mem:retention",
|
|
1826
|
+
accessLog: "mem:access",
|
|
1827
|
+
imageRefs: "mem:image-refs",
|
|
1828
|
+
imageEmbeddings: "mem:image-embeddings",
|
|
1829
|
+
slots: "mem:slots",
|
|
1830
|
+
globalSlots: "mem:slots:global",
|
|
1831
|
+
state: "mem:state",
|
|
1832
|
+
commits: "mem:commits",
|
|
1833
|
+
recentSearches: "mem:recent-searches",
|
|
1834
|
+
projectSessionsIndex: "mem:idx:project-sessions",
|
|
1835
|
+
obsSessionIndex: (shard) => `mem:idx:obs:${shard}`,
|
|
1836
|
+
captureInbox: "mem:capture:inbox",
|
|
1837
|
+
captureEvents: (shard) => `mem:capture:events:${shard}`,
|
|
1838
|
+
capturePrompts: "mem:capture:prompts"
|
|
1839
|
+
};
|
|
1378
1840
|
function generateId(prefix) {
|
|
1379
1841
|
return `${prefix}_${Date.now().toString(36)}_${crypto.randomUUID().replace(/-/g, "").slice(0, 12)}`;
|
|
1380
1842
|
}
|
|
1843
|
+
process.env["AGENTMEMORY_VERBOSE"] === "1" || process.env["AGENTMEMORY_VERBOSE"];
|
|
1844
|
+
new AsyncLocalStorage();
|
|
1845
|
+
KV.auditMonths;
|
|
1846
|
+
const AUDIT_MIGRATION_STATE_KEY = "migration";
|
|
1847
|
+
async function readAuditMigrationState(kv) {
|
|
1848
|
+
return kv.get(KV.auditMonths, AUDIT_MIGRATION_STATE_KEY);
|
|
1849
|
+
}
|
|
1850
|
+
function monthStartMs(month) {
|
|
1851
|
+
const [year, mon] = month.split("-").map(Number);
|
|
1852
|
+
return Date.UTC(year, mon - 1, 1);
|
|
1853
|
+
}
|
|
1854
|
+
function monthEndMs(month) {
|
|
1855
|
+
const [year, mon] = month.split("-").map(Number);
|
|
1856
|
+
return Date.UTC(year, mon, 1) - 1;
|
|
1857
|
+
}
|
|
1858
|
+
async function readAuditMonthIndex(kv) {
|
|
1859
|
+
return (await kv.get(KV.auditMonths, "index"))?.months ?? [];
|
|
1860
|
+
}
|
|
1861
|
+
async function listAuditMonthsDesc(kv) {
|
|
1862
|
+
return [...await readAuditMonthIndex(kv)].sort().reverse();
|
|
1863
|
+
}
|
|
1864
|
+
async function queryAudit(kv, filter) {
|
|
1865
|
+
const limit = filter?.limit || 100;
|
|
1866
|
+
let fromMs;
|
|
1867
|
+
if (filter?.dateFrom) {
|
|
1868
|
+
fromMs = new Date(filter.dateFrom).getTime();
|
|
1869
|
+
if (Number.isNaN(fromMs)) throw new Error(`Invalid dateFrom: ${filter.dateFrom}`);
|
|
1870
|
+
}
|
|
1871
|
+
const query = filter?.query?.trim().toLowerCase();
|
|
1872
|
+
let toMs;
|
|
1873
|
+
if (filter?.dateTo) {
|
|
1874
|
+
toMs = new Date(filter.dateTo).getTime();
|
|
1875
|
+
if (Number.isNaN(toMs)) throw new Error(`Invalid dateTo: ${filter.dateTo}`);
|
|
1876
|
+
}
|
|
1877
|
+
const matches = (entry) => {
|
|
1878
|
+
if (filter?.operation && entry.operation !== filter.operation) return false;
|
|
1879
|
+
const t = new Date(entry.timestamp).getTime();
|
|
1880
|
+
if (fromMs !== void 0 && t < fromMs) return false;
|
|
1881
|
+
if (toMs !== void 0 && t > toMs) return false;
|
|
1882
|
+
if (query && ![entry.functionId, ...entry.targetIds || []].some((v) => String(v || "").toLowerCase().includes(query))) return false;
|
|
1883
|
+
return true;
|
|
1884
|
+
};
|
|
1885
|
+
const seenIds = /* @__PURE__ */ new Set();
|
|
1886
|
+
const collected = [];
|
|
1887
|
+
const addIfNew = (row) => {
|
|
1888
|
+
if (seenIds.has(row.id)) return;
|
|
1889
|
+
seenIds.add(row.id);
|
|
1890
|
+
if (matches(row)) collected.push(row);
|
|
1891
|
+
};
|
|
1892
|
+
const months = await listAuditMonthsDesc(kv);
|
|
1893
|
+
for (const month of months) {
|
|
1894
|
+
if (collected.length >= limit) break;
|
|
1895
|
+
if (toMs !== void 0 && monthStartMs(month) > toMs) continue;
|
|
1896
|
+
if (fromMs !== void 0 && monthEndMs(month) < fromMs) break;
|
|
1897
|
+
const rows = await kv.list(KV.auditMonth(month));
|
|
1898
|
+
for (const row of rows) addIfNew(row);
|
|
1899
|
+
}
|
|
1900
|
+
let legacyFrozen = false;
|
|
1901
|
+
let legacyFrozenBytes;
|
|
1902
|
+
if (collected.length < limit) {
|
|
1903
|
+
const migrationState = await readAuditMigrationState(kv);
|
|
1904
|
+
if (migrationState?.safeToListLegacy) {
|
|
1905
|
+
const legacyRows = await kv.list(KV.audit);
|
|
1906
|
+
for (const row of legacyRows) addIfNew(row);
|
|
1907
|
+
} else if (migrationState?.status === "too-large" || migrationState?.status === "unreadable") {
|
|
1908
|
+
legacyFrozen = true;
|
|
1909
|
+
legacyFrozenBytes = migrationState.legacySizeBytes;
|
|
1910
|
+
}
|
|
1911
|
+
}
|
|
1912
|
+
collected.sort((a, b) => new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime());
|
|
1913
|
+
return {
|
|
1914
|
+
entries: collected.slice(0, limit),
|
|
1915
|
+
legacyFrozen,
|
|
1916
|
+
legacyFrozenBytes
|
|
1917
|
+
};
|
|
1918
|
+
}
|
|
1919
|
+
//#endregion
|
|
1920
|
+
//#region src/secret-store.ts
|
|
1921
|
+
const SECRET_KEY = "AGENTMEMORY_SECRET";
|
|
1922
|
+
function agentmemoryHomeDir() {
|
|
1923
|
+
return process.env["AGENTMEMORY_DATA_DIR"] || join(homedir(), ".agentmemory");
|
|
1924
|
+
}
|
|
1925
|
+
function secretFilePath() {
|
|
1926
|
+
return join(agentmemoryHomeDir(), "secret");
|
|
1927
|
+
}
|
|
1928
|
+
function usable(value) {
|
|
1929
|
+
if (typeof value !== "string") return "";
|
|
1930
|
+
const trimmed = value.trim();
|
|
1931
|
+
if (!trimmed) return "";
|
|
1932
|
+
if (trimmed.startsWith("${") && trimmed.endsWith("}")) return "";
|
|
1933
|
+
return trimmed;
|
|
1934
|
+
}
|
|
1935
|
+
function unquote(value) {
|
|
1936
|
+
const quote = value[0];
|
|
1937
|
+
if ((quote === "\"" || quote === "'") && value.length > 1) {
|
|
1938
|
+
const close = value.indexOf(quote, 1);
|
|
1939
|
+
if (close !== -1) return value.slice(1, close);
|
|
1940
|
+
}
|
|
1941
|
+
const hash = value.indexOf(" #");
|
|
1942
|
+
return hash === -1 ? value : value.slice(0, hash).trim();
|
|
1943
|
+
}
|
|
1944
|
+
function readEnvFileSecret() {
|
|
1945
|
+
let content;
|
|
1946
|
+
try {
|
|
1947
|
+
content = readFileSync(process.env["AGENTMEMORY_ENV_FILE"] || join(homedir(), ".agentmemory", ".env"), "utf-8");
|
|
1948
|
+
} catch {
|
|
1949
|
+
return "";
|
|
1950
|
+
}
|
|
1951
|
+
if (typeof content !== "string") return "";
|
|
1952
|
+
let found = "";
|
|
1953
|
+
for (const line of content.split("\n")) {
|
|
1954
|
+
const trimmed = line.trim();
|
|
1955
|
+
if (trimmed.startsWith("#")) continue;
|
|
1956
|
+
const eq = trimmed.indexOf("=");
|
|
1957
|
+
if (eq === -1) continue;
|
|
1958
|
+
if (trimmed.slice(0, eq).replace(/^export\s+/, "").trim() !== SECRET_KEY) continue;
|
|
1959
|
+
found = usable(unquote(trimmed.slice(eq + 1).trim()));
|
|
1960
|
+
}
|
|
1961
|
+
return found;
|
|
1962
|
+
}
|
|
1963
|
+
function readSecretFile(path) {
|
|
1964
|
+
try {
|
|
1965
|
+
return usable(readFileSync(path, "utf-8"));
|
|
1966
|
+
} catch {
|
|
1967
|
+
return "";
|
|
1968
|
+
}
|
|
1969
|
+
}
|
|
1970
|
+
function legacyDataDirSecretPaths(env = process.env) {
|
|
1971
|
+
const dataDir = env["AGENTMEMORY_DATA_DIR"];
|
|
1972
|
+
if (!dataDir) return [];
|
|
1973
|
+
const paths = [
|
|
1974
|
+
join(dataDir, "secret"),
|
|
1975
|
+
join(dataDir, ".hmac"),
|
|
1976
|
+
join(dataDir, "..", ".hmac")
|
|
1977
|
+
];
|
|
1978
|
+
return [...new Set(paths.filter((path) => path !== secretFilePath()))];
|
|
1979
|
+
}
|
|
1980
|
+
function readStoredSecret(env = process.env) {
|
|
1981
|
+
const canonicalPath = canonicalSecretPath();
|
|
1982
|
+
const localPath = secretFilePath();
|
|
1983
|
+
const legacyPaths = legacyDataDirSecretPaths(env);
|
|
1984
|
+
return readSecretFile(canonicalPath) || (localPath === canonicalPath ? "" : readSecretFile(localPath)) || legacyPaths.map(readSecretFile).find(Boolean) || "";
|
|
1985
|
+
}
|
|
1986
|
+
function isLoopbackUrl(url) {
|
|
1987
|
+
let hostname;
|
|
1988
|
+
try {
|
|
1989
|
+
hostname = new URL(url).hostname.toLowerCase();
|
|
1990
|
+
} catch {
|
|
1991
|
+
return false;
|
|
1992
|
+
}
|
|
1993
|
+
const bare = hostname.replace(/^\[|\]$/g, "");
|
|
1994
|
+
return bare === "localhost" || bare === "::1" || /^127(?:\.\d{1,3}){3}$/.test(bare);
|
|
1995
|
+
}
|
|
1996
|
+
function resolveClientSecret(baseUrl, env = process.env) {
|
|
1997
|
+
const fromEnv = usable(env[SECRET_KEY]);
|
|
1998
|
+
if (fromEnv) return fromEnv;
|
|
1999
|
+
if (env.AGENTMEMORY_CREDENTIAL_MODE === "explicit") return "";
|
|
2000
|
+
if (!isLoopbackUrl(baseUrl)) return "";
|
|
2001
|
+
return readEnvFileSecret() || readStoredSecret(env);
|
|
2002
|
+
}
|
|
2003
|
+
function canonicalSecretPath() {
|
|
2004
|
+
return join(homedir(), ".agentmemory", "secret");
|
|
2005
|
+
}
|
|
1381
2006
|
//#endregion
|
|
1382
2007
|
//#region src/mcp/rest-proxy.ts
|
|
1383
2008
|
const DEFAULT_URL = "http://localhost:3111";
|
|
@@ -1390,11 +2015,22 @@ function probeTimeoutMs() {
|
|
|
1390
2015
|
const n = Number(raw);
|
|
1391
2016
|
return Number.isFinite(n) && n > 0 ? Math.floor(n) : DEFAULT_HEALTH_PROBE_TIMEOUT_MS;
|
|
1392
2017
|
}
|
|
1393
|
-
function
|
|
2018
|
+
function isProxyRequired() {
|
|
1394
2019
|
const raw = process.env["AGENTMEMORY_FORCE_PROXY"];
|
|
1395
2020
|
return raw === "1" || raw === "true";
|
|
1396
2021
|
}
|
|
2022
|
+
var ProxyCallError = class extends Error {
|
|
2023
|
+
status;
|
|
2024
|
+
body;
|
|
2025
|
+
constructor(message, status, body) {
|
|
2026
|
+
super(message);
|
|
2027
|
+
this.name = "ProxyCallError";
|
|
2028
|
+
this.status = status;
|
|
2029
|
+
this.body = body;
|
|
2030
|
+
}
|
|
2031
|
+
};
|
|
1397
2032
|
let cached = null;
|
|
2033
|
+
let cachedUrl = null;
|
|
1398
2034
|
let cachedAt = 0;
|
|
1399
2035
|
let probeInFlight = null;
|
|
1400
2036
|
function resolveEnvOrEmpty(name) {
|
|
@@ -1404,17 +2040,25 @@ function resolveEnvOrEmpty(name) {
|
|
|
1404
2040
|
return raw;
|
|
1405
2041
|
}
|
|
1406
2042
|
function baseUrl() {
|
|
1407
|
-
|
|
2043
|
+
const value = resolveEnvOrEmpty("AGENTMEMORY_URL") || DEFAULT_URL;
|
|
2044
|
+
try {
|
|
2045
|
+
const parsed = new URL(value);
|
|
2046
|
+
if (!["http:", "https:"].includes(parsed.protocol) || !parsed.hostname || parsed.username || parsed.password || /[?#\s]/.test(value)) throw new Error();
|
|
2047
|
+
return value.replace(/\/+$/, "");
|
|
2048
|
+
} catch {
|
|
2049
|
+
throw new Error("AGENTMEMORY_URL must be an HTTP(S) URL without credentials, query, or fragment");
|
|
2050
|
+
}
|
|
1408
2051
|
}
|
|
1409
|
-
function authHeader() {
|
|
1410
|
-
const secret =
|
|
2052
|
+
function authHeader(url) {
|
|
2053
|
+
const secret = resolveClientSecret(url);
|
|
1411
2054
|
return secret ? { authorization: `Bearer ${secret}` } : {};
|
|
1412
2055
|
}
|
|
1413
2056
|
const defaultLivezProbe = async (url, timeoutMs, headers) => {
|
|
1414
2057
|
const res = await fetch(`${url}/agentmemory/livez`, {
|
|
1415
2058
|
method: "GET",
|
|
1416
2059
|
headers,
|
|
1417
|
-
signal: AbortSignal.timeout(timeoutMs)
|
|
2060
|
+
signal: AbortSignal.timeout(timeoutMs),
|
|
2061
|
+
redirect: "error"
|
|
1418
2062
|
});
|
|
1419
2063
|
return {
|
|
1420
2064
|
ok: res.ok,
|
|
@@ -1426,7 +2070,7 @@ let livezProbe = defaultLivezProbe;
|
|
|
1426
2070
|
async function probe(url) {
|
|
1427
2071
|
const timeout = probeTimeoutMs();
|
|
1428
2072
|
try {
|
|
1429
|
-
const res = await livezProbe(url, timeout, authHeader());
|
|
2073
|
+
const res = await livezProbe(url, timeout, authHeader(url));
|
|
1430
2074
|
if (!res.ok) process.stderr.write(`[@agentmemory/mcp] livez probe ${url}/agentmemory/livez -> ${res.status ?? "?"} ${res.statusText ?? ""}; falling back to local InMemoryKV (set AGENTMEMORY_FORCE_PROXY=1 to skip the probe)\n`);
|
|
1431
2075
|
return res.ok;
|
|
1432
2076
|
} catch (err) {
|
|
@@ -1436,52 +2080,73 @@ async function probe(url) {
|
|
|
1436
2080
|
}
|
|
1437
2081
|
function invalidateHandle() {
|
|
1438
2082
|
cached = null;
|
|
2083
|
+
cachedUrl = null;
|
|
1439
2084
|
cachedAt = 0;
|
|
1440
2085
|
}
|
|
1441
2086
|
async function resolveHandle() {
|
|
1442
2087
|
const now = Date.now();
|
|
2088
|
+
const url = baseUrl();
|
|
2089
|
+
if (cached && (cachedUrl !== url || cached.mode === "local" && isProxyRequired())) invalidateHandle();
|
|
1443
2090
|
if (cached) if (cached.mode === "local" && now - cachedAt >= LOCAL_MODE_TTL_MS) {
|
|
1444
2091
|
cached = null;
|
|
1445
2092
|
cachedAt = 0;
|
|
1446
2093
|
} else return cached;
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
const
|
|
1450
|
-
probeInFlight = (async () => {
|
|
2094
|
+
const skipProbe = isProxyRequired();
|
|
2095
|
+
if (probeInFlight?.url === url && probeInFlight.forceProxy === skipProbe) return probeInFlight.promise;
|
|
2096
|
+
const pending = (async () => {
|
|
1451
2097
|
const up = skipProbe ? true : await probe(url);
|
|
2098
|
+
if (baseUrl() !== url || isProxyRequired() !== skipProbe) return resolveHandle();
|
|
1452
2099
|
if (skipProbe) process.stderr.write(`[@agentmemory/mcp] AGENTMEMORY_FORCE_PROXY set; skipping livez probe and trusting ${url}\n`);
|
|
1453
2100
|
if (up) {
|
|
1454
2101
|
const handle = {
|
|
1455
2102
|
mode: "proxy",
|
|
1456
2103
|
baseUrl: url,
|
|
1457
2104
|
call: async (path, init) => {
|
|
2105
|
+
if (baseUrl() !== url) throw new Error("AgentMemory endpoint changed; resolve a new proxy handle before retrying.");
|
|
1458
2106
|
const res = await fetch(`${url}${path}`, {
|
|
1459
2107
|
...init,
|
|
1460
2108
|
headers: {
|
|
1461
2109
|
"content-type": "application/json",
|
|
1462
|
-
...authHeader(),
|
|
2110
|
+
...authHeader(url),
|
|
1463
2111
|
...init?.headers
|
|
1464
2112
|
},
|
|
1465
|
-
signal: AbortSignal.timeout(CALL_TIMEOUT_MS)
|
|
2113
|
+
signal: AbortSignal.timeout(CALL_TIMEOUT_MS),
|
|
2114
|
+
redirect: "error"
|
|
1466
2115
|
});
|
|
1467
|
-
if (!res.ok)
|
|
2116
|
+
if (!res.ok) {
|
|
2117
|
+
const errText = await res.text().catch(() => "");
|
|
2118
|
+
let errBody = void 0;
|
|
2119
|
+
if (errText) try {
|
|
2120
|
+
errBody = JSON.parse(errText);
|
|
2121
|
+
} catch {
|
|
2122
|
+
errBody = void 0;
|
|
2123
|
+
}
|
|
2124
|
+
throw new ProxyCallError(`${init?.method || "GET"} ${path} -> ${res.status} ${res.statusText}`, res.status, errBody);
|
|
2125
|
+
}
|
|
1468
2126
|
const text = await res.text();
|
|
1469
2127
|
return text ? JSON.parse(text) : null;
|
|
1470
2128
|
}
|
|
1471
2129
|
};
|
|
1472
2130
|
cached = handle;
|
|
2131
|
+
cachedUrl = url;
|
|
1473
2132
|
cachedAt = Date.now();
|
|
1474
2133
|
return handle;
|
|
1475
2134
|
}
|
|
1476
2135
|
const local = { mode: "local" };
|
|
1477
2136
|
cached = local;
|
|
2137
|
+
cachedUrl = url;
|
|
1478
2138
|
cachedAt = Date.now();
|
|
1479
2139
|
return local;
|
|
1480
2140
|
})();
|
|
2141
|
+
probeInFlight = {
|
|
2142
|
+
url,
|
|
2143
|
+
forceProxy: skipProbe,
|
|
2144
|
+
promise: pending
|
|
2145
|
+
};
|
|
1481
2146
|
try {
|
|
1482
|
-
return await
|
|
2147
|
+
return await pending;
|
|
1483
2148
|
} finally {
|
|
1484
|
-
probeInFlight = null;
|
|
2149
|
+
if (probeInFlight?.promise === pending) probeInFlight = null;
|
|
1485
2150
|
}
|
|
1486
2151
|
}
|
|
1487
2152
|
//#endregion
|
|
@@ -1541,6 +2206,9 @@ function textResponse(payload, pretty = false) {
|
|
|
1541
2206
|
text: JSON.stringify(payload, null, pretty ? 2 : 0)
|
|
1542
2207
|
}] };
|
|
1543
2208
|
}
|
|
2209
|
+
function isAuthenticationError(error) {
|
|
2210
|
+
return error instanceof ProxyCallError && (error.status === 401 || error.status === 403);
|
|
2211
|
+
}
|
|
1544
2212
|
function validate(toolName, args) {
|
|
1545
2213
|
if (!IMPLEMENTED_TOOLS.has(toolName)) throw new Error(`Unknown tool: ${toolName}`);
|
|
1546
2214
|
const v = { tool: toolName };
|
|
@@ -1558,22 +2226,41 @@ function validate(toolName, args) {
|
|
|
1558
2226
|
}
|
|
1559
2227
|
case "memory_recall":
|
|
1560
2228
|
case "memory_smart_search": {
|
|
2229
|
+
if (args.targetLayer !== void 0 && !isSearchLayer(args.targetLayer)) throw new Error("targetLayer must be one of: all, memory, observation");
|
|
2230
|
+
v.targetLayer = args.targetLayer ?? "all";
|
|
2231
|
+
for (const field of [
|
|
2232
|
+
"project",
|
|
2233
|
+
"cwd",
|
|
2234
|
+
"agentId",
|
|
2235
|
+
"sessionId",
|
|
2236
|
+
"source"
|
|
2237
|
+
]) {
|
|
2238
|
+
if (args[field] !== void 0 && typeof args[field] !== "string") throw new Error(`${field} must be a string`);
|
|
2239
|
+
if (typeof args[field] === "string" && args[field].trim()) v[field] = args[field].trim();
|
|
2240
|
+
}
|
|
2241
|
+
if (toolName === "memory_smart_search") {
|
|
2242
|
+
v.expandIds = parseSearchExpansionIds(args.expandIds);
|
|
2243
|
+
if (typeof args.includeLessons === "boolean") v.includeLessons = args.includeLessons;
|
|
2244
|
+
}
|
|
1561
2245
|
const query = args["query"];
|
|
1562
|
-
if (typeof query !== "string" || !query.trim())
|
|
1563
|
-
|
|
2246
|
+
if (typeof query !== "string" || !query.trim()) {
|
|
2247
|
+
if (!v.expandIds?.length) throw new Error("query is required unless expandIds is provided");
|
|
2248
|
+
} else v.query = query.trim();
|
|
1564
2249
|
v.limit = parseLimit(args["limit"]);
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
2250
|
+
if (toolName === "memory_recall") {
|
|
2251
|
+
const format = typeof args.format === "string" ? args.format.trim().toLowerCase() : args.format ?? "full";
|
|
2252
|
+
if (format !== "full" && format !== "compact" && format !== "narrative") throw new Error("format must be one of: full, compact, narrative");
|
|
2253
|
+
v.format = format;
|
|
2254
|
+
if (args.token_budget !== void 0) {
|
|
2255
|
+
const budget = typeof args.token_budget === "string" ? Number(args.token_budget) : args.token_budget;
|
|
2256
|
+
if (typeof budget !== "number" || !Number.isInteger(budget) || budget < 1) throw new Error("token_budget must be a positive integer");
|
|
2257
|
+
v.tokenBudget = budget;
|
|
2258
|
+
}
|
|
1572
2259
|
}
|
|
1573
2260
|
return v;
|
|
1574
2261
|
}
|
|
1575
2262
|
case "memory_sessions":
|
|
1576
|
-
v.
|
|
2263
|
+
v.sessionQuery = parseSessionArguments(args);
|
|
1577
2264
|
return v;
|
|
1578
2265
|
case "memory_governance_delete": {
|
|
1579
2266
|
const ids = normalizeList(args["memoryIds"]);
|
|
@@ -1582,7 +2269,22 @@ function validate(toolName, args) {
|
|
|
1582
2269
|
v.reason = args["reason"] || "plugin skill request";
|
|
1583
2270
|
return v;
|
|
1584
2271
|
}
|
|
1585
|
-
case "memory_export":
|
|
2272
|
+
case "memory_export": {
|
|
2273
|
+
const query = new URLSearchParams();
|
|
2274
|
+
for (const key of [
|
|
2275
|
+
"maxSessions",
|
|
2276
|
+
"offset",
|
|
2277
|
+
"collectionLimit",
|
|
2278
|
+
"collectionOffset"
|
|
2279
|
+
]) {
|
|
2280
|
+
const n = Number(args[key]);
|
|
2281
|
+
const min = key === "maxSessions" || key === "collectionLimit" ? 1 : 0;
|
|
2282
|
+
if (args[key] !== void 0 && Number.isInteger(n) && n >= min) query.set(key, String(n));
|
|
2283
|
+
}
|
|
2284
|
+
if (typeof args["collections"] === "string") query.set("collections", args["collections"]);
|
|
2285
|
+
v.exportQuery = query.toString();
|
|
2286
|
+
return v;
|
|
2287
|
+
}
|
|
1586
2288
|
case "memory_audit":
|
|
1587
2289
|
v.limit = parseLimit(args["limit"], 50);
|
|
1588
2290
|
return v;
|
|
@@ -1606,7 +2308,11 @@ async function handleProxy(v, handle) {
|
|
|
1606
2308
|
const body = {
|
|
1607
2309
|
query: v.query,
|
|
1608
2310
|
limit: v.limit,
|
|
1609
|
-
format: v.format ?? "full"
|
|
2311
|
+
format: v.format ?? "full",
|
|
2312
|
+
targetLayer: v.targetLayer,
|
|
2313
|
+
project: v.project,
|
|
2314
|
+
cwd: v.cwd,
|
|
2315
|
+
agentId: v.agentId
|
|
1610
2316
|
};
|
|
1611
2317
|
if (v.tokenBudget != null) body["token_budget"] = v.tokenBudget;
|
|
1612
2318
|
return textResponse(await handle.call("/agentmemory/search", {
|
|
@@ -1617,16 +2323,21 @@ async function handleProxy(v, handle) {
|
|
|
1617
2323
|
case "memory_smart_search": {
|
|
1618
2324
|
const body = {
|
|
1619
2325
|
query: v.query,
|
|
1620
|
-
limit: v.limit
|
|
2326
|
+
limit: v.limit,
|
|
2327
|
+
targetLayer: v.targetLayer,
|
|
2328
|
+
project: v.project,
|
|
2329
|
+
agentId: v.agentId,
|
|
2330
|
+
expandIds: v.expandIds,
|
|
2331
|
+
sessionId: v.sessionId,
|
|
2332
|
+
source: v.source,
|
|
2333
|
+
includeLessons: v.includeLessons
|
|
1621
2334
|
};
|
|
1622
|
-
if (v.format != null) body["format"] = v.format;
|
|
1623
|
-
if (v.tokenBudget != null) body["token_budget"] = v.tokenBudget;
|
|
1624
2335
|
return textResponse(await handle.call("/agentmemory/smart-search", {
|
|
1625
2336
|
method: "POST",
|
|
1626
2337
|
body: JSON.stringify(body)
|
|
1627
2338
|
}), true);
|
|
1628
2339
|
}
|
|
1629
|
-
case "memory_sessions": return textResponse(await handle.call(`/agentmemory/sessions
|
|
2340
|
+
case "memory_sessions": return textResponse(await handle.call(`/agentmemory/sessions?${new URLSearchParams(v.sessionQuery)}`, { method: "GET" }), true);
|
|
1630
2341
|
case "memory_governance_delete": return textResponse(await handle.call("/agentmemory/governance/memories", {
|
|
1631
2342
|
method: "DELETE",
|
|
1632
2343
|
body: JSON.stringify({
|
|
@@ -1634,11 +2345,23 @@ async function handleProxy(v, handle) {
|
|
|
1634
2345
|
reason: v.reason
|
|
1635
2346
|
})
|
|
1636
2347
|
}));
|
|
1637
|
-
case "memory_export":
|
|
2348
|
+
case "memory_export": try {
|
|
2349
|
+
return textResponse(await handle.call(`/agentmemory/export${v.exportQuery ? `?${v.exportQuery}` : ""}`, { method: "GET" }), true);
|
|
2350
|
+
} catch (err) {
|
|
2351
|
+
if (err instanceof ProxyCallError && err.status === 413 && err.body != null && typeof err.body === "object" && err.body.oversized === true) return textResponse(err.body, true);
|
|
2352
|
+
throw err;
|
|
2353
|
+
}
|
|
1638
2354
|
case "memory_audit": return textResponse(await handle.call(`/agentmemory/audit?limit=${v.limit}`, { method: "GET" }), true);
|
|
1639
2355
|
default: throw new Error(`Unknown tool: ${v.tool}`);
|
|
1640
2356
|
}
|
|
1641
2357
|
}
|
|
2358
|
+
function localFallbackNotice(persisted) {
|
|
2359
|
+
const store = persisted ? "the local fallback file, which the server does not read" : "this process's in-memory fallback store, which is lost when the process exits";
|
|
2360
|
+
return {
|
|
2361
|
+
storage: "local",
|
|
2362
|
+
warning: `agentmemory server at ${displayAgentmemoryUrl()} did not confirm this call, so it ran against ${store}.`
|
|
2363
|
+
};
|
|
2364
|
+
}
|
|
1642
2365
|
async function handleLocal(v, kvInstance) {
|
|
1643
2366
|
switch (v.tool) {
|
|
1644
2367
|
case "memory_save": {
|
|
@@ -1656,34 +2379,96 @@ async function handleLocal(v, kvInstance) {
|
|
|
1656
2379
|
strength: 7,
|
|
1657
2380
|
version: 1,
|
|
1658
2381
|
isLatest: true,
|
|
1659
|
-
sessionIds: []
|
|
2382
|
+
sessionIds: [],
|
|
2383
|
+
...v.project !== void 0 && { project: v.project },
|
|
2384
|
+
...(v.agentId ?? getAgentId()) !== void 0 && { agentId: v.agentId ?? getAgentId() }
|
|
2385
|
+
});
|
|
2386
|
+
return textResponse({
|
|
2387
|
+
saved: id,
|
|
2388
|
+
...localFallbackNotice(kvInstance.persist())
|
|
1660
2389
|
});
|
|
1661
|
-
kvInstance.persist();
|
|
1662
|
-
return textResponse({ saved: id });
|
|
1663
2390
|
}
|
|
1664
2391
|
case "memory_recall":
|
|
1665
2392
|
case "memory_smart_search": {
|
|
2393
|
+
const isolated = isAgentScopeIsolated();
|
|
2394
|
+
const agentId = v.agentId === "*" ? void 0 : v.agentId ?? (isolated ? getAgentId() : void 0);
|
|
2395
|
+
if (isolated && v.agentId !== "*" && !agentId) throw new Error("AGENTMEMORY_AGENT_SCOPE=isolated requires an agentId; pass '*' to read across agents");
|
|
1666
2396
|
const query = (v.query || "").toLowerCase();
|
|
1667
2397
|
const limit = v.limit ?? DEFAULT_LIMIT;
|
|
2398
|
+
const all = v.targetLayer === "observation" ? [] : await kvInstance.list("mem:memories");
|
|
2399
|
+
const sessions = v.project || v.cwd ? await kvInstance.list("mem:sessions") : [];
|
|
2400
|
+
const sessionsById = new Map(sessions.map((session) => [session.id, session]));
|
|
2401
|
+
const scoped = all.filter((memory) => {
|
|
2402
|
+
if (memory.isLatest === false || agentId && memory.agentId !== agentId) return false;
|
|
2403
|
+
const linkedSessions = (memory.sessionIds ?? []).map((id) => sessionsById.get(id));
|
|
2404
|
+
if (v.project && (memory.project ? memory.project !== v.project : !linkedSessions.some((session) => session?.project === v.project))) return false;
|
|
2405
|
+
if (v.cwd && !linkedSessions.some((session) => session?.cwd === v.cwd)) return false;
|
|
2406
|
+
return true;
|
|
2407
|
+
});
|
|
2408
|
+
if (v.tool === "memory_smart_search" && v.expandIds?.length) {
|
|
2409
|
+
const ids = v.expandIds.map((entry) => typeof entry === "string" ? entry : entry.obsId);
|
|
2410
|
+
const byId = new Map(scoped.map((memory) => [memory.id, memory]));
|
|
2411
|
+
const eligible = ids.filter((id) => byId.has(id));
|
|
2412
|
+
return textResponse({
|
|
2413
|
+
mode: "expanded",
|
|
2414
|
+
results: eligible.slice(0, 20).map((id) => {
|
|
2415
|
+
const observation = memoryToObservation(byId.get(id));
|
|
2416
|
+
return {
|
|
2417
|
+
obsId: id,
|
|
2418
|
+
sessionId: observation.sessionId,
|
|
2419
|
+
observation,
|
|
2420
|
+
layer: "memory"
|
|
2421
|
+
};
|
|
2422
|
+
}),
|
|
2423
|
+
truncated: eligible.length > 20
|
|
2424
|
+
}, true);
|
|
2425
|
+
}
|
|
2426
|
+
const results = scoped.filter((memory) => {
|
|
2427
|
+
const text = [
|
|
2428
|
+
memory.title,
|
|
2429
|
+
memory.content,
|
|
2430
|
+
...memory.files ?? [],
|
|
2431
|
+
...memory.concepts ?? [],
|
|
2432
|
+
...memory.sessionIds ?? [],
|
|
2433
|
+
memory.id
|
|
2434
|
+
].join(" ").toLowerCase();
|
|
2435
|
+
return query.split(/\s+/).every((word) => text.includes(word));
|
|
2436
|
+
}).slice(0, limit);
|
|
2437
|
+
if (v.tool === "memory_recall") return textResponse(buildRecallResponse(results.map((memory) => {
|
|
2438
|
+
const observation = memoryToObservation(memory);
|
|
2439
|
+
return {
|
|
2440
|
+
sessionId: observation.sessionId,
|
|
2441
|
+
observation,
|
|
2442
|
+
score: 1,
|
|
2443
|
+
layer: "memory"
|
|
2444
|
+
};
|
|
2445
|
+
}), v.format ?? "full", v.tokenBudget), true);
|
|
1668
2446
|
return textResponse({
|
|
1669
2447
|
mode: "compact",
|
|
1670
|
-
results:
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
Array.isArray(m["sessionIds"]) ? m["sessionIds"].join(" ") : "",
|
|
1677
|
-
typeof m["id"] === "string" ? m["id"] : ""
|
|
1678
|
-
].join(" ").toLowerCase();
|
|
1679
|
-
return query.split(/\s+/).every((word) => text.includes(word));
|
|
1680
|
-
}).slice(0, limit)
|
|
2448
|
+
results: results.map((memory) => ({
|
|
2449
|
+
...memory,
|
|
2450
|
+
obsId: memory.id,
|
|
2451
|
+
sessionId: memory.sessionIds?.[0] ?? "memory",
|
|
2452
|
+
layer: "memory"
|
|
2453
|
+
}))
|
|
1681
2454
|
}, true);
|
|
1682
2455
|
}
|
|
1683
2456
|
case "memory_sessions": {
|
|
1684
|
-
const
|
|
1685
|
-
const
|
|
1686
|
-
|
|
2457
|
+
const query = v.sessionQuery;
|
|
2458
|
+
const agentId = query.agentId === "*" ? void 0 : query.agentId ?? (isAgentScopeIsolated() ? getAgentId() : void 0);
|
|
2459
|
+
const sessions = (await kvInstance.list("mem:sessions")).filter((session) => session && typeof session.id === "string" && session.id.length > 0).filter((session) => !query.project || session.project === query.project).filter((session) => !agentId || session.agentId === agentId);
|
|
2460
|
+
const key = (session) => session.startedAt || "";
|
|
2461
|
+
const { page, nextCursor } = pageAfterCursor(sortByKeyDesc(sessions, key, (session) => session.id), key, (session) => session.id, query.cursor, Number(query.limit));
|
|
2462
|
+
return textResponse({
|
|
2463
|
+
sessions: await Promise.all(page.map(async (session) => {
|
|
2464
|
+
const summary = await kvInstance.get("mem:summaries", session.id);
|
|
2465
|
+
return summary ? {
|
|
2466
|
+
...session,
|
|
2467
|
+
summary
|
|
2468
|
+
} : session;
|
|
2469
|
+
})),
|
|
2470
|
+
nextCursor
|
|
2471
|
+
}, true);
|
|
1687
2472
|
}
|
|
1688
2473
|
case "memory_governance_delete": {
|
|
1689
2474
|
let deleted = 0;
|
|
@@ -1691,11 +2476,12 @@ async function handleLocal(v, kvInstance) {
|
|
|
1691
2476
|
await kvInstance.delete("mem:memories", id);
|
|
1692
2477
|
deleted++;
|
|
1693
2478
|
}
|
|
1694
|
-
kvInstance.persist();
|
|
2479
|
+
const persisted = kvInstance.persist();
|
|
1695
2480
|
return textResponse({
|
|
1696
2481
|
deleted,
|
|
1697
2482
|
requested: (v.memoryIds || []).length,
|
|
1698
|
-
reason: v.reason
|
|
2483
|
+
reason: v.reason,
|
|
2484
|
+
...localFallbackNotice(persisted)
|
|
1699
2485
|
});
|
|
1700
2486
|
}
|
|
1701
2487
|
case "memory_export": return textResponse({
|
|
@@ -1703,11 +2489,7 @@ async function handleLocal(v, kvInstance) {
|
|
|
1703
2489
|
memories: await kvInstance.list("mem:memories"),
|
|
1704
2490
|
sessions: await kvInstance.list("mem:sessions")
|
|
1705
2491
|
}, true);
|
|
1706
|
-
case "memory_audit": {
|
|
1707
|
-
const entries = await kvInstance.list("mem:audit");
|
|
1708
|
-
const limit = v.limit ?? 50;
|
|
1709
|
-
return textResponse({ entries: entries.slice(0, limit) }, true);
|
|
1710
|
-
}
|
|
2492
|
+
case "memory_audit": return textResponse(await queryAudit(kvInstance, { limit: v.limit ?? 50 }), true);
|
|
1711
2493
|
default: throw new Error(`Unknown tool: ${v.tool}`);
|
|
1712
2494
|
}
|
|
1713
2495
|
}
|
|
@@ -1739,6 +2521,10 @@ async function handleToolCall(toolName, args, kvInstance = kv) {
|
|
|
1739
2521
|
if (handle.mode === "proxy") try {
|
|
1740
2522
|
return await handleProxy(validated, handle);
|
|
1741
2523
|
} catch (err) {
|
|
2524
|
+
if (toolName === "memory_sessions" || isAuthenticationError(err) || isProxyRequired()) {
|
|
2525
|
+
invalidateHandle();
|
|
2526
|
+
throw err;
|
|
2527
|
+
}
|
|
1742
2528
|
process.stderr.write(`[@agentmemory/mcp] proxy call failed for ${toolName}: ${err instanceof Error ? err.message : String(err)}; invalidating handle and falling back to local KV\n`);
|
|
1743
2529
|
invalidateHandle();
|
|
1744
2530
|
}
|
|
@@ -1759,10 +2545,12 @@ async function handleToolsList() {
|
|
|
1759
2545
|
if (debug) process.stderr.write(`[@agentmemory/mcp] tools/list: returning ${remote.tools.length} tools from server\n`);
|
|
1760
2546
|
return { tools: remote.tools };
|
|
1761
2547
|
}
|
|
2548
|
+
if (isProxyRequired()) throw new Error("AgentMemory returned an invalid tool inventory");
|
|
1762
2549
|
process.stderr.write(`[@agentmemory/mcp] tools/list: server returned unexpected shape (no .tools array); falling back to local IMPLEMENTED_TOOLS list. Set AGENTMEMORY_DEBUG=1 to inspect response.\n`);
|
|
1763
2550
|
} catch (err) {
|
|
1764
|
-
process.stderr.write(`[@agentmemory/mcp] tools/list proxy failed: ${err instanceof Error ? err.message : String(err)}; falling back to local list\n`);
|
|
1765
2551
|
invalidateHandle();
|
|
2552
|
+
if (isAuthenticationError(err) || isProxyRequired()) throw err;
|
|
2553
|
+
process.stderr.write(`[@agentmemory/mcp] tools/list proxy failed: ${err instanceof Error ? err.message : String(err)}; falling back to local list\n`);
|
|
1766
2554
|
}
|
|
1767
2555
|
const fallback = getAllTools().filter((t) => IMPLEMENTED_TOOLS.has(t.name));
|
|
1768
2556
|
if (debug) process.stderr.write(`[@agentmemory/mcp] tools/list: returning ${fallback.length} local fallback tools (${fallback.map((t) => t.name).join(",")})\n`);
|