@nowledge/openclaw-nowledge-mem 0.8.26 → 0.8.30
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/CHANGELOG.md +27 -0
- package/README.md +13 -3
- package/SKILL.md +35 -2
- package/openclaw.plugin.json +15 -1
- package/package.json +5 -3
- package/src/hooks/capture.js +8 -1
- package/src/index.js +10 -0
- package/src/tools/status.js +118 -31
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,33 @@ All notable changes to the Nowledge Mem OpenClaw plugin will be documented in th
|
|
|
4
4
|
|
|
5
5
|
## Unreleased
|
|
6
6
|
|
|
7
|
+
## [0.8.30] - 2026-07-12
|
|
8
|
+
|
|
9
|
+
### Fixed
|
|
10
|
+
|
|
11
|
+
- Setup guidance now preserves existing OpenClaw tool policy while granting the complete plugin contract under restrictive profiles such as `coding`. It uses the plugin id in `tools.alsoAllow` (or an existing `tools.allow`) instead of fragile individual tool names.
|
|
12
|
+
- Setup now explicitly grants `plugins.entries.openclaw-nowledge-mem.hooks.allowConversationAccess=true`, which current OpenClaw releases require before non-bundled plugins can use `agent_end` as the thread-capture safety net.
|
|
13
|
+
- `nowledge_mem_status` now reports restricted tool profiles and blocked conversation hooks instead of claiming all tools and both capture paths are active.
|
|
14
|
+
|
|
15
|
+
## [0.8.29] - 2026-07-11
|
|
16
|
+
|
|
17
|
+
### Fixed
|
|
18
|
+
|
|
19
|
+
- Conversation capture now converts OpenClaw's numeric message timestamps to the textual timestamp format required by Mem. Automatic thread sync no longer stops while memory tools continue to work.
|
|
20
|
+
|
|
21
|
+
## [0.8.28] - 2026-07-08
|
|
22
|
+
|
|
23
|
+
### Improved
|
|
24
|
+
|
|
25
|
+
- `nowledge_mem_status` now checks OpenClaw's Mem HTTP thread-sync API separately from the `nmem` CLI. This makes session-capture issues visible when memory tools still work but conversation sync cannot reach `/threads`.
|
|
26
|
+
|
|
27
|
+
## [0.8.27] - 2026-06-26
|
|
28
|
+
|
|
29
|
+
### Fixed
|
|
30
|
+
|
|
31
|
+
- OpenClaw 2026.6.10+ now loads the plugin correctly. The plugin manifest declares all Nowledge Mem agent tools through `contracts.tools`, matching OpenClaw's newer tool-ownership contract and preventing startup failures such as `must declare contracts.tools before registering agent tools`.
|
|
32
|
+
- Thread sync, memory search, and `nowledge_mem_status` are available again after upgrading OpenClaw and restarting the gateway.
|
|
33
|
+
|
|
7
34
|
## [0.8.26] - 2026-06-10
|
|
8
35
|
|
|
9
36
|
### Fixed
|
package/README.md
CHANGED
|
@@ -17,7 +17,15 @@ This is not a flat note store. Nowledge Mem links related knowledge into a graph
|
|
|
17
17
|
openclaw plugins install clawhub:@nowledge/openclaw-nowledge-mem
|
|
18
18
|
```
|
|
19
19
|
|
|
20
|
-
OpenClaw's installer writes the install record, enables the plugin, and switches the `memory` slot to `openclaw-nowledge-mem`. On current OpenClaw builds, that same install flow may also set `plugins.slots.contextEngine` to `openclaw-nowledge-mem`. Plugin `0.8.18+` accepts that automatically as a compatibility alias
|
|
20
|
+
OpenClaw's installer writes the install record, enables the plugin, and switches the `memory` slot to `openclaw-nowledge-mem`. On current OpenClaw builds, that same install flow may also set `plugins.slots.contextEngine` to `openclaw-nowledge-mem`. Plugin `0.8.18+` accepts that automatically as a compatibility alias.
|
|
21
|
+
|
|
22
|
+
Grant the conversation hook used as the thread-sync safety net:
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
openclaw config set plugins.entries.openclaw-nowledge-mem.hooks.allowConversationAccess true --strict-json
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
If `openclaw config get tools` shows a restrictive profile such as `coding`, preserve its existing policy and add `openclaw-nowledge-mem` to `tools.alsoAllow`. If `tools.allow` already exists, add the plugin id there instead. The plugin id expands to all manifest-declared tools; do not list individual `nowledge_mem_*` names.
|
|
21
29
|
|
|
22
30
|
To update the plugin, re-run the ClawHub install with `--force`:
|
|
23
31
|
|
|
@@ -135,7 +143,7 @@ NMEM_SPACE="Research Agent"
|
|
|
135
143
|
|
|
136
144
|
Nowledge Mem's CLI-backed Working Memory, memory search/save, and the plugin's API-backed thread/feed fallbacks will then stay in that lane together. There is no second OpenClaw-only vault setting; the shared Mem boundary is still one hidden space key, but humans and agents should normally work with the space name instead.
|
|
137
145
|
|
|
138
|
-
For multi-agent orchestrators, set `NMEM_AGENT_ID=<agent-slug>` per spawned OpenClaw worker. Add `NMEM_SPACE` only when that run should override the AI Identity's default space. `NMEM_HOST_AGENT_ID` is for advanced
|
|
146
|
+
For multi-agent orchestrators, set `NMEM_AGENT_ID=<agent-slug>` per spawned OpenClaw worker. Add `NMEM_SPACE` only when that run should override the AI Identity's default space. `NMEM_HOST_AGENT_ID` is for advanced external aliases. Context Bundle will use the stable identity while keeping `source_app=openclaw` for provenance. Keep these as launcher environment variables instead of plugin config keys so OpenClaw's strict config validation remains stable.
|
|
139
147
|
|
|
140
148
|
Shared spaces, default retrieval, and agent guidance still live in Mem's own space profile. OpenClaw chooses the lane and preserves it across transports; it should not duplicate the profile semantics.
|
|
141
149
|
|
|
@@ -434,7 +442,7 @@ openclaw nowledge-mem status
|
|
|
434
442
|
|
|
435
443
|
## Configuration
|
|
436
444
|
|
|
437
|
-
|
|
445
|
+
The plugin defaults work for local Mem, and `openclaw plugins install` enables the plugin and selects the memory slot. Current OpenClaw releases still require one explicit conversation-hook grant for the `agent_end` capture fallback. Restrictive tool profiles also need the plugin id added to their effective allow policy; see Installation above.
|
|
438
446
|
|
|
439
447
|
To change settings, use the OpenClaw plugin settings UI. Changes take effect on restart.
|
|
440
448
|
|
|
@@ -556,6 +564,8 @@ All 10 plugin tools register automatically when the plugin loads. No tool-level
|
|
|
556
564
|
}
|
|
557
565
|
```
|
|
558
566
|
|
|
567
|
+
If OpenClaw logs `must declare contracts.tools before registering agent tools`, update the plugin to `0.8.27` or newer and restart OpenClaw. That error means a newer OpenClaw build is enforcing plugin tool ownership metadata before it accepts runtime tool registration.
|
|
568
|
+
|
|
559
569
|
**`corpusSupplement: true` is set, but startup still logs `corpus=false`**
|
|
560
570
|
|
|
561
571
|
Update to `0.8.15` or newer. Older builds could disable the plugin too early when `memory-core` owned the memory slot, which made supplement mode look unavailable even on new OpenClaw builds.
|
package/SKILL.md
CHANGED
|
@@ -129,6 +129,37 @@ Important facts:
|
|
|
129
129
|
|
|
130
130
|
Do not tell the user to hand-edit those settings unless they are using a manual/path setup.
|
|
131
131
|
|
|
132
|
+
### Step 3a — Grant the Runtime Capabilities the Plugin Uses
|
|
133
|
+
|
|
134
|
+
Current OpenClaw releases require an explicit grant before a non-bundled plugin
|
|
135
|
+
can read conversation content from `agent_end`. Set it after install:
|
|
136
|
+
|
|
137
|
+
```bash
|
|
138
|
+
openclaw config set plugins.entries.openclaw-nowledge-mem.hooks.allowConversationAccess true --strict-json
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
Then inspect the host's effective tool policy:
|
|
142
|
+
|
|
143
|
+
```bash
|
|
144
|
+
openclaw config get tools
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
- If `tools.allow` already exists, preserve that list and add
|
|
148
|
+
`openclaw-nowledge-mem` to it.
|
|
149
|
+
- Otherwise, when a restrictive profile such as `coding`, `messaging`, or
|
|
150
|
+
`minimal` is set, preserve `tools.alsoAllow` and add
|
|
151
|
+
`openclaw-nowledge-mem` to it.
|
|
152
|
+
- If no restrictive profile or allowlist exists, no tool-policy change is
|
|
153
|
+
needed.
|
|
154
|
+
- Never replace an existing list, and never add individual `nowledge_mem_*`
|
|
155
|
+
names. The plugin id expands to the complete manifest-declared tool contract.
|
|
156
|
+
|
|
157
|
+
Example for a `coding` profile with no prior `alsoAllow` entries:
|
|
158
|
+
|
|
159
|
+
```bash
|
|
160
|
+
openclaw config set tools.alsoAllow '["openclaw-nowledge-mem"]' --strict-json
|
|
161
|
+
```
|
|
162
|
+
|
|
132
163
|
### Step 4 — Configure Remote Only When Needed
|
|
133
164
|
|
|
134
165
|
Local mode:
|
|
@@ -189,7 +220,7 @@ First check the plugin status:
|
|
|
189
220
|
openclaw nowledge-mem status
|
|
190
221
|
```
|
|
191
222
|
|
|
192
|
-
If only `memory_search` and `memory_get` tools are available (other Nowledge Mem tools missing),
|
|
223
|
+
If only `memory_search` and `memory_get` tools are available (other Nowledge Mem tools missing), inspect `openclaw config get tools` first. A restrictive profile needs the plugin id in `tools.alsoAllow`, or in the existing `tools.allow` list. Then verify the memory slot in `~/.openclaw/openclaw.json`:
|
|
193
224
|
|
|
194
225
|
```json
|
|
195
226
|
{
|
|
@@ -253,7 +284,9 @@ What to expect:
|
|
|
253
284
|
| `plugins.allow is empty` warning | Add `openclaw-nowledge-mem` to `plugins.allow` if the user wants explicit trust |
|
|
254
285
|
| Remote config seems ignored | Check whether `~/.nowledge-mem/openclaw.json` is overriding plugin settings |
|
|
255
286
|
| Local mode unexpectedly talks to a remote server | Check for stale `NMEM_API_URL` / `NMEM_API_KEY` in the environment or an overriding `~/.nowledge-mem/openclaw.json` |
|
|
256
|
-
| Plugin tools missing |
|
|
287
|
+
| Plugin tools missing | Inspect `openclaw config get tools`. Under a restrictive profile, preserve `tools.alsoAllow` and add `openclaw-nowledge-mem`; if `tools.allow` already exists, add the plugin id there instead. Do not add individual `nowledge_mem_*` names. Also ensure the plugin is trusted in `plugins.allow`. |
|
|
288
|
+
| Memory tools work but Threads do not sync | Update to `0.8.30+`, set `plugins.entries.openclaw-nowledge-mem.hooks.allowConversationAccess=true`, restart the gateway, and verify with `nmem t list --source openclaw -n 20`. |
|
|
289
|
+
| `must declare contracts.tools before registering agent tools` | Update the plugin to `0.8.27+` and restart OpenClaw. Newer OpenClaw builds require plugin authors to declare tool ownership in the manifest before runtime tool registration. |
|
|
257
290
|
|
|
258
291
|
## Notes for Agents
|
|
259
292
|
|
package/openclaw.plugin.json
CHANGED
|
@@ -2,8 +2,22 @@
|
|
|
2
2
|
"id": "openclaw-nowledge-mem",
|
|
3
3
|
"name": "Nowledge Mem",
|
|
4
4
|
"description": "Cross-tool knowledge graph memory for OpenClaw with startup context, graph search, and session distillation.",
|
|
5
|
-
"version": "0.8.
|
|
5
|
+
"version": "0.8.30",
|
|
6
6
|
"kind": ["memory", "context-engine"],
|
|
7
|
+
"contracts": {
|
|
8
|
+
"tools": [
|
|
9
|
+
"memory_search",
|
|
10
|
+
"memory_get",
|
|
11
|
+
"nowledge_mem_save",
|
|
12
|
+
"nowledge_mem_context",
|
|
13
|
+
"nowledge_mem_connections",
|
|
14
|
+
"nowledge_mem_timeline",
|
|
15
|
+
"nowledge_mem_forget",
|
|
16
|
+
"nowledge_mem_thread_search",
|
|
17
|
+
"nowledge_mem_thread_fetch",
|
|
18
|
+
"nowledge_mem_status"
|
|
19
|
+
]
|
|
20
|
+
},
|
|
7
21
|
"skills": [
|
|
8
22
|
"skills/memory-guide"
|
|
9
23
|
],
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nowledge/openclaw-nowledge-mem",
|
|
3
3
|
"displayName": "Nowledge Mem for OpenClaw",
|
|
4
|
-
"version": "0.8.
|
|
4
|
+
"version": "0.8.30",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"description": "Nowledge Mem memory plugin for OpenClaw, local-first personal knowledge base",
|
|
7
7
|
"author": {
|
|
@@ -29,13 +29,15 @@
|
|
|
29
29
|
"./src/index.js"
|
|
30
30
|
],
|
|
31
31
|
"install": {
|
|
32
|
-
"
|
|
32
|
+
"clawhubSpec": "clawhub:@nowledge/openclaw-nowledge-mem",
|
|
33
|
+
"npmSpec": "@nowledge/openclaw-nowledge-mem",
|
|
34
|
+
"defaultChoice": "clawhub"
|
|
33
35
|
},
|
|
34
36
|
"compat": {
|
|
35
37
|
"pluginApi": ">=2026.5.3"
|
|
36
38
|
},
|
|
37
39
|
"build": {
|
|
38
|
-
"openclawVersion": "2026.
|
|
40
|
+
"openclawVersion": "2026.6.10"
|
|
39
41
|
},
|
|
40
42
|
"release": {
|
|
41
43
|
"publishToClawHub": true,
|
package/src/hooks/capture.js
CHANGED
|
@@ -246,8 +246,15 @@ export function normalizeRoleMessage(
|
|
|
246
246
|
if (role === "user" && text.startsWith("/")) return null;
|
|
247
247
|
|
|
248
248
|
let timestamp;
|
|
249
|
-
if (typeof msg.timestamp === "string"
|
|
249
|
+
if (typeof msg.timestamp === "string") {
|
|
250
250
|
timestamp = msg.timestamp;
|
|
251
|
+
} else if (
|
|
252
|
+
typeof msg.timestamp === "number" &&
|
|
253
|
+
Number.isFinite(msg.timestamp)
|
|
254
|
+
) {
|
|
255
|
+
// OpenClaw emits epoch milliseconds, while Mem's thread API deliberately
|
|
256
|
+
// accepts textual timestamps so every connector shares one wire contract.
|
|
257
|
+
timestamp = new Date(msg.timestamp).toISOString();
|
|
251
258
|
}
|
|
252
259
|
|
|
253
260
|
const openclawMeta =
|
package/src/index.js
CHANGED
|
@@ -78,6 +78,12 @@ export default {
|
|
|
78
78
|
// - memory/context-engine slot routing for capture and recall
|
|
79
79
|
const contextEngineSlot = api.config?.plugins?.slots?.contextEngine;
|
|
80
80
|
const pluginsAllow = api.config?.plugins?.allow;
|
|
81
|
+
const pluginEntry = api.config?.plugins?.entries?.[api.id];
|
|
82
|
+
const toolsProfile = api.config?.tools?.profile;
|
|
83
|
+
const toolsAllow = api.config?.tools?.allow;
|
|
84
|
+
const toolsAlsoAllow = api.config?.tools?.alsoAllow;
|
|
85
|
+
const allowConversationAccess =
|
|
86
|
+
pluginEntry?.hooks?.allowConversationAccess === true;
|
|
81
87
|
let contextEngineRegistered = false;
|
|
82
88
|
let contextEngineRegistrationError = null;
|
|
83
89
|
let corpusSupplementActive = false;
|
|
@@ -140,6 +146,10 @@ export default {
|
|
|
140
146
|
contextEngineSlot,
|
|
141
147
|
contextEngineIds: NOWLEDGE_MEM_CONTEXT_ENGINE_IDS,
|
|
142
148
|
pluginsAllow,
|
|
149
|
+
toolsProfile,
|
|
150
|
+
toolsAllow,
|
|
151
|
+
toolsAlsoAllow,
|
|
152
|
+
allowConversationAccess,
|
|
143
153
|
contextEngineRegistered,
|
|
144
154
|
contextEngineRegistrationError,
|
|
145
155
|
corpusSupplementActive,
|
package/src/tools/status.js
CHANGED
|
@@ -27,10 +27,10 @@ export function createStatusTool(client, _logger, cfg, runtimeInfo = {}) {
|
|
|
27
27
|
const lines = [];
|
|
28
28
|
const details = {};
|
|
29
29
|
const sources = cfg._sources || {};
|
|
30
|
+
const pluginId = "openclaw-nowledge-mem";
|
|
30
31
|
|
|
31
32
|
// 0a. Plugin trust check — detect missing plugins.allow
|
|
32
33
|
const pluginsAllow = runtimeInfo.pluginsAllow;
|
|
33
|
-
const pluginId = "openclaw-nowledge-mem";
|
|
34
34
|
details.pluginsAllow = !Array.isArray(pluginsAllow)
|
|
35
35
|
? "(not set)"
|
|
36
36
|
: pluginsAllow.includes(pluginId)
|
|
@@ -64,7 +64,48 @@ export function createStatusTool(client, _logger, cfg, runtimeInfo = {}) {
|
|
|
64
64
|
lines.push(`Plugin trust: ${pluginId} (allowlisted)`);
|
|
65
65
|
}
|
|
66
66
|
|
|
67
|
-
// 0b.
|
|
67
|
+
// 0b. Effective tool policy. OpenClaw profiles are restrictive; the
|
|
68
|
+
// plugin id expands to this plugin's declared tool contract.
|
|
69
|
+
const toolsProfile = runtimeInfo.toolsProfile;
|
|
70
|
+
const toolsAllow = Array.isArray(runtimeInfo.toolsAllow)
|
|
71
|
+
? runtimeInfo.toolsAllow
|
|
72
|
+
: null;
|
|
73
|
+
const toolsAlsoAllow = Array.isArray(runtimeInfo.toolsAlsoAllow)
|
|
74
|
+
? runtimeInfo.toolsAlsoAllow
|
|
75
|
+
: null;
|
|
76
|
+
const profileRestrictsPlugins =
|
|
77
|
+
typeof toolsProfile === "string" && toolsProfile !== "full";
|
|
78
|
+
const pluginExplicitlyAllowed =
|
|
79
|
+
toolsAllow?.includes(pluginId) || toolsAlsoAllow?.includes(pluginId);
|
|
80
|
+
const toolPolicyBlocksPlugin =
|
|
81
|
+
(toolsAllow !== null && !toolsAllow.includes(pluginId)) ||
|
|
82
|
+
(profileRestrictsPlugins && !pluginExplicitlyAllowed);
|
|
83
|
+
details.toolsProfile = toolsProfile ?? "(not set)";
|
|
84
|
+
details.pluginToolsAllowed = !toolPolicyBlocksPlugin;
|
|
85
|
+
if (toolPolicyBlocksPlugin) {
|
|
86
|
+
lines.push(
|
|
87
|
+
`⚠ Tool policy does not expose the complete ${pluginId} tool contract.`,
|
|
88
|
+
);
|
|
89
|
+
if (toolsAllow !== null) {
|
|
90
|
+
lines.push(
|
|
91
|
+
` Fix: preserve tools.allow and add "${pluginId}" to that list.`,
|
|
92
|
+
);
|
|
93
|
+
} else {
|
|
94
|
+
lines.push(
|
|
95
|
+
` Fix: preserve tools.alsoAllow and add "${pluginId}" to that list.`,
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
lines.push(
|
|
99
|
+
" Do not list individual nowledge_mem_* tools; use the plugin id so the manifest contract stays complete.",
|
|
100
|
+
);
|
|
101
|
+
lines.push("");
|
|
102
|
+
} else if (toolsProfile) {
|
|
103
|
+
lines.push(
|
|
104
|
+
`Tool policy: ${toolsProfile} profile + ${pluginId} (complete contract allowed)`,
|
|
105
|
+
);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// 0c. Memory slot check — show current mode and options
|
|
68
109
|
const memorySlot = runtimeInfo.memorySlot;
|
|
69
110
|
const contextEngineSlot = runtimeInfo.contextEngineSlot;
|
|
70
111
|
const contextEngineRegistered =
|
|
@@ -135,14 +176,20 @@ export function createStatusTool(client, _logger, cfg, runtimeInfo = {}) {
|
|
|
135
176
|
lines.push("Memory slot: openclaw-nowledge-mem (active)");
|
|
136
177
|
}
|
|
137
178
|
|
|
138
|
-
//
|
|
179
|
+
// 0d. Capture routing — hooks vs context engine
|
|
139
180
|
const ceActive =
|
|
140
181
|
isNowledgeMemContextEngineSlot(ceSlot) && contextEngineRegistered;
|
|
182
|
+
const hookCaptureAllowed = runtimeInfo.allowConversationAccess === true;
|
|
183
|
+
details.allowConversationAccess = hookCaptureAllowed;
|
|
141
184
|
const captureMode = !cfg.sessionDigest
|
|
142
185
|
? "disabled"
|
|
143
186
|
: ceActive
|
|
144
|
-
?
|
|
145
|
-
|
|
187
|
+
? hookCaptureAllowed
|
|
188
|
+
? "context-engine+hooks"
|
|
189
|
+
: "context-engine"
|
|
190
|
+
: hookCaptureAllowed
|
|
191
|
+
? "hooks"
|
|
192
|
+
: "blocked";
|
|
146
193
|
details.captureMode = captureMode;
|
|
147
194
|
if (ceActive) {
|
|
148
195
|
if (ceSlot === NOWLEDGE_MEM_CONTEXT_ENGINE_COMPAT_ALIAS) {
|
|
@@ -158,7 +205,9 @@ export function createStatusTool(client, _logger, cfg, runtimeInfo = {}) {
|
|
|
158
205
|
);
|
|
159
206
|
}
|
|
160
207
|
lines.push(
|
|
161
|
-
|
|
208
|
+
hookCaptureAllowed
|
|
209
|
+
? " Thread capture runs through Context Engine afterTurn with hook fallback (agent_end, after_compaction, before_reset)."
|
|
210
|
+
: " Thread capture runs through Context Engine afterTurn; the agent_end fallback is blocked by OpenClaw policy.",
|
|
162
211
|
);
|
|
163
212
|
} else if (isNowledgeMemContextEngineSlot(ceSlot)) {
|
|
164
213
|
if (ceSlot === NOWLEDGE_MEM_CONTEXT_ENGINE_COMPAT_ALIAS) {
|
|
@@ -194,6 +243,14 @@ export function createStatusTool(client, _logger, cfg, runtimeInfo = {}) {
|
|
|
194
243
|
if (!cfg.sessionDigest) {
|
|
195
244
|
lines.push("Thread capture: disabled (sessionDigest=false)");
|
|
196
245
|
} else {
|
|
246
|
+
if (!hookCaptureAllowed) {
|
|
247
|
+
lines.push(
|
|
248
|
+
"⚠ Hook fallback blocked: set plugins.entries.openclaw-nowledge-mem.hooks.allowConversationAccess=true.",
|
|
249
|
+
);
|
|
250
|
+
lines.push(
|
|
251
|
+
" OpenClaw requires this explicit grant before a non-bundled plugin can read agent_end conversation content.",
|
|
252
|
+
);
|
|
253
|
+
}
|
|
197
254
|
lines.push(
|
|
198
255
|
" Thread identity follows OpenClaw session lifecycle: /new or /reset starts a fresh thread, while compaction stays in the same thread.",
|
|
199
256
|
);
|
|
@@ -228,38 +285,68 @@ export function createStatusTool(client, _logger, cfg, runtimeInfo = {}) {
|
|
|
228
285
|
lines.push("CLI: not found (install with: pip install nmem-cli)");
|
|
229
286
|
}
|
|
230
287
|
|
|
231
|
-
// 3. Backend health
|
|
232
|
-
|
|
288
|
+
// 3. Backend health. Memory tools and thread capture travel through
|
|
289
|
+
// different surfaces: most reads/writes use the nmem CLI, while thread
|
|
290
|
+
// auto-sync writes directly to the HTTP API so large transcripts do not
|
|
291
|
+
// become argv-sized blobs. Report them separately; otherwise `nmem status`
|
|
292
|
+
// can produce a false green for users whose conversation capture is broken.
|
|
293
|
+
let cliHealthy = false;
|
|
233
294
|
try {
|
|
234
|
-
|
|
295
|
+
cliHealthy = await client.checkHealth();
|
|
235
296
|
} catch {
|
|
236
297
|
// checkHealth already returns false on error
|
|
237
298
|
}
|
|
238
|
-
details.
|
|
299
|
+
details.cliBackendReachable = cliHealthy;
|
|
239
300
|
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
301
|
+
lines.push(`CLI backend: ${cliHealthy ? "reachable" : "not reachable"}`);
|
|
302
|
+
|
|
303
|
+
let httpHealthy = false;
|
|
304
|
+
try {
|
|
305
|
+
const health = await client.apiJson("GET", "/health", undefined, 5000);
|
|
306
|
+
httpHealthy = true;
|
|
307
|
+
if (health.version) {
|
|
308
|
+
details.version = health.version;
|
|
309
|
+
lines.push(`Version: ${health.version}`);
|
|
310
|
+
}
|
|
311
|
+
if (health.database_connected !== undefined) {
|
|
312
|
+
details.databaseConnected = health.database_connected;
|
|
313
|
+
lines.push(
|
|
314
|
+
`Database: ${health.database_connected ? "connected" : "disconnected"}`,
|
|
249
315
|
);
|
|
250
|
-
if (health.version) {
|
|
251
|
-
details.version = health.version;
|
|
252
|
-
lines.push(`Version: ${health.version}`);
|
|
253
|
-
}
|
|
254
|
-
if (health.database_connected !== undefined) {
|
|
255
|
-
details.databaseConnected = health.database_connected;
|
|
256
|
-
lines.push(
|
|
257
|
-
`Database: ${health.database_connected ? "connected" : "disconnected"}`,
|
|
258
|
-
);
|
|
259
|
-
}
|
|
260
|
-
} catch {
|
|
261
|
-
// Health endpoint not available on older backends
|
|
262
316
|
}
|
|
317
|
+
} catch (err) {
|
|
318
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
319
|
+
details.httpHealthError = message;
|
|
320
|
+
}
|
|
321
|
+
details.httpBackendReachable = httpHealthy;
|
|
322
|
+
|
|
323
|
+
let threadApiHealthy = false;
|
|
324
|
+
try {
|
|
325
|
+
await client.apiJson("GET", "/threads/sources", undefined, 5000);
|
|
326
|
+
threadApiHealthy = true;
|
|
327
|
+
} catch (err) {
|
|
328
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
329
|
+
details.threadSyncHttpError = message;
|
|
330
|
+
}
|
|
331
|
+
details.threadSyncHttpReachable = threadApiHealthy;
|
|
332
|
+
details.healthy = cliHealthy && threadApiHealthy;
|
|
333
|
+
|
|
334
|
+
if (threadApiHealthy) {
|
|
335
|
+
lines.push("Thread sync HTTP API: reachable");
|
|
336
|
+
} else {
|
|
337
|
+
lines.push("Thread sync HTTP API: not reachable");
|
|
338
|
+
lines.push(
|
|
339
|
+
" Conversation capture writes to the Mem HTTP API. It will not sync while this is unreachable, even if memory tools still work through the CLI.",
|
|
340
|
+
);
|
|
341
|
+
if (details.threadSyncHttpError) {
|
|
342
|
+
lines.push(` Detail: ${details.threadSyncHttpError}`);
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
if (cliHealthy && threadApiHealthy) {
|
|
347
|
+
lines.push("Backend: reachable");
|
|
348
|
+
} else if (cliHealthy || threadApiHealthy || httpHealthy) {
|
|
349
|
+
lines.push("Backend: partially reachable");
|
|
263
350
|
} else {
|
|
264
351
|
lines.push("Backend: not reachable");
|
|
265
352
|
if (remote) {
|