Skip to content

fix(plugins): expose ephemeral sessionId in tool contexts for per-conversation isolation#31304

Closed
Sid-Qin wants to merge 1 commit intoopenclaw:mainfrom
Sid-Qin:fix/mem0-session-memory-isolation-31253
Closed

fix(plugins): expose ephemeral sessionId in tool contexts for per-conversation isolation#31304
Sid-Qin wants to merge 1 commit intoopenclaw:mainfrom
Sid-Qin:fix/mem0-session-memory-isolation-31253

Conversation

@Sid-Qin
Copy link
Contributor

@Sid-Qin Sid-Qin commented Mar 2, 2026

Summary

  • Problem: Plugin tool contexts (OpenClawPluginToolContext and PluginHookToolContext) only provide sessionKey, which is a durable channel identifier (e.g. agent:main:telegram:direct:5263871946) that survives /new and /reset. Plugins like mem0 that need per-conversation isolation have no way to distinguish between conversations, causing session-scoped memories to grow unbounded.
  • Root cause: sessionId (the ephemeral UUID regenerated on /new and /reset) was available in the agent context (PluginHookAgentContext) but missing from tool contexts. Plugins registering tools via registerTool factories could only access sessionKey.
  • What changed: Added sessionId to OpenClawPluginToolContext, PluginHookToolContext, and the internal HookContext for tool call wrappers. Threaded the value from the run attempt through createOpenClawCodingTools -> createOpenClawTools -> resolvePluginTools and through the wrapToolWithBeforeToolCallHook wrapper.
  • What did NOT change: sessionKey remains available for durable channel identification. All new fields are optional and backward-compatible.

Change Type (select all)

  • Bug fix
  • Feature
  • Refactor
  • Docs
  • Security hardening
  • Chore/infra

Scope (select all touched areas)

  • Gateway / orchestration
  • Skills / tool execution
  • Auth / tokens
  • Memory / storage
  • Integrations
  • API / contracts
  • UI / DX
  • CI/CD / infra

Linked Issue/PR

User-visible / Behavior Changes

  1. Plugin tool factories (registerTool) now receive ctx.sessionId (ephemeral UUID) in addition to ctx.sessionKey (durable channel ID).
  2. before_tool_call and after_tool_call hook contexts now include sessionId.
  3. Plugins like mem0 can use sessionId as run_id to properly isolate session-scoped memories per conversation.

Security Impact (required)

  • New permissions/capabilities? No
  • Secrets/tokens handling changed? No
  • New/changed network calls? No
  • Command/tool execution surface changed? No
  • Data access scope changed? No (sessionId is already available in agent contexts)

Repro + Verification

Environment

  • OS: Linux / macOS
  • Runtime: Node.js 22+
  • Plugin: openclaw-mem0 or any plugin using registerTool

Steps

  1. Register a plugin tool that reads ctx.sessionId from its factory context
  2. Send a message to trigger the tool
  3. Run /new to start a new conversation
  4. Send another message to trigger the tool
  5. Verify ctx.sessionId changed between conversations

Expected

  • sessionId changes on /new and /reset, enabling per-conversation isolation
  • sessionKey remains the same (durable channel ID)

Actual

  • Before: sessionId was not available in tool contexts; plugins could only use sessionKey
  • After: sessionId is available and changes per conversation

Evidence

  • Failing test/log before + passing after
  • Trace/log snippets
  • Screenshot/recording
  • Perf numbers (if relevant)

New test case in openclaw-tools.plugin-context.test.ts:

  • forwards ephemeral sessionId to plugin tool context - verifies sessionId is passed through

Human Verification (required)

  • Verified scenarios: sessionId flows from attempt -> pi-tools -> openclaw-tools -> plugin context; sessionId flows through tool hook context; backward compat with plugins that don't read sessionId.
  • Edge cases: sessionId is undefined when not supplied (old call sites); plugins that only read sessionKey are unaffected.
  • What you did not verify: Live mem0 plugin with Qdrant using sessionId as run_id.

Compatibility / Migration

  • Backward compatible? Yes
  • Config/env changes? No
  • Migration needed? No

Failure Recovery (if this breaks)

  • How to revert: Remove sessionId fields from the 3 context types and 3 call sites. All additive changes.
  • Files to restore: src/plugins/types.ts, src/agents/pi-tools.before-tool-call.ts, src/agents/pi-tools.ts, src/agents/openclaw-tools.ts, src/agents/pi-embedded-runner/run/attempt.ts

Risks and Mitigations

  • Risk: None. All changes are additive optional fields with full backward compatibility.

…versation isolation

The plugin tool context (`OpenClawPluginToolContext`) and tool hook
context (`PluginHookToolContext`) only provided `sessionKey`, which
is a durable channel identifier that survives /new and /reset.
Plugins like mem0 that need per-conversation isolation (e.g. mapping
Mem0 `run_id`) had no way to distinguish between conversations,
causing session-scoped memories to persist unbounded across resets.

Add `sessionId` (ephemeral UUID regenerated on /new and /reset) to:
- `OpenClawPluginToolContext` (factory context for plugin tools)
- `PluginHookToolContext` (before_tool_call / after_tool_call hooks)
- Internal `HookContext` for tool call wrappers

Thread the value from the run attempt through createOpenClawCodingTools
→ createOpenClawTools → resolvePluginTools and through the tool hook
wrapper.

Closes openclaw#31253

Made-with: Cursor
@greptile-apps
Copy link
Contributor

greptile-apps bot commented Mar 2, 2026

Greptile Summary

Added ephemeral sessionId (UUID regenerated on /new and /reset) to plugin tool contexts and hook contexts, enabling plugins like mem0 to properly isolate per-conversation state. Previously only sessionKey (durable channel ID) was available.

  • Threaded sessionId from run attempt through pi-toolsopenclaw-tools → plugin context and hook wrappers
  • All changes are additive optional fields with full backward compatibility
  • Test coverage added to verify sessionId propagation

Confidence Score: 5/5

  • This PR is safe to merge with minimal risk
  • All changes are purely additive optional fields with clear documentation, proper type safety, comprehensive threading through the call chain, and test coverage. No breaking changes or risky modifications.
  • No files require special attention

Last reviewed commit: 09834bd

@vincentkoc
Copy link
Member

Linking for consolidation context: #32201 is the Option A landing PR for embedded after_tool_call context + single-fire behavior.

sessionId contract expansion is intentionally kept out of Option A and remains follow-up scope.

Link: #32201

@vincentkoc
Copy link
Member

Update after #32201 merge: Option A is complete and merged via #32201.

Keeping this PR open for follow-up sessionId contract/context expansion (intentionally out of Option A scope).

@vincentkoc
Copy link
Member

Superseding this with #32273 so we can land the full follow-up scope on top of current main in one reviewable patch set.

What #32273 carries forward from this PR:

  • sessionId contract/context additions in plugin tool + hook contexts

What #32273 adds to complete runtime propagation:

  • embedded after_tool_call hook context now includes sessionId
  • embedded subscribe/handler context threading for sessionId
  • client-tool before_tool_call context includes sessionId
  • compaction path now passes sessionId into tool construction
  • updated hook tests + changelog entry

Thanks @Sid-Qin for the original #31304 implementation and groundwork.

@vincentkoc vincentkoc closed this Mar 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agents Agent runtime and tooling size: XS

Projects

None yet

Development

Successfully merging this pull request may close these issues.

mem0 plugin: session-scoped memories persist across /new resets (run_id = stable sessionKey)

2 participants