Patches for the @mem0/openclaw-mem0 plugin (v1.0.11) to fix critical issues with agent-level memory isolation, run_id generation, and autoCapture after OpenClaw 5.3+ upgrade.
After upgrading OpenClaw to 5.3+, the @mem0/openclaw-mem0 plugin (v1.0.11) has three critical issues:
| Issue | Symptom | Impact |
|---|---|---|
| user_id not concatenated | user_id: jiaod instead of jiaod:agent:feishu-main |
All agents share the same memory namespace — no isolation |
| run_id missing | run_id: None |
Session-scoped memories cannot be filtered or expired |
| autoCapture broken | No memories auto-captured after conversation | Important facts from conversations are lost |
In OpenClaw 5.3+, the plugin's register() function is called multiple times per conversation. Each call creates a new closure with its own currentSessionId variable:
before_prompt_buildhook setscurrentSessionIdin Instance Amemory_addtool readscurrentSessionIdfrom Instance B — alwaysundefined
This means:
extractAgentId(currentSessionId)returnsundefined→ no agent isolationbuildAddOptions()has norun_idfallback →run_idisNoneautoCaptureinagent_endhook runs in a different instance → fails silently
The registerHooks() function is defined as a standalone function (not inside the register() closure). It directly references currentSessionId which causes ReferenceError: currentSessionId is not defined in the hook handler.
The agent_end hook (used for autoCapture) requires allowConversationAccess: true in the plugin configuration. Without it, the hook is blocked by OpenClaw's security model.
Added a module-level _globalSessionIdMap variable to share currentSessionId across all plugin instances:
// Module level (outside any function)
var _globalSessionIdMap = {};
// In setCurrentSessionId
setCurrentSessionId: (id) => {
currentSessionId = id;
_globalSessionIdMap["latest"] = id; // Write to global
},
// In getCurrentSessionId
getCurrentSessionId: () => currentSessionId || _globalSessionIdMap["latest"], // Fallback to globalReplaced all direct currentSessionId references inside registerHooks() with session.getCurrentSessionId():
// Before (causes ReferenceError)
const sessionId = ctx?.sessionKey ?? currentSessionId ?? void 0;
// After (works across instances)
const sessionId = ctx?.sessionKey ?? session.getCurrentSessionId() ?? void 0;Added getCurrentSessionId to the session object passed to registerHooks():
{
setCurrentSessionId: (id) => { currentSessionId = id; _globalSessionIdMap["latest"] = id; },
getCurrentSessionId: () => currentSessionId || _globalSessionIdMap["latest"],
getStateDir: () => pluginStateDir
}// In buildAddOptions, fallback chain
const fallbackSessionId = currentSessionId || _globalSessionIdMap["latest"];
if (fallbackSessionId) opts.run_id = fallbackSessionId;const _resolveUserId = (opts) => resolveUserId(cfg.userId, opts, currentSessionId || _globalSessionIdMap["latest"]);Each tool now auto-extracts agentId from currentSessionId when not explicitly provided:
// memory_add
const effectiveAgentId = p.agentId ?? extractAgentId(currentSessionId);
const uid = resolveUserId3({ agentId: effectiveAgentId, userId: p.userId });
// memory_search, memory_list, memory_delete
const effectiveAgentId = agentId ?? extractAgentId(getCurrentSessionId());
const uid = resolveUserId3({ agentId: effectiveAgentId, userId });Required in openclaw.json:
{
"plugins": {
"entries": {
"openclaw-mem0": {
"hooks": {
"allowConversationAccess": true
}
}
}
}
}| Field | Before | After |
|---|---|---|
user_id |
jiaod |
jiaod:agent:feishu-main |
run_id |
None |
agent:feishu-main:feishu:direct:ou_xxx |
autoCapture |
Not working | Working |
| Agent isolation | None | Per-agent namespace via user_id suffix |
# Backup original
cp ~/.openclaw/npm/node_modules/@mem0/openclaw-mem0/dist/index.js \
~/.openclaw/npm/node_modules/@mem0/openclaw-mem0/dist/index.js.bak
# Copy patched file
cp dist/index.js ~/.openclaw/npm/node_modules/@mem0/openclaw-mem0/dist/index.js
# Restart Gateway
systemctl --user restart openclaw-gateway.service# Create extensions directory
mkdir -p ~/.openclaw/extensions/openclaw-mem0/dist
# Copy patched file
cp dist/index.js ~/.openclaw/extensions/openclaw-mem0/dist/index.js
cp dist/openclaw.plugin.json ~/.openclaw/extensions/openclaw-mem0/dist/Note: The extensions path may take priority over the npm path depending on your OpenClaw version. Verify with
openclaw plugins list.
Ensure your ~/.openclaw/openclaw.json includes:
{
"plugins": {
"slots": {
"memory": "openclaw-mem0"
},
"entries": {
"openclaw-mem0": {
"enabled": true,
"hooks": {
"allowConversationAccess": true
}
}
},
"allow": [
"openclaw-mem0"
]
}
}See config/openclaw-mem0-example.json for a complete example.
Session Key: agent:feishu-main:feishu:direct:ou_xxx
│
▼
extractAgentId() → "feishu-main"
│
▼
agentUserId("jiaod", "feishu-main")
│
▼
user_id = "jiaod:agent:feishu-main"
Each agent gets a unique user_id namespace:
- Agent
feishu-main→jiaod:agent:feishu-main - Agent
custom-bot→jiaod:agent:custom-bot - Main agent (no suffix) →
jiaod
Mem0's search() and getAll() filter by user_id, so memories are naturally isolated per agent.
| Component | Version |
|---|---|
| OpenClaw | 4.26+ |
| @mem0/openclaw-mem0 | 1.0.11 |
| mem0ai (npm) | 3.0.1 |
| Qdrant | 1.x |
Note: Issues started after upgrading @mem0/openclaw-mem0 to the latest version on OpenClaw 4.26 (run_id missing, unable to read old data). Fixed in 5.2, broke again in 5.3, now fixed permanently.
This patch modifies the compiled
dist/index.jsfile. It will be overwritten when the@mem0/openclaw-mem0package is updated viaopenclaw plugins updateornpm update. Re-apply the patch after any upgrade, or use the extensions directory approach.
This patch is provided under the same license as the original @mem0/openclaw-mem0 plugin (Apache-2.0). The original plugin is copyright of mem0ai.