@agentmemory/agentmemory 0.9.1 → 0.9.3
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/README.md +40 -13
- package/dist/cli.mjs +147 -26
- package/dist/cli.mjs.map +1 -1
- package/dist/hooks/notification.mjs +6 -0
- package/dist/hooks/notification.mjs.map +1 -1
- package/dist/hooks/post-tool-failure.mjs +6 -0
- package/dist/hooks/post-tool-failure.mjs.map +1 -1
- package/dist/hooks/post-tool-use.mjs +35 -1
- package/dist/hooks/post-tool-use.mjs.map +1 -1
- package/dist/hooks/pre-compact.mjs +6 -0
- package/dist/hooks/pre-compact.mjs.map +1 -1
- package/dist/hooks/pre-tool-use.mjs +6 -0
- package/dist/hooks/pre-tool-use.mjs.map +1 -1
- package/dist/hooks/prompt-submit.mjs +6 -0
- package/dist/hooks/prompt-submit.mjs.map +1 -1
- package/dist/hooks/session-end.mjs +6 -0
- package/dist/hooks/session-end.mjs.map +1 -1
- package/dist/hooks/session-start.mjs +6 -0
- package/dist/hooks/session-start.mjs.map +1 -1
- package/dist/hooks/stop.mjs +6 -0
- package/dist/hooks/stop.mjs.map +1 -1
- package/dist/hooks/subagent-start.mjs +6 -0
- package/dist/hooks/subagent-start.mjs.map +1 -1
- package/dist/hooks/subagent-stop.mjs +6 -0
- package/dist/hooks/subagent-stop.mjs.map +1 -1
- package/dist/hooks/task-completed.mjs +6 -0
- package/dist/hooks/task-completed.mjs.map +1 -1
- package/dist/image-refs-CESf9ndJ.mjs +3 -0
- package/dist/image-store-DGvZMMrI.mjs +3 -0
- package/dist/index.mjs +2100 -157
- package/dist/index.mjs.map +1 -1
- package/dist/{src-Dw_gJcCy.mjs → src-3Snd7D3T.mjs} +2021 -267
- package/dist/src-3Snd7D3T.mjs.map +1 -0
- package/dist/{standalone-BEWvWM5P.mjs → standalone-BG9uPsDK.mjs} +2 -2
- package/dist/{standalone-BEWvWM5P.mjs.map → standalone-BG9uPsDK.mjs.map} +1 -1
- package/dist/standalone.mjs +136 -2
- package/dist/standalone.mjs.map +1 -1
- package/dist/{tools-registry-BvWNlj6u.mjs → tools-registry-m8Ofn9vV.mjs} +166 -12
- package/dist/tools-registry-m8Ofn9vV.mjs.map +1 -0
- package/dist/viewer/index.html +528 -68
- package/package.json +5 -3
- package/plugin/.claude-plugin/plugin.json +2 -2
- package/plugin/scripts/notification.mjs +6 -0
- package/plugin/scripts/notification.mjs.map +1 -1
- package/plugin/scripts/post-tool-failure.mjs +6 -0
- package/plugin/scripts/post-tool-failure.mjs.map +1 -1
- package/plugin/scripts/post-tool-use.mjs +35 -1
- package/plugin/scripts/post-tool-use.mjs.map +1 -1
- package/plugin/scripts/pre-compact.mjs +6 -0
- package/plugin/scripts/pre-compact.mjs.map +1 -1
- package/plugin/scripts/pre-tool-use.mjs +6 -0
- package/plugin/scripts/pre-tool-use.mjs.map +1 -1
- package/plugin/scripts/prompt-submit.mjs +6 -0
- package/plugin/scripts/prompt-submit.mjs.map +1 -1
- package/plugin/scripts/session-end.mjs +6 -0
- package/plugin/scripts/session-end.mjs.map +1 -1
- package/plugin/scripts/session-start.mjs +6 -0
- package/plugin/scripts/session-start.mjs.map +1 -1
- package/plugin/scripts/stop.mjs +6 -0
- package/plugin/scripts/stop.mjs.map +1 -1
- package/plugin/scripts/subagent-start.mjs +6 -0
- package/plugin/scripts/subagent-start.mjs.map +1 -1
- package/plugin/scripts/subagent-stop.mjs +6 -0
- package/plugin/scripts/subagent-stop.mjs.map +1 -1
- package/plugin/scripts/task-completed.mjs +6 -0
- package/plugin/scripts/task-completed.mjs.map +1 -1
- package/dist/src-Dw_gJcCy.mjs.map +0 -1
- package/dist/tools-registry-BvWNlj6u.mjs.map +0 -1
- package/dist/transformers-BX_tgxdO.mjs +0 -38684
- package/dist/transformers-BX_tgxdO.mjs.map +0 -1
- package/dist/transformers-KMm1i9no.mjs +0 -38683
- package/dist/transformers-KMm1i9no.mjs.map +0 -1
package/README.md
CHANGED
|
@@ -25,10 +25,10 @@
|
|
|
25
25
|
<p align="center">
|
|
26
26
|
<picture><source media="(prefers-color-scheme: dark)" srcset="assets/tags/light/stat-recall.svg"><img src="assets/tags/stat-recall.svg" alt="95.2% retrieval R@5" height="38" /></picture>
|
|
27
27
|
<picture><source media="(prefers-color-scheme: dark)" srcset="assets/tags/light/stat-tokens.svg"><img src="assets/tags/stat-tokens.svg" alt="92% fewer tokens" height="38" /></picture>
|
|
28
|
-
<picture><source media="(prefers-color-scheme: dark)" srcset="assets/tags/light/stat-tools.svg"><img src="assets/tags/stat-tools.svg" alt="
|
|
28
|
+
<picture><source media="(prefers-color-scheme: dark)" srcset="assets/tags/light/stat-tools.svg"><img src="assets/tags/stat-tools.svg" alt="51 MCP tools" height="38" /></picture>
|
|
29
29
|
<picture><source media="(prefers-color-scheme: dark)" srcset="assets/tags/light/stat-hooks.svg"><img src="assets/tags/stat-hooks.svg" alt="12 auto hooks" height="38" /></picture>
|
|
30
30
|
<picture><source media="(prefers-color-scheme: dark)" srcset="assets/tags/light/stat-deps.svg"><img src="assets/tags/stat-deps.svg" alt="0 external DBs" height="38" /></picture>
|
|
31
|
-
<picture><source media="(prefers-color-scheme: dark)" srcset="assets/tags/light/stat-tests.svg"><img src="assets/tags/stat-tests.svg" alt="
|
|
31
|
+
<picture><source media="(prefers-color-scheme: dark)" srcset="assets/tags/light/stat-tests.svg"><img src="assets/tags/stat-tests.svg" alt="827 tests passing" height="38" /></picture>
|
|
32
32
|
</p>
|
|
33
33
|
|
|
34
34
|
<p align="center">
|
|
@@ -334,14 +334,14 @@ Implementation details live in `src/cli.ts` (see `runUpgrade` around the `src/cl
|
|
|
334
334
|
### Claude Code (one block, paste it)
|
|
335
335
|
|
|
336
336
|
```
|
|
337
|
-
Install agentmemory: run `npx @agentmemory/agentmemory` in a separate terminal to start the memory server. Then run `/plugin marketplace add rohitg00/agentmemory` and `/plugin install agentmemory` — the plugin registers all 12 hooks, 4 skills, AND auto-wires the `@agentmemory/mcp` stdio server via its `.mcp.json`, so you get
|
|
337
|
+
Install agentmemory: run `npx @agentmemory/agentmemory` in a separate terminal to start the memory server. Then run `/plugin marketplace add rohitg00/agentmemory` and `/plugin install agentmemory` — the plugin registers all 12 hooks, 4 skills, AND auto-wires the `@agentmemory/mcp` stdio server via its `.mcp.json`, so you get 51 MCP tools (memory_smart_search, memory_save, memory_sessions, memory_governance_delete, etc.) without any extra config step. Verify with `curl http://localhost:3111/agentmemory/health`. The real-time viewer is at http://localhost:3113.
|
|
338
338
|
```
|
|
339
339
|
|
|
340
340
|
<details>
|
|
341
341
|
<summary><b>OpenClaw (paste this prompt)</b></summary>
|
|
342
342
|
|
|
343
343
|
```
|
|
344
|
-
Install agentmemory for OpenClaw. Run `npx @agentmemory/agentmemory` in a separate terminal to start the memory server on localhost:3111. Then add this to my OpenClaw MCP config so agentmemory is available with all
|
|
344
|
+
Install agentmemory for OpenClaw. Run `npx @agentmemory/agentmemory` in a separate terminal to start the memory server on localhost:3111. Then add this to my OpenClaw MCP config so agentmemory is available with all 50 memory tools:
|
|
345
345
|
|
|
346
346
|
{
|
|
347
347
|
"mcpServers": {
|
|
@@ -363,7 +363,7 @@ Full guide: [`integrations/openclaw/`](integrations/openclaw/)
|
|
|
363
363
|
<summary><b>Hermes Agent (paste this prompt)</b></summary>
|
|
364
364
|
|
|
365
365
|
```
|
|
366
|
-
Install agentmemory for Hermes. Run `npx @agentmemory/agentmemory` in a separate terminal to start the memory server on localhost:3111. Then add this to ~/.hermes/config.yaml so Hermes can use agentmemory as an MCP server with all
|
|
366
|
+
Install agentmemory for Hermes. Run `npx @agentmemory/agentmemory` in a separate terminal to start the memory server on localhost:3111. Then add this to ~/.hermes/config.yaml so Hermes can use agentmemory as an MCP server with all 50 memory tools:
|
|
367
367
|
|
|
368
368
|
mcp_servers:
|
|
369
369
|
agentmemory:
|
|
@@ -593,9 +593,9 @@ npm install @xenova/transformers
|
|
|
593
593
|
|
|
594
594
|
<h2 id="mcp-server"><picture><source media="(prefers-color-scheme: dark)" srcset="assets/tags/light/section-mcp.svg"><img src="assets/tags/section-mcp.svg" alt="MCP Server" height="32" /></picture></h2>
|
|
595
595
|
|
|
596
|
-
|
|
596
|
+
51 tools, 6 resources, 3 prompts, and 4 skills — the most comprehensive MCP memory toolkit for any agent.
|
|
597
597
|
|
|
598
|
-
###
|
|
598
|
+
### 50 Tools
|
|
599
599
|
|
|
600
600
|
<details>
|
|
601
601
|
<summary>Core tools (always available)</summary>
|
|
@@ -617,7 +617,7 @@ npm install @xenova/transformers
|
|
|
617
617
|
</details>
|
|
618
618
|
|
|
619
619
|
<details>
|
|
620
|
-
<summary>Extended tools (
|
|
620
|
+
<summary>Extended tools (50 total — set AGENTMEMORY_TOOLS=all)</summary>
|
|
621
621
|
|
|
622
622
|
| Tool | Description |
|
|
623
623
|
|------|-------------|
|
|
@@ -779,25 +779,35 @@ agentmemory auto-detects from your environment. No API key needed if you have a
|
|
|
779
779
|
|
|
780
780
|
| Provider | Config | Notes |
|
|
781
781
|
|----------|--------|-------|
|
|
782
|
-
| **
|
|
782
|
+
| **No-op (default)** | No config needed | LLM-backed compress/summarize is DISABLED. Synthetic BM25 compression + recall still work. See `AGENTMEMORY_ALLOW_AGENT_SDK` below if you used to rely on the Claude-subscription fallback. |
|
|
783
783
|
| Anthropic API | `ANTHROPIC_API_KEY` | Per-token billing |
|
|
784
784
|
| MiniMax | `MINIMAX_API_KEY` | Anthropic-compatible |
|
|
785
785
|
| Gemini | `GEMINI_API_KEY` | Also enables embeddings |
|
|
786
786
|
| OpenRouter | `OPENROUTER_API_KEY` | Any model |
|
|
787
|
+
| Claude subscription fallback | `AGENTMEMORY_ALLOW_AGENT_SDK=true` | Opt-in only. Spawns `@anthropic-ai/claude-agent-sdk` sessions — used to cause unbounded Stop-hook recursion (#149 follow-up) so it is no longer the default. |
|
|
787
788
|
|
|
788
789
|
### Environment Variables
|
|
789
790
|
|
|
790
791
|
Create `~/.agentmemory/.env`:
|
|
791
792
|
|
|
792
793
|
```env
|
|
793
|
-
# LLM provider (pick one
|
|
794
|
+
# LLM provider (pick one — default is the no-op provider: no LLM calls)
|
|
794
795
|
# ANTHROPIC_API_KEY=sk-ant-...
|
|
796
|
+
# ANTHROPIC_BASE_URL=... # Optional: Anthropic-compatible proxy / Azure
|
|
795
797
|
# GEMINI_API_KEY=...
|
|
796
798
|
# OPENROUTER_API_KEY=...
|
|
799
|
+
# MINIMAX_API_KEY=...
|
|
800
|
+
# Opt-in Claude-subscription fallback (spawns @anthropic-ai/claude-agent-sdk);
|
|
801
|
+
# leave OFF unless you understand the Stop-hook recursion risk (#149 follow-up):
|
|
802
|
+
# AGENTMEMORY_ALLOW_AGENT_SDK=true
|
|
797
803
|
|
|
798
804
|
# Embedding provider (auto-detected, or override)
|
|
799
805
|
# EMBEDDING_PROVIDER=local
|
|
800
806
|
# VOYAGE_API_KEY=...
|
|
807
|
+
# OPENAI_API_KEY=sk-...
|
|
808
|
+
# OPENAI_BASE_URL=https://api.openai.com # Override for Azure / vLLM / LM Studio / proxies
|
|
809
|
+
# OPENAI_EMBEDDING_MODEL=text-embedding-3-small
|
|
810
|
+
# OPENAI_EMBEDDING_DIMENSIONS=1536 # Required when the model is not in the known-models table
|
|
801
811
|
|
|
802
812
|
# Search tuning
|
|
803
813
|
# BM25_WEIGHT=0.4
|
|
@@ -816,6 +826,23 @@ Create `~/.agentmemory/.env`:
|
|
|
816
826
|
# LLM provider to compress the
|
|
817
827
|
# observation — expect significant
|
|
818
828
|
# token spend on active sessions.
|
|
829
|
+
# AGENTMEMORY_SLOTS=false # OFF by default. Editable pinned
|
|
830
|
+
# memory slots — persona,
|
|
831
|
+
# user_preferences, tool_guidelines,
|
|
832
|
+
# project_context, guidance,
|
|
833
|
+
# pending_items, session_patterns,
|
|
834
|
+
# self_notes. Size-limited; agent
|
|
835
|
+
# edits via memory_slot_* tools.
|
|
836
|
+
# Pinned slots addressable for
|
|
837
|
+
# SessionStart injection.
|
|
838
|
+
# AGENTMEMORY_REFLECT=false # OFF by default. Requires SLOTS=on.
|
|
839
|
+
# Stop hook fires mem::slot-reflect:
|
|
840
|
+
# scans recent observations, auto-
|
|
841
|
+
# appends TODOs to pending_items,
|
|
842
|
+
# counts patterns in
|
|
843
|
+
# session_patterns, records touched
|
|
844
|
+
# files in project_context. Fire-
|
|
845
|
+
# and-forget; does not block.
|
|
819
846
|
# AGENTMEMORY_INJECT_CONTEXT=false # OFF by default (#143). When on:
|
|
820
847
|
# - SessionStart may inject ~1-2K
|
|
821
848
|
# chars of project context into
|
|
@@ -843,7 +870,7 @@ Create `~/.agentmemory/.env`:
|
|
|
843
870
|
# USER_ID=
|
|
844
871
|
# TEAM_MODE=private
|
|
845
872
|
|
|
846
|
-
# Tool visibility: "core" (8 tools) or "all" (
|
|
873
|
+
# Tool visibility: "core" (8 tools) or "all" (51 tools)
|
|
847
874
|
# AGENTMEMORY_TOOLS=core
|
|
848
875
|
```
|
|
849
876
|
|
|
@@ -884,7 +911,7 @@ Full endpoint list: [`src/triggers/api.ts`](src/triggers/api.ts)
|
|
|
884
911
|
|
|
885
912
|
Built on [iii-engine](https://iii.dev)'s three primitives — no Express, no Postgres, no Redis.
|
|
886
913
|
|
|
887
|
-
**118 source files · ~21,800 LOC ·
|
|
914
|
+
**118 source files · ~21,800 LOC · 800 tests · 123 functions · 34 KV scopes**
|
|
888
915
|
|
|
889
916
|
<details>
|
|
890
917
|
<summary>What iii-engine replaces</summary>
|
|
@@ -904,7 +931,7 @@ Built on [iii-engine](https://iii.dev)'s three primitives — no Express, no Pos
|
|
|
904
931
|
```bash
|
|
905
932
|
npm run dev # Hot reload
|
|
906
933
|
npm run build # Production build
|
|
907
|
-
npm test #
|
|
934
|
+
npm test # 800 tests (~1.7s)
|
|
908
935
|
npm run test:integration # API tests (requires running services)
|
|
909
936
|
```
|
|
910
937
|
|
package/dist/cli.mjs
CHANGED
|
@@ -47,7 +47,12 @@ const KV = {
|
|
|
47
47
|
enrichedChunks: (sessionId) => `mem:enriched:${sessionId}`,
|
|
48
48
|
latentEmbeddings: (obsId) => `mem:latent:${obsId}`,
|
|
49
49
|
retentionScores: "mem:retention",
|
|
50
|
-
accessLog: "mem:access"
|
|
50
|
+
accessLog: "mem:access",
|
|
51
|
+
imageRefs: "mem:image-refs",
|
|
52
|
+
imageEmbeddings: "mem:image-embeddings",
|
|
53
|
+
slots: "mem:slots",
|
|
54
|
+
globalSlots: "mem:slots:global",
|
|
55
|
+
state: "mem:state"
|
|
51
56
|
};
|
|
52
57
|
const STREAM = {
|
|
53
58
|
name: "mem-live",
|
|
@@ -87,7 +92,8 @@ Usage: agentmemory [command] [options]
|
|
|
87
92
|
|
|
88
93
|
Commands:
|
|
89
94
|
(default) Start agentmemory worker
|
|
90
|
-
status Show connection status, memory count, and health
|
|
95
|
+
status Show connection status, memory count, flags, and health
|
|
96
|
+
doctor Run diagnostic checks (server, flags, graph, providers)
|
|
91
97
|
demo Seed sample sessions and show recall in action
|
|
92
98
|
upgrade Upgrade local deps + iii runtime (best effort)
|
|
93
99
|
mcp Start standalone MCP server (no engine required)
|
|
@@ -100,10 +106,15 @@ Options:
|
|
|
100
106
|
--no-engine Skip auto-starting iii-engine
|
|
101
107
|
--port <N> Override REST port (default: 3111)
|
|
102
108
|
|
|
109
|
+
Environment:
|
|
110
|
+
AGENTMEMORY_URL Full REST base URL (e.g. http://localhost:3111).
|
|
111
|
+
Honored by status, doctor, and MCP shim commands.
|
|
112
|
+
|
|
103
113
|
Quick start:
|
|
104
114
|
npx @agentmemory/agentmemory # start with local iii-engine or Docker
|
|
105
|
-
npx @agentmemory/agentmemory
|
|
106
|
-
npx @agentmemory/agentmemory
|
|
115
|
+
npx @agentmemory/agentmemory demo # see semantic recall in 30 seconds
|
|
116
|
+
npx @agentmemory/agentmemory doctor # diagnose config + feature flags
|
|
117
|
+
npx @agentmemory/agentmemory status # health + memory count + flags
|
|
107
118
|
npx @agentmemory/agentmemory upgrade # upgrade agentmemory + iii runtime
|
|
108
119
|
npx @agentmemory/agentmemory mcp # standalone MCP server (no engine)
|
|
109
120
|
npx @agentmemory/mcp # same as above (shim package)
|
|
@@ -116,16 +127,44 @@ const portIdx = args.indexOf("--port");
|
|
|
116
127
|
if (portIdx !== -1 && args[portIdx + 1]) process.env["III_REST_PORT"] = args[portIdx + 1];
|
|
117
128
|
const skipEngine = args.includes("--no-engine");
|
|
118
129
|
function getRestPort() {
|
|
130
|
+
const url = process.env["AGENTMEMORY_URL"];
|
|
131
|
+
if (url) try {
|
|
132
|
+
const parsed = new URL(url).port;
|
|
133
|
+
if (parsed) return parseInt(parsed, 10);
|
|
134
|
+
} catch {}
|
|
119
135
|
return parseInt(process.env["III_REST_PORT"] || "3111", 10) || 3111;
|
|
120
136
|
}
|
|
137
|
+
function getBaseUrl() {
|
|
138
|
+
const url = process.env["AGENTMEMORY_URL"];
|
|
139
|
+
if (url) return url.replace(/\/+$/, "");
|
|
140
|
+
return `http://localhost:${getRestPort()}`;
|
|
141
|
+
}
|
|
142
|
+
function getViewerUrl() {
|
|
143
|
+
const envUrl = process.env["AGENTMEMORY_VIEWER_URL"];
|
|
144
|
+
if (envUrl) return envUrl.replace(/\/+$/, "");
|
|
145
|
+
try {
|
|
146
|
+
const u = new URL(getBaseUrl());
|
|
147
|
+
const vPort = (parseInt(u.port || "3111", 10) || 3111) + 2;
|
|
148
|
+
return `${u.protocol}//${u.hostname}:${vPort}`;
|
|
149
|
+
} catch {
|
|
150
|
+
return `http://localhost:${getRestPort() + 2}`;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
121
153
|
async function isEngineRunning() {
|
|
122
154
|
try {
|
|
123
|
-
await fetch(
|
|
155
|
+
await fetch(`${getBaseUrl()}/`, { signal: AbortSignal.timeout(2e3) });
|
|
124
156
|
return true;
|
|
125
157
|
} catch {
|
|
126
158
|
return false;
|
|
127
159
|
}
|
|
128
160
|
}
|
|
161
|
+
async function isAgentmemoryReady() {
|
|
162
|
+
try {
|
|
163
|
+
return (await fetch(`${getBaseUrl()}/agentmemory/livez`, { signal: AbortSignal.timeout(2e3) })).ok;
|
|
164
|
+
} catch {
|
|
165
|
+
return false;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
129
168
|
function findIiiConfig() {
|
|
130
169
|
const candidates = [
|
|
131
170
|
join(__dirname, "iii-config.yaml"),
|
|
@@ -287,12 +326,12 @@ async function main() {
|
|
|
287
326
|
p.intro("agentmemory");
|
|
288
327
|
if (skipEngine) {
|
|
289
328
|
p.log.info("Skipping engine check (--no-engine)");
|
|
290
|
-
await import("./src-
|
|
329
|
+
await import("./src-3Snd7D3T.mjs");
|
|
291
330
|
return;
|
|
292
331
|
}
|
|
293
332
|
if (await isEngineRunning()) {
|
|
294
333
|
p.log.success("iii-engine is running");
|
|
295
|
-
await import("./src-
|
|
334
|
+
await import("./src-3Snd7D3T.mjs");
|
|
296
335
|
return;
|
|
297
336
|
}
|
|
298
337
|
if (!await startEngine()) {
|
|
@@ -336,30 +375,38 @@ async function main() {
|
|
|
336
375
|
process.exit(1);
|
|
337
376
|
}
|
|
338
377
|
s.stop("iii-engine is ready");
|
|
339
|
-
await import("./src-
|
|
378
|
+
await import("./src-3Snd7D3T.mjs");
|
|
379
|
+
}
|
|
380
|
+
async function apiFetch(base, path, timeoutMs = 5e3) {
|
|
381
|
+
try {
|
|
382
|
+
return await (await fetch(`${base}/agentmemory/${path}`, { signal: AbortSignal.timeout(timeoutMs) })).json();
|
|
383
|
+
} catch {
|
|
384
|
+
return null;
|
|
385
|
+
}
|
|
340
386
|
}
|
|
341
387
|
async function runStatus() {
|
|
342
|
-
|
|
343
|
-
const base =
|
|
388
|
+
getRestPort();
|
|
389
|
+
const base = getBaseUrl();
|
|
344
390
|
p.intro("agentmemory status");
|
|
345
391
|
if (!await isEngineRunning()) {
|
|
346
|
-
p.log.error(`Not running — no response
|
|
392
|
+
p.log.error(`Not running — no response at ${base}`);
|
|
347
393
|
p.log.info("Start with: npx @agentmemory/agentmemory");
|
|
348
394
|
process.exit(1);
|
|
349
395
|
}
|
|
350
396
|
try {
|
|
351
|
-
const [healthRes, sessionsRes, graphRes, memoriesRes] = await Promise.all([
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
397
|
+
const [healthRes, sessionsRes, graphRes, memoriesRes, flagsRes] = await Promise.all([
|
|
398
|
+
apiFetch(base, "health"),
|
|
399
|
+
apiFetch(base, "sessions"),
|
|
400
|
+
apiFetch(base, "graph/stats"),
|
|
401
|
+
apiFetch(base, "export"),
|
|
402
|
+
apiFetch(base, "config/flags")
|
|
356
403
|
]);
|
|
357
404
|
const h = healthRes?.health;
|
|
358
405
|
const status = healthRes?.status || "unknown";
|
|
359
406
|
const version = healthRes?.version || "?";
|
|
360
407
|
const sessions = Array.isArray(sessionsRes?.sessions) ? sessionsRes.sessions.length : 0;
|
|
361
|
-
const nodes = graphRes?.nodes
|
|
362
|
-
const edges = graphRes?.edges
|
|
408
|
+
const nodes = Number(graphRes?.totalNodes ?? graphRes?.nodes ?? graphRes?.nodeCount ?? 0);
|
|
409
|
+
const edges = Number(graphRes?.totalEdges ?? graphRes?.edges ?? graphRes?.edgeCount ?? 0);
|
|
363
410
|
const cb = healthRes?.circuitBreaker?.state || "closed";
|
|
364
411
|
const heapMB = h?.memory ? Math.round(h.memory.heapUsed / 1048576) : 0;
|
|
365
412
|
const uptime = h?.uptimeSeconds ? Math.round(h.uptimeSeconds) : 0;
|
|
@@ -369,7 +416,7 @@ async function runStatus() {
|
|
|
369
416
|
const estInjectedTokens = Math.min(obsCount, 50) * 38;
|
|
370
417
|
const tokensSaved = estFullTokens - estInjectedTokens;
|
|
371
418
|
const pctSaved = estFullTokens > 0 ? Math.round(tokensSaved / estFullTokens * 100) : 0;
|
|
372
|
-
p.log.success(`Connected — v${version}
|
|
419
|
+
p.log.success(`Connected — v${version} at ${base}`);
|
|
373
420
|
const lines = [
|
|
374
421
|
`Health: ${status === "healthy" ? "✓ healthy" : status}`,
|
|
375
422
|
`Sessions: ${sessions}`,
|
|
@@ -379,7 +426,7 @@ async function runStatus() {
|
|
|
379
426
|
`Circuit: ${cb}`,
|
|
380
427
|
`Heap: ${heapMB} MB`,
|
|
381
428
|
`Uptime: ${uptime}s`,
|
|
382
|
-
`Viewer:
|
|
429
|
+
`Viewer: ${getViewerUrl()}`
|
|
383
430
|
];
|
|
384
431
|
if (obsCount > 0) {
|
|
385
432
|
lines.push("");
|
|
@@ -387,12 +434,85 @@ async function runStatus() {
|
|
|
387
434
|
lines.push(` Full context: ~${estFullTokens.toLocaleString()} tokens`);
|
|
388
435
|
lines.push(` Injected: ~${estInjectedTokens.toLocaleString()} tokens`);
|
|
389
436
|
}
|
|
437
|
+
if (flagsRes) {
|
|
438
|
+
const provider = flagsRes.provider === "llm" ? "✓ llm" : "✗ noop (no key)";
|
|
439
|
+
const embed = flagsRes.embeddingProvider === "embeddings" ? "✓ embeddings" : "bm25-only";
|
|
440
|
+
const flagRows = (flagsRes.flags || []).map((f) => ` ${f.enabled ? "✓" : "✗"} ${f.key.padEnd(32)} ${f.label}`);
|
|
441
|
+
lines.push("");
|
|
442
|
+
lines.push(`Provider: ${provider}`);
|
|
443
|
+
lines.push(`Embeddings: ${embed}`);
|
|
444
|
+
lines.push(`Flags:`);
|
|
445
|
+
flagRows.forEach((r) => lines.push(r));
|
|
446
|
+
}
|
|
390
447
|
p.note(lines.join("\n"), "agentmemory");
|
|
391
448
|
} catch (err) {
|
|
392
449
|
p.log.error(err instanceof Error ? err.message : String(err));
|
|
393
450
|
process.exit(1);
|
|
394
451
|
}
|
|
395
452
|
}
|
|
453
|
+
function formatChecks(checks) {
|
|
454
|
+
return checks.map((c) => `${c.ok ? "✓" : "✗"} ${c.name}${c.hint ? `\n ${c.hint}` : ""}`).join("\n");
|
|
455
|
+
}
|
|
456
|
+
async function runDoctor() {
|
|
457
|
+
p.intro("agentmemory doctor");
|
|
458
|
+
const base = getBaseUrl();
|
|
459
|
+
const viewerUrl = getViewerUrl();
|
|
460
|
+
const checks = [];
|
|
461
|
+
const serverUp = await isEngineRunning();
|
|
462
|
+
checks.push({
|
|
463
|
+
name: "Server reachable",
|
|
464
|
+
ok: serverUp,
|
|
465
|
+
hint: serverUp ? void 0 : `Start with: npx @agentmemory/agentmemory (tried ${base})`
|
|
466
|
+
});
|
|
467
|
+
if (!serverUp) {
|
|
468
|
+
p.note(formatChecks(checks), "server unreachable");
|
|
469
|
+
process.exit(1);
|
|
470
|
+
}
|
|
471
|
+
const [health, flags, graph] = await Promise.all([
|
|
472
|
+
apiFetch(base, "health", 3e3),
|
|
473
|
+
apiFetch(base, "config/flags", 3e3),
|
|
474
|
+
apiFetch(base, "graph/stats", 3e3)
|
|
475
|
+
]);
|
|
476
|
+
const viewerUp = await fetch(viewerUrl, { signal: AbortSignal.timeout(2e3) }).then((r) => r.ok).catch(() => false);
|
|
477
|
+
const hasLlm = flags?.provider === "llm";
|
|
478
|
+
const hasEmbed = flags?.embeddingProvider === "embeddings";
|
|
479
|
+
const graphHas = Number(graph?.totalNodes ?? graph?.nodes ?? graph?.nodeCount ?? 0) > 0;
|
|
480
|
+
checks.push({
|
|
481
|
+
name: "Health status",
|
|
482
|
+
ok: health?.status === "healthy",
|
|
483
|
+
hint: health?.status === "healthy" ? void 0 : `Status: ${health?.status || "unknown"}`
|
|
484
|
+
}, {
|
|
485
|
+
name: "Viewer reachable",
|
|
486
|
+
ok: viewerUp,
|
|
487
|
+
hint: viewerUp ? void 0 : `${viewerUrl} not responding`
|
|
488
|
+
}, {
|
|
489
|
+
name: "LLM provider",
|
|
490
|
+
ok: hasLlm,
|
|
491
|
+
hint: hasLlm ? void 0 : "export ANTHROPIC_API_KEY=sk-ant-... (or GEMINI/OPENROUTER/MINIMAX) then restart"
|
|
492
|
+
}, {
|
|
493
|
+
name: "Embedding provider",
|
|
494
|
+
ok: hasEmbed,
|
|
495
|
+
hint: hasEmbed ? void 0 : "Running BM25-only. Add OPENAI_API_KEY / VOYAGE_API_KEY / COHERE_API_KEY / OLLAMA_HOST for semantic recall"
|
|
496
|
+
});
|
|
497
|
+
for (const f of flags?.flags || []) checks.push({
|
|
498
|
+
name: f.label,
|
|
499
|
+
ok: f.enabled,
|
|
500
|
+
hint: f.enabled ? void 0 : f.enableHow
|
|
501
|
+
});
|
|
502
|
+
checks.push({
|
|
503
|
+
name: "Knowledge graph populated",
|
|
504
|
+
ok: graphHas,
|
|
505
|
+
hint: graphHas ? void 0 : "Graph is empty. Run a session with GRAPH_EXTRACTION_ENABLED=true, or POST /agentmemory/graph/extract"
|
|
506
|
+
});
|
|
507
|
+
const passed = checks.filter((c) => c.ok).length;
|
|
508
|
+
const total = checks.length;
|
|
509
|
+
p.note(formatChecks(checks), `${passed}/${total} checks passing`);
|
|
510
|
+
if (passed === total) p.outro("✓ All checks passed. agentmemory is healthy.");
|
|
511
|
+
else {
|
|
512
|
+
p.outro(`${total - passed} issue(s) — follow hints above to fix.`);
|
|
513
|
+
process.exit(1);
|
|
514
|
+
}
|
|
515
|
+
}
|
|
396
516
|
function buildDemoSessions() {
|
|
397
517
|
return [
|
|
398
518
|
{
|
|
@@ -521,9 +641,9 @@ async function runDemo() {
|
|
|
521
641
|
const port = getRestPort();
|
|
522
642
|
const base = `http://localhost:${port}`;
|
|
523
643
|
p.intro("agentmemory demo");
|
|
524
|
-
if (!await
|
|
525
|
-
p.log.error(`
|
|
526
|
-
p.log.info("Start
|
|
644
|
+
if (!await isAgentmemoryReady()) {
|
|
645
|
+
p.log.error(`agentmemory worker not reachable on port ${port} (livez probe failed). Something may be on the port but it isn't serving /agentmemory/*.`);
|
|
646
|
+
p.log.info("Start it with: npx @agentmemory/agentmemory");
|
|
527
647
|
process.exit(1);
|
|
528
648
|
}
|
|
529
649
|
const demoProject = "/tmp/agentmemory-demo";
|
|
@@ -553,7 +673,7 @@ async function runDemo() {
|
|
|
553
673
|
`Notice: searching "database performance optimization"`,
|
|
554
674
|
`found the N+1 query fix — keyword matching can't do that.`,
|
|
555
675
|
"",
|
|
556
|
-
`Viewer:
|
|
676
|
+
`Viewer: ${getViewerUrl()}`,
|
|
557
677
|
`Clean up with: curl -X DELETE "${base}/agentmemory/sessions?project=${demoProject}"`
|
|
558
678
|
];
|
|
559
679
|
p.note(lines.join("\n"), "demo complete");
|
|
@@ -645,7 +765,7 @@ async function runUpgrade() {
|
|
|
645
765
|
].join("\n"), "agentmemory upgrade");
|
|
646
766
|
}
|
|
647
767
|
async function runMcp() {
|
|
648
|
-
await import("./standalone-
|
|
768
|
+
await import("./standalone-BG9uPsDK.mjs");
|
|
649
769
|
}
|
|
650
770
|
async function runImportJsonl() {
|
|
651
771
|
const pathArg = args.slice(1).filter((a) => !a.startsWith("-"))[0];
|
|
@@ -701,7 +821,7 @@ async function runImportJsonl() {
|
|
|
701
821
|
process.exit(1);
|
|
702
822
|
}
|
|
703
823
|
spinner.stop(`imported ${json.imported ?? 0} file(s), ${json.observations ?? 0} observation(s) across ${json.sessionIds?.length || 0} session(s)`);
|
|
704
|
-
if (json.sessionIds && json.sessionIds.length > 0) p.log.info(`View at
|
|
824
|
+
if (json.sessionIds && json.sessionIds.length > 0) p.log.info(`View at ${getViewerUrl()} → Replay tab`);
|
|
705
825
|
} catch (err) {
|
|
706
826
|
spinner.stop("failed");
|
|
707
827
|
if (err instanceof Error && err.name === "TimeoutError") p.log.error("import timed out after 2 minutes");
|
|
@@ -711,6 +831,7 @@ async function runImportJsonl() {
|
|
|
711
831
|
}
|
|
712
832
|
({
|
|
713
833
|
status: runStatus,
|
|
834
|
+
doctor: runDoctor,
|
|
714
835
|
demo: runDemo,
|
|
715
836
|
upgrade: runUpgrade,
|
|
716
837
|
mcp: runMcp,
|