@agentmemory/agentmemory 0.9.30 → 0.9.32
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.example +57 -48
- package/AGENTS.md +8 -8
- package/README.md +256 -819
- package/dist/.env.example +57 -48
- package/dist/cli.d.mts.map +1 -1
- package/dist/cli.mjs +2257 -1027
- package/dist/cli.mjs.map +1 -1
- package/dist/compression-recovery-CZh63Jmz.mjs +5997 -0
- package/dist/compression-recovery-CZh63Jmz.mjs.map +1 -0
- package/dist/{connect-B4_ca6BD.mjs → connect-BX3njQ3Y.mjs} +897 -276
- package/dist/connect-BX3njQ3Y.mjs.map +1 -0
- package/dist/hooks/_capture.d.mts +5 -1
- package/dist/hooks/_capture.d.mts.map +1 -1
- package/dist/hooks/_capture.mjs +141 -26
- package/dist/hooks/_capture.mjs.map +1 -1
- package/dist/hooks/notification.mjs +20 -6
- package/dist/hooks/notification.mjs.map +1 -1
- package/dist/hooks/post-commit.mjs +83 -10
- package/dist/hooks/post-commit.mjs.map +1 -1
- package/dist/hooks/post-tool-failure.mjs +19 -6
- package/dist/hooks/post-tool-failure.mjs.map +1 -1
- package/dist/hooks/post-tool-use.mjs +19 -6
- package/dist/hooks/post-tool-use.mjs.map +1 -1
- package/dist/hooks/pre-compact.mjs +104 -22
- package/dist/hooks/pre-compact.mjs.map +1 -1
- package/dist/hooks/pre-tool-use.mjs +83 -10
- package/dist/hooks/pre-tool-use.mjs.map +1 -1
- package/dist/hooks/prompt-submit.mjs +12 -4
- package/dist/hooks/prompt-submit.mjs.map +1 -1
- package/dist/hooks/session-end.mjs +59 -17
- package/dist/hooks/session-end.mjs.map +1 -1
- package/dist/hooks/session-start.mjs +95 -15
- package/dist/hooks/session-start.mjs.map +1 -1
- package/dist/hooks/stop.mjs +75 -72
- package/dist/hooks/stop.mjs.map +1 -1
- package/dist/hooks/subagent-start.mjs +13 -5
- package/dist/hooks/subagent-start.mjs.map +1 -1
- package/dist/hooks/subagent-stop.mjs +32 -10
- package/dist/hooks/subagent-stop.mjs.map +1 -1
- package/dist/hooks/task-completed.mjs +21 -6
- package/dist/hooks/task-completed.mjs.map +1 -1
- package/dist/{image-refs-T_urbwHM.mjs → image-refs-Cyta4Lf9.mjs} +2 -2
- package/dist/{image-refs-T_urbwHM.mjs.map → image-refs-Cyta4Lf9.mjs.map} +1 -1
- package/dist/index.mjs +16390 -11530
- package/dist/index.mjs.map +1 -1
- package/dist/integrations/dsh.d.mts +55 -0
- package/dist/integrations/dsh.d.mts.map +1 -0
- package/dist/integrations/dsh.mjs +1172 -0
- package/dist/integrations/dsh.mjs.map +1 -0
- package/dist/{keyed-mutex-DchXsyfP.mjs → keyed-mutex-DCUh7PG-.mjs} +58 -9
- package/dist/keyed-mutex-DCUh7PG-.mjs.map +1 -0
- package/dist/{secret-store-BnY3A50C.mjs → secret-store-iYXRcrO8.mjs} +717 -474
- package/dist/secret-store-iYXRcrO8.mjs.map +1 -0
- package/dist/session-arguments-zxsbbd8y.mjs +113 -0
- package/dist/session-arguments-zxsbbd8y.mjs.map +1 -0
- package/dist/{src-Jsq9LCeH.mjs → src-C23nMpda.mjs} +5263 -4667
- package/dist/src-C23nMpda.mjs.map +1 -0
- package/dist/{standalone-DKCdrf1d.mjs → standalone-BYo5USDb.mjs} +379 -63
- package/dist/standalone-BYo5USDb.mjs.map +1 -0
- package/dist/standalone.d.mts +1 -1
- package/dist/standalone.d.mts.map +1 -1
- package/dist/standalone.mjs +864 -81
- package/dist/standalone.mjs.map +1 -1
- package/dist/viewer/index.html +337 -168
- package/integrations/hermes/README.md +94 -0
- package/integrations/hermes/__init__.py +670 -0
- package/integrations/hermes/plugin.yaml +27 -0
- package/integrations/omp/LICENSE +190 -0
- package/integrations/omp/README.md +76 -0
- package/integrations/omp/capture.ts +1 -0
- package/integrations/omp/dist/index.mjs +1477 -0
- package/integrations/omp/index.ts +488 -0
- package/integrations/omp/package.json +13 -0
- package/integrations/omp/security.ts +67 -0
- package/integrations/omp/skills/agentmemory-agents/REFERENCE.md +32 -0
- package/integrations/omp/skills/agentmemory-agents/SKILL.md +48 -0
- package/integrations/omp/skills/agentmemory-agents/TROUBLESHOOTING.md +70 -0
- package/integrations/omp/skills/agentmemory-architecture/SKILL.md +37 -0
- package/integrations/omp/skills/agentmemory-architecture/TROUBLESHOOTING.md +70 -0
- package/integrations/omp/skills/agentmemory-config/REFERENCE.md +91 -0
- package/integrations/omp/skills/agentmemory-config/SKILL.md +98 -0
- package/integrations/omp/skills/agentmemory-config/TROUBLESHOOTING.md +70 -0
- package/integrations/omp/skills/agentmemory-hooks/REFERENCE.md +20 -0
- package/integrations/omp/skills/agentmemory-hooks/SKILL.md +60 -0
- package/integrations/omp/skills/agentmemory-hooks/TROUBLESHOOTING.md +70 -0
- package/integrations/omp/skills/agentmemory-mcp-tools/REFERENCE.md +66 -0
- package/integrations/omp/skills/agentmemory-mcp-tools/SKILL.md +52 -0
- package/integrations/omp/skills/agentmemory-mcp-tools/TROUBLESHOOTING.md +70 -0
- package/integrations/omp/skills/agentmemory-rest-api/REFERENCE.md +159 -0
- package/integrations/omp/skills/agentmemory-rest-api/SKILL.md +49 -0
- package/integrations/omp/skills/agentmemory-rest-api/TROUBLESHOOTING.md +70 -0
- package/integrations/omp/skills/commit-context/EXAMPLES.md +71 -0
- package/integrations/omp/skills/commit-context/SKILL.md +64 -0
- package/integrations/omp/skills/commit-context/TROUBLESHOOTING.md +70 -0
- package/integrations/omp/skills/commit-history/EXAMPLES.md +71 -0
- package/integrations/omp/skills/commit-history/SKILL.md +62 -0
- package/integrations/omp/skills/commit-history/TROUBLESHOOTING.md +70 -0
- package/integrations/omp/skills/forget/EXAMPLES.md +40 -0
- package/integrations/omp/skills/forget/SKILL.md +73 -0
- package/integrations/omp/skills/forget/TROUBLESHOOTING.md +70 -0
- package/integrations/omp/skills/handoff/EXAMPLES.md +57 -0
- package/integrations/omp/skills/handoff/SKILL.md +75 -0
- package/integrations/omp/skills/handoff/TROUBLESHOOTING.md +70 -0
- package/integrations/omp/skills/lesson/SKILL.md +64 -0
- package/integrations/omp/skills/lesson/TROUBLESHOOTING.md +70 -0
- package/integrations/omp/skills/memory-discipline/SKILL.md +65 -0
- package/integrations/omp/skills/memory-discipline/TROUBLESHOOTING.md +70 -0
- package/integrations/omp/skills/recall/EXAMPLES.md +74 -0
- package/integrations/omp/skills/recall/SKILL.md +74 -0
- package/integrations/omp/skills/recall/TROUBLESHOOTING.md +70 -0
- package/integrations/omp/skills/recap/EXAMPLES.md +62 -0
- package/integrations/omp/skills/recap/SKILL.md +68 -0
- package/integrations/omp/skills/recap/TROUBLESHOOTING.md +70 -0
- package/integrations/omp/skills/remember/EXAMPLES.md +67 -0
- package/integrations/omp/skills/remember/SKILL.md +66 -0
- package/integrations/omp/skills/remember/TROUBLESHOOTING.md +70 -0
- package/integrations/omp/skills/session-history/EXAMPLES.md +59 -0
- package/integrations/omp/skills/session-history/SKILL.md +67 -0
- package/integrations/omp/skills/session-history/TROUBLESHOOTING.md +70 -0
- package/integrations/omp/skills/write-agentmemory-skill/SKILL.md +41 -0
- package/integrations/omp/skills/write-agentmemory-skill/TROUBLESHOOTING.md +70 -0
- package/integrations/openclaw/LICENSE +190 -0
- package/integrations/openclaw/README.md +98 -0
- package/integrations/openclaw/openclaw.plugin.json +71 -0
- package/integrations/openclaw/package.json +38 -0
- package/integrations/openclaw/plugin.mjs +425 -0
- package/integrations/openclaw/plugin.yaml +26 -0
- package/integrations/openclaw/skills/agentmemory-agents/REFERENCE.md +32 -0
- package/integrations/openclaw/skills/agentmemory-agents/SKILL.md +48 -0
- package/integrations/openclaw/skills/agentmemory-agents/TROUBLESHOOTING.md +70 -0
- package/integrations/openclaw/skills/agentmemory-architecture/SKILL.md +37 -0
- package/integrations/openclaw/skills/agentmemory-architecture/TROUBLESHOOTING.md +70 -0
- package/integrations/openclaw/skills/agentmemory-config/REFERENCE.md +91 -0
- package/integrations/openclaw/skills/agentmemory-config/SKILL.md +98 -0
- package/integrations/openclaw/skills/agentmemory-config/TROUBLESHOOTING.md +70 -0
- package/integrations/openclaw/skills/agentmemory-hooks/REFERENCE.md +20 -0
- package/integrations/openclaw/skills/agentmemory-hooks/SKILL.md +60 -0
- package/integrations/openclaw/skills/agentmemory-hooks/TROUBLESHOOTING.md +70 -0
- package/integrations/openclaw/skills/agentmemory-mcp-tools/REFERENCE.md +66 -0
- package/integrations/openclaw/skills/agentmemory-mcp-tools/SKILL.md +52 -0
- package/integrations/openclaw/skills/agentmemory-mcp-tools/TROUBLESHOOTING.md +70 -0
- package/integrations/openclaw/skills/agentmemory-rest-api/REFERENCE.md +159 -0
- package/integrations/openclaw/skills/agentmemory-rest-api/SKILL.md +49 -0
- package/integrations/openclaw/skills/agentmemory-rest-api/TROUBLESHOOTING.md +70 -0
- package/integrations/openclaw/skills/commit-context/EXAMPLES.md +71 -0
- package/integrations/openclaw/skills/commit-context/SKILL.md +64 -0
- package/integrations/openclaw/skills/commit-context/TROUBLESHOOTING.md +70 -0
- package/integrations/openclaw/skills/commit-history/EXAMPLES.md +71 -0
- package/integrations/openclaw/skills/commit-history/SKILL.md +62 -0
- package/integrations/openclaw/skills/commit-history/TROUBLESHOOTING.md +70 -0
- package/integrations/openclaw/skills/forget/EXAMPLES.md +40 -0
- package/integrations/openclaw/skills/forget/SKILL.md +73 -0
- package/integrations/openclaw/skills/forget/TROUBLESHOOTING.md +70 -0
- package/integrations/openclaw/skills/handoff/EXAMPLES.md +57 -0
- package/integrations/openclaw/skills/handoff/SKILL.md +75 -0
- package/integrations/openclaw/skills/handoff/TROUBLESHOOTING.md +70 -0
- package/integrations/openclaw/skills/lesson/SKILL.md +64 -0
- package/integrations/openclaw/skills/lesson/TROUBLESHOOTING.md +70 -0
- package/integrations/openclaw/skills/memory-discipline/SKILL.md +65 -0
- package/integrations/openclaw/skills/memory-discipline/TROUBLESHOOTING.md +70 -0
- package/integrations/openclaw/skills/recall/EXAMPLES.md +74 -0
- package/integrations/openclaw/skills/recall/SKILL.md +74 -0
- package/integrations/openclaw/skills/recall/TROUBLESHOOTING.md +70 -0
- package/integrations/openclaw/skills/recap/EXAMPLES.md +62 -0
- package/integrations/openclaw/skills/recap/SKILL.md +68 -0
- package/integrations/openclaw/skills/recap/TROUBLESHOOTING.md +70 -0
- package/integrations/openclaw/skills/remember/EXAMPLES.md +67 -0
- package/integrations/openclaw/skills/remember/SKILL.md +66 -0
- package/integrations/openclaw/skills/remember/TROUBLESHOOTING.md +70 -0
- package/integrations/openclaw/skills/session-history/EXAMPLES.md +59 -0
- package/integrations/openclaw/skills/session-history/SKILL.md +67 -0
- package/integrations/openclaw/skills/session-history/TROUBLESHOOTING.md +70 -0
- package/integrations/openclaw/skills/write-agentmemory-skill/SKILL.md +41 -0
- package/integrations/openclaw/skills/write-agentmemory-skill/TROUBLESHOOTING.md +70 -0
- package/integrations/pi/LICENSE +190 -0
- package/integrations/pi/README.md +46 -51
- package/integrations/pi/dist/index.mjs +1460 -0
- package/integrations/pi/index.ts +192 -175
- package/integrations/pi/package.json +17 -7
- package/integrations/pi/security.ts +6 -26
- package/integrations/pi/skills/agentmemory-agents/REFERENCE.md +32 -0
- package/integrations/pi/skills/agentmemory-agents/SKILL.md +48 -0
- package/integrations/pi/skills/agentmemory-agents/TROUBLESHOOTING.md +70 -0
- package/integrations/pi/skills/agentmemory-architecture/SKILL.md +37 -0
- package/integrations/pi/skills/agentmemory-architecture/TROUBLESHOOTING.md +70 -0
- package/integrations/pi/skills/agentmemory-config/REFERENCE.md +91 -0
- package/integrations/pi/skills/agentmemory-config/SKILL.md +98 -0
- package/integrations/pi/skills/agentmemory-config/TROUBLESHOOTING.md +70 -0
- package/integrations/pi/skills/agentmemory-hooks/REFERENCE.md +20 -0
- package/integrations/pi/skills/agentmemory-hooks/SKILL.md +60 -0
- package/integrations/pi/skills/agentmemory-hooks/TROUBLESHOOTING.md +70 -0
- package/integrations/pi/skills/agentmemory-mcp-tools/REFERENCE.md +66 -0
- package/integrations/pi/skills/agentmemory-mcp-tools/SKILL.md +52 -0
- package/integrations/pi/skills/agentmemory-mcp-tools/TROUBLESHOOTING.md +70 -0
- package/integrations/pi/skills/agentmemory-rest-api/REFERENCE.md +159 -0
- package/integrations/pi/skills/agentmemory-rest-api/SKILL.md +49 -0
- package/integrations/pi/skills/agentmemory-rest-api/TROUBLESHOOTING.md +70 -0
- package/integrations/pi/skills/commit-context/EXAMPLES.md +71 -0
- package/integrations/pi/skills/commit-context/SKILL.md +64 -0
- package/integrations/pi/skills/commit-context/TROUBLESHOOTING.md +70 -0
- package/integrations/pi/skills/commit-history/EXAMPLES.md +71 -0
- package/integrations/pi/skills/commit-history/SKILL.md +62 -0
- package/integrations/pi/skills/commit-history/TROUBLESHOOTING.md +70 -0
- package/integrations/pi/skills/forget/EXAMPLES.md +40 -0
- package/integrations/pi/skills/forget/SKILL.md +73 -0
- package/integrations/pi/skills/forget/TROUBLESHOOTING.md +70 -0
- package/integrations/pi/skills/handoff/EXAMPLES.md +57 -0
- package/integrations/pi/skills/handoff/SKILL.md +75 -0
- package/integrations/pi/skills/handoff/TROUBLESHOOTING.md +70 -0
- package/integrations/pi/skills/lesson/SKILL.md +64 -0
- package/integrations/pi/skills/lesson/TROUBLESHOOTING.md +70 -0
- package/integrations/pi/skills/memory-discipline/SKILL.md +65 -0
- package/integrations/pi/skills/memory-discipline/TROUBLESHOOTING.md +70 -0
- package/integrations/pi/skills/recall/EXAMPLES.md +74 -0
- package/integrations/pi/skills/recall/SKILL.md +74 -0
- package/integrations/pi/skills/recall/TROUBLESHOOTING.md +70 -0
- package/integrations/pi/skills/recap/EXAMPLES.md +62 -0
- package/integrations/pi/skills/recap/SKILL.md +68 -0
- package/integrations/pi/skills/recap/TROUBLESHOOTING.md +70 -0
- package/integrations/pi/skills/remember/EXAMPLES.md +67 -0
- package/integrations/pi/skills/remember/SKILL.md +66 -0
- package/integrations/pi/skills/remember/TROUBLESHOOTING.md +70 -0
- package/integrations/pi/skills/session-history/EXAMPLES.md +59 -0
- package/integrations/pi/skills/session-history/SKILL.md +67 -0
- package/integrations/pi/skills/session-history/TROUBLESHOOTING.md +70 -0
- package/integrations/pi/skills/write-agentmemory-skill/SKILL.md +41 -0
- package/integrations/pi/skills/write-agentmemory-skill/TROUBLESHOOTING.md +70 -0
- package/package.json +33 -11
- package/plugin/.claude-plugin/plugin.json +16 -3
- package/plugin/.codex-plugin/plugin.json +4 -3
- package/plugin/.devin-plugin/plugin.json +6 -5
- package/plugin/.mcp.json +5 -1
- package/plugin/README.md +71 -0
- package/plugin/cursor/hooks.json +23 -8
- package/plugin/hooks/hooks.json +24 -12
- package/plugin/hooks.json +67 -0
- package/plugin/opencode/README.md +1 -1
- package/plugin/opencode/agentmemory-capture.ts +25 -11
- package/plugin/opencode/plugin.json +1 -1
- package/plugin/plugin.json +1 -1
- package/plugin/scripts/_capture.d.mts +5 -1
- package/plugin/scripts/_capture.d.mts.map +1 -1
- package/plugin/scripts/_capture.mjs +141 -26
- package/plugin/scripts/_capture.mjs.map +1 -1
- package/plugin/scripts/cursor/run-detached.mjs +786 -0
- package/plugin/scripts/cursor/run-detached.mjs.map +1 -0
- package/plugin/scripts/cursor/run-hook.d.mts +1 -0
- package/plugin/scripts/cursor/run-hook.mjs +704 -0
- package/plugin/scripts/cursor/run-hook.mjs.map +1 -0
- package/plugin/scripts/notification.mjs +20 -6
- package/plugin/scripts/notification.mjs.map +1 -1
- package/plugin/scripts/plugin-bridge.mjs +61 -11
- package/plugin/scripts/post-tool-failure.mjs +19 -6
- package/plugin/scripts/post-tool-failure.mjs.map +1 -1
- package/plugin/scripts/post-tool-use.mjs +19 -6
- package/plugin/scripts/post-tool-use.mjs.map +1 -1
- package/plugin/scripts/pre-compact.mjs +104 -22
- package/plugin/scripts/pre-compact.mjs.map +1 -1
- package/plugin/scripts/pre-tool-use.mjs +83 -10
- package/plugin/scripts/pre-tool-use.mjs.map +1 -1
- package/plugin/scripts/prompt-submit.mjs +12 -4
- package/plugin/scripts/prompt-submit.mjs.map +1 -1
- package/plugin/scripts/session-end.mjs +59 -17
- package/plugin/scripts/session-end.mjs.map +1 -1
- package/plugin/scripts/session-start.mjs +95 -15
- package/plugin/scripts/session-start.mjs.map +1 -1
- package/plugin/scripts/stop.mjs +75 -72
- package/plugin/scripts/stop.mjs.map +1 -1
- package/plugin/scripts/subagent-start.mjs +13 -5
- package/plugin/scripts/subagent-start.mjs.map +1 -1
- package/plugin/scripts/subagent-stop.mjs +32 -10
- package/plugin/scripts/subagent-stop.mjs.map +1 -1
- package/plugin/scripts/task-completed.mjs +21 -6
- package/plugin/scripts/task-completed.mjs.map +1 -1
- package/plugin/skills/_shared/TROUBLESHOOTING.md +21 -7
- package/plugin/skills/agentmemory-agents/REFERENCE.md +8 -7
- package/plugin/skills/agentmemory-agents/SKILL.md +19 -5
- package/plugin/skills/agentmemory-agents/TROUBLESHOOTING.md +70 -0
- package/plugin/skills/agentmemory-architecture/SKILL.md +8 -4
- package/plugin/skills/agentmemory-architecture/TROUBLESHOOTING.md +70 -0
- package/plugin/skills/agentmemory-config/REFERENCE.md +13 -15
- package/plugin/skills/agentmemory-config/SKILL.md +34 -10
- package/plugin/skills/agentmemory-config/TROUBLESHOOTING.md +70 -0
- package/plugin/skills/agentmemory-hooks/SKILL.md +31 -10
- package/plugin/skills/agentmemory-hooks/TROUBLESHOOTING.md +70 -0
- package/plugin/skills/agentmemory-mcp-tools/REFERENCE.md +5 -5
- package/plugin/skills/agentmemory-mcp-tools/SKILL.md +16 -3
- package/plugin/skills/agentmemory-mcp-tools/TROUBLESHOOTING.md +70 -0
- package/plugin/skills/agentmemory-rest-api/REFERENCE.md +10 -1
- package/plugin/skills/agentmemory-rest-api/SKILL.md +12 -6
- package/plugin/skills/agentmemory-rest-api/TROUBLESHOOTING.md +70 -0
- package/plugin/skills/commit-context/SKILL.md +1 -1
- package/plugin/skills/commit-context/TROUBLESHOOTING.md +70 -0
- package/plugin/skills/commit-history/SKILL.md +1 -1
- package/plugin/skills/commit-history/TROUBLESHOOTING.md +70 -0
- package/plugin/skills/forget/EXAMPLES.md +19 -54
- package/plugin/skills/forget/SKILL.md +16 -12
- package/plugin/skills/forget/TROUBLESHOOTING.md +70 -0
- package/plugin/skills/handoff/EXAMPLES.md +5 -4
- package/plugin/skills/handoff/SKILL.md +10 -5
- package/plugin/skills/handoff/TROUBLESHOOTING.md +70 -0
- package/plugin/skills/lesson/SKILL.md +1 -1
- package/plugin/skills/lesson/TROUBLESHOOTING.md +70 -0
- package/plugin/skills/memory-discipline/SKILL.md +1 -1
- package/plugin/skills/memory-discipline/TROUBLESHOOTING.md +70 -0
- package/plugin/skills/recall/SKILL.md +18 -7
- package/plugin/skills/recall/TROUBLESHOOTING.md +70 -0
- package/plugin/skills/recap/EXAMPLES.md +5 -3
- package/plugin/skills/recap/SKILL.md +11 -6
- package/plugin/skills/recap/TROUBLESHOOTING.md +70 -0
- package/plugin/skills/remember/EXAMPLES.md +3 -3
- package/plugin/skills/remember/SKILL.md +1 -1
- package/plugin/skills/remember/TROUBLESHOOTING.md +70 -0
- package/plugin/skills/session-history/EXAMPLES.md +2 -2
- package/plugin/skills/session-history/SKILL.md +10 -4
- package/plugin/skills/session-history/TROUBLESHOOTING.md +70 -0
- package/plugin/skills/write-agentmemory-skill/SKILL.md +2 -1
- package/plugin/skills/write-agentmemory-skill/TROUBLESHOOTING.md +70 -0
- package/dist/connect-B4_ca6BD.mjs.map +0 -1
- package/dist/docker-compose.yml +0 -73
- package/dist/iii-config.docker.yaml +0 -53
- package/dist/iii-config.yaml +0 -63
- package/dist/keyed-mutex-DchXsyfP.mjs.map +0 -1
- package/dist/secret-store-BnY3A50C.mjs.map +0 -1
- package/dist/src-Jsq9LCeH.mjs.map +0 -1
- package/dist/standalone-DKCdrf1d.mjs.map +0 -1
- package/dist/status-IRz7ta8-.mjs +0 -2344
- package/dist/status-IRz7ta8-.mjs.map +0 -1
- package/docker-compose.yml +0 -73
- package/iii-config.docker.yaml +0 -53
- package/iii-config.yaml +0 -63
- package/plugin/scripts/post-commit.mjs +0 -184
- package/plugin/scripts/post-commit.mjs.map +0 -1
- /package/plugin/scripts/{post-commit.d.mts → cursor/run-detached.d.mts} +0 -0
package/dist/viewer/index.html
CHANGED
|
@@ -1005,8 +1005,8 @@
|
|
|
1005
1005
|
.cb-open { border-color: var(--accent); color: var(--accent); }
|
|
1006
1006
|
.cb-half-open { border-color: var(--yellow); color: var(--yellow); }
|
|
1007
1007
|
|
|
1008
|
-
.worker-row { display: flex; align-items: center; gap: 8px; padding: 4px 0; font-size: 12px; font-family: var(--font-ui); }
|
|
1009
|
-
.worker-dot { width: 8px; height: 8px; }
|
|
1008
|
+
.worker-row { display: flex; align-items: center; flex-wrap: wrap; overflow-wrap: anywhere; gap: 8px; padding: 4px 0; font-size: 12px; font-family: var(--font-ui); }
|
|
1009
|
+
.worker-dot { width: 8px; height: 8px; flex-shrink: 0; background: var(--ink-faint); }
|
|
1010
1010
|
.worker-dot.running { background: var(--green); }
|
|
1011
1011
|
.worker-dot.stopped { background: var(--accent); }
|
|
1012
1012
|
.worker-dot.starting { background: var(--yellow); }
|
|
@@ -1521,28 +1521,17 @@
|
|
|
1521
1521
|
var params = new URLSearchParams(window.location.search);
|
|
1522
1522
|
var paramPort = params.get('port');
|
|
1523
1523
|
var locPort = window.location.port;
|
|
1524
|
-
var
|
|
1525
|
-
var REST, WS_URL, WS_DIRECT_URL, wsPort;
|
|
1524
|
+
var REST;
|
|
1526
1525
|
if (paramPort) {
|
|
1527
1526
|
var resolvedPort = parseInt(paramPort) === 3111 ? '3113' : paramPort;
|
|
1528
1527
|
REST = window.location.protocol + '//' + window.location.hostname + ':' + resolvedPort;
|
|
1529
|
-
wsPort = params.get('wsPort') || String(parseInt(resolvedPort) - 1);
|
|
1530
|
-
WS_URL = wsProto + '//' + window.location.hostname + ':' + wsPort;
|
|
1531
|
-
WS_DIRECT_URL = WS_URL + '/stream/mem-live/viewer';
|
|
1532
1528
|
} else if (locPort) {
|
|
1533
1529
|
var resolvedPort = parseInt(locPort) === 3111 ? '3113' : locPort;
|
|
1534
1530
|
REST = window.location.protocol + '//' + window.location.hostname + ':' + resolvedPort;
|
|
1535
|
-
wsPort = params.get('wsPort') || String(parseInt(resolvedPort) - 1);
|
|
1536
|
-
WS_URL = wsProto + '//' + window.location.hostname + ':' + wsPort;
|
|
1537
|
-
WS_DIRECT_URL = WS_URL + '/stream/mem-live/viewer';
|
|
1538
1531
|
} else {
|
|
1539
1532
|
REST = window.location.origin;
|
|
1540
|
-
wsPort = params.get('wsPort');
|
|
1541
|
-
WS_URL = wsPort
|
|
1542
|
-
? wsProto + '//' + window.location.hostname + ':' + wsPort
|
|
1543
|
-
: wsProto + '//' + window.location.host;
|
|
1544
|
-
WS_DIRECT_URL = WS_URL + '/stream/mem-live/viewer';
|
|
1545
1533
|
}
|
|
1534
|
+
var LIVE_EVENTS_URL = REST + '/agentmemory/viewer/events';
|
|
1546
1535
|
|
|
1547
1536
|
var dateEl = document.getElementById('dateline');
|
|
1548
1537
|
if (dateEl) dateEl.textContent = new Date().toLocaleDateString('en-US', { weekday: 'short', year: 'numeric', month: 'short', day: 'numeric' });
|
|
@@ -1654,12 +1643,12 @@
|
|
|
1654
1643
|
eventLoop: { term: 'Event loop delay', text: 'How far behind the worker is in handling work. Under 20 ms is healthy; a large value means it is busy or blocked.' },
|
|
1655
1644
|
uptime: { term: 'Uptime', text: 'How long the agentmemory worker has been running since it last started.' },
|
|
1656
1645
|
health: { term: 'Health status', text: 'Healthy means everything is normal. Degraded means something needs attention but memory still works. Critical means a core part is failing.' },
|
|
1657
|
-
stateBackend: { term: 'State store', text: 'Where the
|
|
1658
|
-
engineConnection: { term: 'Engine connection', text: 'Whether the agentmemory worker is connected to the iii engine that
|
|
1659
|
-
live: { term: 'Live updates', text: 'The viewer keeps one
|
|
1646
|
+
stateBackend: { term: 'State store', text: 'Where the state worker keeps every record: file (local files on this machine, the default) or redis (a Redis server set by AGENTMEMORY_STATE_BACKEND and AGENTMEMORY_REDIS_URL). ok means a test write and read just succeeded; the number is how long it took.' },
|
|
1647
|
+
engineConnection: { term: 'Engine connection', text: 'Whether the agentmemory worker is connected to the iii engine that routes calls between workers.' },
|
|
1648
|
+
live: { term: 'Live updates', text: 'The viewer keeps one SSE connection open and updates every page the moment data changes. Nothing is refreshed on a timer.' },
|
|
1660
1649
|
flags: { term: 'Feature flags', text: 'Optional features that are on or off in this install. Off features leave some pages empty; each one lists the setting that turns it on.' },
|
|
1661
1650
|
audit: { term: 'Audit log', text: 'A record of every change agentmemory made to stored data: saves, deletes, imports, consolidation runs. Use it to see who changed what and when.' },
|
|
1662
|
-
workers: { term: 'Workers', text: '
|
|
1651
|
+
workers: { term: 'Workers', text: 'Application workers provide memory, storage and HTTP. Engine details lists the coordinator and internal runtime services; available means a service is registered, not that an optional feature is enabled.' },
|
|
1663
1652
|
latency: { term: 'Average latency', text: 'Average time one call of the function took to finish.' },
|
|
1664
1653
|
failureRate: { term: 'Failure rate', text: 'Share of calls that failed. Functions that need an LLM show as off, not failing, when no LLM provider is set.' },
|
|
1665
1654
|
replay: { term: 'Replay', text: 'Plays back a past session step by step: prompts, responses and tool calls in the order they happened, with their real timing. Works for any session agentmemory recorded, from any connected agent.' },
|
|
@@ -1670,20 +1659,19 @@
|
|
|
1670
1659
|
var state = {
|
|
1671
1660
|
activeTab: 'dashboard',
|
|
1672
1661
|
dashboard: { loaded: false },
|
|
1673
|
-
graph: { loaded: false, loading: false, dirty: false, nodeMap: {}, edgeMap: {}, degrees: {}, rev: 0, localDegree: null, localDegreeRev: -1, stats: null, hidden: {}, search: '', searchOpen: false, searchIndex: 0, selectedId: null, detail: null, queryError: null, disabledInfo: null, warning: '', truncated: false, totalNodes: 0, totalEdges: 0, requestSeq: 0, fetches: 0, patches: 0, lastPatchAt: 0, fresh: {}, simStale: false, rebuildResult: '' },
|
|
1662
|
+
graph: { loaded: false, loading: false, dirty: false, nodeMap: {}, edgeMap: {}, degrees: {}, rev: 0, localDegree: null, localDegreeRev: -1, stats: null, hidden: {}, search: '', searchOpen: false, searchIndex: 0, selectedId: null, detail: null, queryError: null, disabledInfo: null, warning: '', truncated: false, totalNodes: 0, totalEdges: 0, requestSeq: 0, searchRequestSeq: 0, resetSeq: 0, generation: undefined, fetches: 0, patches: 0, lastPatchAt: 0, fresh: {}, simStale: false, rebuildResult: '' },
|
|
1674
1663
|
memories: { search: '', typeFilter: '', projectFilter: '', agentFilter: '', selectedId: null, nextCursor: null, loadingMore: false, searchIds: null, searchMode: '', searching: false, query: null, facets: null, checked: {}, editing: null, saving: false, pendingId: null, fetches: {}, diffId: null, error: '' },
|
|
1675
1664
|
sessions: { selectedId: null, autoSelected: false, closed: false, nextCursor: null, loadingMore: false, filters: { q: '', project: '', agent: '', status: '' }, query: null, facets: null, detail: null, pendingObs: null, notice: null, summarizing: '' },
|
|
1676
1665
|
audit: { opFilter: '', selectedIdx: null, from: '', to: '', q: '', query: null, loadingMore: false, exhausted: {}, fresh: {} },
|
|
1677
1666
|
activity: { loaded: false, observations: [], sessionCount: 0, typeFilter: '', fileFilter: '', day: '' },
|
|
1678
1667
|
lessons: { search: '', selectedId: null, projectFilter: '', notice: null, busy: '' },
|
|
1679
|
-
actions: { frontier: [], statusFilter: '', search: '', selectedId: null, notice: null, busy: '' },
|
|
1668
|
+
actions: { frontier: [], statusFilter: '', search: '', selectedId: null, notice: null, busy: '', detailLoading: '', detailAttemptedId: '', detailRequestFailedId: '', loadError: false },
|
|
1680
1669
|
crystals: { search: '', selectedId: null },
|
|
1681
1670
|
profile: { loaded: false, selectedProject: '', data: null, dataProject: '', userPicked: false, notice: null },
|
|
1682
|
-
health: { error: null, checking: false, consolidating: false, reveal: '' },
|
|
1671
|
+
health: { error: null, checking: false, consolidating: false, reveal: '', engineDetailsOpen: false },
|
|
1683
1672
|
replay: { loaded: false, selectedId: '', timeline: null, cursor: 0, playing: false, speed: 1, timer: null, startAt: 0, offsetAt: 0, loadingTimeline: false, loadError: '', importPath: '', importing: false, importOpen: false, importStatus: null },
|
|
1684
1673
|
flagsOpen: false,
|
|
1685
1674
|
freshRows: {},
|
|
1686
|
-
ws: null
|
|
1687
1675
|
};
|
|
1688
1676
|
|
|
1689
1677
|
var store = {
|
|
@@ -1714,7 +1702,7 @@
|
|
|
1714
1702
|
memory: { path: 'memories?latest=true&limit=100&facets=true', key: 'memories' },
|
|
1715
1703
|
session: { path: 'sessions?limit=100&facets=true', key: 'sessions' },
|
|
1716
1704
|
lesson: { path: 'lessons', key: 'lessons' },
|
|
1717
|
-
action: { path: 'actions', key: 'actions' },
|
|
1705
|
+
action: { path: 'actions', key: 'actions', allPages: true },
|
|
1718
1706
|
crystal: { path: 'crystals', key: 'crystals' },
|
|
1719
1707
|
semantic: { path: 'semantic', key: 'facts', fallbackKey: 'semantic' },
|
|
1720
1708
|
procedural: { path: 'procedural', key: 'procedures', fallbackKey: 'procedural' },
|
|
@@ -2314,6 +2302,20 @@
|
|
|
2314
2302
|
store.entities[kind] = bucket;
|
|
2315
2303
|
}
|
|
2316
2304
|
|
|
2305
|
+
async function loadAllPages(spec, apiGet) {
|
|
2306
|
+
var rows = [];
|
|
2307
|
+
var cursor = null;
|
|
2308
|
+
var result;
|
|
2309
|
+
do {
|
|
2310
|
+
var path = spec.path + '?limit=500' + (cursor ? '&cursor=' + encodeURIComponent(cursor) : '');
|
|
2311
|
+
result = await apiGet(path);
|
|
2312
|
+
if (result === null) return null;
|
|
2313
|
+
rows.push.apply(rows, listOr([], result, spec.key, spec.fallbackKey));
|
|
2314
|
+
cursor = result.nextCursor || null;
|
|
2315
|
+
} while (cursor);
|
|
2316
|
+
return Object.assign({}, result, { [spec.key]: rows });
|
|
2317
|
+
}
|
|
2318
|
+
|
|
2317
2319
|
async function ensureLoaded(kind) {
|
|
2318
2320
|
if (store.loaded[kind]) return;
|
|
2319
2321
|
if (store.loading[kind]) return store.loading[kind];
|
|
@@ -2323,8 +2325,16 @@
|
|
|
2323
2325
|
try {
|
|
2324
2326
|
await bootGate;
|
|
2325
2327
|
var seqAtStart = eventSeq;
|
|
2326
|
-
var result
|
|
2327
|
-
if (
|
|
2328
|
+
var result;
|
|
2329
|
+
if (spec.allPages) {
|
|
2330
|
+
result = await loadAllPages(spec, apiGet);
|
|
2331
|
+
} else {
|
|
2332
|
+
result = await apiGet(spec.path);
|
|
2333
|
+
}
|
|
2334
|
+
if (result === null) {
|
|
2335
|
+
if (kind === 'action') state.actions.loadError = true;
|
|
2336
|
+
return;
|
|
2337
|
+
}
|
|
2328
2338
|
replaceBucket(kind, listOr([], result, spec.key, spec.fallbackKey));
|
|
2329
2339
|
if (kind === 'memory') {
|
|
2330
2340
|
state.memories.nextCursor = result.nextCursor || null;
|
|
@@ -2343,6 +2353,9 @@
|
|
|
2343
2353
|
}
|
|
2344
2354
|
replayEventsSince(seqAtStart, kind);
|
|
2345
2355
|
store.loaded[kind] = true;
|
|
2356
|
+
if (kind === 'action') state.actions.loadError = false;
|
|
2357
|
+
} catch {
|
|
2358
|
+
if (kind === 'action') state.actions.loadError = true;
|
|
2346
2359
|
} finally {
|
|
2347
2360
|
store.loading[kind] = null;
|
|
2348
2361
|
}
|
|
@@ -2358,11 +2371,14 @@
|
|
|
2358
2371
|
});
|
|
2359
2372
|
}
|
|
2360
2373
|
|
|
2361
|
-
async function loadSnapshot() {
|
|
2374
|
+
async function loadSnapshot(retried) {
|
|
2375
|
+
var resetSeq = state.graph.resetSeq;
|
|
2362
2376
|
var snap = await apiGet('viewer/snapshot');
|
|
2377
|
+
if (resetSeq !== state.graph.resetSeq) return retried ? false : loadSnapshot(true);
|
|
2363
2378
|
if (!snap) return false;
|
|
2364
2379
|
var graphBefore = store.graph && store.graph.updatedAt;
|
|
2365
2380
|
var reconnect = !!store.snapshotAt;
|
|
2381
|
+
noteGraphGeneration(snap.graph);
|
|
2366
2382
|
applySnapshot(store, snap);
|
|
2367
2383
|
renderFlagsChip();
|
|
2368
2384
|
renderFlagsPanel();
|
|
@@ -2612,7 +2628,7 @@
|
|
|
2612
2628
|
|
|
2613
2629
|
html += renderMemoryLayers(store.consolidationStatus, entityList('semantic'), entityList('procedural'));
|
|
2614
2630
|
|
|
2615
|
-
html += '<details class="card" style="margin-top:16px;"><summary class="card-title" style="cursor:pointer;margin-bottom:0;border-bottom:none;">Function metrics
|
|
2631
|
+
html += '<details class="card" style="margin-top:16px;"><summary class="card-title" style="cursor:pointer;margin-bottom:0;border-bottom:none;">Function metrics ' + help('functionCalls') + '</summary>';
|
|
2616
2632
|
if (fMetrics.length > 0) {
|
|
2617
2633
|
var sorted = fMetrics.slice().sort(function(a, b) { return (b.totalCalls || 0) - (a.totalCalls || 0); });
|
|
2618
2634
|
html += '<div class="table-wrap" style="margin-top:10px;"><table class="metric-table"><tr><th>Function</th><th style="text-align:right">Calls</th><th style="text-align:right">Failed</th><th style="text-align:right">Avg latency ' + help('latency') + '</th></tr>';
|
|
@@ -2627,14 +2643,7 @@
|
|
|
2627
2643
|
} else {
|
|
2628
2644
|
html += '<p style="font-size:12px;color:var(--ink-muted);margin-top:10px;">No function has run since the worker started. Calls appear here as agents observe, search and save.</p>';
|
|
2629
2645
|
}
|
|
2630
|
-
|
|
2631
|
-
if (workers.length > 0) {
|
|
2632
|
-
html += '<div style="margin-top:12px;font-family:var(--font-ui);font-size:10px;letter-spacing:0.12em;text-transform:uppercase;color:var(--ink-muted);font-weight:700;">Workers ' + help('workers') + '</div>';
|
|
2633
|
-
workers.forEach(function(w) {
|
|
2634
|
-
var statusClass = w.status === 'running' ? 'running' : w.status === 'starting' ? 'starting' : 'stopped';
|
|
2635
|
-
html += '<div class="worker-row"><span class="worker-dot ' + statusClass + '"></span><span style="color:var(--ink);font-weight:600;">' + esc(w.name) + '</span><span class="badge ' + (w.status === 'running' ? 'badge-green' : 'badge-muted') + '">' + esc(w.status) + '</span></div>';
|
|
2636
|
-
});
|
|
2637
|
-
}
|
|
2646
|
+
html += '<p class="hnote"><a href="#health">Worker status and engine details →</a></p>';
|
|
2638
2647
|
html += '</details>';
|
|
2639
2648
|
|
|
2640
2649
|
setViewHtml(el, html);
|
|
@@ -2806,8 +2815,54 @@
|
|
|
2806
2815
|
return graphNodeList().filter(function(n) { return !deg[n.id]; }).length;
|
|
2807
2816
|
}
|
|
2808
2817
|
|
|
2818
|
+
function clearGraphView() {
|
|
2819
|
+
var g = state.graph;
|
|
2820
|
+
g.resetSeq++;
|
|
2821
|
+
g.requestSeq++;
|
|
2822
|
+
g.searchRequestSeq++;
|
|
2823
|
+
g.selectedId = null;
|
|
2824
|
+
g.detail = null;
|
|
2825
|
+
g.nodeMap = {};
|
|
2826
|
+
g.edgeMap = {};
|
|
2827
|
+
g.degrees = {};
|
|
2828
|
+
g.fresh = {};
|
|
2829
|
+
g.stats = null;
|
|
2830
|
+
g.totalNodes = 0;
|
|
2831
|
+
g.totalEdges = 0;
|
|
2832
|
+
g.truncated = false;
|
|
2833
|
+
g.loading = false;
|
|
2834
|
+
g.loaded = false;
|
|
2835
|
+
g.dirty = false;
|
|
2836
|
+
g.queryError = null;
|
|
2837
|
+
g.disabledInfo = null;
|
|
2838
|
+
g.warning = '';
|
|
2839
|
+
g.searchOpen = false;
|
|
2840
|
+
g.rev++;
|
|
2841
|
+
g.simStale = true;
|
|
2842
|
+
if (graphReloadTimer) clearTimeout(graphReloadTimer);
|
|
2843
|
+
graphReloadTimer = null;
|
|
2844
|
+
graphSim.hoverId = null;
|
|
2845
|
+
graphSim.drag = null;
|
|
2846
|
+
graphSim.nodes = [];
|
|
2847
|
+
graphSim.byId = {};
|
|
2848
|
+
graphSim.edges = [];
|
|
2849
|
+
graphSim.isolatedBox = null;
|
|
2850
|
+
setRouteEntity('graph', '');
|
|
2851
|
+
renderGraphDetail();
|
|
2852
|
+
requestGraphDraw();
|
|
2853
|
+
}
|
|
2854
|
+
|
|
2855
|
+
function noteGraphGeneration(data) {
|
|
2856
|
+
if (!data) return;
|
|
2857
|
+
var g = state.graph;
|
|
2858
|
+
if (data.reset === true && data.source === 'items') store.graph = null;
|
|
2859
|
+
if (data.reset === true || ('generation' in data && g.generation !== undefined && g.generation !== data.generation)) clearGraphView();
|
|
2860
|
+
if ('generation' in data) g.generation = data.generation;
|
|
2861
|
+
}
|
|
2862
|
+
|
|
2809
2863
|
function setGraphData(result) {
|
|
2810
2864
|
var g = state.graph;
|
|
2865
|
+
if (!(result.nodes || []).length && !result.truncated && !result.totalNodes && (g.selectedId || g.detail || Object.keys(g.nodeMap).length)) clearGraphView();
|
|
2811
2866
|
var nodeMap = {};
|
|
2812
2867
|
var edgeMap = {};
|
|
2813
2868
|
(result.nodes || []).forEach(function(n) { if (n && n.id) nodeMap[n.id] = n; });
|
|
@@ -2841,6 +2896,7 @@
|
|
|
2841
2896
|
g.loading = false;
|
|
2842
2897
|
if (result === null) {
|
|
2843
2898
|
var stats = await api('graph/stats', { readErrorBody: true });
|
|
2899
|
+
if (seq !== g.requestSeq) return;
|
|
2844
2900
|
if (stats && stats.error && stats.flag) {
|
|
2845
2901
|
g.disabledInfo = stats;
|
|
2846
2902
|
g.queryError = null;
|
|
@@ -2865,8 +2921,9 @@
|
|
|
2865
2921
|
|
|
2866
2922
|
function applyGraphDelta(delta) {
|
|
2867
2923
|
var g = state.graph;
|
|
2868
|
-
if (!g.loaded
|
|
2924
|
+
if (!delta || (!g.loaded && !delta.full)) return false;
|
|
2869
2925
|
if (delta.full) {
|
|
2926
|
+
if (!(delta.nodes || []).length && (g.selectedId || g.detail || Object.keys(g.nodeMap).length)) clearGraphView();
|
|
2870
2927
|
var keepNodes = {};
|
|
2871
2928
|
(delta.nodes || []).forEach(function(n) { keepNodes[n.id] = true; });
|
|
2872
2929
|
Object.keys(g.nodeMap).forEach(function(id) { if (!keepNodes[id] && id !== g.selectedId) delete g.nodeMap[id]; });
|
|
@@ -2893,13 +2950,14 @@
|
|
|
2893
2950
|
g.lastPatchAt = Date.now();
|
|
2894
2951
|
Object.keys(touched).forEach(function(id) { g.fresh[id] = Date.now(); });
|
|
2895
2952
|
if (g.selectedId && touched[g.selectedId] && g.detail && g.detail.id === g.selectedId) g.detail.stale = true;
|
|
2953
|
+
g.loaded = true;
|
|
2896
2954
|
return true;
|
|
2897
2955
|
}
|
|
2898
2956
|
|
|
2899
2957
|
function handleGraphChange(data) {
|
|
2900
2958
|
var g = state.graph;
|
|
2901
2959
|
if (!data) return;
|
|
2902
|
-
|
|
2960
|
+
noteGraphGeneration(data);
|
|
2903
2961
|
if (data.source === 'snapshot') {
|
|
2904
2962
|
if (data.delta && applyGraphDelta(data.delta)) {
|
|
2905
2963
|
if (graphSim.canvas && state.activeTab === 'graph') { syncGraphSim(false); requestGraphDraw(); setTimeout(requestGraphDraw, 4200); }
|
|
@@ -2925,10 +2983,10 @@
|
|
|
2925
2983
|
|
|
2926
2984
|
async function fetchGraphDetail(id) {
|
|
2927
2985
|
var g = state.graph;
|
|
2928
|
-
g.detail = { id: id, loading: true, data: null, error: '', stale: false };
|
|
2986
|
+
var detail = g.detail = { id: id, loading: true, data: null, error: '', stale: false };
|
|
2929
2987
|
renderGraphDetail();
|
|
2930
2988
|
var res = await api('graph/node?id=' + encodeURIComponent(id), { readErrorBody: true });
|
|
2931
|
-
if (
|
|
2989
|
+
if (g.detail !== detail) return;
|
|
2932
2990
|
if (!res || res.error) {
|
|
2933
2991
|
g.detail = { id: id, loading: false, data: null, error: res && res.error ? res.error : 'request failed', stale: false };
|
|
2934
2992
|
} else {
|
|
@@ -3584,7 +3642,7 @@
|
|
|
3584
3642
|
title: 'The knowledge graph is off',
|
|
3585
3643
|
what: 'Entities and relations agentmemory pulls out of what agents do.',
|
|
3586
3644
|
why: esc(g.disabledInfo.enableHow || 'Graph extraction is disabled on this server.'),
|
|
3587
|
-
steps: [{ label: 'Turn it on and restart:', cmd: 'export GRAPH_EXTRACTION_ENABLED=true\nexport ANTHROPIC_API_KEY=sk-ant-...\nnpx @agentmemory/agentmemory' }],
|
|
3645
|
+
steps: [{ label: 'Turn it on and restart:', cmd: 'export GRAPH_EXTRACTION_ENABLED=true\nexport AGENTMEMORY_LLM_PROVIDER=anthropic\nexport ANTHROPIC_API_KEY=sk-ant-...\nnpx @agentmemory/agentmemory' }],
|
|
3588
3646
|
link: g.disabledInfo.docsHref ? { href: g.disabledInfo.docsHref, text: 'Knowledge graph docs' } : null
|
|
3589
3647
|
});
|
|
3590
3648
|
} else if (g.queryError) {
|
|
@@ -3604,7 +3662,7 @@
|
|
|
3604
3662
|
steps: [
|
|
3605
3663
|
{ label: 'Build it now from every stored observation (spends LLM tokens when extraction is on):', cmd: curlPost('graph/build', {}) },
|
|
3606
3664
|
{ label: 'Or import a structural code graph made by graphify (no LLM needed):', cmd: curlPost('graph/import-graphify', { cwd: '/path/to/repo' }) },
|
|
3607
|
-
{ label: 'For typed entities and relations, turn on LLM extraction and restart:', cmd: 'export GRAPH_EXTRACTION_ENABLED=true\nexport ANTHROPIC_API_KEY=sk-ant-...' }
|
|
3665
|
+
{ label: 'For typed entities and relations, turn on LLM extraction and restart:', cmd: 'export GRAPH_EXTRACTION_ENABLED=true\nexport AGENTMEMORY_LLM_PROVIDER=anthropic\nexport ANTHROPIC_API_KEY=sk-ant-...' }
|
|
3608
3666
|
]
|
|
3609
3667
|
}) + '<div class="graph-msg-actions"><button type="button" class="btn btn-primary" data-action="rebuild-graph">Build from observations</button></div>';
|
|
3610
3668
|
}
|
|
@@ -3671,7 +3729,7 @@
|
|
|
3671
3729
|
html += copyBtn('memory_graph_query { "startNodeId": ' + JSON.stringify(id) + ', "maxDepth": 1 }', 'MCP call').replace('>copy<', '>copy MCP call<');
|
|
3672
3730
|
html += copyBtn(curlGet('graph/node?id=' + encodeURIComponent(id)), 'curl command').replace('>copy<', '>copy curl<');
|
|
3673
3731
|
html += '</div>';
|
|
3674
|
-
if (d && d.stale) html += '<div class="mem-note">This node changed on the
|
|
3732
|
+
if (d && d.stale) html += '<div class="mem-note">This node changed on the SSE feed. <button type="button" class="linkish" data-action="graph-refresh-detail" data-node-id="' + esc(id) + '">Reload sources</button></div>';
|
|
3675
3733
|
|
|
3676
3734
|
var rels = graphDetailRelations(id);
|
|
3677
3735
|
var relTotal = data && typeof data.relationsTotal === 'number' ? Math.max(data.relationsTotal, rels.length) : rels.length;
|
|
@@ -3761,7 +3819,7 @@
|
|
|
3761
3819
|
html += '<div class="go-intro"><strong>Knowledge graph</strong> ' + help('graph') + ' The files, functions, concepts and decisions agents worked with, and how they relate. Click a node to see its relations and the observations it came from.</div>';
|
|
3762
3820
|
html += '<div class="go-stats"><div><b>' + fmtNum(t.nodes) + '</b><span>nodes ' + help('graphNode') + '</span></div><div><b>' + fmtNum(t.edges) + '</b><span>relations ' + help('graphEdge') + '</span></div><div><b>' + fmtNum(iso) + '</b><span>unlinked ' + help('graphIsolated') + '</span></div></div>';
|
|
3763
3821
|
if (shown >= 3 && (iso / shown > 0.4 || t.edges < shown / 2)) {
|
|
3764
|
-
html += '<div class="mem-note go-sparse"><b>Sparse graph.</b> ' + fmtNum(iso) + ' of ' + fmtNum(shown) + ' nodes have no relations yet. ' + esc(graphLlmNote()) + (graphLlmMode() !== 'llm' ? cmdBlock('export GRAPH_EXTRACTION_ENABLED=true\nexport ANTHROPIC_API_KEY=sk-ant-...') : '') + '</div>';
|
|
3822
|
+
html += '<div class="mem-note go-sparse"><b>Sparse graph.</b> ' + fmtNum(iso) + ' of ' + fmtNum(shown) + ' nodes have no relations yet. ' + esc(graphLlmNote()) + (graphLlmMode() !== 'llm' ? cmdBlock('export GRAPH_EXTRACTION_ENABLED=true\nexport AGENTMEMORY_LLM_PROVIDER=anthropic\nexport ANTHROPIC_API_KEY=sk-ant-...') : '') + '</div>';
|
|
3765
3823
|
}
|
|
3766
3824
|
if (g.truncated && shown < t.nodes) html += '<div class="mem-note">Showing the ' + fmtNum(shown) + ' most connected of ' + fmtNum(t.nodes) + ' nodes. Search finds the rest on the server.</div>';
|
|
3767
3825
|
if (g.warning) html += '<div class="mem-note">' + esc(g.warning) + '</div>';
|
|
@@ -3796,7 +3854,7 @@
|
|
|
3796
3854
|
html += '<div class="empty-step-label" style="margin-top:8px;">Query it from an agent:</div>' + cmdBlock('memory_graph_query { "query": "checkout" }');
|
|
3797
3855
|
html += '</div>';
|
|
3798
3856
|
if (g.rebuildResult) html += '<div class="mem-note">' + esc(g.rebuildResult) + '</div>';
|
|
3799
|
-
html += '<div class="go-live">' + (g.patches ? 'Patched ' + fmtNum(g.patches) + ' time' + (g.patches === 1 ? '' : 's') + ' from the
|
|
3857
|
+
html += '<div class="go-live">' + (g.patches ? 'Patched ' + fmtNum(g.patches) + ' time' + (g.patches === 1 ? '' : 's') + ' from the SSE feed, last ' + relTime(new Date(g.lastPatchAt).toISOString()) + '.' : 'Updates arrive on the SSE feed; nothing refreshes on a timer.') + ' ' + help('live') + '</div>';
|
|
3800
3858
|
html += '</div>';
|
|
3801
3859
|
setViewHtml(host, html);
|
|
3802
3860
|
}
|
|
@@ -4021,9 +4079,11 @@
|
|
|
4021
4079
|
|
|
4022
4080
|
async function searchGraphRemote(q) {
|
|
4023
4081
|
var g = state.graph;
|
|
4082
|
+
var seq = ++g.searchRequestSeq;
|
|
4024
4083
|
var box = document.getElementById('graph-search-results');
|
|
4025
4084
|
if (box) { box.hidden = false; box.innerHTML = '<div class="gs-empty">Searching all nodes…</div>'; }
|
|
4026
4085
|
var res = await apiPost('graph/query', { query: q, limit: 50 });
|
|
4086
|
+
if (seq !== g.searchRequestSeq) return;
|
|
4027
4087
|
if (!res) {
|
|
4028
4088
|
if (box) box.innerHTML = '<div class="gs-empty">The server search failed.</div>';
|
|
4029
4089
|
return;
|
|
@@ -4097,7 +4157,7 @@
|
|
|
4097
4157
|
try {
|
|
4098
4158
|
var result = await apiPost('graph/build', {});
|
|
4099
4159
|
g.rebuildResult = result && result.success
|
|
4100
|
-
? 'Rebuilt from ' + (result.sessions || 0) + ' sessions: ' + (result.nodes || 0) + ' nodes and ' + (result.edges || 0) + ' relations extracted. New ones arrive on the
|
|
4160
|
+
? 'Rebuilt from ' + (result.sessions || 0) + ' sessions: ' + (result.nodes || 0) + ' nodes and ' + (result.edges || 0) + ' relations extracted. New ones arrive on the SSE feed.'
|
|
4101
4161
|
: 'The rebuild failed. Check the server log.';
|
|
4102
4162
|
} finally {
|
|
4103
4163
|
graphRebuilding = false;
|
|
@@ -4505,7 +4565,7 @@
|
|
|
4505
4565
|
var mem = store.entities.memory[id];
|
|
4506
4566
|
if (!mem) {
|
|
4507
4567
|
if (m.pendingId === id) {
|
|
4508
|
-
setViewHtml(panel, '<div class="detail-panel mem-detail"><div class="mem-detail-head"><span>Saving the new version</span>' + memoryCloseBtn() + '</div><div class="mem-note">Saved. Waiting for the new version to arrive on the
|
|
4568
|
+
setViewHtml(panel, '<div class="detail-panel mem-detail"><div class="mem-detail-head"><span>Saving the new version</span>' + memoryCloseBtn() + '</div><div class="mem-note">Saved. Waiting for the new version to arrive on the SSE feed…</div>' + skeleton(4) + '</div>');
|
|
4509
4569
|
return;
|
|
4510
4570
|
}
|
|
4511
4571
|
if (!m.fetches[id]) fetchMemoryVersion(id);
|
|
@@ -6144,7 +6204,7 @@
|
|
|
6144
6204
|
var body = '<h3>Summarize this session?</h3>' +
|
|
6145
6205
|
'<p>An LLM reads the observations of <b>' + esc(sessionDisplayName(s)) + '</b> (' + fmtNum(s.observationCount || 0) + ') and writes a short summary: a title, what happened and the key decisions. The summary is shown here and in the session list, and later feeds consolidation into facts and procedures. Running it again replaces the old summary.</p>';
|
|
6146
6206
|
if (!llm) {
|
|
6147
|
-
body += '<div class="mem-note err">No LLM provider is configured, so Summarize would do nothing. Set a key and restart agentmemory:</div>' + cmdBlock('export ANTHROPIC_API_KEY=sk-ant-...\nnpx @agentmemory/agentmemory');
|
|
6207
|
+
body += '<div class="mem-note err">No LLM provider is configured, so Summarize would do nothing. Set a key and restart agentmemory:</div>' + cmdBlock('export AGENTMEMORY_LLM_PROVIDER=anthropic\nexport ANTHROPIC_API_KEY=sk-ant-...\nnpx @agentmemory/agentmemory');
|
|
6148
6208
|
body += '<div class="modal-actions" style="margin-top:14px;"><button class="btn" data-action="close-modal">Close</button></div>';
|
|
6149
6209
|
} else {
|
|
6150
6210
|
body += '<p style="font-size:11px;">Same call from a terminal: <code>' + esc(curlPost('summarize', { sessionId: id }).replace(/\s*\\\n\s*/g, ' ')) + '</code></p>';
|
|
@@ -6404,7 +6464,7 @@
|
|
|
6404
6464
|
var res = await apiPost('lessons/strengthen', { lessonId: id });
|
|
6405
6465
|
l.busy = '';
|
|
6406
6466
|
l.notice = res && res.success !== false
|
|
6407
|
-
? { id: id, html: 'Recorded one more use. Confidence and uses update here from the
|
|
6467
|
+
? { id: id, html: 'Recorded one more use. Confidence and uses update here from the SSE feed.' }
|
|
6408
6468
|
: { id: id, err: true, html: 'Strengthen failed' + (res && res.error ? ': ' + esc(res.error) : '. Check that agentmemory is running.') };
|
|
6409
6469
|
renderLessons();
|
|
6410
6470
|
}
|
|
@@ -6497,12 +6557,15 @@
|
|
|
6497
6557
|
function renderActions() {
|
|
6498
6558
|
var el = document.getElementById('view-actions');
|
|
6499
6559
|
var a = state.actions;
|
|
6500
|
-
|
|
6560
|
+
var all = entityList('action');
|
|
6561
|
+
if (!store.loaded.action && !all.length) {
|
|
6501
6562
|
listDetailShell(el, 'actions', '');
|
|
6502
|
-
setViewHtml(document.getElementById('actions-list'),
|
|
6563
|
+
setViewHtml(document.getElementById('actions-list'), a.loadError
|
|
6564
|
+
? '<div class="empty-state compact"><div class="empty-title">Could not load actions</div><div class="empty-what">Check that agentmemory is running, then try again.</div><button type="button" class="btn" data-action="action-list-retry">Retry</button></div>'
|
|
6565
|
+
: skeleton(8));
|
|
6566
|
+
renderActionDetail({});
|
|
6503
6567
|
return;
|
|
6504
6568
|
}
|
|
6505
|
-
var all = entityList('action');
|
|
6506
6569
|
var rows = actionRows();
|
|
6507
6570
|
var frontierIds = {};
|
|
6508
6571
|
(a.frontier || []).forEach(function(f) {
|
|
@@ -6560,24 +6623,82 @@
|
|
|
6560
6623
|
html += '</tbody></table></div>';
|
|
6561
6624
|
if (all.length < 8) html += usageCard('action');
|
|
6562
6625
|
}
|
|
6626
|
+
if (a.loadError) {
|
|
6627
|
+
html = '<div class="inline-note"><strong>Could not refresh actions.</strong> Showing previously loaded actions. <button type="button" class="btn" data-action="action-list-retry">Retry</button></div>' + html;
|
|
6628
|
+
}
|
|
6563
6629
|
setViewHtml(document.getElementById('actions-list'), html);
|
|
6630
|
+
renderActionDetail(frontierIds);
|
|
6631
|
+
}
|
|
6632
|
+
|
|
6633
|
+
function renderActionDetail(frontierIds) {
|
|
6634
|
+
var a = state.actions;
|
|
6564
6635
|
var detail = document.getElementById('actions-detail');
|
|
6565
6636
|
var sel = a.selectedId ? store.entities.action[a.selectedId] : null;
|
|
6566
6637
|
if (a.selectedId && !sel) {
|
|
6567
|
-
|
|
6638
|
+
ensureActionById(a.selectedId);
|
|
6639
|
+
var loadingAction = a.detailLoading === a.selectedId;
|
|
6640
|
+
var actionBody = loadingAction ? '<div class="empty-state compact"><div class="empty-title">Loading action…</div></div>' : a.detailRequestFailedId === a.selectedId
|
|
6641
|
+
? '<div class="empty-state compact"><div class="empty-title">Could not load action</div><div class="empty-what">Check that agentmemory is running, then try again.</div><button type="button" class="btn" data-action="action-retry">Retry</button></div>'
|
|
6642
|
+
: emptyState({
|
|
6568
6643
|
compact: true,
|
|
6569
6644
|
icon: '🔍',
|
|
6570
6645
|
title: 'Action not found',
|
|
6571
6646
|
what: 'Action links anywhere in the viewer open this panel by id.',
|
|
6572
6647
|
why: 'No action has the id <code>' + esc(a.selectedId) + '</code>. It was removed, or the link comes from another install.',
|
|
6573
6648
|
steps: [{ label: 'Check from a terminal:', cmd: curlGet('actions/get?actionId=' + encodeURIComponent(a.selectedId)) }]
|
|
6574
|
-
})
|
|
6649
|
+
});
|
|
6650
|
+
setViewHtml(detail, '<div id="action-detail" class="detail-panel mem-detail"><div class="mem-detail-head"><span>Action</span><button type="button" class="icon-btn icon-close" data-action="action-close" aria-label="Close action details">close</button></div>' + actionBody + '</div>');
|
|
6575
6651
|
} else {
|
|
6576
6652
|
setViewHtml(detail, sel ? actionDetailHtml(sel, !!frontierIds[sel.id]) : '');
|
|
6577
6653
|
}
|
|
6578
6654
|
document.getElementById('actions-layout').classList.toggle('has-detail', !!detail.firstElementChild);
|
|
6579
6655
|
}
|
|
6580
6656
|
|
|
6657
|
+
async function ensureActionById(id) {
|
|
6658
|
+
var a = state.actions;
|
|
6659
|
+
if (!id || store.entities.action[id] || a.detailLoading === id || a.detailAttemptedId === id) return;
|
|
6660
|
+
a.detailAttemptedId = id;
|
|
6661
|
+
a.detailLoading = id;
|
|
6662
|
+
try {
|
|
6663
|
+
var result = await apiGet('actions/get?actionId=' + encodeURIComponent(id));
|
|
6664
|
+
if (result && result.success && result.action && result.action.id) {
|
|
6665
|
+
store.entities.action[result.action.id] = result.action;
|
|
6666
|
+
a.detailRequestFailedId = '';
|
|
6667
|
+
renderActions();
|
|
6668
|
+
} else if (result === null) {
|
|
6669
|
+
a.detailRequestFailedId = id;
|
|
6670
|
+
}
|
|
6671
|
+
} catch (_) {
|
|
6672
|
+
a.detailRequestFailedId = id;
|
|
6673
|
+
} finally {
|
|
6674
|
+
if (a.detailLoading === id) {
|
|
6675
|
+
a.detailLoading = '';
|
|
6676
|
+
if (!store.entities.action[id]) renderActions();
|
|
6677
|
+
}
|
|
6678
|
+
}
|
|
6679
|
+
}
|
|
6680
|
+
|
|
6681
|
+
function retryActionById(id) {
|
|
6682
|
+
var a = state.actions;
|
|
6683
|
+
if (a.detailLoading === id) return;
|
|
6684
|
+
a.detailAttemptedId = '';
|
|
6685
|
+
a.detailRequestFailedId = '';
|
|
6686
|
+
return ensureActionById(id);
|
|
6687
|
+
}
|
|
6688
|
+
|
|
6689
|
+
async function retryActionList() {
|
|
6690
|
+
if (store.loading.action) return store.loading.action;
|
|
6691
|
+
state.actions.loadError = false;
|
|
6692
|
+
store.loaded.action = false;
|
|
6693
|
+
renderActions();
|
|
6694
|
+
await ensureLoaded('action');
|
|
6695
|
+
if (state.actions.selectedId && !store.entities.action[state.actions.selectedId]) {
|
|
6696
|
+
state.actions.detailAttemptedId = '';
|
|
6697
|
+
state.actions.detailRequestFailedId = '';
|
|
6698
|
+
}
|
|
6699
|
+
renderActions();
|
|
6700
|
+
}
|
|
6701
|
+
|
|
6581
6702
|
async function setActionStatus(id, status) {
|
|
6582
6703
|
var a = state.actions;
|
|
6583
6704
|
a.busy = id;
|
|
@@ -6585,7 +6706,7 @@
|
|
|
6585
6706
|
var res = await apiPost('actions/update', { actionId: id, status: status });
|
|
6586
6707
|
a.busy = '';
|
|
6587
6708
|
a.notice = res && res.success !== false
|
|
6588
|
-
? { id: id, html: 'Status set to <b>' + esc(status) + '</b>. Ready markers update from the
|
|
6709
|
+
? { id: id, html: 'Status set to <b>' + esc(status) + '</b>. Ready markers update from the SSE feed.' }
|
|
6589
6710
|
: { id: id, err: true, html: 'Update failed' + (res && res.error ? ': ' + esc(res.error) : '. Check that agentmemory is running.') };
|
|
6590
6711
|
renderActions();
|
|
6591
6712
|
}
|
|
@@ -6615,7 +6736,7 @@
|
|
|
6615
6736
|
{ label: 'Crystallize every finished action now:', cmd: curlPost('crystals/auto', {}) },
|
|
6616
6737
|
{ label: 'Or from an agent, for specific actions:', cmd: 'memory_crystallize { "actionIds": ["act_..."] }' }
|
|
6617
6738
|
] : [
|
|
6618
|
-
{ label: 'Set an LLM key and restart agentmemory:', cmd: 'export ANTHROPIC_API_KEY=sk-ant-...\nnpx @agentmemory/agentmemory' },
|
|
6739
|
+
{ label: 'Set an LLM key and restart agentmemory:', cmd: 'export AGENTMEMORY_LLM_PROVIDER=anthropic\nexport ANTHROPIC_API_KEY=sk-ant-...\nnpx @agentmemory/agentmemory' },
|
|
6619
6740
|
{ label: 'Then crystallize finished actions:', cmd: curlPost('crystals/auto', {}) }
|
|
6620
6741
|
],
|
|
6621
6742
|
link: { href: 'https://github.com/rohitg00/agentmemory#crystals', text: 'How crystals are built' }
|
|
@@ -6679,6 +6800,8 @@
|
|
|
6679
6800
|
return true;
|
|
6680
6801
|
}
|
|
6681
6802
|
if (action === 'action-close') { state.actions.selectedId = null; setRouteEntity('actions', ''); renderActions(); return true; }
|
|
6803
|
+
if (action === 'action-retry') { retryActionById(state.actions.selectedId); return true; }
|
|
6804
|
+
if (action === 'action-list-retry') { retryActionList(); return true; }
|
|
6682
6805
|
if (action === 'action-set-status') { setActionStatus(target.getAttribute('data-action-id'), target.getAttribute('data-status')); return true; }
|
|
6683
6806
|
if (action === 'action-clear-filters') { state.actions.search = ''; state.actions.statusFilter = ''; var ai = document.getElementById('actions-search'); if (ai) ai.value = ''; renderActions(); return true; }
|
|
6684
6807
|
if (action === 'activity-type' || action === 'activity-file' || action === 'activity-day' || action === 'activity-clear') { handleActivityAction(action, target); return true; }
|
|
@@ -7051,7 +7174,7 @@
|
|
|
7051
7174
|
}
|
|
7052
7175
|
|
|
7053
7176
|
var BM25_EXPLAINER = 'The keyword index holds observations, memories and lessons, so its total is larger than the observation count.';
|
|
7054
|
-
var LLM_KEY_FIX = '
|
|
7177
|
+
var LLM_KEY_FIX = 'Set AGENTMEMORY_LLM_PROVIDER and that provider\'s key (for example AGENTMEMORY_LLM_PROVIDER=anthropic and ANTHROPIC_API_KEY) in ~/.agentmemory/.env and restart.';
|
|
7055
7178
|
|
|
7056
7179
|
function hrow(label, valueHtml, helpKey, note) {
|
|
7057
7180
|
return '<div class="detail-row"><div class="dl">' + esc(label) + (helpKey ? ' ' + help(helpKey) : '') + '</div><div class="dv">' + valueHtml + (note ? '<div class="hnote">' + note + '</div>' : '') + '</div></div>';
|
|
@@ -7079,7 +7202,7 @@
|
|
|
7079
7202
|
}
|
|
7080
7203
|
if (store.lastHealthAt && Date.now() - store.lastHealthAt > HEALTH_STALE_MS) {
|
|
7081
7204
|
var secs = Math.round((Date.now() - store.lastHealthAt) / 1000);
|
|
7082
|
-
return '<div class="hstale" id="health-live-state"><strong>Stale: no health report for ' + secs + 's.</strong> Reports normally arrive every 30 seconds. The
|
|
7205
|
+
return '<div class="hstale" id="health-live-state"><strong>Stale: no health report for ' + secs + 's.</strong> Reports normally arrive every 30 seconds. The SSE feed is connected, but the worker may be busy or unable to publish a health report. The numbers below are from ' + esc(last) + '.' +
|
|
7083
7206
|
'<div style="margin-top:6px;">Fix: wait a minute; if it stays stale, press Re-check now for the full report, check the server log and restart agentmemory.</div></div>';
|
|
7084
7207
|
}
|
|
7085
7208
|
return '';
|
|
@@ -7105,7 +7228,7 @@
|
|
|
7105
7228
|
}
|
|
7106
7229
|
html += '<div class="verdict"><span class="verdict-badge ' + esc(level) + '">' + esc(badgeText) + '</span><div style="min-width:0;flex:1;">' +
|
|
7107
7230
|
'<div class="verdict-text">' + esc(text) + '</div>' +
|
|
7108
|
-
'<div class="verdict-meta">' + (r ? 'Report ' + relTime(r.checkedAt) + ' · ' : '') + 'updates every 30 s over
|
|
7231
|
+
'<div class="verdict-meta">' + (r ? 'Report ' + relTime(r.checkedAt) + ' · ' : '') + 'updates every 30 s over SSE, no refresh needed ' + help('live') + '</div></div></div>';
|
|
7109
7232
|
html += healthStaleHtml(r);
|
|
7110
7233
|
if (state.health.error) html += '<div class="mem-note err" style="margin-top:10px;">' + esc(state.health.error) + '</div>';
|
|
7111
7234
|
if (r && r.problems.length) {
|
|
@@ -7120,20 +7243,45 @@
|
|
|
7120
7243
|
return html + '</div>';
|
|
7121
7244
|
}
|
|
7122
7245
|
|
|
7246
|
+
function workerRowHtml(w) {
|
|
7247
|
+
var status = w.status || 'unknown';
|
|
7248
|
+
var statusClass = status === 'running' || status === 'connected' ? 'running' :
|
|
7249
|
+
status === 'starting' || status === 'reconnecting' ? 'starting' :
|
|
7250
|
+
['stopped', 'disconnected', 'failed', 'error'].indexOf(status) !== -1 ? 'stopped' : 'unknown';
|
|
7251
|
+
var badge = statusClass === 'running' ? 'badge-green' : statusClass === 'starting' ? 'badge-yellow' : statusClass === 'stopped' ? 'badge-red' : 'badge-muted';
|
|
7252
|
+
return '<div class="worker-row"><span class="worker-dot ' + statusClass + '" aria-hidden="true"></span><strong>' + esc(w.name || w.id || 'Unnamed worker') + '</strong><span class="badge ' + badge + '">' + esc(status) + '</span></div>';
|
|
7253
|
+
}
|
|
7254
|
+
|
|
7255
|
+
function workersHtml(workers, expanded) {
|
|
7256
|
+
if (!workers || !workers.length) return '';
|
|
7257
|
+
var application = [], internal = [];
|
|
7258
|
+
workers.forEach(function(w) {
|
|
7259
|
+
var engine = w.runtime === 'engine' || w.isolation === 'in-process' || w.name === 'compose';
|
|
7260
|
+
(engine ? internal : application).push(w);
|
|
7261
|
+
});
|
|
7262
|
+
var html = '<div style="margin-top:16px;"><div class="card-title">Workers ' + help('workers') + '</div>';
|
|
7263
|
+
html += application.map(workerRowHtml).join('');
|
|
7264
|
+
if (internal.length) {
|
|
7265
|
+
html += '<details id="health-engine-details"' + (expanded ? ' open' : '') + ' style="margin-top:12px;"><summary style="cursor:pointer;">Engine details (' + internal.length + ')</summary>' +
|
|
7266
|
+
'<p class="hnote">Runtime coordination and internal services. Available means registered; it does not indicate whether an optional feature such as telemetry is enabled.</p>' +
|
|
7267
|
+
internal.map(workerRowHtml).join('') + '</details>';
|
|
7268
|
+
}
|
|
7269
|
+
return html + '</div>';
|
|
7270
|
+
}
|
|
7271
|
+
|
|
7123
7272
|
function engineCardHtml(r, snap) {
|
|
7124
7273
|
var ports = (r && r.service && r.service.ports) || {};
|
|
7125
7274
|
var kv = snap.kvConnectivity;
|
|
7126
7275
|
var backend = r && r.service ? r.service.stateBackend : null;
|
|
7127
7276
|
var streamText = conn.state === 'live' ? 'live' : conn.state;
|
|
7128
7277
|
return '<div class="card"><div class="card-title">Engine and connection ' + help('engineConnection') + '</div>' +
|
|
7129
|
-
hrow('Engine connection', esc(snap.connectionState || 'unknown'), 'engineConnection', 'The worker\'s link to the iii engine, which
|
|
7130
|
-
((kv || backend) ? hrow('State store', esc((backend ? backend + (kv ? ' · ' : '') : '') + (kv ? kv.status + (kv.latencyMs !== undefined ? ' · ' + kv.latencyMs + ' ms' : '') + (kv.error ? ' · ' + kv.error : '') : '')), 'stateBackend', backend === 'redis' ? '
|
|
7131
|
-
hrow('Viewer
|
|
7132
|
-
(snap.streamRelay ? hrow('Redis event relay', esc(snap.streamRelay), 'live', snap.streamRelay === 'down' ? 'The engine stopped relaying live events through Redis, usually after Redis restarted. Data is still saved. Restart agentmemory to resume live updates.' : 'A test event sent through Redis every 30 seconds came back to the worker.') : '') +
|
|
7278
|
+
hrow('Engine connection', esc(snap.connectionState || 'unknown'), 'engineConnection', 'The worker\'s link to the iii engine, which routes calls between workers.') +
|
|
7279
|
+
((kv || backend) ? hrow('State store', esc((backend ? backend + (kv ? ' · ' : '') : '') + (kv ? kv.status + (kv.latencyMs !== undefined ? ' · ' + kv.latencyMs + ' ms' : '') + (kv.error ? ' · ' + kv.error : '') : '')), 'stateBackend', backend === 'redis' ? 'The state worker stores records in Redis (AGENTMEMORY_STATE_BACKEND=redis).' : 'The state worker stores records in local files (the default). Set AGENTMEMORY_STATE_BACKEND=redis to use Redis.') : '') +
|
|
7280
|
+
hrow('Viewer feed', esc(streamText), 'live', 'This page\'s own connection. Offline means the numbers here stop changing.') +
|
|
7133
7281
|
hrow('Uptime', esc(formatUptime(snap.uptimeSeconds)), 'uptime') +
|
|
7134
|
-
hrow('Version', esc('v' + (store.version || (r && r.service.version) || '?') + (r ? ' · engine ' + r.service.
|
|
7135
|
-
hrow('Ports', esc('REST ' + (ports.rest || '?') + ' ·
|
|
7136
|
-
'</div>';
|
|
7282
|
+
hrow('Version', esc('v' + (store.version || (r && r.service.version) || '?') + (r ? ' · engine pinned ' + r.service.enginePinnedVersion : ''))) +
|
|
7283
|
+
hrow('Ports', esc('REST ' + (ports.rest || '?') + ' · viewer ' + (ports.viewer || 'off'))) +
|
|
7284
|
+
workersHtml(snap.workers, state.health.engineDetailsOpen) + '</div>';
|
|
7137
7285
|
}
|
|
7138
7286
|
|
|
7139
7287
|
function legText(leg) {
|
|
@@ -7152,7 +7300,7 @@
|
|
|
7152
7300
|
html += hrow('Keyword index', esc(fmtNum(idx.bm25Documents) + ' documents'), 'bm25',
|
|
7153
7301
|
(b ? esc(fmtNum(b.observations) + ' observations + ' + fmtNum(b.memories) + ' memories + ' + fmtNum(b.lessons) + ' lessons. ') : '') + esc(BM25_EXPLAINER));
|
|
7154
7302
|
html += hrow('Vector index', hasVectors ? esc(fmtNum(idx.vectorDocuments) + ' vectors') : 'off', 'vector',
|
|
7155
|
-
hasVectors ? 'Meaning-based search. Each vector is one embedded record.' : 'No embedding provider, so search is keyword only. Set
|
|
7303
|
+
hasVectors ? 'Meaning-based search. Each vector is one embedded record.' : 'No embedding provider, so search is keyword only. Set EMBEDDING_PROVIDER (local runs on-device; openai, voyage, cohere, gemini or openrouter also need that provider\'s key) and restart.');
|
|
7156
7304
|
var bfState = ri.vectorBackfillState;
|
|
7157
7305
|
var bfNote = bfState === 'paused' ? 'Paused because the embedding provider did not return vectors. Retried on the next start.' :
|
|
7158
7306
|
bfState === 'waiting-for-opt-in' ? 'Waiting for AGENTMEMORY_VECTOR_BACKFILL=all and a restart.' :
|
|
@@ -7168,17 +7316,18 @@
|
|
|
7168
7316
|
'New and removed vectors are written here right away and replayed after a crash, so nothing is embedded twice. Each save empties it.');
|
|
7169
7317
|
}
|
|
7170
7318
|
}
|
|
7171
|
-
html += hrow('Graph', esc(fmtNum(c.graphNodes) + ' nodes · ' + fmtNum(c.graphEdges) + ' edges'), 'graph', store.graph && store.graph.updatedAt ? '
|
|
7319
|
+
html += hrow('Graph', esc(fmtNum(c.graphNodes) + ' nodes · ' + fmtNum(c.graphEdges) + ' edges'), 'graph', store.graph && store.graph.updatedAt ? 'Graph index updated ' + esc(timeAgo(store.graph.updatedAt)) + '.' : '');
|
|
7172
7320
|
if (r && r.graphCompaction) html += graphCompactionRowHtml(r.graphCompaction);
|
|
7173
7321
|
return html + '</div>';
|
|
7174
7322
|
}
|
|
7175
7323
|
|
|
7176
7324
|
function graphCompactionRowHtml(g) {
|
|
7177
7325
|
var where = g.phase === 'snapshot' || g.total === null || g.total === undefined ? (g.phase || 'nodes') : g.phase + ' ' + fmtNum(g.processed || 0) + ' of ' + fmtNum(g.total);
|
|
7178
|
-
var text = g.state === 'off' ? 'off' : g.state === 'pending' ? 'pending' : g.state === 'running' ? 'running, ' + where : g.state === 'failed' ? 'failed at ' + where : 'done';
|
|
7326
|
+
var text = g.state === 'off' ? 'off' : g.state === 'pending' ? 'pending' : g.state === 'deferred' ? 'deferred' : g.state === 'running' ? 'running, ' + where : g.state === 'failed' ? 'failed at ' + where : 'done';
|
|
7179
7327
|
var note = 'A one-time pass that trims each graph node and edge to its newest 32 source observations, so stores from older versions stop slowing graph search.';
|
|
7180
7328
|
if (g.state === 'done') note = fmtNum(g.trimmed || 0) + ' records trimmed, ' + fmtNum(g.idsRemoved || 0) + ' ids removed' + (g.completedAt ? ', finished ' + timeAgo(g.completedAt) : '') + '. It does not run again.';
|
|
7181
7329
|
else if (g.state === 'running') note += ' It runs in the background, resumes after a restart and stops by itself.';
|
|
7330
|
+
else if (g.state === 'deferred') note = 'Compaction is deferred because it reads complete legacy graph scopes. Run it only during explicit maintenance.';
|
|
7182
7331
|
else if (g.state === 'off') note = 'Turned off with AGENTMEMORY_GRAPH_COMPACT_ON_BOOT=false. Run it by hand if graph search is slow:';
|
|
7183
7332
|
else if (g.state === 'failed') note = esc(g.error || 'unknown error') + '. It resumes on the next start. To run it now:';
|
|
7184
7333
|
var cmd = g.state === 'off' || g.state === 'failed' ? cmdBlock(curlPost('graph/compact', {})) : '';
|
|
@@ -7193,7 +7342,7 @@
|
|
|
7193
7342
|
html += hrow('LLM provider', noLlm ? '<span class="badge badge-muted">none</span>' : '<span class="badge badge-green">configured</span>', null,
|
|
7194
7343
|
noLlm ? 'Capture, keyword and vector search, saved memories, lessons and the structural graph all work without one.' : 'Used for summaries, consolidation, typed graph extraction and optional compression.');
|
|
7195
7344
|
if (noLlm && off.length) {
|
|
7196
|
-
html += hrow('Off without an LLM', esc(off.join(', ')), null, esc(LLM_KEY_FIX) + cmdBlock("
|
|
7345
|
+
html += hrow('Off without an LLM', esc(off.join(', ')), null, esc(LLM_KEY_FIX) + cmdBlock("printf 'AGENTMEMORY_LLM_PROVIDER=anthropic\\nANTHROPIC_API_KEY=sk-ant-...\\n' >> ~/.agentmemory/.env"));
|
|
7197
7346
|
}
|
|
7198
7347
|
var emb = (r && r.provider.embeddings) || store.embeddingProvider || 'none';
|
|
7199
7348
|
html += hrow('Embeddings', esc(emb === 'none' ? 'none (keyword search only)' : emb), 'vector', emb === 'none' ? 'Meaning-based search is off.' : 'The number in brackets is the vector size (dimensions) the provider returns.');
|
|
@@ -7312,7 +7461,7 @@
|
|
|
7312
7461
|
}
|
|
7313
7462
|
|
|
7314
7463
|
function consolidationWhyEmpty(cs, c) {
|
|
7315
|
-
if (!cs.llmConfigured) return { text: 'No LLM provider is configured on this instance, so no session summaries are written and consolidation never runs. Semantic facts and procedures stay at zero.', cmd: "
|
|
7464
|
+
if (!cs.llmConfigured) return { text: 'No LLM provider is configured on this instance, so no session summaries are written and consolidation never runs. Semantic facts and procedures stay at zero.', cmd: "printf 'AGENTMEMORY_LLM_PROVIDER=anthropic\\nANTHROPIC_API_KEY=sk-ant-...\\n' >> ~/.agentmemory/.env" };
|
|
7316
7465
|
if (!cs.enabled) return { text: 'CONSOLIDATION_ENABLED is set to false, so consolidation is switched off even though an LLM key exists. Remove that line from ~/.agentmemory/.env (or set it to true) and restart. Find it with:', cmd: 'grep -n CONSOLIDATION_ENABLED ~/.agentmemory/.env' };
|
|
7317
7466
|
var t = cs.thresholds || {};
|
|
7318
7467
|
if ((c.semantic || 0) === 0 && cs.summaries < (t.semanticMinSummaries || 5)) return { text: 'Not enough finished sessions yet: semantic facts need ' + (t.semanticMinSummaries || 5) + ' session summaries and there are ' + cs.summaries + '. End sessions normally (the Stop hook does it) so each one gets a summary.', cmd: curlPost('session/end', { sessionId: 'ses_...' }) };
|
|
@@ -7401,12 +7550,14 @@
|
|
|
7401
7550
|
var snap = store.health || {};
|
|
7402
7551
|
var idx = store.indexes || {};
|
|
7403
7552
|
var c = store.counts || {};
|
|
7404
|
-
var html = '<div class="inline-note"><strong>Health</strong> ' + help('health') + ' is the live version of the <a class="empty-link" href="' + esc(REST) + '/agentmemory/status" target="_blank" rel="noopener">/agentmemory/status</a> page: the same checks and verdict, pushed over
|
|
7553
|
+
var html = '<div class="inline-note"><strong>Health</strong> ' + help('health') + ' is the live version of the <a class="empty-link" href="' + esc(REST) + '/agentmemory/status" target="_blank" rel="noopener">/agentmemory/status</a> page: the same checks and verdict, pushed over SSE every 30 seconds. Every problem says what to do. Scroll down for how consolidation works.</div>';
|
|
7405
7554
|
html += healthVerdictHtml(r);
|
|
7406
7555
|
html += '<div class="hgrid">' + engineCardHtml(r, snap) + indexCardHtml(r, idx, c) + captureCardHtml(r) + llmCardHtml(r) + flagsCardHtml(r) + processCardHtml(snap) + recordsCardHtml(c) + '</div>';
|
|
7407
7556
|
html += consolidationPanelHtml(store.consolidationStatus, c);
|
|
7408
7557
|
html += functionsCardHtml(r);
|
|
7409
7558
|
setViewHtml(el, html);
|
|
7559
|
+
var details = document.getElementById('health-engine-details');
|
|
7560
|
+
if (details) details.ontoggle = function() { state.health.engineDetailsOpen = details.open; };
|
|
7410
7561
|
var reveal = state.health.reveal && document.getElementById('health-' + state.health.reveal);
|
|
7411
7562
|
if (reveal) {
|
|
7412
7563
|
state.health.reveal = '';
|
|
@@ -7611,14 +7762,12 @@
|
|
|
7611
7762
|
|
|
7612
7763
|
var wsReconnectTimer = null;
|
|
7613
7764
|
var wsRetries = 0;
|
|
7614
|
-
var directFailed = true;
|
|
7615
|
-
var directFailures = 0;
|
|
7616
7765
|
var wsHasConnected = false;
|
|
7617
7766
|
var wsOpenedAt = null;
|
|
7618
|
-
var DIRECT_FAILURE_THRESHOLD = 2;
|
|
7619
7767
|
var OFFLINE_AFTER_RETRIES = 3;
|
|
7620
7768
|
var HEALTH_STALE_MS = 90000;
|
|
7621
7769
|
var conn = { state: 'connecting', nextRetryAt: 0, lostAt: 0 };
|
|
7770
|
+
var liveAbortController = null;
|
|
7622
7771
|
|
|
7623
7772
|
function reconnectDelay(attempt) {
|
|
7624
7773
|
var n = Math.max(1, attempt || 1);
|
|
@@ -7704,90 +7853,110 @@
|
|
|
7704
7853
|
function reconnectNow() {
|
|
7705
7854
|
if (wsReconnectTimer) clearTimeout(wsReconnectTimer);
|
|
7706
7855
|
wsReconnectTimer = null;
|
|
7707
|
-
directFailures = 0;
|
|
7708
|
-
directFailed = true;
|
|
7709
7856
|
conn.nextRetryAt = 0;
|
|
7710
|
-
|
|
7711
|
-
|
|
7857
|
+
if (liveAbortController) {
|
|
7858
|
+
liveAbortController.abort();
|
|
7859
|
+
liveAbortController = null;
|
|
7860
|
+
}
|
|
7712
7861
|
connectWs();
|
|
7713
7862
|
}
|
|
7714
7863
|
|
|
7715
|
-
|
|
7864
|
+
function parseSseFrame(frame) {
|
|
7865
|
+
var id = '';
|
|
7866
|
+
var type = '';
|
|
7867
|
+
var data = [];
|
|
7868
|
+
frame.split(/\r?\n/).forEach(function(line) {
|
|
7869
|
+
if (!line || line.charAt(0) === ':') return;
|
|
7870
|
+
var colon = line.indexOf(':');
|
|
7871
|
+
var field = colon < 0 ? line : line.slice(0, colon);
|
|
7872
|
+
var value = colon < 0 ? '' : line.slice(colon + 1).replace(/^ /, '');
|
|
7873
|
+
if (field === 'id') id = value;
|
|
7874
|
+
else if (field === 'event') type = value;
|
|
7875
|
+
else if (field === 'data') data.push(value);
|
|
7876
|
+
});
|
|
7877
|
+
if (!type || !data.length) return null;
|
|
7878
|
+
try { return { id: id, type: type, data: JSON.parse(data.join('\n')) }; } catch (_) { return null; }
|
|
7879
|
+
}
|
|
7880
|
+
|
|
7881
|
+
function consumeSseChunk(buffer, chunk) {
|
|
7882
|
+
buffer += chunk;
|
|
7883
|
+
var frames = [];
|
|
7884
|
+
var match;
|
|
7885
|
+
while ((match = /\r?\n\r?\n/.exec(buffer))) {
|
|
7886
|
+
var frame = buffer.slice(0, match.index);
|
|
7887
|
+
buffer = buffer.slice(match.index + match[0].length);
|
|
7888
|
+
var parsed = parseSseFrame(frame);
|
|
7889
|
+
if (parsed) frames.push(parsed);
|
|
7890
|
+
}
|
|
7891
|
+
return { buffer: buffer, frames: frames };
|
|
7892
|
+
}
|
|
7716
7893
|
|
|
7717
|
-
function connectWs() {
|
|
7894
|
+
async function connectWs() {
|
|
7718
7895
|
wsReconnectTimer = null;
|
|
7719
7896
|
conn.nextRetryAt = 0;
|
|
7720
|
-
var
|
|
7721
|
-
|
|
7897
|
+
var controller = new AbortController();
|
|
7898
|
+
liveAbortController = controller;
|
|
7722
7899
|
try {
|
|
7723
|
-
|
|
7724
|
-
|
|
7725
|
-
|
|
7726
|
-
|
|
7727
|
-
|
|
7728
|
-
|
|
7729
|
-
|
|
7730
|
-
if (ws.readyState === WebSocket.CONNECTING) {
|
|
7731
|
-
try { ws.close(); } catch {}
|
|
7900
|
+
var headers = { 'Cache-Control': 'no-cache', Accept: 'text/event-stream' };
|
|
7901
|
+
var viewerToken = getViewerToken();
|
|
7902
|
+
if (viewerToken) headers.Authorization = 'Bearer ' + viewerToken;
|
|
7903
|
+
var response = await fetch(LIVE_EVENTS_URL, { headers: headers, signal: controller.signal });
|
|
7904
|
+
if (!response.ok || !response.body) {
|
|
7905
|
+
if (response.status === 401) showViewerAuthPrompt();
|
|
7906
|
+
throw new Error('SSE request failed: ' + response.status);
|
|
7732
7907
|
}
|
|
7733
|
-
|
|
7734
|
-
ws.onopen = function() {
|
|
7735
|
-
clearTimeout(connectTimer);
|
|
7736
|
-
if (state.ws !== ws) return;
|
|
7908
|
+
hideViewerAuthPrompt();
|
|
7737
7909
|
wsRetries = 0;
|
|
7738
|
-
if (!ws.__direct) {
|
|
7739
|
-
ws.send(JSON.stringify({
|
|
7740
|
-
type: 'join',
|
|
7741
|
-
data: {
|
|
7742
|
-
subscriptionId: 'viewer-' + Date.now(),
|
|
7743
|
-
streamName: 'mem-live',
|
|
7744
|
-
groupId: 'viewer'
|
|
7745
|
-
}
|
|
7746
|
-
}));
|
|
7747
|
-
}
|
|
7748
7910
|
var firstConnect = !wsHasConnected;
|
|
7749
7911
|
wsHasConnected = true;
|
|
7750
7912
|
wsOpenedAt = Date.now();
|
|
7751
7913
|
setConnection('live');
|
|
7752
7914
|
updateFooter();
|
|
7753
|
-
resyncAfterConnect(firstConnect);
|
|
7754
|
-
|
|
7755
|
-
|
|
7756
|
-
|
|
7757
|
-
|
|
7758
|
-
|
|
7759
|
-
|
|
7915
|
+
await resyncAfterConnect(firstConnect);
|
|
7916
|
+
var reader = response.body.getReader();
|
|
7917
|
+
var decoder = new TextDecoder();
|
|
7918
|
+
var buffer = '';
|
|
7919
|
+
while (true) {
|
|
7920
|
+
var result = await reader.read();
|
|
7921
|
+
if (result.done) break;
|
|
7922
|
+
buffer += decoder.decode(result.value, { stream: true });
|
|
7923
|
+
var parsed = consumeSseChunk(buffer, '');
|
|
7924
|
+
buffer = parsed.buffer;
|
|
7925
|
+
parsed.frames.forEach(function(frame) {
|
|
7926
|
+
store.lastEventAt = Date.now();
|
|
7927
|
+
if (frame.type === 'raw_observation') {
|
|
7928
|
+
var obs = frame.data && frame.data.data && (frame.data.data.observation || frame.data.data);
|
|
7929
|
+
if (looksLikeObservation(obs)) routeWsMessage({ observation: obs, fresh: true });
|
|
7930
|
+
} else if (frame.type === 'compressed_observation') {
|
|
7931
|
+
var compressed = frame.data && frame.data.data && (frame.data.data.observation || frame.data.data);
|
|
7932
|
+
if (looksLikeObservation(compressed)) routeWsMessage({ observation: compressed, fresh: true });
|
|
7933
|
+
} else {
|
|
7934
|
+
handleLiveEvent(frame.type, frame.data && frame.data.data || {});
|
|
7935
|
+
}
|
|
7936
|
+
});
|
|
7760
7937
|
}
|
|
7761
|
-
|
|
7762
|
-
|
|
7763
|
-
|
|
7764
|
-
|
|
7765
|
-
|
|
7766
|
-
|
|
7767
|
-
|
|
7768
|
-
|
|
7769
|
-
|
|
7770
|
-
};
|
|
7771
|
-
ws.onclose = function() {
|
|
7772
|
-
clearTimeout(connectTimer);
|
|
7773
|
-
if (state.ws !== ws) return;
|
|
7774
|
-
wsOpenedAt = null;
|
|
7775
|
-
updateFooter();
|
|
7776
|
-
directFailures += 1;
|
|
7777
|
-
if (directFailures >= DIRECT_FAILURE_THRESHOLD) {
|
|
7778
|
-
directFailed = ws.__direct;
|
|
7779
|
-
directFailures = 0;
|
|
7938
|
+
if (!controller.signal.aborted) throw new Error('SSE stream ended');
|
|
7939
|
+
} catch (err) {
|
|
7940
|
+
if (!controller.signal.aborted) console.warn('[viewer] SSE connection failed:', err);
|
|
7941
|
+
} finally {
|
|
7942
|
+
if (liveAbortController === controller) liveAbortController = null;
|
|
7943
|
+
if (!controller.signal.aborted) {
|
|
7944
|
+
wsOpenedAt = null;
|
|
7945
|
+
updateFooter();
|
|
7946
|
+
scheduleReconnect();
|
|
7780
7947
|
}
|
|
7781
|
-
|
|
7782
|
-
};
|
|
7783
|
-
ws.onerror = function() {
|
|
7784
|
-
if (state.ws !== ws) return;
|
|
7785
|
-
try { ws.close(); } catch {}
|
|
7786
|
-
};
|
|
7787
|
-
state.ws = ws;
|
|
7948
|
+
}
|
|
7788
7949
|
}
|
|
7789
7950
|
|
|
7790
7951
|
var resyncing = null;
|
|
7952
|
+
function resetLoadedKindForReload(kind) {
|
|
7953
|
+
store.loaded[kind] = false;
|
|
7954
|
+
if (kind === 'action') {
|
|
7955
|
+
state.actions.detailAttemptedId = '';
|
|
7956
|
+
state.actions.detailRequestFailedId = '';
|
|
7957
|
+
}
|
|
7958
|
+
}
|
|
7959
|
+
|
|
7791
7960
|
async function resyncAfterConnect(firstConnect) {
|
|
7792
7961
|
openBootGate();
|
|
7793
7962
|
if (resyncing) return resyncing;
|
|
@@ -7795,9 +7964,10 @@
|
|
|
7795
7964
|
resyncing = (async function() {
|
|
7796
7965
|
try {
|
|
7797
7966
|
await loadSnapshot();
|
|
7967
|
+
await loadRecentObservations();
|
|
7798
7968
|
scheduleHealthStaleCheck();
|
|
7799
7969
|
if (!firstConnect || reloadKinds.length) {
|
|
7800
|
-
reloadKinds.forEach(
|
|
7970
|
+
reloadKinds.forEach(resetLoadedKindForReload);
|
|
7801
7971
|
await Promise.all(reloadKinds.map(ensureLoaded));
|
|
7802
7972
|
state.graph.dirty = state.graph.loaded;
|
|
7803
7973
|
state.activity.loaded = false;
|
|
@@ -7814,6 +7984,24 @@
|
|
|
7814
7984
|
}
|
|
7815
7985
|
|
|
7816
7986
|
var LIVE_BUFFER_MAX = 200;
|
|
7987
|
+
var ACTIVITY_SESSIONS = 10;
|
|
7988
|
+
async function loadRecentObservations() {
|
|
7989
|
+
var sessionResult = await apiGet('sessions?limit=' + ACTIVITY_SESSIONS);
|
|
7990
|
+
var sessions = sortByTimeDesc((sessionResult && sessionResult.sessions) || [], ['startedAt']).filter(function(x) { return sessionId(x); }).slice(0, ACTIVITY_SESSIONS);
|
|
7991
|
+
mergeSessionRows(sessions);
|
|
7992
|
+
var results = await Promise.all(sessions.map(function(x) {
|
|
7993
|
+
return apiGet('observations?sessionId=' + encodeURIComponent(sessionId(x)) + '&limit=100');
|
|
7994
|
+
}));
|
|
7995
|
+
var seen = {};
|
|
7996
|
+
results.forEach(function(result) {
|
|
7997
|
+
((result && result.observations) || []).slice(-LIVE_BUFFER_MAX).forEach(function(observation) {
|
|
7998
|
+
if (!observation || !observation.id || seen[observation.id]) return;
|
|
7999
|
+
seen[observation.id] = true;
|
|
8000
|
+
routeWsMessage({ observation: observation });
|
|
8001
|
+
});
|
|
8002
|
+
});
|
|
8003
|
+
}
|
|
8004
|
+
|
|
7817
8005
|
|
|
7818
8006
|
function looksLikeObservation(obj) {
|
|
7819
8007
|
return !!(obj && typeof obj === 'object' && obj.id && obj.timestamp);
|
|
@@ -8055,15 +8243,6 @@
|
|
|
8055
8243
|
if (looksLikeObservation(observation)) {
|
|
8056
8244
|
routeWsMessage({ observation: observation, fresh: true });
|
|
8057
8245
|
}
|
|
8058
|
-
} else if (evt.type === 'sync') {
|
|
8059
|
-
var items = Array.isArray(evt.data) ? evt.data.slice(-LIVE_BUFFER_MAX) : [];
|
|
8060
|
-
items.forEach(function(item) {
|
|
8061
|
-
var payload = item.data || item;
|
|
8062
|
-
observation = payload.observation || payload;
|
|
8063
|
-
if (looksLikeObservation(observation)) {
|
|
8064
|
-
routeWsMessage({ observation: observation });
|
|
8065
|
-
}
|
|
8066
|
-
});
|
|
8067
8246
|
}
|
|
8068
8247
|
}
|
|
8069
8248
|
|
|
@@ -8159,9 +8338,9 @@
|
|
|
8159
8338
|
items.push({
|
|
8160
8339
|
on: false,
|
|
8161
8340
|
title: 'No LLM provider',
|
|
8162
|
-
key: '
|
|
8163
|
-
desc: 'Compression, summaries, consolidation and graph extraction stay off until an LLM
|
|
8164
|
-
enable: 'export ANTHROPIC_API_KEY=sk-ant-...\n# then restart: npx @agentmemory/agentmemory',
|
|
8341
|
+
key: 'AGENTMEMORY_LLM_PROVIDER',
|
|
8342
|
+
desc: 'Compression, summaries, consolidation and graph extraction stay off until you choose an LLM provider. Memories, search and sessions still work.',
|
|
8343
|
+
enable: 'export AGENTMEMORY_LLM_PROVIDER=anthropic\nexport ANTHROPIC_API_KEY=sk-ant-...\n# then restart: npx @agentmemory/agentmemory',
|
|
8165
8344
|
affects: ['Overview', 'Graph', 'Crystals']
|
|
8166
8345
|
});
|
|
8167
8346
|
}
|
|
@@ -8169,9 +8348,9 @@
|
|
|
8169
8348
|
items.push({
|
|
8170
8349
|
on: false,
|
|
8171
8350
|
title: 'No embedding provider',
|
|
8172
|
-
key: '
|
|
8351
|
+
key: 'EMBEDDING_PROVIDER',
|
|
8173
8352
|
desc: 'Search matches exact keywords only. With embeddings it also finds memories by meaning.',
|
|
8174
|
-
enable: 'export
|
|
8353
|
+
enable: 'export EMBEDDING_PROVIDER=local\n# or EMBEDDING_PROVIDER=openai with OPENAI_API_KEY (also voyage, cohere, gemini, openrouter)',
|
|
8175
8354
|
affects: ['Memories', 'Health']
|
|
8176
8355
|
});
|
|
8177
8356
|
}
|
|
@@ -8226,7 +8405,7 @@
|
|
|
8226
8405
|
var sync = document.getElementById('footer-sync');
|
|
8227
8406
|
if (sync) {
|
|
8228
8407
|
var syncText = store.snapshotAt ? 'full sync ' + new Date(store.snapshotAt).toLocaleTimeString() : 'waiting for first sync';
|
|
8229
|
-
if (store.snapshotAt) syncText += wsOpenedAt ? ',
|
|
8408
|
+
if (store.snapshotAt) syncText += wsOpenedAt ? ', live via SSE since ' + new Date(wsOpenedAt).toLocaleTimeString() : ', SSE reconnecting';
|
|
8230
8409
|
sync.textContent = syncText;
|
|
8231
8410
|
}
|
|
8232
8411
|
var fbEl = document.getElementById('footer-feedback');
|
|
@@ -8323,7 +8502,7 @@
|
|
|
8323
8502
|
var modal = document.getElementById('modal');
|
|
8324
8503
|
var overlay = document.getElementById('modal-overlay');
|
|
8325
8504
|
var html = '<h3>How to read this viewer</h3>';
|
|
8326
|
-
html += '<p style="margin-bottom:8px;">Everything on these pages updates live over one
|
|
8505
|
+
html += '<p style="margin-bottom:8px;">Everything on these pages updates live over one SSE connection; nothing refreshes on a timer. Click any <span class="help" style="cursor:default;">?</span> for a short explanation, or use the keys below.</p>';
|
|
8327
8506
|
html += '<div class="kbd-list">' +
|
|
8328
8507
|
'<div><kbd>/</kbd> focus search on this page</div>' +
|
|
8329
8508
|
'<div><kbd>?</kbd> open this help</div>' +
|
|
@@ -8894,16 +9073,7 @@
|
|
|
8894
9073
|
|
|
8895
9074
|
var bootRoute = parseRoute(window.location.hash);
|
|
8896
9075
|
switchTab(bootRoute.tab, { replaceRoute: true, skipRoute: !!bootRoute.obs && !bootRoute.redirect, id: bootRoute.id, obs: bootRoute.obs });
|
|
8897
|
-
(
|
|
8898
|
-
try {
|
|
8899
|
-
var live = await api('livez', { signal: AbortSignal.timeout(5000) });
|
|
8900
|
-
if (live && typeof live.streamsPort === 'number' && live.streamsPort > 0) {
|
|
8901
|
-
WS_URL = wsProto + '//' + window.location.hostname + ':' + live.streamsPort;
|
|
8902
|
-
WS_DIRECT_URL = WS_URL + '/stream/mem-live/viewer';
|
|
8903
|
-
}
|
|
8904
|
-
} catch (_) {}
|
|
8905
|
-
connectWs();
|
|
8906
|
-
})();
|
|
9076
|
+
connectWs();
|
|
8907
9077
|
setTimeout(function() {
|
|
8908
9078
|
if (wsHasConnected) return;
|
|
8909
9079
|
openBootGate();
|
|
@@ -8913,8 +9083,7 @@
|
|
|
8913
9083
|
|
|
8914
9084
|
document.addEventListener('visibilitychange', function() {
|
|
8915
9085
|
if (document.visibilityState !== 'visible') return;
|
|
8916
|
-
|
|
8917
|
-
if (ws && (ws.readyState === WebSocket.OPEN || ws.readyState === WebSocket.CONNECTING)) return;
|
|
9086
|
+
if (liveAbortController) return;
|
|
8918
9087
|
wsRetries = 0;
|
|
8919
9088
|
reconnectNow();
|
|
8920
9089
|
});
|