@mem9/mem9 0.4.8-alpha.0 → 0.4.9
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 +16 -3
- package/hooks.ts +12 -6
- package/index.test.ts +21 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -31,6 +31,9 @@ Add mem9 to your project's `openclaw.json`:
|
|
|
31
31
|
"entries": {
|
|
32
32
|
"mem9": {
|
|
33
33
|
"enabled": true,
|
|
34
|
+
"hooks": {
|
|
35
|
+
"allowConversationAccess": true
|
|
36
|
+
},
|
|
34
37
|
"config": {
|
|
35
38
|
"apiUrl": "http://localhost:8080",
|
|
36
39
|
"apiKey": "uuid",
|
|
@@ -146,6 +149,9 @@ Each agent uses the same `apiKey` for the shared memory pool. The plugin sends t
|
|
|
146
149
|
"entries": {
|
|
147
150
|
"mem9": {
|
|
148
151
|
"enabled": true,
|
|
152
|
+
"hooks": {
|
|
153
|
+
"allowConversationAccess": true
|
|
154
|
+
},
|
|
149
155
|
"config": {
|
|
150
156
|
"apiUrl": "http://your-server:8080",
|
|
151
157
|
"apiKey": "uuid"
|
|
@@ -156,7 +162,7 @@ Each agent uses the same `apiKey` for the shared memory pool. The plugin sends t
|
|
|
156
162
|
}
|
|
157
163
|
```
|
|
158
164
|
|
|
159
|
-
That's it. The server handles scoping and conflict resolution. Conceptually, the
|
|
165
|
+
That's it. The server handles scoping and conflict resolution. Conceptually, the required mem9 credential values are `apiUrl` + `apiKey`; OpenClaw 4.23+ also needs the entry-level hook permission shown above for automatic conversation upload.
|
|
160
166
|
|
|
161
167
|
### Verify
|
|
162
168
|
|
|
@@ -184,7 +190,9 @@ Defined in `openclaw.plugin.json`:
|
|
|
184
190
|
| `debugRecall` | boolean | Deprecated alias for `debug` |
|
|
185
191
|
| `tenantID` | string | Legacy alias for `apiKey`. The plugin still uses `/v1alpha2/mem9s/...` with `X-API-Key`. |
|
|
186
192
|
|
|
187
|
-
> **Note**: `apiKey` takes precedence when both fields are set. If only `tenantID` is present, the plugin treats it as a legacy alias for `apiKey`, still uses v1alpha2, and logs a deprecation warning once at startup. `provisionToken` and `provisionQueryParams` are ignored after an `apiKey` is already configured, and non-`utm_*` keys are dropped before the provision request is sent. During create-new onboarding, the plugin shares one in-flight provision result across concurrent local registrations and reuses the persisted result for the same `provisionToken`, so repeated reloads or repeated setup retries do not create multiple keys.
|
|
193
|
+
> **Note**: `apiKey` takes precedence when both fields are set. If only `tenantID` is present, the plugin treats it as a legacy alias for `apiKey`, still uses v1alpha2, and logs a deprecation warning once at startup. `provisionToken` and `provisionQueryParams` are ignored after an `apiKey` is already configured, and non-`utm_*` keys are dropped before the provision request is sent. During create-new onboarding, the plugin shares one in-flight provision result across concurrent local registrations and reuses the persisted result for the same `provisionToken`, so repeated reloads or repeated setup retries do not create multiple keys. The only valid secret path is `plugins.entries.mem9.config.apiKey`; `plugins.entries.mem9.apiKey` at the entry top level is invalid on OpenClaw and prevents the gateway from loading.
|
|
194
|
+
|
|
195
|
+
OpenClaw 4.23+ / 2026.4.22+ requires the entry-level hook policy `plugins.entries.mem9.hooks.allowConversationAccess = true` for `agent_end` to include conversation messages. Without it, mem9 can still load, but automatic conversation upload cannot read the conversation to ingest it. This is an OpenClaw plugin-entry permission, not a mem9 `config` field. Older OpenClaw builds that reject this hook policy should omit the `hooks` block and upgrade for full automatic conversation upload.
|
|
188
196
|
|
|
189
197
|
For debugging, set `"debug": true` in the plugin config. The plugin will emit `[mem9][debug]` lines; current coverage shows how `before_prompt_build` stripped OpenClaw metadata wrappers before issuing the recall search. `"debugRecall": true` still works as a deprecated alias.
|
|
190
198
|
|
|
@@ -201,8 +209,11 @@ Example:
|
|
|
201
209
|
{
|
|
202
210
|
"plugins": {
|
|
203
211
|
"entries": {
|
|
204
|
-
"
|
|
212
|
+
"mem9": {
|
|
205
213
|
"enabled": true,
|
|
214
|
+
"hooks": {
|
|
215
|
+
"allowConversationAccess": true
|
|
216
|
+
},
|
|
206
217
|
"config": {
|
|
207
218
|
"apiUrl": "http://your-server:8080",
|
|
208
219
|
"apiKey": "uuid",
|
|
@@ -235,6 +246,8 @@ openclaw-plugin/
|
|
|
235
246
|
|---|---|---|
|
|
236
247
|
| `No mode configured` | Missing config | Add `apiUrl` and `apiKey` (or legacy `tenantID`) to plugin config |
|
|
237
248
|
| `Server mode requires...` | Missing key | Add `apiKey` (or legacy `tenantID`) to config |
|
|
249
|
+
| `config reload skipped (invalid config): plugins.entries.mem9: Unrecognized key: "apiKey"` | Setup wrote `plugins.entries.mem9.apiKey` instead of `plugins.entries.mem9.config.apiKey` | Remove the invalid top-level key and keep the secret only under `config.apiKey` |
|
|
238
250
|
| Multiple auto-provisioned keys appear during create-new | Setup retriggered create-new provisioning before the first result was reused, or an older plugin still auto-provisions on startup | Upgrade to `@mem9/mem9@0.4.7+`; newer builds provision only from the first post-restart user message and reuse one local result across duplicate setup retries |
|
|
239
251
|
| Search requests time out | Hybrid/vector search exceeds plugin timeout | Increase `searchTimeoutMs` in plugin config |
|
|
252
|
+
| Conversations are not uploaded on OpenClaw 4.23+ | `agent_end` does not include conversation messages without explicit hook permission | Set `plugins.entries.mem9.hooks.allowConversationAccess` to `true` and restart OpenClaw |
|
|
240
253
|
| Plugin not loading | Not in memory slot | Set `"slots": {"memory": "mem9"}` in openclaw.json |
|
package/hooks.ts
CHANGED
|
@@ -212,6 +212,7 @@ export function registerHooks(
|
|
|
212
212
|
},
|
|
213
213
|
): void {
|
|
214
214
|
const maxIngestBytes = options?.maxIngestBytes ?? DEFAULT_MAX_INGEST_BYTES;
|
|
215
|
+
let loggedMissingConversationAccess = false;
|
|
215
216
|
|
|
216
217
|
// --------------------------------------------------------------------------
|
|
217
218
|
// before_prompt_build — inject relevant memories into every LLM call
|
|
@@ -335,7 +336,17 @@ export function registerHooks(
|
|
|
335
336
|
agentId?: string;
|
|
336
337
|
};
|
|
337
338
|
const hookCtx = (context ?? {}) as HookContext;
|
|
338
|
-
if (!evt?.success
|
|
339
|
+
if (!evt?.success) return;
|
|
340
|
+
if (!Array.isArray(evt.messages)) {
|
|
341
|
+
if (!loggedMissingConversationAccess) {
|
|
342
|
+
logger.info(
|
|
343
|
+
"[mem9] agent_end conversation messages are unavailable; on OpenClaw 4.23+ / 2026.4.22+ set plugins.entries.mem9.hooks.allowConversationAccess=true to enable automatic conversation upload",
|
|
344
|
+
);
|
|
345
|
+
loggedMissingConversationAccess = true;
|
|
346
|
+
}
|
|
347
|
+
return;
|
|
348
|
+
}
|
|
349
|
+
if (evt.messages.length === 0) return;
|
|
339
350
|
|
|
340
351
|
// Skip cron/heartbeat-triggered runs — they produce low-value messages
|
|
341
352
|
if (hookCtx.trigger === "cron" || hookCtx.trigger === "heartbeat") {
|
|
@@ -351,11 +362,6 @@ export function registerHooks(
|
|
|
351
362
|
const role = typeof m.role === "string" ? m.role : "";
|
|
352
363
|
if (!role) continue;
|
|
353
364
|
|
|
354
|
-
// Skip cron tool results — structured JSON job definitions with no memory value
|
|
355
|
-
if (role === "toolResult" && typeof m.toolName === "string" && m.toolName === "cron") {
|
|
356
|
-
continue;
|
|
357
|
-
}
|
|
358
|
-
|
|
359
365
|
let content = "";
|
|
360
366
|
if (typeof m.content === "string") {
|
|
361
367
|
content = m.content;
|
package/index.test.ts
CHANGED
|
@@ -479,6 +479,27 @@ test("debugRecall still works as a deprecated alias for debug", async () => {
|
|
|
479
479
|
}
|
|
480
480
|
});
|
|
481
481
|
|
|
482
|
+
test("agent_end logs conversation-access diagnostic once when messages are unavailable", async () => {
|
|
483
|
+
const infoLogs: string[] = [];
|
|
484
|
+
const api = createStubApi(
|
|
485
|
+
{
|
|
486
|
+
apiUrl: uniqueApiUrl("agent-end-no-messages"),
|
|
487
|
+
apiKey: "space-agent-end-no-messages",
|
|
488
|
+
},
|
|
489
|
+
{ infoLogs },
|
|
490
|
+
);
|
|
491
|
+
mnemoPlugin.register(api);
|
|
492
|
+
|
|
493
|
+
const agentEnd = api.getHook("agent_end");
|
|
494
|
+
await agentEnd({ success: true });
|
|
495
|
+
await agentEnd({ success: true });
|
|
496
|
+
|
|
497
|
+
assert.equal(
|
|
498
|
+
infoLogs.filter((line) => line.includes("allowConversationAccess=true")).length,
|
|
499
|
+
1,
|
|
500
|
+
);
|
|
501
|
+
});
|
|
502
|
+
|
|
482
503
|
test("first post-restart prompt provisions once and unlocks memory access", async () => {
|
|
483
504
|
const originalFetch = globalThis.fetch;
|
|
484
505
|
const apiUrl = uniqueApiUrl("explicit-provision");
|
package/package.json
CHANGED