@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
|
@@ -0,0 +1,2449 @@
|
|
|
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
|
+
import { homedir } from "node:os";
|
|
5
|
+
import pc from "picocolors";
|
|
6
|
+
import { randomBytes } from "node:crypto";
|
|
7
|
+
import { readFile, stat } from "node:fs/promises";
|
|
8
|
+
//#region src/config.ts
|
|
9
|
+
const MAX_IMPORT_OBS_PER_SESSION = 5e3;
|
|
10
|
+
function safeParseInt(value, fallback) {
|
|
11
|
+
if (!value) return fallback;
|
|
12
|
+
const parsed = parseInt(value, 10);
|
|
13
|
+
return Number.isNaN(parsed) ? fallback : parsed;
|
|
14
|
+
}
|
|
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");
|
|
17
|
+
let warnPremiumModelShown = false;
|
|
18
|
+
let providerNoticeShown = false;
|
|
19
|
+
let obsCapImportCeilingWarned = false;
|
|
20
|
+
function writeProviderNoticeOnce(text) {
|
|
21
|
+
if (providerNoticeShown) return;
|
|
22
|
+
providerNoticeShown = true;
|
|
23
|
+
process.stderr.write(text);
|
|
24
|
+
}
|
|
25
|
+
let envFileCache;
|
|
26
|
+
function loadEnvFile() {
|
|
27
|
+
if (envFileCache) return envFileCache;
|
|
28
|
+
if (!existsSync(ENV_FILE)) {
|
|
29
|
+
envFileCache = {};
|
|
30
|
+
return envFileCache;
|
|
31
|
+
}
|
|
32
|
+
envFileCache = parseEnvContent(readFileSync(ENV_FILE, "utf-8"));
|
|
33
|
+
return envFileCache;
|
|
34
|
+
}
|
|
35
|
+
function parseEnvContent(content) {
|
|
36
|
+
const vars = {};
|
|
37
|
+
for (const line of content.split("\n")) {
|
|
38
|
+
const trimmed = line.trim();
|
|
39
|
+
if (!trimmed || trimmed.startsWith("#")) continue;
|
|
40
|
+
const eqIdx = trimmed.indexOf("=");
|
|
41
|
+
if (eqIdx === -1) continue;
|
|
42
|
+
const key = trimmed.slice(0, eqIdx).trim();
|
|
43
|
+
let val = trimmed.slice(eqIdx + 1).trim();
|
|
44
|
+
const quoteChar = val[0] === "\"" || val[0] === "'" ? val[0] : "";
|
|
45
|
+
if (quoteChar) {
|
|
46
|
+
const closeIdx = val.indexOf(quoteChar, 1);
|
|
47
|
+
if (closeIdx !== -1) val = val.slice(1, closeIdx);
|
|
48
|
+
} else {
|
|
49
|
+
const hashIdx = val.indexOf(" #");
|
|
50
|
+
if (hashIdx !== -1) val = val.slice(0, hashIdx).trim();
|
|
51
|
+
}
|
|
52
|
+
vars[key] = val;
|
|
53
|
+
}
|
|
54
|
+
return vars;
|
|
55
|
+
}
|
|
56
|
+
function hasRealValue(v) {
|
|
57
|
+
return typeof v === "string" && v.trim().length > 0;
|
|
58
|
+
}
|
|
59
|
+
function hydrateProcessEnvFromFile() {
|
|
60
|
+
const beforeHydration = { ...process.env };
|
|
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
|
+
function detectProvider(env) {
|
|
70
|
+
const maxTokens = parseInt(env["MAX_TOKENS"] || "4096", 10);
|
|
71
|
+
if (hasRealValue(env["OPENAI_API_KEY"]) && env["OPENAI_API_KEY_FOR_LLM"] !== "false") {
|
|
72
|
+
const model = env["OPENAI_MODEL"] || "gpt-5.6-luna";
|
|
73
|
+
warnIfPremiumModel(env, "OPENAI_MODEL", model);
|
|
74
|
+
return {
|
|
75
|
+
provider: "openai",
|
|
76
|
+
model,
|
|
77
|
+
maxTokens,
|
|
78
|
+
baseURL: env["OPENAI_BASE_URL"]
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
if (hasRealValue(env["MINIMAX_API_KEY"])) return {
|
|
82
|
+
provider: "minimax",
|
|
83
|
+
model: env["MINIMAX_MODEL"] || "MiniMax-M3",
|
|
84
|
+
maxTokens
|
|
85
|
+
};
|
|
86
|
+
if (hasRealValue(env["ANTHROPIC_API_KEY"])) return {
|
|
87
|
+
provider: "anthropic",
|
|
88
|
+
model: env["ANTHROPIC_MODEL"] || "claude-sonnet-5",
|
|
89
|
+
maxTokens,
|
|
90
|
+
baseURL: env["ANTHROPIC_BASE_URL"]
|
|
91
|
+
};
|
|
92
|
+
if (hasRealValue(env["GEMINI_API_KEY"]) || hasRealValue(env["GOOGLE_API_KEY"])) {
|
|
93
|
+
if (!hasRealValue(env["GEMINI_API_KEY"]) && hasRealValue(env["GOOGLE_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");
|
|
94
|
+
return {
|
|
95
|
+
provider: "gemini",
|
|
96
|
+
model: env["GEMINI_MODEL"] || "gemini-3.7-flash",
|
|
97
|
+
maxTokens
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
if (hasRealValue(env["OPENROUTER_API_KEY"])) {
|
|
101
|
+
const model = env["OPENROUTER_MODEL"] || "anthropic/claude-sonnet-5";
|
|
102
|
+
warnIfPremiumModel(env, "OPENROUTER_MODEL", model);
|
|
103
|
+
return {
|
|
104
|
+
provider: "openrouter",
|
|
105
|
+
model,
|
|
106
|
+
maxTokens
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
if (!(env["AGENTMEMORY_ALLOW_AGENT_SDK"] === "true")) {
|
|
110
|
+
writeProviderNoticeOnce(pc.dim("[agentmemory] No LLM provider key set — running zero-LLM: no LLM compression or summaries; search uses BM25 plus any configured embedding provider. Set EMBEDDING_PROVIDER=local for on-device semantic embeddings if none is configured. Set ANTHROPIC_API_KEY (or GEMINI/OPENAI/OPENROUTER/MINIMAX) in ~/.agentmemory/.env for LLM compression and summaries. Agent-SDK fallback stays off by default to avoid a Stop-hook recursion loop; opt in with AGENTMEMORY_AUTO_COMPRESS=true + AGENTMEMORY_ALLOW_AGENT_SDK=true.\n"));
|
|
111
|
+
return {
|
|
112
|
+
provider: "noop",
|
|
113
|
+
model: "noop",
|
|
114
|
+
maxTokens
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
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");
|
|
118
|
+
return {
|
|
119
|
+
provider: "agent-sdk",
|
|
120
|
+
model: "claude-sonnet-5",
|
|
121
|
+
maxTokens
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
function loadConfig() {
|
|
125
|
+
const env = getMergedEnv();
|
|
126
|
+
const provider = detectProvider(env);
|
|
127
|
+
const restPort = parseInt(env["III_REST_PORT"] || "3111", 10) || 3111;
|
|
128
|
+
const viewerPort = parseInt(env["III_VIEWER_PORT"] || "", 10) || restPort + 2;
|
|
129
|
+
const engineUrl = env["III_ENGINE_URL"] || env["III_URL"] || `ws://localhost:${parseInt(env["III_ENGINE_PORT"] || "", 10) || restPort + 46023}`;
|
|
130
|
+
const maxObservationsPerSession = safeParseInt(env["MAX_OBS_PER_SESSION"], 500);
|
|
131
|
+
if (!obsCapImportCeilingWarned && (maxObservationsPerSession === 0 || maxObservationsPerSession > 5e3)) {
|
|
132
|
+
obsCapImportCeilingWarned = true;
|
|
133
|
+
const capDesc = maxObservationsPerSession === 0 ? "uncapped (0)" : String(maxObservationsPerSession);
|
|
134
|
+
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`);
|
|
135
|
+
}
|
|
136
|
+
return {
|
|
137
|
+
engineUrl,
|
|
138
|
+
restPort,
|
|
139
|
+
viewerPort,
|
|
140
|
+
provider,
|
|
141
|
+
tokenBudget: safeParseInt(env["TOKEN_BUDGET"], 2e3),
|
|
142
|
+
maxObservationsPerSession,
|
|
143
|
+
compressionModel: provider.model,
|
|
144
|
+
dataDir: DATA_DIR
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
function getMergedEnv(overrides) {
|
|
148
|
+
return {
|
|
149
|
+
...loadEnvFile(),
|
|
150
|
+
...process.env,
|
|
151
|
+
...overrides
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
function getEnvVar(key) {
|
|
155
|
+
return getMergedEnv()[key];
|
|
156
|
+
}
|
|
157
|
+
function isSessionSweepEnabled() {
|
|
158
|
+
return getMergedEnv()["AGENTMEMORY_SESSION_SWEEP_ENABLED"] !== "false";
|
|
159
|
+
}
|
|
160
|
+
function getSessionSweepStaleHours() {
|
|
161
|
+
const raw = getMergedEnv()["AGENTMEMORY_SESSION_SWEEP_STALE_HOURS"];
|
|
162
|
+
if (!raw || !/^\d+$/.test(raw.trim())) return 24;
|
|
163
|
+
const parsed = parseInt(raw.trim(), 10);
|
|
164
|
+
return parsed > 0 ? parsed : 24;
|
|
165
|
+
}
|
|
166
|
+
function getFinalizeIdleMs() {
|
|
167
|
+
const raw = getMergedEnv()["AGENTMEMORY_FINALIZE_IDLE_MS"];
|
|
168
|
+
if (!raw || !/^\d+$/.test(raw.trim())) return 12e4;
|
|
169
|
+
return parseInt(raw.trim(), 10);
|
|
170
|
+
}
|
|
171
|
+
function isGraphCompactOnBootEnabled() {
|
|
172
|
+
return getMergedEnv()["AGENTMEMORY_GRAPH_COMPACT_ON_BOOT"] !== "false";
|
|
173
|
+
}
|
|
174
|
+
function isDropStaleIndexEnabled() {
|
|
175
|
+
return getMergedEnv()["AGENTMEMORY_DROP_STALE_INDEX"] === "true";
|
|
176
|
+
}
|
|
177
|
+
const VALID_STATE_BACKENDS = new Set(["file", "redis"]);
|
|
178
|
+
function getStateBackend() {
|
|
179
|
+
const raw = (getMergedEnv()["AGENTMEMORY_STATE_BACKEND"] || "").trim().toLowerCase();
|
|
180
|
+
if (!raw) return "file";
|
|
181
|
+
if (!VALID_STATE_BACKENDS.has(raw)) throw new Error(`AGENTMEMORY_STATE_BACKEND="${raw}" is not a recognized state backend. Use "file" (the default) or "redis", or unset it to keep the default file store.`);
|
|
182
|
+
return raw;
|
|
183
|
+
}
|
|
184
|
+
function getRedisUrl() {
|
|
185
|
+
const value = getMergedEnv()["AGENTMEMORY_REDIS_URL"];
|
|
186
|
+
return hasRealValue(value) ? value.trim() : void 0;
|
|
187
|
+
}
|
|
188
|
+
function getAuditRetentionMonths() {
|
|
189
|
+
return safeParseInt(getMergedEnv()["AGENTMEMORY_AUDIT_RETENTION_MONTHS"], 0);
|
|
190
|
+
}
|
|
191
|
+
function getAuditMigrateMaxBytes() {
|
|
192
|
+
return safeParseInt(getMergedEnv()["AGENTMEMORY_AUDIT_MIGRATE_MAX_BYTES"], 32 * 1024 * 1024);
|
|
193
|
+
}
|
|
194
|
+
function detectLlmProviderKind(env = getMergedEnv()) {
|
|
195
|
+
if (hasRealValue(env["ANTHROPIC_API_KEY"]) || hasRealValue(env["GEMINI_API_KEY"]) || hasRealValue(env["GOOGLE_API_KEY"]) || hasRealValue(env["OPENROUTER_API_KEY"]) || hasRealValue(env["MINIMAX_API_KEY"]) || hasRealValue(env["OPENAI_API_KEY"]) && env["OPENAI_API_KEY_FOR_LLM"] !== "false" || env["AGENTMEMORY_ALLOW_AGENT_SDK"] === "true") return "llm";
|
|
196
|
+
return "noop";
|
|
197
|
+
}
|
|
198
|
+
function describeLlmRoute(provider) {
|
|
199
|
+
if (provider.provider === "noop") return null;
|
|
200
|
+
const parts = [provider.provider, provider.model];
|
|
201
|
+
if (provider.baseURL) try {
|
|
202
|
+
parts.push(new URL(provider.baseURL).host);
|
|
203
|
+
} catch {
|
|
204
|
+
parts.push("custom base URL");
|
|
205
|
+
}
|
|
206
|
+
return parts.join(" · ");
|
|
207
|
+
}
|
|
208
|
+
function loadEmbeddingConfig() {
|
|
209
|
+
const env = getMergedEnv();
|
|
210
|
+
let bm25Weight = parseFloat(env["BM25_WEIGHT"] || "0.4");
|
|
211
|
+
let vectorWeight = parseFloat(env["VECTOR_WEIGHT"] || "0.6");
|
|
212
|
+
bm25Weight = isNaN(bm25Weight) || bm25Weight < 0 ? .4 : Math.min(bm25Weight, 1);
|
|
213
|
+
vectorWeight = isNaN(vectorWeight) || vectorWeight < 0 ? .6 : Math.min(vectorWeight, 1);
|
|
214
|
+
return {
|
|
215
|
+
provider: env["EMBEDDING_PROVIDER"] || void 0,
|
|
216
|
+
bm25Weight,
|
|
217
|
+
vectorWeight
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
function detectEmbeddingProvider(env) {
|
|
221
|
+
const source = env ?? getMergedEnv();
|
|
222
|
+
const forced = source["EMBEDDING_PROVIDER"];
|
|
223
|
+
if (forced) return forced;
|
|
224
|
+
if (source["GEMINI_API_KEY"]) return "gemini";
|
|
225
|
+
if (source["OPENAI_API_KEY"] || source["OPENAI_EMBEDDING_API_KEY"]) return "openai";
|
|
226
|
+
if (source["VOYAGE_API_KEY"]) return "voyage";
|
|
227
|
+
if (source["COHERE_API_KEY"]) return "cohere";
|
|
228
|
+
if (source["OPENROUTER_API_KEY"]) return "openrouter";
|
|
229
|
+
return null;
|
|
230
|
+
}
|
|
231
|
+
function loadClaudeBridgeConfig() {
|
|
232
|
+
const env = getMergedEnv();
|
|
233
|
+
const enabled = env["CLAUDE_MEMORY_BRIDGE"] === "true";
|
|
234
|
+
const projectPath = env["CLAUDE_PROJECT_PATH"] || "";
|
|
235
|
+
const lineBudget = safeParseInt(env["CLAUDE_MEMORY_LINE_BUDGET"], 200);
|
|
236
|
+
let memoryFilePath = "";
|
|
237
|
+
if (enabled && projectPath) {
|
|
238
|
+
const safePath = projectPath.replace(/[/\\]/g, "-");
|
|
239
|
+
memoryFilePath = join(homedir(), ".claude", "projects", safePath, "memory", "MEMORY.md");
|
|
240
|
+
}
|
|
241
|
+
return {
|
|
242
|
+
enabled,
|
|
243
|
+
projectPath,
|
|
244
|
+
memoryFilePath,
|
|
245
|
+
lineBudget
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
function loadTeamConfig() {
|
|
249
|
+
const env = getMergedEnv();
|
|
250
|
+
const teamId = env["TEAM_ID"];
|
|
251
|
+
const userId = env["USER_ID"];
|
|
252
|
+
if (!teamId || !userId) return null;
|
|
253
|
+
return {
|
|
254
|
+
teamId,
|
|
255
|
+
userId,
|
|
256
|
+
mode: env["TEAM_MODE"] === "shared" ? "shared" : "private"
|
|
257
|
+
};
|
|
258
|
+
}
|
|
259
|
+
function loadAgentScope() {
|
|
260
|
+
const env = getMergedEnv();
|
|
261
|
+
const raw = env["AGENT_ID"];
|
|
262
|
+
if (!raw) return null;
|
|
263
|
+
const agentId = raw.trim().slice(0, 128);
|
|
264
|
+
if (!agentId) return null;
|
|
265
|
+
return {
|
|
266
|
+
agentId,
|
|
267
|
+
mode: env["AGENTMEMORY_AGENT_SCOPE"] === "isolated" ? "isolated" : "shared"
|
|
268
|
+
};
|
|
269
|
+
}
|
|
270
|
+
function getAgentId() {
|
|
271
|
+
return loadAgentScope()?.agentId;
|
|
272
|
+
}
|
|
273
|
+
function isAgentScopeIsolated() {
|
|
274
|
+
return loadAgentScope()?.mode === "isolated";
|
|
275
|
+
}
|
|
276
|
+
const SNAPSHOT_INTERVAL_DEFAULT_SECONDS = 3600;
|
|
277
|
+
const MIN_SNAPSHOT_INTERVAL_SECONDS = 1;
|
|
278
|
+
function loadSnapshotConfig() {
|
|
279
|
+
const env = getMergedEnv();
|
|
280
|
+
const rawInterval = safeParseInt(env["SNAPSHOT_INTERVAL"], SNAPSHOT_INTERVAL_DEFAULT_SECONDS);
|
|
281
|
+
const interval = rawInterval >= MIN_SNAPSHOT_INTERVAL_SECONDS ? rawInterval : SNAPSHOT_INTERVAL_DEFAULT_SECONDS;
|
|
282
|
+
return {
|
|
283
|
+
enabled: env["SNAPSHOT_ENABLED"] === "true",
|
|
284
|
+
interval,
|
|
285
|
+
dir: env["SNAPSHOT_DIR"] || join(homedir(), ".agentmemory", "snapshots")
|
|
286
|
+
};
|
|
287
|
+
}
|
|
288
|
+
function isGraphExtractionEnabled() {
|
|
289
|
+
return getMergedEnv()["GRAPH_EXTRACTION_ENABLED"] === "true";
|
|
290
|
+
}
|
|
291
|
+
const FOLLOWUP_WINDOW_DEFAULT_SECONDS = 30;
|
|
292
|
+
function getFollowupWindowSeconds() {
|
|
293
|
+
return safeParseInt(getMergedEnv()["AGENTMEMORY_FOLLOWUP_WINDOW_SECONDS"], FOLLOWUP_WINDOW_DEFAULT_SECONDS);
|
|
294
|
+
}
|
|
295
|
+
function isConsolidationEnabled() {
|
|
296
|
+
const env = getMergedEnv();
|
|
297
|
+
const explicit = env["CONSOLIDATION_ENABLED"];
|
|
298
|
+
if (explicit === "false" || explicit === "0") return false;
|
|
299
|
+
if (explicit === "true" || explicit === "1") return true;
|
|
300
|
+
if ((env["AGENTMEMORY_PROVIDER"] || "").toLowerCase() === "noop") return false;
|
|
301
|
+
return detectLlmProviderKind(env) === "llm";
|
|
302
|
+
}
|
|
303
|
+
function isAutoCompressEnabled() {
|
|
304
|
+
return getMergedEnv()["AGENTMEMORY_AUTO_COMPRESS"] === "true";
|
|
305
|
+
}
|
|
306
|
+
function isContextInjectionEnabled() {
|
|
307
|
+
return getMergedEnv()["AGENTMEMORY_INJECT_CONTEXT"] === "true";
|
|
308
|
+
}
|
|
309
|
+
const CONSOLIDATION_INTERVAL_DEFAULT_MS = 72e5;
|
|
310
|
+
function getConsolidationIntervalMs() {
|
|
311
|
+
const raw = parseInt(process.env.CONSOLIDATION_INTERVAL_MS || String(72e5), 10);
|
|
312
|
+
return Number.isFinite(raw) && raw > 0 ? raw : CONSOLIDATION_INTERVAL_DEFAULT_MS;
|
|
313
|
+
}
|
|
314
|
+
function getConsolidationDecayDays() {
|
|
315
|
+
return safeParseInt(getMergedEnv()["CONSOLIDATION_DECAY_DAYS"], 30);
|
|
316
|
+
}
|
|
317
|
+
const CONSOLIDATION_COOLDOWN_DEFAULT_MS = 3e5;
|
|
318
|
+
function getConsolidationCooldownMs() {
|
|
319
|
+
const raw = safeParseInt(getMergedEnv()["AGENTMEMORY_CONSOLIDATION_COOLDOWN_MS"], CONSOLIDATION_COOLDOWN_DEFAULT_MS);
|
|
320
|
+
return raw >= 0 ? raw : CONSOLIDATION_COOLDOWN_DEFAULT_MS;
|
|
321
|
+
}
|
|
322
|
+
const INDEX_SAVE_INTERVAL_DEFAULT_MS = 6e5;
|
|
323
|
+
function getIndexSaveIntervalMs() {
|
|
324
|
+
const raw = safeParseInt(getMergedEnv()["AGENTMEMORY_INDEX_SAVE_INTERVAL_MS"], INDEX_SAVE_INTERVAL_DEFAULT_MS);
|
|
325
|
+
return raw > 0 ? raw : INDEX_SAVE_INTERVAL_DEFAULT_MS;
|
|
326
|
+
}
|
|
327
|
+
const STATE_SAVE_INTERVAL_DEFAULT_MS = 2e3;
|
|
328
|
+
function getStateSaveIntervalMs() {
|
|
329
|
+
const value = getMergedEnv()["AGENTMEMORY_STATE_SAVE_INTERVAL_MS"];
|
|
330
|
+
if (value === void 0 || value.trim() === "") return STATE_SAVE_INTERVAL_DEFAULT_MS;
|
|
331
|
+
if (!/^\d+$/.test(value.trim())) return STATE_SAVE_INTERVAL_DEFAULT_MS;
|
|
332
|
+
const raw = Number(value);
|
|
333
|
+
return Number.isSafeInteger(raw) && raw >= 100 && raw <= 36e5 ? raw : STATE_SAVE_INTERVAL_DEFAULT_MS;
|
|
334
|
+
}
|
|
335
|
+
function getVectorBucketSize() {
|
|
336
|
+
const raw = safeParseInt(getMergedEnv()["AGENTMEMORY_VECTOR_BUCKET_SIZE"], 500);
|
|
337
|
+
return raw > 0 ? raw : 500;
|
|
338
|
+
}
|
|
339
|
+
function getVectorBackfillMax() {
|
|
340
|
+
const raw = safeParseInt(getMergedEnv()["AGENTMEMORY_VECTOR_BACKFILL_MAX"], 500);
|
|
341
|
+
return raw > 0 ? raw : 500;
|
|
342
|
+
}
|
|
343
|
+
function isVectorBackfillAllEnabled() {
|
|
344
|
+
return getMergedEnv()["AGENTMEMORY_VECTOR_BACKFILL"] === "all";
|
|
345
|
+
}
|
|
346
|
+
function getStandalonePersistPath() {
|
|
347
|
+
return getMergedEnv()["STANDALONE_PERSIST_PATH"] || join(homedir(), ".agentmemory", "standalone.json");
|
|
348
|
+
}
|
|
349
|
+
const VALID_PROVIDERS = new Set([
|
|
350
|
+
"anthropic",
|
|
351
|
+
"gemini",
|
|
352
|
+
"openrouter",
|
|
353
|
+
"agent-sdk",
|
|
354
|
+
"minimax",
|
|
355
|
+
"openai"
|
|
356
|
+
]);
|
|
357
|
+
function loadFallbackConfig() {
|
|
358
|
+
const env = getMergedEnv();
|
|
359
|
+
const raw = env["FALLBACK_PROVIDERS"] || "";
|
|
360
|
+
const allowAgentSdk = env["AGENTMEMORY_ALLOW_AGENT_SDK"] === "true";
|
|
361
|
+
return { providers: raw.split(",").map((p) => p.trim()).filter((p) => Boolean(p) && VALID_PROVIDERS.has(p)).filter((p) => {
|
|
362
|
+
if (p === "agent-sdk" && !allowAgentSdk) {
|
|
363
|
+
process.stderr.write("[agentmemory] Ignoring FALLBACK_PROVIDERS entry 'agent-sdk' (AGENTMEMORY_ALLOW_AGENT_SDK is not 'true'). The agent-sdk fallback can spawn Claude Agent SDK child sessions that trigger the Stop-hook recursion loop. Opt in explicitly with AGENTMEMORY_ALLOW_AGENT_SDK=true if this is intentional.\n");
|
|
364
|
+
return false;
|
|
365
|
+
}
|
|
366
|
+
return true;
|
|
367
|
+
}) };
|
|
368
|
+
}
|
|
369
|
+
//#endregion
|
|
370
|
+
//#region src/cli/engine-launch.ts
|
|
371
|
+
function runtimeConfigPath(dataDir) {
|
|
372
|
+
return join(dataDir, "iii-config.runtime.yaml");
|
|
373
|
+
}
|
|
374
|
+
const CREDENTIAL_URL_PATTERN = /:\/\/[^@\s/]*@/g;
|
|
375
|
+
function redactCredentialUrls(text) {
|
|
376
|
+
return text.replace(CREDENTIAL_URL_PATTERN, "://***@");
|
|
377
|
+
}
|
|
378
|
+
//#endregion
|
|
379
|
+
//#region src/cli/engine-config.ts
|
|
380
|
+
const ENGINE_DEFAULT_SAVE_INTERVAL_MS = 5e3;
|
|
381
|
+
const ENGINE_FLUSH_MARGIN_MS = 1500;
|
|
382
|
+
function engineFlushWaitMs(stateBackend, configTexts) {
|
|
383
|
+
if (stateBackend === "redis") return 0;
|
|
384
|
+
return engineSaveIntervalMs(configTexts) + ENGINE_FLUSH_MARGIN_MS;
|
|
385
|
+
}
|
|
386
|
+
function captureDurableAfterMs(stateBackend, configTexts) {
|
|
387
|
+
if (stateBackend === "redis") return ENGINE_FLUSH_MARGIN_MS;
|
|
388
|
+
return engineSaveIntervalMs(configTexts) + ENGINE_FLUSH_MARGIN_MS;
|
|
389
|
+
}
|
|
390
|
+
function engineSaveIntervalMs(configTexts, env = process.env) {
|
|
391
|
+
const intervals = [];
|
|
392
|
+
for (const text of configTexts) {
|
|
393
|
+
const explicit = [];
|
|
394
|
+
for (const match of text.matchAll(/save_interval_ms:\s*["']?(\d+|\$\{([A-Za-z_][A-Za-z0-9_]*)(?::-(\d+))?\})/g)) {
|
|
395
|
+
const raw = match[2] ? env[match[2]] || match[3] : match[1];
|
|
396
|
+
if (raw && /^\d+$/.test(raw) && Number.isSafeInteger(Number(raw))) explicit.push(Number(raw));
|
|
397
|
+
}
|
|
398
|
+
intervals.push(...explicit);
|
|
399
|
+
if ((text.match(/store_method:\s*file_based/g)?.length ?? 0) > explicit.length) intervals.push(ENGINE_DEFAULT_SAVE_INTERVAL_MS);
|
|
400
|
+
}
|
|
401
|
+
return intervals.length > 0 ? Math.max(...intervals) : ENGINE_DEFAULT_SAVE_INTERVAL_MS;
|
|
402
|
+
}
|
|
403
|
+
function engineStateConfigPaths(engineCwd, runtimePath) {
|
|
404
|
+
return [...new Set([
|
|
405
|
+
join(engineCwd, "compose", "worker-compose.yaml"),
|
|
406
|
+
join(engineCwd, "compose", "config", "state.yaml"),
|
|
407
|
+
join(engineCwd, "worker-compose.runtime.yaml"),
|
|
408
|
+
join(engineCwd, "config", "state.yaml"),
|
|
409
|
+
runtimePath
|
|
410
|
+
])];
|
|
411
|
+
}
|
|
412
|
+
//#endregion
|
|
413
|
+
//#region src/logger.ts
|
|
414
|
+
function fmt(level, msg, fields) {
|
|
415
|
+
if (!fields || Object.keys(fields).length === 0) return `[agentmemory] ${level} ${msg}`;
|
|
416
|
+
try {
|
|
417
|
+
return `[agentmemory] ${level} ${msg} ${JSON.stringify(fields)}`;
|
|
418
|
+
} catch {
|
|
419
|
+
return `[agentmemory] ${level} ${msg}`;
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
function emit(level, msg, fields) {
|
|
423
|
+
try {
|
|
424
|
+
const line = fmt(level, msg, fields) + "\n";
|
|
425
|
+
if (level === "error" || process.env["AGENTMEMORY_MCP_STDIO__"] === "1") process.stderr.write(line);
|
|
426
|
+
else process.stdout.write(line);
|
|
427
|
+
} catch {}
|
|
428
|
+
}
|
|
429
|
+
const logger = {
|
|
430
|
+
info(msg, fields) {
|
|
431
|
+
emit("info", msg, fields);
|
|
432
|
+
},
|
|
433
|
+
warn(msg, fields) {
|
|
434
|
+
emit("warn", msg, fields);
|
|
435
|
+
},
|
|
436
|
+
error(msg, fields) {
|
|
437
|
+
emit("error", msg, fields);
|
|
438
|
+
}
|
|
439
|
+
};
|
|
440
|
+
let bootVerbose = process.env["AGENTMEMORY_VERBOSE"] === "1" || process.env["AGENTMEMORY_VERBOSE"] === "true";
|
|
441
|
+
const bootBuffer = [];
|
|
442
|
+
function setBootVerbose(enabled) {
|
|
443
|
+
bootVerbose = enabled;
|
|
444
|
+
}
|
|
445
|
+
function bootLog(msg) {
|
|
446
|
+
if (bootVerbose) {
|
|
447
|
+
try {
|
|
448
|
+
process.stderr.write(`[agentmemory] ${msg}\n`);
|
|
449
|
+
} catch {}
|
|
450
|
+
return;
|
|
451
|
+
}
|
|
452
|
+
if (bootBuffer.length < 500) bootBuffer.push(msg);
|
|
453
|
+
}
|
|
454
|
+
function bootWarn(msg) {
|
|
455
|
+
try {
|
|
456
|
+
process.stderr.write(`[agentmemory] warn ${msg}\n`);
|
|
457
|
+
} catch {}
|
|
458
|
+
}
|
|
459
|
+
//#endregion
|
|
460
|
+
//#region src/version.ts
|
|
461
|
+
const VERSION = "0.9.31";
|
|
462
|
+
const III_PINNED_VERSION = "0.25.0";
|
|
463
|
+
//#endregion
|
|
464
|
+
//#region src/mcp/tools-registry.ts
|
|
465
|
+
const CORE_TOOLS = [
|
|
466
|
+
{
|
|
467
|
+
name: "memory_recall",
|
|
468
|
+
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.",
|
|
469
|
+
inputSchema: {
|
|
470
|
+
type: "object",
|
|
471
|
+
properties: {
|
|
472
|
+
query: {
|
|
473
|
+
type: "string",
|
|
474
|
+
description: "Search query (keywords, file names, concepts)"
|
|
475
|
+
},
|
|
476
|
+
limit: {
|
|
477
|
+
type: "number",
|
|
478
|
+
description: "Max results to return (default 10)"
|
|
479
|
+
},
|
|
480
|
+
format: {
|
|
481
|
+
type: "string",
|
|
482
|
+
description: "Result format: full, compact, or narrative (default full)"
|
|
483
|
+
},
|
|
484
|
+
token_budget: {
|
|
485
|
+
type: "number",
|
|
486
|
+
description: "Optional estimated content token budget; response includes truncation and recovery metadata"
|
|
487
|
+
},
|
|
488
|
+
targetLayer: {
|
|
489
|
+
type: "string",
|
|
490
|
+
enum: [
|
|
491
|
+
"all",
|
|
492
|
+
"memory",
|
|
493
|
+
"observation"
|
|
494
|
+
],
|
|
495
|
+
description: "Search all indexed layers (default), durable memories, or raw observations before ranking"
|
|
496
|
+
},
|
|
497
|
+
project: {
|
|
498
|
+
type: "string",
|
|
499
|
+
description: "Filter by project path"
|
|
500
|
+
},
|
|
501
|
+
cwd: {
|
|
502
|
+
type: "string",
|
|
503
|
+
description: "Filter by session working directory"
|
|
504
|
+
},
|
|
505
|
+
agentId: {
|
|
506
|
+
type: "string",
|
|
507
|
+
description: "Filter by owning agent; '*' reads across agents"
|
|
508
|
+
}
|
|
509
|
+
},
|
|
510
|
+
required: ["query"]
|
|
511
|
+
}
|
|
512
|
+
},
|
|
513
|
+
{
|
|
514
|
+
name: "memory_compress_file",
|
|
515
|
+
description: "Compress a markdown file to reduce token usage while preserving headings, URLs, and code blocks. Creates a .original.md backup before writing.",
|
|
516
|
+
inputSchema: {
|
|
517
|
+
type: "object",
|
|
518
|
+
properties: { filePath: {
|
|
519
|
+
type: "string",
|
|
520
|
+
description: "Path to the markdown file to compress"
|
|
521
|
+
} },
|
|
522
|
+
required: ["filePath"]
|
|
523
|
+
}
|
|
524
|
+
},
|
|
525
|
+
{
|
|
526
|
+
name: "memory_save",
|
|
527
|
+
description: "Explicitly save an important insight, decision, or pattern to long-term memory.",
|
|
528
|
+
inputSchema: {
|
|
529
|
+
type: "object",
|
|
530
|
+
properties: {
|
|
531
|
+
content: {
|
|
532
|
+
type: "string",
|
|
533
|
+
description: "The insight or decision to remember"
|
|
534
|
+
},
|
|
535
|
+
type: {
|
|
536
|
+
type: "string",
|
|
537
|
+
description: "Memory type: pattern, preference, architecture, bug, workflow, or fact"
|
|
538
|
+
},
|
|
539
|
+
concepts: {
|
|
540
|
+
type: "string",
|
|
541
|
+
description: "Comma-separated key concepts"
|
|
542
|
+
},
|
|
543
|
+
files: {
|
|
544
|
+
type: "string",
|
|
545
|
+
description: "Comma-separated relevant file paths"
|
|
546
|
+
},
|
|
547
|
+
project: {
|
|
548
|
+
type: "string",
|
|
549
|
+
description: "Stable canonical project identifier this memory belongs to (e.g. a slug, UUID, or registry key). Must match the value used when the session was started. Do not use filesystem paths or ad-hoc display names — those change across machines and will silently break project scoping."
|
|
550
|
+
},
|
|
551
|
+
agentId: {
|
|
552
|
+
type: "string",
|
|
553
|
+
description: "Agent identity to scope this memory to. When set, agent-scoped recall and search only surface it for the same agentId. Omit for shared memory."
|
|
554
|
+
}
|
|
555
|
+
},
|
|
556
|
+
required: ["content"]
|
|
557
|
+
}
|
|
558
|
+
},
|
|
559
|
+
{
|
|
560
|
+
name: "memory_file_history",
|
|
561
|
+
description: "Get past observations about specific files.",
|
|
562
|
+
inputSchema: {
|
|
563
|
+
type: "object",
|
|
564
|
+
properties: {
|
|
565
|
+
files: {
|
|
566
|
+
type: "string",
|
|
567
|
+
description: "Comma-separated file paths"
|
|
568
|
+
},
|
|
569
|
+
sessionId: {
|
|
570
|
+
type: "string",
|
|
571
|
+
description: "Current session ID to exclude"
|
|
572
|
+
}
|
|
573
|
+
},
|
|
574
|
+
required: ["files"]
|
|
575
|
+
}
|
|
576
|
+
},
|
|
577
|
+
{
|
|
578
|
+
name: "memory_patterns",
|
|
579
|
+
description: "Detect recurring patterns across sessions.",
|
|
580
|
+
inputSchema: {
|
|
581
|
+
type: "object",
|
|
582
|
+
properties: {
|
|
583
|
+
project: {
|
|
584
|
+
type: "string",
|
|
585
|
+
description: "Project path to analyze"
|
|
586
|
+
},
|
|
587
|
+
limit: {
|
|
588
|
+
type: "integer",
|
|
589
|
+
description: "Most recent sessions to scan (default 50, max 500)"
|
|
590
|
+
}
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
},
|
|
594
|
+
{
|
|
595
|
+
name: "memory_sessions",
|
|
596
|
+
description: "List recent sessions with status, observation counts, summaries and a continuation cursor. Filters apply before pagination; retain them when requesting the next page.",
|
|
597
|
+
inputSchema: {
|
|
598
|
+
type: "object",
|
|
599
|
+
properties: {
|
|
600
|
+
project: {
|
|
601
|
+
type: "string",
|
|
602
|
+
description: "Exact project identifier used when sessions were started"
|
|
603
|
+
},
|
|
604
|
+
agentId: {
|
|
605
|
+
type: "string",
|
|
606
|
+
description: "Filter by owning agent; '*' reads across agents"
|
|
607
|
+
},
|
|
608
|
+
limit: {
|
|
609
|
+
type: "integer",
|
|
610
|
+
description: "Page size (default 20, max 100)"
|
|
611
|
+
},
|
|
612
|
+
cursor: {
|
|
613
|
+
type: "string",
|
|
614
|
+
description: "nextCursor from the previous page; omit for the first page"
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
},
|
|
619
|
+
{
|
|
620
|
+
name: "memory_smart_search",
|
|
621
|
+
description: "Hybrid semantic+keyword search with progressive disclosure. Pass query to search, or expandIds to recover full results.",
|
|
622
|
+
inputSchema: {
|
|
623
|
+
type: "object",
|
|
624
|
+
properties: {
|
|
625
|
+
query: {
|
|
626
|
+
type: "string",
|
|
627
|
+
description: "Search query"
|
|
628
|
+
},
|
|
629
|
+
expandIds: {
|
|
630
|
+
type: "string",
|
|
631
|
+
description: "Comma-separated memory or observation IDs to expand; query is optional when provided"
|
|
632
|
+
},
|
|
633
|
+
limit: {
|
|
634
|
+
type: "number",
|
|
635
|
+
description: "Max results (default 10)"
|
|
636
|
+
},
|
|
637
|
+
targetLayer: {
|
|
638
|
+
type: "string",
|
|
639
|
+
enum: [
|
|
640
|
+
"all",
|
|
641
|
+
"memory",
|
|
642
|
+
"observation"
|
|
643
|
+
],
|
|
644
|
+
description: "Search all indexed layers (default), durable memories, or raw observations before ranking"
|
|
645
|
+
},
|
|
646
|
+
project: {
|
|
647
|
+
type: "string",
|
|
648
|
+
description: "Filter by project path"
|
|
649
|
+
},
|
|
650
|
+
agentId: {
|
|
651
|
+
type: "string",
|
|
652
|
+
description: "Filter by owning agent; '*' reads across agents"
|
|
653
|
+
},
|
|
654
|
+
includeLessons: {
|
|
655
|
+
type: "boolean",
|
|
656
|
+
description: "Include lesson matches when targetLayer is all (default true)"
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
}
|
|
660
|
+
},
|
|
661
|
+
{
|
|
662
|
+
name: "memory_vision_search",
|
|
663
|
+
description: "Cross-modal image search via CLIP embeddings. Pass queryText to find screenshots matching a description, or queryImageBase64/queryImageRef to find similar images. Requires AGENTMEMORY_IMAGE_EMBEDDINGS=true.",
|
|
664
|
+
inputSchema: {
|
|
665
|
+
type: "object",
|
|
666
|
+
properties: {
|
|
667
|
+
queryText: {
|
|
668
|
+
type: "string",
|
|
669
|
+
description: "Text query (e.g. 'login form with error banner')"
|
|
670
|
+
},
|
|
671
|
+
queryImageRef: {
|
|
672
|
+
type: "string",
|
|
673
|
+
description: "Absolute path to a stored image to match against"
|
|
674
|
+
},
|
|
675
|
+
queryImageBase64: {
|
|
676
|
+
type: "string",
|
|
677
|
+
description: "Raw base64 image bytes or data URL"
|
|
678
|
+
},
|
|
679
|
+
topK: {
|
|
680
|
+
type: "number",
|
|
681
|
+
description: "Max results (default 10, max 50)"
|
|
682
|
+
},
|
|
683
|
+
sessionId: {
|
|
684
|
+
type: "string",
|
|
685
|
+
description: "Filter to a single session"
|
|
686
|
+
}
|
|
687
|
+
}
|
|
688
|
+
}
|
|
689
|
+
},
|
|
690
|
+
{
|
|
691
|
+
name: "memory_timeline",
|
|
692
|
+
description: "Chronological observations around an anchor point.",
|
|
693
|
+
inputSchema: {
|
|
694
|
+
type: "object",
|
|
695
|
+
properties: {
|
|
696
|
+
anchor: {
|
|
697
|
+
type: "string",
|
|
698
|
+
description: "Anchor point: ISO date or keyword"
|
|
699
|
+
},
|
|
700
|
+
project: {
|
|
701
|
+
type: "string",
|
|
702
|
+
description: "Filter by project path"
|
|
703
|
+
},
|
|
704
|
+
before: {
|
|
705
|
+
type: "number",
|
|
706
|
+
description: "Observations before anchor (default 5)"
|
|
707
|
+
},
|
|
708
|
+
after: {
|
|
709
|
+
type: "number",
|
|
710
|
+
description: "Observations after anchor (default 5)"
|
|
711
|
+
}
|
|
712
|
+
},
|
|
713
|
+
required: ["anchor"]
|
|
714
|
+
}
|
|
715
|
+
},
|
|
716
|
+
{
|
|
717
|
+
name: "memory_profile",
|
|
718
|
+
description: "User/project profile with top concepts and file patterns.",
|
|
719
|
+
inputSchema: {
|
|
720
|
+
type: "object",
|
|
721
|
+
properties: {
|
|
722
|
+
project: {
|
|
723
|
+
type: "string",
|
|
724
|
+
description: "Project path"
|
|
725
|
+
},
|
|
726
|
+
refresh: {
|
|
727
|
+
type: "string",
|
|
728
|
+
description: "Set to 'true' to force rebuild"
|
|
729
|
+
}
|
|
730
|
+
},
|
|
731
|
+
required: ["project"]
|
|
732
|
+
}
|
|
733
|
+
},
|
|
734
|
+
{
|
|
735
|
+
name: "memory_export",
|
|
736
|
+
description: "Export memory data as JSON. Past the transport size limit the export is refused, so use the paging arguments on a large store.",
|
|
737
|
+
inputSchema: {
|
|
738
|
+
type: "object",
|
|
739
|
+
properties: {
|
|
740
|
+
maxSessions: {
|
|
741
|
+
type: "number",
|
|
742
|
+
description: "Sessions per page (with their observations)"
|
|
743
|
+
},
|
|
744
|
+
offset: {
|
|
745
|
+
type: "number",
|
|
746
|
+
description: "Session offset"
|
|
747
|
+
},
|
|
748
|
+
collectionLimit: {
|
|
749
|
+
type: "number",
|
|
750
|
+
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"
|
|
751
|
+
},
|
|
752
|
+
collectionOffset: {
|
|
753
|
+
type: "number",
|
|
754
|
+
description: "Row offset for the top-level collections"
|
|
755
|
+
},
|
|
756
|
+
collections: {
|
|
757
|
+
type: "string",
|
|
758
|
+
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."
|
|
759
|
+
}
|
|
760
|
+
}
|
|
761
|
+
}
|
|
762
|
+
},
|
|
763
|
+
{
|
|
764
|
+
name: "memory_relations",
|
|
765
|
+
description: "Query the memory relationship graph.",
|
|
766
|
+
inputSchema: {
|
|
767
|
+
type: "object",
|
|
768
|
+
properties: {
|
|
769
|
+
memoryId: {
|
|
770
|
+
type: "string",
|
|
771
|
+
description: "Memory ID to find relations for"
|
|
772
|
+
},
|
|
773
|
+
maxHops: {
|
|
774
|
+
type: "number",
|
|
775
|
+
description: "Max traversal depth (default 2)"
|
|
776
|
+
},
|
|
777
|
+
minConfidence: {
|
|
778
|
+
type: "number",
|
|
779
|
+
description: "Min confidence (0-1, default 0)"
|
|
780
|
+
}
|
|
781
|
+
},
|
|
782
|
+
required: ["memoryId"]
|
|
783
|
+
}
|
|
784
|
+
},
|
|
785
|
+
{
|
|
786
|
+
name: "memory_commit_lookup",
|
|
787
|
+
description: "Look up the agent session(s) that produced a specific git commit, given its SHA. Returns the commit metadata and linked sessions.",
|
|
788
|
+
inputSchema: {
|
|
789
|
+
type: "object",
|
|
790
|
+
properties: { sha: {
|
|
791
|
+
type: "string",
|
|
792
|
+
description: "Full git commit SHA"
|
|
793
|
+
} },
|
|
794
|
+
required: ["sha"]
|
|
795
|
+
}
|
|
796
|
+
},
|
|
797
|
+
{
|
|
798
|
+
name: "memory_commits",
|
|
799
|
+
description: "List recent commits linked to agent sessions, optionally filtered by branch or repo.",
|
|
800
|
+
inputSchema: {
|
|
801
|
+
type: "object",
|
|
802
|
+
properties: {
|
|
803
|
+
branch: {
|
|
804
|
+
type: "string",
|
|
805
|
+
description: "Filter by branch name"
|
|
806
|
+
},
|
|
807
|
+
repo: {
|
|
808
|
+
type: "string",
|
|
809
|
+
description: "Filter by remote URL"
|
|
810
|
+
},
|
|
811
|
+
limit: {
|
|
812
|
+
type: "number",
|
|
813
|
+
description: "Max results (default 100, max 500)"
|
|
814
|
+
}
|
|
815
|
+
}
|
|
816
|
+
}
|
|
817
|
+
}
|
|
818
|
+
];
|
|
819
|
+
const V040_TOOLS = [
|
|
820
|
+
{
|
|
821
|
+
name: "memory_claude_bridge_sync",
|
|
822
|
+
description: "Sync memory state to/from Claude Code's native MEMORY.md file.",
|
|
823
|
+
inputSchema: {
|
|
824
|
+
type: "object",
|
|
825
|
+
properties: { direction: {
|
|
826
|
+
type: "string",
|
|
827
|
+
description: "'read' to import from MEMORY.md, 'write' to export to MEMORY.md"
|
|
828
|
+
} },
|
|
829
|
+
required: ["direction"]
|
|
830
|
+
}
|
|
831
|
+
},
|
|
832
|
+
{
|
|
833
|
+
name: "memory_graph_query",
|
|
834
|
+
description: "Query the knowledge graph for entities and relationships.",
|
|
835
|
+
inputSchema: {
|
|
836
|
+
type: "object",
|
|
837
|
+
properties: {
|
|
838
|
+
startNodeId: {
|
|
839
|
+
type: "string",
|
|
840
|
+
description: "Starting node ID for traversal"
|
|
841
|
+
},
|
|
842
|
+
nodeType: {
|
|
843
|
+
type: "string",
|
|
844
|
+
description: "Filter by node type"
|
|
845
|
+
},
|
|
846
|
+
maxDepth: {
|
|
847
|
+
type: "number",
|
|
848
|
+
description: "Max BFS depth (default 3, max 5)"
|
|
849
|
+
},
|
|
850
|
+
query: {
|
|
851
|
+
type: "string",
|
|
852
|
+
description: "Search nodes by name"
|
|
853
|
+
}
|
|
854
|
+
}
|
|
855
|
+
}
|
|
856
|
+
},
|
|
857
|
+
{
|
|
858
|
+
name: "memory_consolidate",
|
|
859
|
+
description: "Run the 4-tier memory consolidation pipeline (working -> episodic -> semantic -> procedural).",
|
|
860
|
+
inputSchema: {
|
|
861
|
+
type: "object",
|
|
862
|
+
properties: { tier: {
|
|
863
|
+
type: "string",
|
|
864
|
+
description: "Target tier: episodic, semantic, or procedural"
|
|
865
|
+
} }
|
|
866
|
+
}
|
|
867
|
+
},
|
|
868
|
+
{
|
|
869
|
+
name: "memory_team_share",
|
|
870
|
+
description: "Share a memory or observation with team members.",
|
|
871
|
+
inputSchema: {
|
|
872
|
+
type: "object",
|
|
873
|
+
properties: {
|
|
874
|
+
itemId: {
|
|
875
|
+
type: "string",
|
|
876
|
+
description: "ID of memory or observation to share"
|
|
877
|
+
},
|
|
878
|
+
itemType: {
|
|
879
|
+
type: "string",
|
|
880
|
+
description: "Type: observation, memory, or pattern"
|
|
881
|
+
}
|
|
882
|
+
},
|
|
883
|
+
required: ["itemId", "itemType"]
|
|
884
|
+
}
|
|
885
|
+
},
|
|
886
|
+
{
|
|
887
|
+
name: "memory_team_feed",
|
|
888
|
+
description: "Get recent shared items from all team members.",
|
|
889
|
+
inputSchema: {
|
|
890
|
+
type: "object",
|
|
891
|
+
properties: { limit: {
|
|
892
|
+
type: "number",
|
|
893
|
+
description: "Max items (default 20)"
|
|
894
|
+
} }
|
|
895
|
+
}
|
|
896
|
+
},
|
|
897
|
+
{
|
|
898
|
+
name: "memory_audit",
|
|
899
|
+
description: "View the audit trail of memory operations.",
|
|
900
|
+
inputSchema: {
|
|
901
|
+
type: "object",
|
|
902
|
+
properties: {
|
|
903
|
+
operation: {
|
|
904
|
+
type: "string",
|
|
905
|
+
description: "Filter by operation type"
|
|
906
|
+
},
|
|
907
|
+
limit: {
|
|
908
|
+
type: "number",
|
|
909
|
+
description: "Max entries (default 50)"
|
|
910
|
+
}
|
|
911
|
+
}
|
|
912
|
+
}
|
|
913
|
+
},
|
|
914
|
+
{
|
|
915
|
+
name: "memory_governance_delete",
|
|
916
|
+
description: "Delete specific memories with audit trail.",
|
|
917
|
+
inputSchema: {
|
|
918
|
+
type: "object",
|
|
919
|
+
properties: {
|
|
920
|
+
memoryIds: {
|
|
921
|
+
type: "string",
|
|
922
|
+
description: "Comma-separated memory IDs to delete"
|
|
923
|
+
},
|
|
924
|
+
reason: {
|
|
925
|
+
type: "string",
|
|
926
|
+
description: "Reason for deletion"
|
|
927
|
+
}
|
|
928
|
+
},
|
|
929
|
+
required: ["memoryIds"]
|
|
930
|
+
}
|
|
931
|
+
},
|
|
932
|
+
{
|
|
933
|
+
name: "memory_snapshot_create",
|
|
934
|
+
description: "Create a git-versioned snapshot of current memory state.",
|
|
935
|
+
inputSchema: {
|
|
936
|
+
type: "object",
|
|
937
|
+
properties: { message: {
|
|
938
|
+
type: "string",
|
|
939
|
+
description: "Snapshot description"
|
|
940
|
+
} }
|
|
941
|
+
}
|
|
942
|
+
}
|
|
943
|
+
];
|
|
944
|
+
const V050_TOOLS = [
|
|
945
|
+
{
|
|
946
|
+
name: "memory_action_create",
|
|
947
|
+
description: "Create an actionable work item with typed dependencies. Actions track what agents need to do and how work items relate to each other.",
|
|
948
|
+
inputSchema: {
|
|
949
|
+
type: "object",
|
|
950
|
+
properties: {
|
|
951
|
+
title: {
|
|
952
|
+
type: "string",
|
|
953
|
+
description: "Action title"
|
|
954
|
+
},
|
|
955
|
+
description: {
|
|
956
|
+
type: "string",
|
|
957
|
+
description: "Detailed description of the work"
|
|
958
|
+
},
|
|
959
|
+
priority: {
|
|
960
|
+
type: "number",
|
|
961
|
+
description: "Priority 1-10 (10 highest)"
|
|
962
|
+
},
|
|
963
|
+
project: {
|
|
964
|
+
type: "string",
|
|
965
|
+
description: "Project path"
|
|
966
|
+
},
|
|
967
|
+
tags: {
|
|
968
|
+
type: "string",
|
|
969
|
+
description: "Comma-separated tags"
|
|
970
|
+
},
|
|
971
|
+
parentId: {
|
|
972
|
+
type: "string",
|
|
973
|
+
description: "Parent action ID for hierarchical actions"
|
|
974
|
+
},
|
|
975
|
+
requires: {
|
|
976
|
+
type: "string",
|
|
977
|
+
description: "Comma-separated action IDs that must complete before this"
|
|
978
|
+
}
|
|
979
|
+
},
|
|
980
|
+
required: ["title"]
|
|
981
|
+
}
|
|
982
|
+
},
|
|
983
|
+
{
|
|
984
|
+
name: "memory_action_update",
|
|
985
|
+
description: "Update an action's status, priority, or details. Set status to 'done' to complete it and unblock dependent actions.",
|
|
986
|
+
inputSchema: {
|
|
987
|
+
type: "object",
|
|
988
|
+
properties: {
|
|
989
|
+
actionId: {
|
|
990
|
+
type: "string",
|
|
991
|
+
description: "Action ID to update"
|
|
992
|
+
},
|
|
993
|
+
status: {
|
|
994
|
+
type: "string",
|
|
995
|
+
description: "New status: pending, active, done, blocked, cancelled"
|
|
996
|
+
},
|
|
997
|
+
result: {
|
|
998
|
+
type: "string",
|
|
999
|
+
description: "Outcome description (when completing)"
|
|
1000
|
+
},
|
|
1001
|
+
priority: {
|
|
1002
|
+
type: "number",
|
|
1003
|
+
description: "New priority 1-10"
|
|
1004
|
+
}
|
|
1005
|
+
},
|
|
1006
|
+
required: ["actionId"]
|
|
1007
|
+
}
|
|
1008
|
+
},
|
|
1009
|
+
{
|
|
1010
|
+
name: "memory_frontier",
|
|
1011
|
+
description: "Get all unblocked actions ranked by priority and urgency. Returns the frontier of actionable work with no unsatisfied dependencies.",
|
|
1012
|
+
inputSchema: {
|
|
1013
|
+
type: "object",
|
|
1014
|
+
properties: {
|
|
1015
|
+
project: {
|
|
1016
|
+
type: "string",
|
|
1017
|
+
description: "Filter by project"
|
|
1018
|
+
},
|
|
1019
|
+
agentId: {
|
|
1020
|
+
type: "string",
|
|
1021
|
+
description: "Agent ID to check lease conflicts"
|
|
1022
|
+
},
|
|
1023
|
+
limit: {
|
|
1024
|
+
type: "number",
|
|
1025
|
+
description: "Max results (default 20)"
|
|
1026
|
+
}
|
|
1027
|
+
}
|
|
1028
|
+
}
|
|
1029
|
+
},
|
|
1030
|
+
{
|
|
1031
|
+
name: "memory_next",
|
|
1032
|
+
description: "Get the single most important next action to work on. Combines dependency resolution, priority, and recency into a score.",
|
|
1033
|
+
inputSchema: {
|
|
1034
|
+
type: "object",
|
|
1035
|
+
properties: {
|
|
1036
|
+
project: {
|
|
1037
|
+
type: "string",
|
|
1038
|
+
description: "Filter by project"
|
|
1039
|
+
},
|
|
1040
|
+
agentId: {
|
|
1041
|
+
type: "string",
|
|
1042
|
+
description: "Current agent ID"
|
|
1043
|
+
}
|
|
1044
|
+
}
|
|
1045
|
+
}
|
|
1046
|
+
},
|
|
1047
|
+
{
|
|
1048
|
+
name: "memory_lease",
|
|
1049
|
+
description: "Acquire, release, or renew an exclusive lease on an action. Prevents multiple agents from working on the same thing.",
|
|
1050
|
+
inputSchema: {
|
|
1051
|
+
type: "object",
|
|
1052
|
+
properties: {
|
|
1053
|
+
actionId: {
|
|
1054
|
+
type: "string",
|
|
1055
|
+
description: "Action ID"
|
|
1056
|
+
},
|
|
1057
|
+
agentId: {
|
|
1058
|
+
type: "string",
|
|
1059
|
+
description: "Agent claiming the action"
|
|
1060
|
+
},
|
|
1061
|
+
operation: {
|
|
1062
|
+
type: "string",
|
|
1063
|
+
description: "acquire, release, or renew"
|
|
1064
|
+
},
|
|
1065
|
+
result: {
|
|
1066
|
+
type: "string",
|
|
1067
|
+
description: "Result when releasing (marks action done)"
|
|
1068
|
+
},
|
|
1069
|
+
ttlMs: {
|
|
1070
|
+
type: "number",
|
|
1071
|
+
description: "Lease duration in ms (default 10min, max 1hr)"
|
|
1072
|
+
}
|
|
1073
|
+
},
|
|
1074
|
+
required: [
|
|
1075
|
+
"actionId",
|
|
1076
|
+
"agentId",
|
|
1077
|
+
"operation"
|
|
1078
|
+
]
|
|
1079
|
+
}
|
|
1080
|
+
},
|
|
1081
|
+
{
|
|
1082
|
+
name: "memory_routine_run",
|
|
1083
|
+
description: "Instantiate a frozen workflow routine, creating actions for each step with proper dependencies.",
|
|
1084
|
+
inputSchema: {
|
|
1085
|
+
type: "object",
|
|
1086
|
+
properties: {
|
|
1087
|
+
routineId: {
|
|
1088
|
+
type: "string",
|
|
1089
|
+
description: "Routine template ID"
|
|
1090
|
+
},
|
|
1091
|
+
project: {
|
|
1092
|
+
type: "string",
|
|
1093
|
+
description: "Project context"
|
|
1094
|
+
},
|
|
1095
|
+
initiatedBy: {
|
|
1096
|
+
type: "string",
|
|
1097
|
+
description: "Agent starting the run"
|
|
1098
|
+
}
|
|
1099
|
+
},
|
|
1100
|
+
required: ["routineId"]
|
|
1101
|
+
}
|
|
1102
|
+
},
|
|
1103
|
+
{
|
|
1104
|
+
name: "memory_signal_send",
|
|
1105
|
+
description: "Send a message to another agent or broadcast. Supports threading, typed messages, and TTL expiration.",
|
|
1106
|
+
inputSchema: {
|
|
1107
|
+
type: "object",
|
|
1108
|
+
properties: {
|
|
1109
|
+
from: {
|
|
1110
|
+
type: "string",
|
|
1111
|
+
description: "Sender agent ID"
|
|
1112
|
+
},
|
|
1113
|
+
to: {
|
|
1114
|
+
type: "string",
|
|
1115
|
+
description: "Recipient agent ID (omit for broadcast)"
|
|
1116
|
+
},
|
|
1117
|
+
content: {
|
|
1118
|
+
type: "string",
|
|
1119
|
+
description: "Message content"
|
|
1120
|
+
},
|
|
1121
|
+
type: {
|
|
1122
|
+
type: "string",
|
|
1123
|
+
description: "Message type: info, request, response, alert, handoff"
|
|
1124
|
+
},
|
|
1125
|
+
replyTo: {
|
|
1126
|
+
type: "string",
|
|
1127
|
+
description: "Signal ID to reply to (auto-threads)"
|
|
1128
|
+
}
|
|
1129
|
+
},
|
|
1130
|
+
required: ["from", "content"]
|
|
1131
|
+
}
|
|
1132
|
+
},
|
|
1133
|
+
{
|
|
1134
|
+
name: "memory_signal_read",
|
|
1135
|
+
description: "Read messages for an agent. Marks delivered messages as read.",
|
|
1136
|
+
inputSchema: {
|
|
1137
|
+
type: "object",
|
|
1138
|
+
properties: {
|
|
1139
|
+
agentId: {
|
|
1140
|
+
type: "string",
|
|
1141
|
+
description: "Agent to read messages for"
|
|
1142
|
+
},
|
|
1143
|
+
unreadOnly: {
|
|
1144
|
+
type: "string",
|
|
1145
|
+
description: "Set to 'true' for unread only"
|
|
1146
|
+
},
|
|
1147
|
+
threadId: {
|
|
1148
|
+
type: "string",
|
|
1149
|
+
description: "Filter by conversation thread"
|
|
1150
|
+
},
|
|
1151
|
+
limit: {
|
|
1152
|
+
type: "number",
|
|
1153
|
+
description: "Max messages (default 50)"
|
|
1154
|
+
}
|
|
1155
|
+
},
|
|
1156
|
+
required: ["agentId"]
|
|
1157
|
+
}
|
|
1158
|
+
},
|
|
1159
|
+
{
|
|
1160
|
+
name: "memory_checkpoint",
|
|
1161
|
+
description: "Create or resolve an external checkpoint (CI result, approval, deploy status) that gates action progress.",
|
|
1162
|
+
inputSchema: {
|
|
1163
|
+
type: "object",
|
|
1164
|
+
properties: {
|
|
1165
|
+
operation: {
|
|
1166
|
+
type: "string",
|
|
1167
|
+
description: "create, resolve, or list"
|
|
1168
|
+
},
|
|
1169
|
+
name: {
|
|
1170
|
+
type: "string",
|
|
1171
|
+
description: "Checkpoint name (for create)"
|
|
1172
|
+
},
|
|
1173
|
+
checkpointId: {
|
|
1174
|
+
type: "string",
|
|
1175
|
+
description: "Checkpoint ID (for resolve)"
|
|
1176
|
+
},
|
|
1177
|
+
status: {
|
|
1178
|
+
type: "string",
|
|
1179
|
+
description: "passed or failed (for resolve)"
|
|
1180
|
+
},
|
|
1181
|
+
type: {
|
|
1182
|
+
type: "string",
|
|
1183
|
+
description: "Checkpoint type: ci, approval, deploy, external, timer"
|
|
1184
|
+
},
|
|
1185
|
+
linkedActionIds: {
|
|
1186
|
+
type: "string",
|
|
1187
|
+
description: "Comma-separated action IDs this checkpoint gates (for create)"
|
|
1188
|
+
}
|
|
1189
|
+
},
|
|
1190
|
+
required: ["operation"]
|
|
1191
|
+
}
|
|
1192
|
+
},
|
|
1193
|
+
{
|
|
1194
|
+
name: "memory_mesh_sync",
|
|
1195
|
+
description: "Sync memories and actions with peer agentmemory instances for multi-agent collaboration.",
|
|
1196
|
+
inputSchema: {
|
|
1197
|
+
type: "object",
|
|
1198
|
+
properties: {
|
|
1199
|
+
peerId: {
|
|
1200
|
+
type: "string",
|
|
1201
|
+
description: "Specific peer ID (omit for all)"
|
|
1202
|
+
},
|
|
1203
|
+
direction: {
|
|
1204
|
+
type: "string",
|
|
1205
|
+
description: "push, pull, or both (default both)"
|
|
1206
|
+
}
|
|
1207
|
+
}
|
|
1208
|
+
}
|
|
1209
|
+
}
|
|
1210
|
+
];
|
|
1211
|
+
const V051_TOOLS = [
|
|
1212
|
+
{
|
|
1213
|
+
name: "memory_sentinel_create",
|
|
1214
|
+
description: "Create an event-driven sentinel that watches for conditions (webhook, timer, threshold, pattern, approval) and auto-unblocks gated actions when triggered.",
|
|
1215
|
+
inputSchema: {
|
|
1216
|
+
type: "object",
|
|
1217
|
+
properties: {
|
|
1218
|
+
name: {
|
|
1219
|
+
type: "string",
|
|
1220
|
+
description: "Sentinel name"
|
|
1221
|
+
},
|
|
1222
|
+
type: {
|
|
1223
|
+
type: "string",
|
|
1224
|
+
description: "Type: webhook, timer, threshold, pattern, approval, custom"
|
|
1225
|
+
},
|
|
1226
|
+
config: {
|
|
1227
|
+
type: "string",
|
|
1228
|
+
description: "JSON config (timer: {durationMs}, threshold: {metric,operator,value}, pattern: {pattern}, webhook: {path})"
|
|
1229
|
+
},
|
|
1230
|
+
linkedActionIds: {
|
|
1231
|
+
type: "string",
|
|
1232
|
+
description: "Comma-separated action IDs to gate"
|
|
1233
|
+
},
|
|
1234
|
+
expiresInMs: {
|
|
1235
|
+
type: "number",
|
|
1236
|
+
description: "Auto-expire after ms"
|
|
1237
|
+
}
|
|
1238
|
+
},
|
|
1239
|
+
required: ["name", "type"]
|
|
1240
|
+
}
|
|
1241
|
+
},
|
|
1242
|
+
{
|
|
1243
|
+
name: "memory_sentinel_trigger",
|
|
1244
|
+
description: "Externally fire a sentinel, providing an optional result payload. Unblocks any gated actions.",
|
|
1245
|
+
inputSchema: {
|
|
1246
|
+
type: "object",
|
|
1247
|
+
properties: {
|
|
1248
|
+
sentinelId: {
|
|
1249
|
+
type: "string",
|
|
1250
|
+
description: "Sentinel ID to trigger"
|
|
1251
|
+
},
|
|
1252
|
+
result: {
|
|
1253
|
+
type: "string",
|
|
1254
|
+
description: "JSON result payload"
|
|
1255
|
+
}
|
|
1256
|
+
},
|
|
1257
|
+
required: ["sentinelId"]
|
|
1258
|
+
}
|
|
1259
|
+
},
|
|
1260
|
+
{
|
|
1261
|
+
name: "memory_sketch_create",
|
|
1262
|
+
description: "Create an ephemeral action graph for exploratory work. Auto-expires after TTL. Can be promoted to permanent actions or discarded.",
|
|
1263
|
+
inputSchema: {
|
|
1264
|
+
type: "object",
|
|
1265
|
+
properties: {
|
|
1266
|
+
title: {
|
|
1267
|
+
type: "string",
|
|
1268
|
+
description: "Sketch title"
|
|
1269
|
+
},
|
|
1270
|
+
description: {
|
|
1271
|
+
type: "string",
|
|
1272
|
+
description: "What this sketch explores"
|
|
1273
|
+
},
|
|
1274
|
+
expiresInMs: {
|
|
1275
|
+
type: "number",
|
|
1276
|
+
description: "TTL in ms (default 1 hour)"
|
|
1277
|
+
},
|
|
1278
|
+
project: {
|
|
1279
|
+
type: "string",
|
|
1280
|
+
description: "Project context"
|
|
1281
|
+
}
|
|
1282
|
+
},
|
|
1283
|
+
required: ["title"]
|
|
1284
|
+
}
|
|
1285
|
+
},
|
|
1286
|
+
{
|
|
1287
|
+
name: "memory_sketch_promote",
|
|
1288
|
+
description: "Promote a sketch's ephemeral actions to permanent actions. Makes the exploratory work official.",
|
|
1289
|
+
inputSchema: {
|
|
1290
|
+
type: "object",
|
|
1291
|
+
properties: {
|
|
1292
|
+
sketchId: {
|
|
1293
|
+
type: "string",
|
|
1294
|
+
description: "Sketch ID to promote"
|
|
1295
|
+
},
|
|
1296
|
+
project: {
|
|
1297
|
+
type: "string",
|
|
1298
|
+
description: "Override project for promoted actions"
|
|
1299
|
+
}
|
|
1300
|
+
},
|
|
1301
|
+
required: ["sketchId"]
|
|
1302
|
+
}
|
|
1303
|
+
},
|
|
1304
|
+
{
|
|
1305
|
+
name: "memory_crystallize",
|
|
1306
|
+
description: "Compress completed action chains into compact crystal digests using LLM summarization. Extracts narrative, key outcomes, files affected, and lessons.",
|
|
1307
|
+
inputSchema: {
|
|
1308
|
+
type: "object",
|
|
1309
|
+
properties: {
|
|
1310
|
+
actionIds: {
|
|
1311
|
+
type: "string",
|
|
1312
|
+
description: "Comma-separated completed action IDs to crystallize"
|
|
1313
|
+
},
|
|
1314
|
+
project: {
|
|
1315
|
+
type: "string",
|
|
1316
|
+
description: "Project context"
|
|
1317
|
+
},
|
|
1318
|
+
sessionId: {
|
|
1319
|
+
type: "string",
|
|
1320
|
+
description: "Session context"
|
|
1321
|
+
}
|
|
1322
|
+
},
|
|
1323
|
+
required: ["actionIds"]
|
|
1324
|
+
}
|
|
1325
|
+
},
|
|
1326
|
+
{
|
|
1327
|
+
name: "memory_diagnose",
|
|
1328
|
+
description: "Run health checks across all subsystems (actions, leases, sentinels, sketches, signals, sessions, memories, mesh). Identifies stuck, orphaned, and inconsistent state.",
|
|
1329
|
+
inputSchema: {
|
|
1330
|
+
type: "object",
|
|
1331
|
+
properties: { categories: {
|
|
1332
|
+
type: "string",
|
|
1333
|
+
description: "Comma-separated categories to check (default all)"
|
|
1334
|
+
} }
|
|
1335
|
+
}
|
|
1336
|
+
},
|
|
1337
|
+
{
|
|
1338
|
+
name: "memory_heal",
|
|
1339
|
+
description: "Auto-fix all fixable issues found by diagnostics. Unblocks stuck actions, expires stale leases, cleans up orphaned data.",
|
|
1340
|
+
inputSchema: {
|
|
1341
|
+
type: "object",
|
|
1342
|
+
properties: {
|
|
1343
|
+
categories: {
|
|
1344
|
+
type: "string",
|
|
1345
|
+
description: "Comma-separated categories to heal (default all)"
|
|
1346
|
+
},
|
|
1347
|
+
dryRun: {
|
|
1348
|
+
type: "string",
|
|
1349
|
+
description: "Set to 'true' for dry run (report but don't fix)"
|
|
1350
|
+
}
|
|
1351
|
+
}
|
|
1352
|
+
}
|
|
1353
|
+
},
|
|
1354
|
+
{
|
|
1355
|
+
name: "memory_facet_tag",
|
|
1356
|
+
description: "Attach a structured tag (dimension:value) to an action, memory, or observation for multi-dimensional categorization.",
|
|
1357
|
+
inputSchema: {
|
|
1358
|
+
type: "object",
|
|
1359
|
+
properties: {
|
|
1360
|
+
targetId: {
|
|
1361
|
+
type: "string",
|
|
1362
|
+
description: "ID of the target to tag"
|
|
1363
|
+
},
|
|
1364
|
+
targetType: {
|
|
1365
|
+
type: "string",
|
|
1366
|
+
description: "Type: action, memory, or observation"
|
|
1367
|
+
},
|
|
1368
|
+
dimension: {
|
|
1369
|
+
type: "string",
|
|
1370
|
+
description: "Tag dimension (e.g., priority, team, status)"
|
|
1371
|
+
},
|
|
1372
|
+
value: {
|
|
1373
|
+
type: "string",
|
|
1374
|
+
description: "Tag value (e.g., urgent, backend, reviewed)"
|
|
1375
|
+
}
|
|
1376
|
+
},
|
|
1377
|
+
required: [
|
|
1378
|
+
"targetId",
|
|
1379
|
+
"targetType",
|
|
1380
|
+
"dimension",
|
|
1381
|
+
"value"
|
|
1382
|
+
]
|
|
1383
|
+
}
|
|
1384
|
+
},
|
|
1385
|
+
{
|
|
1386
|
+
name: "memory_facet_query",
|
|
1387
|
+
description: "Query targets by facet tags with AND/OR logic. Find all actions tagged priority:urgent AND team:backend.",
|
|
1388
|
+
inputSchema: {
|
|
1389
|
+
type: "object",
|
|
1390
|
+
properties: {
|
|
1391
|
+
matchAll: {
|
|
1392
|
+
type: "string",
|
|
1393
|
+
description: "Comma-separated dimension:value pairs (AND logic)"
|
|
1394
|
+
},
|
|
1395
|
+
matchAny: {
|
|
1396
|
+
type: "string",
|
|
1397
|
+
description: "Comma-separated dimension:value pairs (OR logic)"
|
|
1398
|
+
},
|
|
1399
|
+
targetType: {
|
|
1400
|
+
type: "string",
|
|
1401
|
+
description: "Filter by type: action, memory, or observation"
|
|
1402
|
+
}
|
|
1403
|
+
}
|
|
1404
|
+
}
|
|
1405
|
+
}
|
|
1406
|
+
];
|
|
1407
|
+
const V061_TOOLS = [{
|
|
1408
|
+
name: "memory_verify",
|
|
1409
|
+
description: "Verify a memory or observation by tracing its citation chain back to source observations and session context. Returns provenance information including confidence scores.",
|
|
1410
|
+
inputSchema: {
|
|
1411
|
+
type: "object",
|
|
1412
|
+
properties: { id: {
|
|
1413
|
+
type: "string",
|
|
1414
|
+
description: "Memory ID or observation ID to verify"
|
|
1415
|
+
} },
|
|
1416
|
+
required: ["id"]
|
|
1417
|
+
}
|
|
1418
|
+
}];
|
|
1419
|
+
const V070_TOOLS = [
|
|
1420
|
+
{
|
|
1421
|
+
name: "memory_lesson_save",
|
|
1422
|
+
description: "Save a lesson learned from this session. Lessons have confidence scores that strengthen when reinforced and decay when not used. Duplicate content auto-strengthens the existing lesson.",
|
|
1423
|
+
inputSchema: {
|
|
1424
|
+
type: "object",
|
|
1425
|
+
properties: {
|
|
1426
|
+
content: {
|
|
1427
|
+
type: "string",
|
|
1428
|
+
description: "The lesson learned (what worked, what to avoid, when to use X approach)"
|
|
1429
|
+
},
|
|
1430
|
+
context: {
|
|
1431
|
+
type: "string",
|
|
1432
|
+
description: "When/where this lesson applies"
|
|
1433
|
+
},
|
|
1434
|
+
confidence: {
|
|
1435
|
+
type: "number",
|
|
1436
|
+
description: "Initial confidence 0.0-1.0 (default 0.5)"
|
|
1437
|
+
},
|
|
1438
|
+
project: {
|
|
1439
|
+
type: "string",
|
|
1440
|
+
description: "Project this lesson is about"
|
|
1441
|
+
},
|
|
1442
|
+
tags: {
|
|
1443
|
+
type: "string",
|
|
1444
|
+
description: "Comma-separated tags"
|
|
1445
|
+
}
|
|
1446
|
+
},
|
|
1447
|
+
required: ["content"]
|
|
1448
|
+
}
|
|
1449
|
+
},
|
|
1450
|
+
{
|
|
1451
|
+
name: "memory_lesson_recall",
|
|
1452
|
+
description: "Search lessons by query. Returns lessons sorted by confidence and recency. Use to check what the agent has learned before making decisions.",
|
|
1453
|
+
inputSchema: {
|
|
1454
|
+
type: "object",
|
|
1455
|
+
properties: {
|
|
1456
|
+
query: {
|
|
1457
|
+
type: "string",
|
|
1458
|
+
description: "Search query"
|
|
1459
|
+
},
|
|
1460
|
+
project: {
|
|
1461
|
+
type: "string",
|
|
1462
|
+
description: "Filter by project"
|
|
1463
|
+
},
|
|
1464
|
+
minConfidence: {
|
|
1465
|
+
type: "number",
|
|
1466
|
+
description: "Minimum confidence threshold (default 0.1)"
|
|
1467
|
+
},
|
|
1468
|
+
limit: {
|
|
1469
|
+
type: "number",
|
|
1470
|
+
description: "Max results (default 10)"
|
|
1471
|
+
}
|
|
1472
|
+
},
|
|
1473
|
+
required: ["query"]
|
|
1474
|
+
}
|
|
1475
|
+
},
|
|
1476
|
+
{
|
|
1477
|
+
name: "memory_lesson_delete",
|
|
1478
|
+
description: "Soft-delete a lesson by id. Deleted lessons are excluded from recall and list; re-saving the same content creates a fresh lesson.",
|
|
1479
|
+
inputSchema: {
|
|
1480
|
+
type: "object",
|
|
1481
|
+
properties: { lessonId: {
|
|
1482
|
+
type: "string",
|
|
1483
|
+
description: "The lesson id (lsn_...)"
|
|
1484
|
+
} },
|
|
1485
|
+
required: ["lessonId"]
|
|
1486
|
+
}
|
|
1487
|
+
},
|
|
1488
|
+
{
|
|
1489
|
+
name: "memory_obsidian_export",
|
|
1490
|
+
description: "Export memories, lessons, and crystals as Obsidian-compatible Markdown files with YAML frontmatter and wikilinks for graph view.",
|
|
1491
|
+
inputSchema: {
|
|
1492
|
+
type: "object",
|
|
1493
|
+
properties: {
|
|
1494
|
+
vaultDir: {
|
|
1495
|
+
type: "string",
|
|
1496
|
+
description: "Output directory (default ~/.agentmemory/vault/)"
|
|
1497
|
+
},
|
|
1498
|
+
types: {
|
|
1499
|
+
type: "string",
|
|
1500
|
+
description: "Comma-separated types to export: memories,lessons,crystals,sessions (default all)"
|
|
1501
|
+
}
|
|
1502
|
+
}
|
|
1503
|
+
}
|
|
1504
|
+
}
|
|
1505
|
+
];
|
|
1506
|
+
const V073_TOOLS = [{
|
|
1507
|
+
name: "memory_reflect",
|
|
1508
|
+
description: "Traverse the knowledge graph, group related memories by concept clusters, and synthesize higher-order insights via LLM. Returns new and reinforced insights.",
|
|
1509
|
+
inputSchema: {
|
|
1510
|
+
type: "object",
|
|
1511
|
+
properties: {
|
|
1512
|
+
project: {
|
|
1513
|
+
type: "string",
|
|
1514
|
+
description: "Filter by project"
|
|
1515
|
+
},
|
|
1516
|
+
maxClusters: {
|
|
1517
|
+
type: "number",
|
|
1518
|
+
description: "Max concept clusters to process (default 10, max 20)"
|
|
1519
|
+
}
|
|
1520
|
+
}
|
|
1521
|
+
}
|
|
1522
|
+
}, {
|
|
1523
|
+
name: "memory_insight_list",
|
|
1524
|
+
description: "List synthesized insights — higher-order observations derived from patterns across memories, lessons, and crystals.",
|
|
1525
|
+
inputSchema: {
|
|
1526
|
+
type: "object",
|
|
1527
|
+
properties: {
|
|
1528
|
+
project: {
|
|
1529
|
+
type: "string",
|
|
1530
|
+
description: "Filter by project"
|
|
1531
|
+
},
|
|
1532
|
+
minConfidence: {
|
|
1533
|
+
type: "number",
|
|
1534
|
+
description: "Minimum confidence threshold (default 0)"
|
|
1535
|
+
},
|
|
1536
|
+
limit: {
|
|
1537
|
+
type: "number",
|
|
1538
|
+
description: "Max results (default 50)"
|
|
1539
|
+
}
|
|
1540
|
+
}
|
|
1541
|
+
}
|
|
1542
|
+
}];
|
|
1543
|
+
const V010_SLOTS_TOOLS = [
|
|
1544
|
+
{
|
|
1545
|
+
name: "memory_slot_list",
|
|
1546
|
+
description: "List all memory slots (pinned + project + global). Slots are editable, size-limited memory units the agent can read and modify across sessions.",
|
|
1547
|
+
inputSchema: {
|
|
1548
|
+
type: "object",
|
|
1549
|
+
properties: {}
|
|
1550
|
+
}
|
|
1551
|
+
},
|
|
1552
|
+
{
|
|
1553
|
+
name: "memory_slot_get",
|
|
1554
|
+
description: "Read a single slot by label.",
|
|
1555
|
+
inputSchema: {
|
|
1556
|
+
type: "object",
|
|
1557
|
+
properties: { label: {
|
|
1558
|
+
type: "string",
|
|
1559
|
+
description: "Slot label (e.g. 'persona', 'pending_items')"
|
|
1560
|
+
} },
|
|
1561
|
+
required: ["label"]
|
|
1562
|
+
}
|
|
1563
|
+
},
|
|
1564
|
+
{
|
|
1565
|
+
name: "memory_slot_create",
|
|
1566
|
+
description: "Create a new slot. Reject if a slot with the same label already exists.",
|
|
1567
|
+
inputSchema: {
|
|
1568
|
+
type: "object",
|
|
1569
|
+
properties: {
|
|
1570
|
+
label: {
|
|
1571
|
+
type: "string",
|
|
1572
|
+
description: "Slot label — lowercase, starts with letter, [a-z0-9_]"
|
|
1573
|
+
},
|
|
1574
|
+
content: {
|
|
1575
|
+
type: "string",
|
|
1576
|
+
description: "Initial content (default empty)"
|
|
1577
|
+
},
|
|
1578
|
+
sizeLimit: {
|
|
1579
|
+
type: "number",
|
|
1580
|
+
description: "Max chars (default 2000, hard cap 20000)"
|
|
1581
|
+
},
|
|
1582
|
+
description: {
|
|
1583
|
+
type: "string",
|
|
1584
|
+
description: "What this slot is for"
|
|
1585
|
+
},
|
|
1586
|
+
pinned: {
|
|
1587
|
+
type: "string",
|
|
1588
|
+
description: "'false' to exclude from context injection; default true"
|
|
1589
|
+
},
|
|
1590
|
+
scope: {
|
|
1591
|
+
type: "string",
|
|
1592
|
+
description: "'project' (default) or 'global' (shared across projects)"
|
|
1593
|
+
}
|
|
1594
|
+
},
|
|
1595
|
+
required: ["label"]
|
|
1596
|
+
}
|
|
1597
|
+
},
|
|
1598
|
+
{
|
|
1599
|
+
name: "memory_slot_append",
|
|
1600
|
+
description: "Append text to an existing slot. Fails with 413 if the append would exceed the slot's sizeLimit — agent must compact via memory_slot_replace first.",
|
|
1601
|
+
inputSchema: {
|
|
1602
|
+
type: "object",
|
|
1603
|
+
properties: {
|
|
1604
|
+
label: {
|
|
1605
|
+
type: "string",
|
|
1606
|
+
description: "Slot label"
|
|
1607
|
+
},
|
|
1608
|
+
text: {
|
|
1609
|
+
type: "string",
|
|
1610
|
+
description: "Text to append"
|
|
1611
|
+
}
|
|
1612
|
+
},
|
|
1613
|
+
required: ["label", "text"]
|
|
1614
|
+
}
|
|
1615
|
+
},
|
|
1616
|
+
{
|
|
1617
|
+
name: "memory_slot_replace",
|
|
1618
|
+
description: "Replace slot content in place. Fails if content exceeds sizeLimit.",
|
|
1619
|
+
inputSchema: {
|
|
1620
|
+
type: "object",
|
|
1621
|
+
properties: {
|
|
1622
|
+
label: {
|
|
1623
|
+
type: "string",
|
|
1624
|
+
description: "Slot label"
|
|
1625
|
+
},
|
|
1626
|
+
content: {
|
|
1627
|
+
type: "string",
|
|
1628
|
+
description: "New full content"
|
|
1629
|
+
}
|
|
1630
|
+
},
|
|
1631
|
+
required: ["label", "content"]
|
|
1632
|
+
}
|
|
1633
|
+
},
|
|
1634
|
+
{
|
|
1635
|
+
name: "memory_slot_delete",
|
|
1636
|
+
description: "Delete a slot. Seeded default slots can be deleted unless marked readOnly.",
|
|
1637
|
+
inputSchema: {
|
|
1638
|
+
type: "object",
|
|
1639
|
+
properties: { label: {
|
|
1640
|
+
type: "string",
|
|
1641
|
+
description: "Slot label"
|
|
1642
|
+
} },
|
|
1643
|
+
required: ["label"]
|
|
1644
|
+
}
|
|
1645
|
+
}
|
|
1646
|
+
];
|
|
1647
|
+
const ESSENTIAL_TOOLS = new Set([
|
|
1648
|
+
"memory_save",
|
|
1649
|
+
"memory_recall",
|
|
1650
|
+
"memory_consolidate",
|
|
1651
|
+
"memory_smart_search",
|
|
1652
|
+
"memory_sessions",
|
|
1653
|
+
"memory_diagnose",
|
|
1654
|
+
"memory_lesson_save",
|
|
1655
|
+
"memory_reflect"
|
|
1656
|
+
]);
|
|
1657
|
+
function getAllTools() {
|
|
1658
|
+
return [
|
|
1659
|
+
...CORE_TOOLS,
|
|
1660
|
+
...V040_TOOLS,
|
|
1661
|
+
...V050_TOOLS,
|
|
1662
|
+
...V051_TOOLS,
|
|
1663
|
+
...V061_TOOLS,
|
|
1664
|
+
...V070_TOOLS,
|
|
1665
|
+
...V073_TOOLS,
|
|
1666
|
+
...V010_SLOTS_TOOLS
|
|
1667
|
+
];
|
|
1668
|
+
}
|
|
1669
|
+
function getVisibleTools() {
|
|
1670
|
+
if ((process.env["AGENTMEMORY_TOOLS"] || "all") === "core") return getAllTools().filter((t) => ESSENTIAL_TOOLS.has(t.name));
|
|
1671
|
+
return getAllTools();
|
|
1672
|
+
}
|
|
1673
|
+
//#endregion
|
|
1674
|
+
//#region src/functions/audit.ts
|
|
1675
|
+
const AUDIT_MIGRATE_FUNCTION_ID = "mem::audit-migrate";
|
|
1676
|
+
const AUDIT_MIGRATION_COPY_CONCURRENCY = 32;
|
|
1677
|
+
const AUDIT_MIGRATION_DELETE_CONCURRENCY = 8;
|
|
1678
|
+
const AUDIT_MONTHS_LOCK = KV.auditMonths;
|
|
1679
|
+
const AUDIT_MIGRATION_LOCK = "mem:audit:migration-lock";
|
|
1680
|
+
const AUDIT_MIGRATION_STATE_KEY = "migration";
|
|
1681
|
+
const AUDIT_MIGRATION_DELETE_WAIT_INTERVALS = 2;
|
|
1682
|
+
const STATE_STORE_DIR_NAME = "state_store.db";
|
|
1683
|
+
function sleep(ms) {
|
|
1684
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
1685
|
+
}
|
|
1686
|
+
function encodeStateIndexSegment(index) {
|
|
1687
|
+
let out = "";
|
|
1688
|
+
for (const byte of Buffer.from(index, "utf8")) {
|
|
1689
|
+
const ch = String.fromCharCode(byte);
|
|
1690
|
+
out += /^[A-Za-z0-9\-_.]$/.test(ch) ? ch : `%${byte.toString(16).toUpperCase().padStart(2, "0")}`;
|
|
1691
|
+
}
|
|
1692
|
+
return out;
|
|
1693
|
+
}
|
|
1694
|
+
function legacyAuditStateFilePath(dataDir) {
|
|
1695
|
+
return join(dataDir, STATE_STORE_DIR_NAME, `${encodeStateIndexSegment(KV.audit)}.bin`);
|
|
1696
|
+
}
|
|
1697
|
+
async function probeLegacyAuditFile() {
|
|
1698
|
+
const dataDir = getEnvVar("AGENTMEMORY_DATA_DIR");
|
|
1699
|
+
if (!dataDir) return {
|
|
1700
|
+
safe: false,
|
|
1701
|
+
reason: "unreadable"
|
|
1702
|
+
};
|
|
1703
|
+
const storeDir = join(dataDir, STATE_STORE_DIR_NAME);
|
|
1704
|
+
try {
|
|
1705
|
+
await stat(storeDir);
|
|
1706
|
+
} catch {
|
|
1707
|
+
return {
|
|
1708
|
+
safe: false,
|
|
1709
|
+
reason: "unreadable"
|
|
1710
|
+
};
|
|
1711
|
+
}
|
|
1712
|
+
let fileStat;
|
|
1713
|
+
try {
|
|
1714
|
+
fileStat = await stat(legacyAuditStateFilePath(dataDir));
|
|
1715
|
+
} catch (err) {
|
|
1716
|
+
if (err.code === "ENOENT") return {
|
|
1717
|
+
safe: true,
|
|
1718
|
+
empty: true
|
|
1719
|
+
};
|
|
1720
|
+
return {
|
|
1721
|
+
safe: false,
|
|
1722
|
+
reason: "unreadable"
|
|
1723
|
+
};
|
|
1724
|
+
}
|
|
1725
|
+
if (fileStat.size > getAuditMigrateMaxBytes()) return {
|
|
1726
|
+
safe: false,
|
|
1727
|
+
reason: "too-large",
|
|
1728
|
+
sizeBytes: fileStat.size
|
|
1729
|
+
};
|
|
1730
|
+
return {
|
|
1731
|
+
safe: true,
|
|
1732
|
+
empty: false,
|
|
1733
|
+
sizeBytes: fileStat.size
|
|
1734
|
+
};
|
|
1735
|
+
}
|
|
1736
|
+
async function probeLegacyAuditScope(kv) {
|
|
1737
|
+
let rows;
|
|
1738
|
+
try {
|
|
1739
|
+
rows = await kv.list(KV.audit);
|
|
1740
|
+
} catch {
|
|
1741
|
+
return {
|
|
1742
|
+
safe: false,
|
|
1743
|
+
reason: "unreadable"
|
|
1744
|
+
};
|
|
1745
|
+
}
|
|
1746
|
+
if (!Array.isArray(rows) || rows.length === 0) return {
|
|
1747
|
+
safe: true,
|
|
1748
|
+
empty: true
|
|
1749
|
+
};
|
|
1750
|
+
const sizeBytes = Buffer.byteLength(JSON.stringify(rows), "utf8");
|
|
1751
|
+
if (sizeBytes > getAuditMigrateMaxBytes()) return {
|
|
1752
|
+
safe: false,
|
|
1753
|
+
reason: "too-large",
|
|
1754
|
+
sizeBytes
|
|
1755
|
+
};
|
|
1756
|
+
return {
|
|
1757
|
+
safe: true,
|
|
1758
|
+
empty: false,
|
|
1759
|
+
sizeBytes
|
|
1760
|
+
};
|
|
1761
|
+
}
|
|
1762
|
+
async function auditMigrationDeleteDelayMs() {
|
|
1763
|
+
const dataDir = getEnvVar("AGENTMEMORY_DATA_DIR");
|
|
1764
|
+
if (!dataDir) return ENGINE_DEFAULT_SAVE_INTERVAL_MS * AUDIT_MIGRATION_DELETE_WAIT_INTERVALS;
|
|
1765
|
+
const configTexts = [];
|
|
1766
|
+
for (const path of engineStateConfigPaths(dataDir, runtimeConfigPath(dataDir))) try {
|
|
1767
|
+
configTexts.push(await readFile(path, "utf-8"));
|
|
1768
|
+
} catch {}
|
|
1769
|
+
return engineSaveIntervalMs(configTexts) * AUDIT_MIGRATION_DELETE_WAIT_INTERVALS;
|
|
1770
|
+
}
|
|
1771
|
+
async function readAuditMigrationState(kv) {
|
|
1772
|
+
return kv.get(KV.auditMonths, AUDIT_MIGRATION_STATE_KEY);
|
|
1773
|
+
}
|
|
1774
|
+
async function writeAuditMigrationState(kv, state) {
|
|
1775
|
+
await kv.set(KV.auditMonths, AUDIT_MIGRATION_STATE_KEY, state);
|
|
1776
|
+
}
|
|
1777
|
+
function auditMonthOf(timestamp) {
|
|
1778
|
+
const parsed = new Date(timestamp);
|
|
1779
|
+
return (Number.isNaN(parsed.getTime()) ? (/* @__PURE__ */ new Date()).toISOString() : parsed.toISOString()).slice(0, 7);
|
|
1780
|
+
}
|
|
1781
|
+
function monthStartMs(month) {
|
|
1782
|
+
const [year, mon] = month.split("-").map(Number);
|
|
1783
|
+
return Date.UTC(year, mon - 1, 1);
|
|
1784
|
+
}
|
|
1785
|
+
function monthEndMs(month) {
|
|
1786
|
+
const [year, mon] = month.split("-").map(Number);
|
|
1787
|
+
return Date.UTC(year, mon, 1) - 1;
|
|
1788
|
+
}
|
|
1789
|
+
function monthNMonthsAgo(count) {
|
|
1790
|
+
const now = /* @__PURE__ */ new Date();
|
|
1791
|
+
return new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth() - count, 1)).toISOString().slice(0, 7);
|
|
1792
|
+
}
|
|
1793
|
+
async function readAuditMonthIndex(kv) {
|
|
1794
|
+
return (await kv.get(KV.auditMonths, "index"))?.months ?? [];
|
|
1795
|
+
}
|
|
1796
|
+
async function markAuditMonth(kv, month) {
|
|
1797
|
+
await withKeyedLock(AUDIT_MONTHS_LOCK, async () => {
|
|
1798
|
+
const months = await readAuditMonthIndex(kv);
|
|
1799
|
+
if (months.includes(month)) return;
|
|
1800
|
+
const next = [...months, month].sort();
|
|
1801
|
+
await kv.set(KV.auditMonths, "index", { months: next });
|
|
1802
|
+
});
|
|
1803
|
+
}
|
|
1804
|
+
async function listAuditMonthsDesc(kv) {
|
|
1805
|
+
return [...await readAuditMonthIndex(kv)].sort().reverse();
|
|
1806
|
+
}
|
|
1807
|
+
let auditRecordedListener = null;
|
|
1808
|
+
function setAuditRecordedListener(listener) {
|
|
1809
|
+
auditRecordedListener = listener;
|
|
1810
|
+
}
|
|
1811
|
+
async function recordAudit(kv, operation, functionId, targetIds, details = {}, qualityScore, userId) {
|
|
1812
|
+
const entry = {
|
|
1813
|
+
id: generateId("aud"),
|
|
1814
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1815
|
+
operation,
|
|
1816
|
+
userId,
|
|
1817
|
+
functionId,
|
|
1818
|
+
targetIds,
|
|
1819
|
+
details,
|
|
1820
|
+
qualityScore
|
|
1821
|
+
};
|
|
1822
|
+
const month = auditMonthOf(entry.timestamp);
|
|
1823
|
+
await kv.set(KV.auditMonth(month), entry.id, entry);
|
|
1824
|
+
await markAuditMonth(kv, month);
|
|
1825
|
+
try {
|
|
1826
|
+
auditRecordedListener?.(entry);
|
|
1827
|
+
} catch {}
|
|
1828
|
+
return entry;
|
|
1829
|
+
}
|
|
1830
|
+
async function safeAudit(kv, operation, functionId, targetIds, details = {}, qualityScore, userId) {
|
|
1831
|
+
try {
|
|
1832
|
+
await recordAudit(kv, operation, functionId, targetIds, details, qualityScore, userId);
|
|
1833
|
+
} catch (err) {
|
|
1834
|
+
try {
|
|
1835
|
+
logger.warn("audit write failed", {
|
|
1836
|
+
functionId,
|
|
1837
|
+
operation,
|
|
1838
|
+
targetIds,
|
|
1839
|
+
error: err instanceof Error ? err.message : String(err)
|
|
1840
|
+
});
|
|
1841
|
+
} catch {}
|
|
1842
|
+
}
|
|
1843
|
+
}
|
|
1844
|
+
async function queryAudit(kv, filter) {
|
|
1845
|
+
const limit = filter?.limit || 100;
|
|
1846
|
+
let fromMs;
|
|
1847
|
+
if (filter?.dateFrom) {
|
|
1848
|
+
fromMs = new Date(filter.dateFrom).getTime();
|
|
1849
|
+
if (Number.isNaN(fromMs)) throw new Error(`Invalid dateFrom: ${filter.dateFrom}`);
|
|
1850
|
+
}
|
|
1851
|
+
const query = filter?.query?.trim().toLowerCase();
|
|
1852
|
+
let toMs;
|
|
1853
|
+
if (filter?.dateTo) {
|
|
1854
|
+
toMs = new Date(filter.dateTo).getTime();
|
|
1855
|
+
if (Number.isNaN(toMs)) throw new Error(`Invalid dateTo: ${filter.dateTo}`);
|
|
1856
|
+
}
|
|
1857
|
+
const matches = (entry) => {
|
|
1858
|
+
if (filter?.operation && entry.operation !== filter.operation) return false;
|
|
1859
|
+
const t = new Date(entry.timestamp).getTime();
|
|
1860
|
+
if (fromMs !== void 0 && t < fromMs) return false;
|
|
1861
|
+
if (toMs !== void 0 && t > toMs) return false;
|
|
1862
|
+
if (query && ![entry.functionId, ...entry.targetIds || []].some((v) => String(v || "").toLowerCase().includes(query))) return false;
|
|
1863
|
+
return true;
|
|
1864
|
+
};
|
|
1865
|
+
const seenIds = /* @__PURE__ */ new Set();
|
|
1866
|
+
const collected = [];
|
|
1867
|
+
const addIfNew = (row) => {
|
|
1868
|
+
if (seenIds.has(row.id)) return;
|
|
1869
|
+
seenIds.add(row.id);
|
|
1870
|
+
if (matches(row)) collected.push(row);
|
|
1871
|
+
};
|
|
1872
|
+
const months = await listAuditMonthsDesc(kv);
|
|
1873
|
+
for (const month of months) {
|
|
1874
|
+
if (collected.length >= limit) break;
|
|
1875
|
+
if (toMs !== void 0 && monthStartMs(month) > toMs) continue;
|
|
1876
|
+
if (fromMs !== void 0 && monthEndMs(month) < fromMs) break;
|
|
1877
|
+
const rows = await kv.list(KV.auditMonth(month));
|
|
1878
|
+
for (const row of rows) addIfNew(row);
|
|
1879
|
+
}
|
|
1880
|
+
let legacyFrozen = false;
|
|
1881
|
+
let legacyFrozenBytes;
|
|
1882
|
+
if (collected.length < limit) {
|
|
1883
|
+
const migrationState = await readAuditMigrationState(kv);
|
|
1884
|
+
if (migrationState?.safeToListLegacy) {
|
|
1885
|
+
const legacyRows = await kv.list(KV.audit);
|
|
1886
|
+
for (const row of legacyRows) addIfNew(row);
|
|
1887
|
+
} else if (migrationState?.status === "too-large" || migrationState?.status === "unreadable") {
|
|
1888
|
+
legacyFrozen = true;
|
|
1889
|
+
legacyFrozenBytes = migrationState.legacySizeBytes;
|
|
1890
|
+
}
|
|
1891
|
+
}
|
|
1892
|
+
collected.sort((a, b) => new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime());
|
|
1893
|
+
return {
|
|
1894
|
+
entries: collected.slice(0, limit),
|
|
1895
|
+
legacyFrozen,
|
|
1896
|
+
legacyFrozenBytes
|
|
1897
|
+
};
|
|
1898
|
+
}
|
|
1899
|
+
async function inParallel(items, concurrency, work) {
|
|
1900
|
+
let next = 0;
|
|
1901
|
+
const runners = Array.from({ length: Math.min(concurrency, items.length) }, async () => {
|
|
1902
|
+
while (next < items.length) {
|
|
1903
|
+
const item = items[next++];
|
|
1904
|
+
await work(item);
|
|
1905
|
+
}
|
|
1906
|
+
});
|
|
1907
|
+
await Promise.all(runners);
|
|
1908
|
+
}
|
|
1909
|
+
async function startAuditMigration(kv, deps = {}) {
|
|
1910
|
+
const onRedis = kv.backend === "redis";
|
|
1911
|
+
const runProbe = deps.probe ?? (onRedis ? () => probeLegacyAuditScope(kv) : probeLegacyAuditFile);
|
|
1912
|
+
const runDeleteDelayMs = deps.deleteDelayMs ?? (onRedis ? async () => 0 : auditMigrationDeleteDelayMs);
|
|
1913
|
+
const marker = await readAuditMigrationState(kv);
|
|
1914
|
+
if (marker?.status === "done") return;
|
|
1915
|
+
const probe = await runProbe();
|
|
1916
|
+
if (probe.safe && probe.empty) {
|
|
1917
|
+
await writeAuditMigrationState(kv, {
|
|
1918
|
+
status: "done",
|
|
1919
|
+
safeToListLegacy: true,
|
|
1920
|
+
legacySizeBytes: 0,
|
|
1921
|
+
migrated: marker?.migrated ?? 0,
|
|
1922
|
+
purged: marker?.purged ?? 0,
|
|
1923
|
+
summaryWritten: marker?.summaryWritten ?? true,
|
|
1924
|
+
checkedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
1925
|
+
});
|
|
1926
|
+
return;
|
|
1927
|
+
}
|
|
1928
|
+
if (!probe.safe) {
|
|
1929
|
+
await writeAuditMigrationState(kv, {
|
|
1930
|
+
status: probe.reason,
|
|
1931
|
+
safeToListLegacy: false,
|
|
1932
|
+
legacySizeBytes: probe.reason === "too-large" ? probe.sizeBytes : marker?.legacySizeBytes,
|
|
1933
|
+
migrated: marker?.migrated ?? 0,
|
|
1934
|
+
purged: marker?.purged ?? 0,
|
|
1935
|
+
summaryWritten: marker?.summaryWritten ?? false,
|
|
1936
|
+
checkedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
1937
|
+
});
|
|
1938
|
+
logger.warn("legacy audit log left frozen; migration only reads it locally and under a size cap", {
|
|
1939
|
+
reason: probe.reason,
|
|
1940
|
+
sizeBytes: probe.reason === "too-large" ? probe.sizeBytes : void 0
|
|
1941
|
+
});
|
|
1942
|
+
return;
|
|
1943
|
+
}
|
|
1944
|
+
let migrated = marker?.migrated ?? 0;
|
|
1945
|
+
let purged = marker?.purged ?? 0;
|
|
1946
|
+
if (marker?.status !== "copied") {
|
|
1947
|
+
let legacy;
|
|
1948
|
+
try {
|
|
1949
|
+
legacy = await kv.list(KV.audit);
|
|
1950
|
+
} catch (err) {
|
|
1951
|
+
logger.warn("audit migration could not read the legacy audit log", { error: err instanceof Error ? err.message : String(err) });
|
|
1952
|
+
return;
|
|
1953
|
+
}
|
|
1954
|
+
if (legacy.length === 0) {
|
|
1955
|
+
await writeAuditMigrationState(kv, {
|
|
1956
|
+
status: "done",
|
|
1957
|
+
safeToListLegacy: true,
|
|
1958
|
+
legacySizeBytes: 0,
|
|
1959
|
+
migrated,
|
|
1960
|
+
purged,
|
|
1961
|
+
summaryWritten: marker?.summaryWritten ?? true,
|
|
1962
|
+
checkedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
1963
|
+
});
|
|
1964
|
+
return;
|
|
1965
|
+
}
|
|
1966
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1967
|
+
const deduped = legacy.filter((entry) => {
|
|
1968
|
+
if (seen.has(entry.id)) return false;
|
|
1969
|
+
seen.add(entry.id);
|
|
1970
|
+
return true;
|
|
1971
|
+
});
|
|
1972
|
+
const kept = deduped.filter((entry) => entry.operation !== "index_persist");
|
|
1973
|
+
purged = deduped.length - kept.length;
|
|
1974
|
+
migrated = kept.length;
|
|
1975
|
+
try {
|
|
1976
|
+
const months = /* @__PURE__ */ new Set();
|
|
1977
|
+
await inParallel(kept, AUDIT_MIGRATION_COPY_CONCURRENCY, async (entry) => {
|
|
1978
|
+
const month = auditMonthOf(entry.timestamp);
|
|
1979
|
+
await kv.set(KV.auditMonth(month), entry.id, entry);
|
|
1980
|
+
months.add(month);
|
|
1981
|
+
});
|
|
1982
|
+
for (const month of months) await markAuditMonth(kv, month);
|
|
1983
|
+
} catch (err) {
|
|
1984
|
+
logger.warn("audit migration stopped before finishing the copy pass; it resumes on the next boot", { error: err instanceof Error ? err.message : String(err) });
|
|
1985
|
+
return;
|
|
1986
|
+
}
|
|
1987
|
+
await writeAuditMigrationState(kv, {
|
|
1988
|
+
status: "copied",
|
|
1989
|
+
safeToListLegacy: false,
|
|
1990
|
+
legacySizeBytes: probe.sizeBytes,
|
|
1991
|
+
migrated,
|
|
1992
|
+
purged,
|
|
1993
|
+
summaryWritten: false,
|
|
1994
|
+
checkedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
1995
|
+
});
|
|
1996
|
+
}
|
|
1997
|
+
await sleep(await runDeleteDelayMs());
|
|
1998
|
+
let remaining;
|
|
1999
|
+
try {
|
|
2000
|
+
remaining = await kv.list(KV.audit);
|
|
2001
|
+
} catch (err) {
|
|
2002
|
+
logger.warn("audit migration could not re-read the legacy audit log before deleting; it resumes on the next boot", { error: err instanceof Error ? err.message : String(err) });
|
|
2003
|
+
return;
|
|
2004
|
+
}
|
|
2005
|
+
try {
|
|
2006
|
+
await inParallel(remaining.slice().reverse(), AUDIT_MIGRATION_DELETE_CONCURRENCY, async (entry) => {
|
|
2007
|
+
await kv.delete(KV.audit, entry.id);
|
|
2008
|
+
});
|
|
2009
|
+
} catch (err) {
|
|
2010
|
+
logger.warn("audit migration stopped before finishing the delete pass; it resumes on the next boot", { error: err instanceof Error ? err.message : String(err) });
|
|
2011
|
+
return;
|
|
2012
|
+
}
|
|
2013
|
+
await withKeyedLock(AUDIT_MIGRATION_LOCK, async () => {
|
|
2014
|
+
if ((await readAuditMigrationState(kv))?.summaryWritten) return;
|
|
2015
|
+
if (purged > 0) await safeAudit(kv, "audit_migrate", AUDIT_MIGRATE_FUNCTION_ID, [], {
|
|
2016
|
+
reason: "index_persist rows predate opt-in auditing",
|
|
2017
|
+
purged,
|
|
2018
|
+
migrated
|
|
2019
|
+
});
|
|
2020
|
+
await writeAuditMigrationState(kv, {
|
|
2021
|
+
status: "done",
|
|
2022
|
+
safeToListLegacy: true,
|
|
2023
|
+
legacySizeBytes: 0,
|
|
2024
|
+
migrated,
|
|
2025
|
+
purged,
|
|
2026
|
+
summaryWritten: true,
|
|
2027
|
+
checkedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
2028
|
+
});
|
|
2029
|
+
});
|
|
2030
|
+
logger.info("audit log moved to monthly scopes", {
|
|
2031
|
+
migrated,
|
|
2032
|
+
purged
|
|
2033
|
+
});
|
|
2034
|
+
}
|
|
2035
|
+
async function runAuditRetentionSweep(kv, retentionMonths) {
|
|
2036
|
+
if (!Number.isFinite(retentionMonths) || retentionMonths <= 0) return {
|
|
2037
|
+
droppedMonths: [],
|
|
2038
|
+
droppedRows: 0
|
|
2039
|
+
};
|
|
2040
|
+
const months = await readAuditMonthIndex(kv);
|
|
2041
|
+
const cutoff = monthNMonthsAgo(retentionMonths);
|
|
2042
|
+
const toDrop = months.filter((month) => month < cutoff).sort();
|
|
2043
|
+
if (toDrop.length === 0) return {
|
|
2044
|
+
droppedMonths: [],
|
|
2045
|
+
droppedRows: 0
|
|
2046
|
+
};
|
|
2047
|
+
let droppedRows = 0;
|
|
2048
|
+
for (const month of toDrop) {
|
|
2049
|
+
const rows = await kv.list(KV.auditMonth(month));
|
|
2050
|
+
for (const row of rows.slice().reverse()) {
|
|
2051
|
+
await kv.delete(KV.auditMonth(month), row.id);
|
|
2052
|
+
droppedRows++;
|
|
2053
|
+
}
|
|
2054
|
+
}
|
|
2055
|
+
await withKeyedLock(AUDIT_MONTHS_LOCK, async () => {
|
|
2056
|
+
const remaining = (await readAuditMonthIndex(kv)).filter((month) => !toDrop.includes(month)).sort();
|
|
2057
|
+
await kv.set(KV.auditMonths, "index", { months: remaining });
|
|
2058
|
+
});
|
|
2059
|
+
return {
|
|
2060
|
+
droppedMonths: toDrop,
|
|
2061
|
+
droppedRows
|
|
2062
|
+
};
|
|
2063
|
+
}
|
|
2064
|
+
//#endregion
|
|
2065
|
+
//#region src/state/search-layer.ts
|
|
2066
|
+
function isSearchLayer(value) {
|
|
2067
|
+
return value === "all" || value === "memory" || value === "observation";
|
|
2068
|
+
}
|
|
2069
|
+
function isSearchResultLayer(value) {
|
|
2070
|
+
return value === "memory" || value === "observation" || value === "lesson" || value === "insight";
|
|
2071
|
+
}
|
|
2072
|
+
function getSearchResultLayer(obsId, sessionId) {
|
|
2073
|
+
if (obsId.startsWith("mem_")) return "memory";
|
|
2074
|
+
if (sessionId === "lesson" || obsId.startsWith("lsn_")) return "lesson";
|
|
2075
|
+
if (sessionId === "insight" || obsId.startsWith("ins_")) return "insight";
|
|
2076
|
+
return "observation";
|
|
2077
|
+
}
|
|
2078
|
+
function matchesSearchLayer(obsId, sessionId, targetLayer = "all", layer) {
|
|
2079
|
+
return targetLayer === "all" || (layer ?? getSearchResultLayer(obsId, sessionId)) === targetLayer;
|
|
2080
|
+
}
|
|
2081
|
+
//#endregion
|
|
2082
|
+
//#region src/state/memory-utils.ts
|
|
2083
|
+
function memoryToObservation(memory) {
|
|
2084
|
+
return {
|
|
2085
|
+
id: memory.id,
|
|
2086
|
+
sessionId: memory.sessionIds?.[0] ?? "memory",
|
|
2087
|
+
timestamp: memory.createdAt,
|
|
2088
|
+
type: "decision",
|
|
2089
|
+
title: memory.title,
|
|
2090
|
+
facts: [memory.content],
|
|
2091
|
+
narrative: memory.content,
|
|
2092
|
+
concepts: memory.concepts,
|
|
2093
|
+
files: memory.files,
|
|
2094
|
+
importance: memory.strength,
|
|
2095
|
+
...memory.agentId ? { agentId: memory.agentId } : {}
|
|
2096
|
+
};
|
|
2097
|
+
}
|
|
2098
|
+
function lessonToObservation(l) {
|
|
2099
|
+
return {
|
|
2100
|
+
id: l.id,
|
|
2101
|
+
sessionId: "lesson",
|
|
2102
|
+
timestamp: l.createdAt,
|
|
2103
|
+
type: "decision",
|
|
2104
|
+
title: l.content.slice(0, 120),
|
|
2105
|
+
facts: [l.content],
|
|
2106
|
+
narrative: l.context || "",
|
|
2107
|
+
concepts: l.tags,
|
|
2108
|
+
files: [],
|
|
2109
|
+
importance: l.confidence
|
|
2110
|
+
};
|
|
2111
|
+
}
|
|
2112
|
+
//#endregion
|
|
2113
|
+
//#region src/functions/recall-response.ts
|
|
2114
|
+
function estimateTokens(value) {
|
|
2115
|
+
return Math.max(1, Math.ceil(JSON.stringify(value).length / 3));
|
|
2116
|
+
}
|
|
2117
|
+
function prefix(text, length) {
|
|
2118
|
+
let end = Math.min(length, text.length);
|
|
2119
|
+
if (end > 0 && end < text.length && /[\uD800-\uDBFF]/.test(text[end - 1])) end--;
|
|
2120
|
+
return text.slice(0, end);
|
|
2121
|
+
}
|
|
2122
|
+
function fitText(text, budget, makeResult) {
|
|
2123
|
+
let low = 0;
|
|
2124
|
+
let high = text.length;
|
|
2125
|
+
while (low < high) {
|
|
2126
|
+
const middle = Math.ceil((low + high) / 2);
|
|
2127
|
+
if (estimateTokens(makeResult(prefix(text, middle))) <= budget) low = middle;
|
|
2128
|
+
else high = middle - 1;
|
|
2129
|
+
}
|
|
2130
|
+
return makeResult(prefix(text, low));
|
|
2131
|
+
}
|
|
2132
|
+
function formatResult(result, format) {
|
|
2133
|
+
if (format === "full") return result;
|
|
2134
|
+
const observation = result.observation;
|
|
2135
|
+
const compact = {
|
|
2136
|
+
obsId: observation.id,
|
|
2137
|
+
sessionId: result.sessionId,
|
|
2138
|
+
title: observation.title,
|
|
2139
|
+
type: observation.type,
|
|
2140
|
+
score: result.score,
|
|
2141
|
+
timestamp: observation.timestamp,
|
|
2142
|
+
...result.layer !== void 0 && { layer: result.layer }
|
|
2143
|
+
};
|
|
2144
|
+
if (format === "compact") return compact;
|
|
2145
|
+
const { type: _type, ...narrative } = compact;
|
|
2146
|
+
return {
|
|
2147
|
+
...narrative,
|
|
2148
|
+
narrative: observation.narrative
|
|
2149
|
+
};
|
|
2150
|
+
}
|
|
2151
|
+
function clipResult(result, format, budget) {
|
|
2152
|
+
const observation = result.observation;
|
|
2153
|
+
const layer = result.layer !== void 0 ? { layer: result.layer } : {};
|
|
2154
|
+
if (format === "compact") {
|
|
2155
|
+
const base = {
|
|
2156
|
+
obsId: observation.id,
|
|
2157
|
+
sessionId: result.sessionId,
|
|
2158
|
+
title: "",
|
|
2159
|
+
type: observation.type,
|
|
2160
|
+
score: result.score,
|
|
2161
|
+
timestamp: observation.timestamp,
|
|
2162
|
+
...layer,
|
|
2163
|
+
content_truncated: true
|
|
2164
|
+
};
|
|
2165
|
+
const minimum = estimateTokens(base);
|
|
2166
|
+
if (minimum > budget) return { minimum };
|
|
2167
|
+
return {
|
|
2168
|
+
result: fitText(observation.title, budget, (title) => ({
|
|
2169
|
+
...base,
|
|
2170
|
+
title
|
|
2171
|
+
})),
|
|
2172
|
+
minimum
|
|
2173
|
+
};
|
|
2174
|
+
}
|
|
2175
|
+
const makeResult = (title, narrative) => {
|
|
2176
|
+
if (format === "narrative") return {
|
|
2177
|
+
obsId: observation.id,
|
|
2178
|
+
sessionId: result.sessionId,
|
|
2179
|
+
title,
|
|
2180
|
+
narrative,
|
|
2181
|
+
score: result.score,
|
|
2182
|
+
timestamp: observation.timestamp,
|
|
2183
|
+
...layer,
|
|
2184
|
+
content_truncated: true
|
|
2185
|
+
};
|
|
2186
|
+
return {
|
|
2187
|
+
observation: {
|
|
2188
|
+
id: observation.id,
|
|
2189
|
+
sessionId: observation.sessionId,
|
|
2190
|
+
timestamp: observation.timestamp,
|
|
2191
|
+
type: observation.type,
|
|
2192
|
+
title,
|
|
2193
|
+
facts: [],
|
|
2194
|
+
narrative,
|
|
2195
|
+
concepts: [],
|
|
2196
|
+
files: [],
|
|
2197
|
+
importance: observation.importance,
|
|
2198
|
+
...observation.confidence !== void 0 && { confidence: observation.confidence },
|
|
2199
|
+
...observation.agentId !== void 0 && { agentId: observation.agentId },
|
|
2200
|
+
...observation.origin && { origin: {
|
|
2201
|
+
channel: observation.origin.channel,
|
|
2202
|
+
capturedAt: observation.origin.capturedAt
|
|
2203
|
+
} }
|
|
2204
|
+
},
|
|
2205
|
+
score: result.score,
|
|
2206
|
+
sessionId: result.sessionId,
|
|
2207
|
+
...layer,
|
|
2208
|
+
content_truncated: true
|
|
2209
|
+
};
|
|
2210
|
+
};
|
|
2211
|
+
const minimum = estimateTokens(makeResult("", ""));
|
|
2212
|
+
if (minimum > budget) return { minimum };
|
|
2213
|
+
const titleResult = fitText(prefix(observation.title, 120), budget, (title) => makeResult(title, ""));
|
|
2214
|
+
const title = "observation" in titleResult ? titleResult.observation.title : titleResult.title;
|
|
2215
|
+
return {
|
|
2216
|
+
result: fitText(observation.narrative || observation.facts.join("\n"), budget, (text) => makeResult(title, text)),
|
|
2217
|
+
minimum
|
|
2218
|
+
};
|
|
2219
|
+
}
|
|
2220
|
+
function buildRecallResponse(results, format, tokenBudget) {
|
|
2221
|
+
const selected = [];
|
|
2222
|
+
let used = 0;
|
|
2223
|
+
let clipped = false;
|
|
2224
|
+
let minimumBudget;
|
|
2225
|
+
for (const result of results) {
|
|
2226
|
+
const formatted = formatResult(result, format);
|
|
2227
|
+
const tokens = estimateTokens(formatted);
|
|
2228
|
+
if (tokenBudget === void 0 || used + tokens <= tokenBudget) {
|
|
2229
|
+
selected.push(formatted);
|
|
2230
|
+
used += tokens;
|
|
2231
|
+
continue;
|
|
2232
|
+
}
|
|
2233
|
+
if (selected.length === 0) {
|
|
2234
|
+
const preview = clipResult(result, format, tokenBudget);
|
|
2235
|
+
if (preview.result) {
|
|
2236
|
+
selected.push(preview.result);
|
|
2237
|
+
used = estimateTokens(preview.result);
|
|
2238
|
+
clipped = true;
|
|
2239
|
+
continue;
|
|
2240
|
+
} else minimumBudget = Math.min(preview.minimum, tokens);
|
|
2241
|
+
}
|
|
2242
|
+
break;
|
|
2243
|
+
}
|
|
2244
|
+
const excluded = results.slice(selected.length);
|
|
2245
|
+
const metadata = {
|
|
2246
|
+
tokens_used: used,
|
|
2247
|
+
tokens_budget: tokenBudget,
|
|
2248
|
+
truncated: clipped || excluded.length > 0,
|
|
2249
|
+
matched_count: results.length,
|
|
2250
|
+
excluded_by_budget: excluded.length,
|
|
2251
|
+
excluded_results: excluded.slice(0, 10).map((result) => ({
|
|
2252
|
+
obsId: result.observation.id,
|
|
2253
|
+
sessionId: result.sessionId,
|
|
2254
|
+
title: prefix(result.observation.title, 120)
|
|
2255
|
+
})),
|
|
2256
|
+
excluded_results_truncated: excluded.length > 10,
|
|
2257
|
+
...minimumBudget !== void 0 && { minimum_budget: minimumBudget }
|
|
2258
|
+
};
|
|
2259
|
+
if (format === "narrative") {
|
|
2260
|
+
const narrativeResults = selected;
|
|
2261
|
+
return {
|
|
2262
|
+
...metadata,
|
|
2263
|
+
format,
|
|
2264
|
+
results: narrativeResults,
|
|
2265
|
+
text: narrativeResults.map((result, index) => `${index + 1}. ${result.title}\n${result.narrative}`).join("\n\n")
|
|
2266
|
+
};
|
|
2267
|
+
}
|
|
2268
|
+
if (format === "compact") return {
|
|
2269
|
+
...metadata,
|
|
2270
|
+
format,
|
|
2271
|
+
results: selected
|
|
2272
|
+
};
|
|
2273
|
+
return {
|
|
2274
|
+
...metadata,
|
|
2275
|
+
format,
|
|
2276
|
+
results: selected
|
|
2277
|
+
};
|
|
2278
|
+
}
|
|
2279
|
+
//#endregion
|
|
2280
|
+
//#region src/secret-store.ts
|
|
2281
|
+
const SECRET_KEY = "AGENTMEMORY_SECRET";
|
|
2282
|
+
function agentmemoryHomeDir() {
|
|
2283
|
+
return process.env["AGENTMEMORY_DATA_DIR"] || join(homedir(), ".agentmemory");
|
|
2284
|
+
}
|
|
2285
|
+
function secretFilePath() {
|
|
2286
|
+
return join(agentmemoryHomeDir(), "secret");
|
|
2287
|
+
}
|
|
2288
|
+
function usable(value) {
|
|
2289
|
+
if (typeof value !== "string") return "";
|
|
2290
|
+
const trimmed = value.trim();
|
|
2291
|
+
if (!trimmed) return "";
|
|
2292
|
+
if (trimmed.startsWith("${") && trimmed.endsWith("}")) return "";
|
|
2293
|
+
return trimmed;
|
|
2294
|
+
}
|
|
2295
|
+
function unquote(value) {
|
|
2296
|
+
const quote = value[0];
|
|
2297
|
+
if ((quote === "\"" || quote === "'") && value.length > 1) {
|
|
2298
|
+
const close = value.indexOf(quote, 1);
|
|
2299
|
+
if (close !== -1) return value.slice(1, close);
|
|
2300
|
+
}
|
|
2301
|
+
const hash = value.indexOf(" #");
|
|
2302
|
+
return hash === -1 ? value : value.slice(0, hash).trim();
|
|
2303
|
+
}
|
|
2304
|
+
function readEnvFileSecret() {
|
|
2305
|
+
let content;
|
|
2306
|
+
try {
|
|
2307
|
+
content = readFileSync(process.env["AGENTMEMORY_ENV_FILE"] || join(homedir(), ".agentmemory", ".env"), "utf-8");
|
|
2308
|
+
} catch {
|
|
2309
|
+
return "";
|
|
2310
|
+
}
|
|
2311
|
+
if (typeof content !== "string") return "";
|
|
2312
|
+
let found = "";
|
|
2313
|
+
for (const line of content.split("\n")) {
|
|
2314
|
+
const trimmed = line.trim();
|
|
2315
|
+
if (trimmed.startsWith("#")) continue;
|
|
2316
|
+
const eq = trimmed.indexOf("=");
|
|
2317
|
+
if (eq === -1) continue;
|
|
2318
|
+
if (trimmed.slice(0, eq).replace(/^export\s+/, "").trim() !== SECRET_KEY) continue;
|
|
2319
|
+
found = usable(unquote(trimmed.slice(eq + 1).trim()));
|
|
2320
|
+
}
|
|
2321
|
+
return found;
|
|
2322
|
+
}
|
|
2323
|
+
function readSecretFile(path) {
|
|
2324
|
+
try {
|
|
2325
|
+
return usable(readFileSync(path, "utf-8"));
|
|
2326
|
+
} catch {
|
|
2327
|
+
return "";
|
|
2328
|
+
}
|
|
2329
|
+
}
|
|
2330
|
+
function legacyDataDirSecretPaths(env = process.env) {
|
|
2331
|
+
const dataDir = env["AGENTMEMORY_DATA_DIR"];
|
|
2332
|
+
if (!dataDir) return [];
|
|
2333
|
+
const paths = [
|
|
2334
|
+
join(dataDir, "secret"),
|
|
2335
|
+
join(dataDir, ".hmac"),
|
|
2336
|
+
join(dataDir, "..", ".hmac")
|
|
2337
|
+
];
|
|
2338
|
+
return [...new Set(paths.filter((path) => path !== secretFilePath()))];
|
|
2339
|
+
}
|
|
2340
|
+
function readStoredSecret(env = process.env) {
|
|
2341
|
+
const canonicalPath = canonicalSecretPath();
|
|
2342
|
+
const localPath = secretFilePath();
|
|
2343
|
+
const legacyPaths = legacyDataDirSecretPaths(env);
|
|
2344
|
+
return readSecretFile(canonicalPath) || (localPath === canonicalPath ? "" : readSecretFile(localPath)) || legacyPaths.map(readSecretFile).find(Boolean) || "";
|
|
2345
|
+
}
|
|
2346
|
+
function explicitSecret(env = process.env) {
|
|
2347
|
+
return usable(env[SECRET_KEY]) || readEnvFileSecret();
|
|
2348
|
+
}
|
|
2349
|
+
function isLoopbackUrl(url) {
|
|
2350
|
+
let hostname;
|
|
2351
|
+
try {
|
|
2352
|
+
hostname = new URL(url).hostname.toLowerCase();
|
|
2353
|
+
} catch {
|
|
2354
|
+
return false;
|
|
2355
|
+
}
|
|
2356
|
+
const bare = hostname.replace(/^\[|\]$/g, "");
|
|
2357
|
+
return bare === "localhost" || bare === "::1" || /^127(?:\.\d{1,3}){3}$/.test(bare);
|
|
2358
|
+
}
|
|
2359
|
+
function resolveClientSecret(baseUrl, env = process.env) {
|
|
2360
|
+
const fromEnv = usable(env[SECRET_KEY]);
|
|
2361
|
+
if (fromEnv) return fromEnv;
|
|
2362
|
+
if (env.AGENTMEMORY_CREDENTIAL_MODE === "explicit") return "";
|
|
2363
|
+
if (!isLoopbackUrl(baseUrl)) return "";
|
|
2364
|
+
return readEnvFileSecret() || readStoredSecret(env);
|
|
2365
|
+
}
|
|
2366
|
+
function canonicalSecretPath() {
|
|
2367
|
+
return join(homedir(), ".agentmemory", "secret");
|
|
2368
|
+
}
|
|
2369
|
+
function writeSecretFile(path, secret) {
|
|
2370
|
+
mkdirSync(join(path, ".."), {
|
|
2371
|
+
recursive: true,
|
|
2372
|
+
mode: 448
|
|
2373
|
+
});
|
|
2374
|
+
const staging = `${path}.${process.pid}.${randomBytes(4).toString("hex")}.tmp`;
|
|
2375
|
+
const fd = openSync(staging, "wx", 384);
|
|
2376
|
+
try {
|
|
2377
|
+
writeSync(fd, `${secret}\n`);
|
|
2378
|
+
} finally {
|
|
2379
|
+
closeSync(fd);
|
|
2380
|
+
}
|
|
2381
|
+
try {
|
|
2382
|
+
chmodSync(staging, 384);
|
|
2383
|
+
renameSync(staging, path);
|
|
2384
|
+
chmodSync(path, 384);
|
|
2385
|
+
} finally {
|
|
2386
|
+
try {
|
|
2387
|
+
unlinkSync(staging);
|
|
2388
|
+
} catch {}
|
|
2389
|
+
}
|
|
2390
|
+
}
|
|
2391
|
+
function writeSecretIfAbsent(path, secret) {
|
|
2392
|
+
mkdirSync(join(path, ".."), {
|
|
2393
|
+
recursive: true,
|
|
2394
|
+
mode: 448
|
|
2395
|
+
});
|
|
2396
|
+
const staging = `${path}.${process.pid}.${randomBytes(4).toString("hex")}.tmp`;
|
|
2397
|
+
const fd = openSync(staging, "wx", 384);
|
|
2398
|
+
try {
|
|
2399
|
+
writeSync(fd, `${secret}\n`);
|
|
2400
|
+
} finally {
|
|
2401
|
+
closeSync(fd);
|
|
2402
|
+
}
|
|
2403
|
+
try {
|
|
2404
|
+
chmodSync(staging, 384);
|
|
2405
|
+
linkSync(staging, path);
|
|
2406
|
+
} catch (err) {
|
|
2407
|
+
if (err.code !== "EEXIST") throw err;
|
|
2408
|
+
} finally {
|
|
2409
|
+
try {
|
|
2410
|
+
unlinkSync(staging);
|
|
2411
|
+
} catch {}
|
|
2412
|
+
}
|
|
2413
|
+
const stored = readSecretFile(path);
|
|
2414
|
+
if (!stored) throw new Error(`Could not read stored API secret at ${path}.`);
|
|
2415
|
+
return stored;
|
|
2416
|
+
}
|
|
2417
|
+
function ensureServerSecret(env = process.env) {
|
|
2418
|
+
const configured = explicitSecret(env);
|
|
2419
|
+
if (configured) return {
|
|
2420
|
+
secret: configured,
|
|
2421
|
+
source: "env"
|
|
2422
|
+
};
|
|
2423
|
+
const localPath = secretFilePath();
|
|
2424
|
+
const canonicalPath = canonicalSecretPath();
|
|
2425
|
+
const canonical = localPath === canonicalPath ? "" : readSecretFile(canonicalPath);
|
|
2426
|
+
if (canonical) {
|
|
2427
|
+
if (localPath !== canonicalPath && readSecretFile(localPath) !== canonical) writeSecretFile(localPath, canonical);
|
|
2428
|
+
return {
|
|
2429
|
+
secret: canonical,
|
|
2430
|
+
source: "file"
|
|
2431
|
+
};
|
|
2432
|
+
}
|
|
2433
|
+
const legacy = readSecretFile(localPath) || legacyDataDirSecretPaths(env).map(readSecretFile).find(Boolean) || "";
|
|
2434
|
+
const localSecret = writeSecretIfAbsent(localPath, legacy || randomBytes(32).toString("hex"));
|
|
2435
|
+
const secret = localPath === canonicalPath ? localSecret : writeSecretIfAbsent(canonicalPath, localSecret);
|
|
2436
|
+
if (localPath !== canonicalPath && localSecret !== secret) writeSecretFile(localPath, secret);
|
|
2437
|
+
return {
|
|
2438
|
+
secret,
|
|
2439
|
+
source: legacy ? "file" : "generated"
|
|
2440
|
+
};
|
|
2441
|
+
}
|
|
2442
|
+
function bearerHeaders(baseUrl, env = process.env) {
|
|
2443
|
+
const secret = resolveClientSecret(baseUrl, env);
|
|
2444
|
+
return secret ? { Authorization: `Bearer ${secret}` } : {};
|
|
2445
|
+
}
|
|
2446
|
+
//#endregion
|
|
2447
|
+
export { getVectorBucketSize as $, engineFlushWaitMs as A, getConsolidationCooldownMs as B, III_PINNED_VERSION as C, logger as D, bootWarn as E, describeLlmRoute as F, getFollowupWindowSeconds as G, getConsolidationIntervalMs as H, detectEmbeddingProvider as I, getSessionSweepStaleHours as J, getIndexSaveIntervalMs as K, detectLlmProviderKind as L, redactCredentialUrls as M, runtimeConfigPath as N, setBootVerbose as O, MAX_IMPORT_OBS_PER_SESSION as P, getVectorBackfillMax as Q, getAgentId as R, getVisibleTools as S, bootLog as T, getEnvVar as U, getConsolidationDecayDays as V, getFinalizeIdleMs as W, getStateBackend as X, getStandalonePersistPath as Y, getStateSaveIntervalMs as Z, safeAudit as _, secretFilePath as a, isDropStaleIndexEnabled as at, ESSENTIAL_TOOLS as b, memoryToObservation as c, isSessionSweepEnabled as ct, isSearchResultLayer as d, loadConfig as dt, hydrateProcessEnvFromFile as et, matchesSearchLayer as f, loadEmbeddingConfig as ft, runAuditRetentionSweep as g, parseEnvContent as gt, recordAudit as h, loadTeamConfig as ht, resolveClientSecret as i, isContextInjectionEnabled as it, engineStateConfigPaths as j, captureDurableAfterMs as k, getSearchResultLayer as l, isVectorBackfillAllEnabled as lt, queryAudit as m, loadSnapshotConfig as mt, ensureServerSecret as n, isAutoCompressEnabled as nt, buildRecallResponse as o, isGraphCompactOnBootEnabled as ot, AUDIT_MIGRATION_STATE_KEY as p, loadFallbackConfig as pt, getRedisUrl as q, explicitSecret as r, isConsolidationEnabled as rt, lessonToObservation as s, isGraphExtractionEnabled as st, bearerHeaders as t, isAgentScopeIsolated as tt, isSearchLayer as u, loadClaudeBridgeConfig as ut, setAuditRecordedListener as v, VERSION as w, getAllTools as x, startAuditMigration as y, getAuditRetentionMonths as z };
|
|
2448
|
+
|
|
2449
|
+
//# sourceMappingURL=secret-store-D9GwO0xp.mjs.map
|