Skip to content

feat(openclaw): add per-agent memory isolation for multi-agent setups#4245

Merged
deshraj merged 2 commits intomainfrom
feat/agent-memories
Mar 9, 2026
Merged

feat(openclaw): add per-agent memory isolation for multi-agent setups#4245
deshraj merged 2 commits intomainfrom
feat/agent-memories

Conversation

@utkarsh240799
Copy link
Copy Markdown
Contributor

@utkarsh240799 utkarsh240799 commented Mar 7, 2026

Summary

Adds automatic per-agent memory namespace isolation for OpenClaw multi-agent setups. Each agent gets its own memory namespace derived from the session key, ensuring no cross-contamination between agents while maintaining full backward compatibility for single-agent users.

Problem

The current plugin treats all agents as a single user — every agent reads and writes to the same userId namespace. In multi-agent setups (e.g. researcher + coder + planner), this means:

  • Agents see each other's memories, causing confusion and irrelevant context
  • No way to query or manage a specific agent's memories
  • Tools (memory_search, memory_store, etc.) have no awareness of which agent is calling them

Solution

Per-agent namespace isolation

Session keys follow the pattern agent:<agentId>:<uuid>. Four helper functions parse and route to collision-safe namespaces:

Session key: "agent:researcher:abc-123"
→ extractAgentId() → "researcher"
→ effectiveUserId() → "utkarsh:agent:researcher"

Session key: undefined | "plain-uuid" | "agent:main:abc-123"
→ extractAgentId() → undefined
→ effectiveUserId() → "utkarsh" (unchanged — backward compatible)

The ${userId}:agent:${agentId} format prevents collisions (e.g. a user named "researcher" won't clash with an agent named "researcher").

Tool-level agent support

All 4 tools gain an agentId parameter for explicit cross-agent operations:

  • memory_search — search a specific agent's memories
  • memory_store — store under a specific agent's namespace
  • memory_list — list a specific agent's memories
  • memory_forget — delete from a specific agent's namespace

Priority: agentId > userId > session-derived > configured default.

CLI enhancements

  • openclaw mem0 search "query" --agent researcher — search a specific agent's namespace
  • openclaw mem0 stats --agent researcher — view stats for a specific agent

Hook updates

  • Auto-recall: passes sessionKey through buildSearchOptions so recalled memories are agent-scoped
  • Auto-capture: passes sessionKey through buildAddOptions so captured memories go to the correct namespace

Backward Compatibility

Zero breaking changes. Single-agent users are unaffected because their session keys are either:

  • undefined → falls back to cfg.userId
  • A plain UUID → no agent: prefix → falls back to cfg.userId
  • agent:main:<uuid>"main" is explicitly treated as the primary session → falls back to cfg.userId

All paths resolve to the same cfg.userId they always did.

Testing

Category Result
Unit tests (isolation helpers) 21/21 passed
Live integration (Mem0 API cross-namespace isolation) 8/8 passed
OpenClaw CLI (--agent flag on search/stats) Verified
Backward compatibility (single-agent behavior) Unchanged
Total 29/29 passed

Key tests verified:

  • Agent Alpha stores/retrieves its own memories (Python preference)
  • Agent Beta stores/retrieves its own memories (Rust preference)
  • Main user stores/retrieves its own memories (TypeScript preference)
  • Alpha does NOT see Beta's memories (cross-isolation)
  • Beta does NOT see Alpha's memories (cross-isolation)
  • Main user does NOT see agent memories (cross-isolation)

Checklist:

  • My code follows the style guidelines of this project
  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes
  • Any dependent changes have been merged and published in downstream modules
  • I have checked my code and corrected any misspellings

Related

  • PR feat(openclaw): per-agent memory isolation via sessionKey #4112 — Earlier attempt at per-agent isolation. This PR supersedes it due to several issues found during review:
    • Namespace collision bug: effectiveUserId() returns the raw agentId (e.g. "researcher") instead of a namespaced ${userId}:agent:${agentId}. This means an agent named "researcher" collides with a real user named "researcher", and agents with the same name across different users share memories.
    • Tools not agent-aware: Only the auto-recall/capture hooks are isolated — the 4 memory tools (memory_search, memory_store, memory_list, memory_forget) still route to the global cfg.userId, bypassing isolation entirely for explicit tool calls.
    • No CLI support: No --agent flag on openclaw mem0 search or openclaw mem0 stats, so operators cannot inspect per-agent memories.
    • Untestable: Helpers are closures inside register() with no way to unit test. This PR exports them as standalone functions with 21 unit tests.
    • No documentation: README not updated with per-agent isolation usage.

Maintainer Checklist

Enable automatic memory namespace isolation when OpenClaw runs multiple
agents. Each agent's memories are scoped via `${userId}:agent:${agentId}`
derived from the session key, ensuring no cross-contamination.

Key changes:
- Add extractAgentId/effectiveUserId/resolveUserId helpers for session
  key parsing and collision-safe namespace derivation
- Update all 4 tools (search, store, list, forget) with `agentId` param
- Update auto-recall and auto-capture hooks to pass sessionKey through
- Add --agent flag to CLI search and stats commands
- Zero breaking changes: single-agent setups always resolve to cfg.userId

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@CLAassistant
Copy link
Copy Markdown

CLAassistant commented Mar 7, 2026

CLA assistant check
All committers have signed the CLA.

Copy link
Copy Markdown

@xkonjin xkonjin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Quick review pass:

  • Main risk area here is auth/session state and stale credential handling.
  • I didn’t see targeted regression coverage in the diff; please add or point CI at a focused test for the changed path in index.ts.
  • Before merge, I’d smoke-test the behavior touched by index.ts with malformed input / retry / rollback cases, since that’s where this class of change usually breaks.

Address reviewer feedback (xkonjin): extract per-agent isolation helpers
(extractAgentId, effectiveUserId, agentUserId, resolveUserId) as exported
pure functions for testability, add 24 focused Vitest regression tests
covering malformed input, edge cases, and the resolve priority chain.
Update README with per-agent isolation docs, agentId tool params, and
--agent CLI examples.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@utkarsh240799 utkarsh240799 requested a review from xkonjin March 8, 2026 17:34
@utkarsh240799 utkarsh240799 requested review from deshraj and xkonjin and removed request for xkonjin March 9, 2026 08:57
All memory tools (`memory_search`, `memory_store`, `memory_list`, `memory_forget`) accept an optional `agentId` parameter to query another agent's namespace:

```
memory_search({ query: "user's tech stack", agentId: "researcher" })
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This type of query pattern will restrict what kinds of filters one can do. We ideally want to support all the params that v2 search endpoint of Mem0 supports.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure if we want to add it as part of this PR or a separate PR.

@deshraj deshraj merged commit 3ffe43f into main Mar 9, 2026
3 checks passed
@deshraj deshraj deleted the feat/agent-memories branch March 9, 2026 15:53
jamebobob pushed a commit to jamebobob/mem0-vigil-recall that referenced this pull request Mar 29, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat: Per-agent memory isolation for openclaw-mem0 plugin

5 participants