Description
When session.dmScope is set to "per-channel-peer", the Web Control UI does not create an independent session key and instead reuses the global session agent:main:main. This causes all Web UI responses to be delivered to whichever channel last updated the session's deliveryContext, leading to message routing conflicts.
Environment
- OpenClaw Version: 2026.3.2
- Configuration:
{
"session": {
"dmScope": "per-channel-peer"
}
}
- Active Channels: Telegram, Slack, WhatsApp, Web Control UI
Steps to Reproduce
- Configure
session.dmScope: "per-channel-peer" in openclaw.json
- Restart OpenClaw Gateway
- Send a message via Telegram (creates session
agent:main:telegram:direct:{user_id})
- Send a message via Web Control UI
- Observe response delivery
Current Behavior
Session keys created:
{
"agent:main:telegram:direct:8658588041": {
"deliveryContext": {
"channel": "telegram",
"to": "telegram:8658588041"
}
},
"agent:main:slack:direct:u049par1b98:thread:...": {
"deliveryContext": {
"channel": "slack",
"to": "user:U049PAR1B98"
}
},
"agent:main:main": {
"origin": {
"provider": "telegram", // ❌ Wrong!
"surface": "webchat"
},
"deliveryContext": {
"channel": "telegram", // ❌ Should be "webchat"
"to": "telegram:8658588041" // ❌ Should be webchat target
}
}
}
Result: Web UI messages are delivered to Telegram instead of staying in the Web UI.
Expected Behavior
Web Control UI should create an independent session when dmScope: "per-channel-peer":
{
"agent:main:webchat:direct:{user_id}": {
"deliveryContext": {
"channel": "webchat",
"to": "webchat:{user_id}"
}
}
}
OR if Web UI must remain global, its deliveryContext.channel should always be "webchat" regardless of other sessions.
Root Cause Analysis
Code Location
File: /app/dist/session-key-a6av96Fj.js
Function: buildAgentMainSessionKey
function buildAgentMainSessionKey(params) {
return `agent:${normalizeAgentId(params.agentId)}:${normalizeMainKey(params.mainKey)}`;
}
Issue: Web Control UI (sender: "openclaw-control-ui") always uses this function, which returns agent:main:main instead of respecting dmScope: "per-channel-peer".
Why Other Channels Work
Telegram, Slack, and WhatsApp use buildAgentPeerSessionKey, which correctly implements per-channel-peer logic:
function buildAgentPeerSessionKey(params) {
const peerKind = params.peerKind ?? "direct";
if (peerKind === "direct") {
const dmScope = params.dmScope ?? "main";
// ... creates agent:main:{channel}:direct:{peer_id}
}
}
Web UI Special Handling
File: /app/dist/gateway-cli-*.js
errorShape(ErrorCodes.INVALID_REQUEST,
`webchat clients cannot ${params.action} sessions; use chat.send for session-scoped updates`)
This suggests Web UI has intentional special handling, but it breaks channel isolation when multiple channels are active.
Impact
- ✅ Works: Single-channel setups (e.g., only Telegram)
- ❌ Broken: Multi-channel setups with
dmScope: "per-channel-peer"
- Affects: Message routing, session isolation, privacy expectations
Proposed Fix
Option 1: Make Web UI respect dmScope (Recommended)
When dmScope: "per-channel-peer", Web UI should:
- Generate session key:
agent:main:webchat:direct:{user_id_or_device_id}
- Set
deliveryContext.channel: "webchat"
- Route replies back to the Web UI only
Option 2: Isolate Web UI deliveryContext
If Web UI must remain global (agent:main:main), ensure:
deliveryContext.channel is always "webchat"
- Never inherit
deliveryContext from other channels
- Prevent cross-contamination with Telegram/Slack/etc.
Option 3: Document the limitation
If this is intentional behavior:
- Update docs to warn that Web UI shares session with other channels
- Recommend avoiding multi-channel usage with Web UI
- Add config option to disable Web UI when using per-channel-peer
Workaround (Temporary)
For users affected by this bug:
- Use only one channel at a time (Web UI XOR Telegram/Slack/etc.)
- OR: Set
session.dmScope: "main" (disables per-channel isolation)
- OR: Manually clear Web UI session before switching channels
Additional Context
- User reference: Issue discovered during multi-channel deployment testing
- Related config:
session.identityLinks (cross-channel identity mapping)
- Memory architecture: Shared vs private memory per channel
Conclusion
This bug prevents users from safely running multi-channel setups with the Web Control UI. The fix should ensure Web UI creates an independent session key or at least isolates its deliveryContext to prevent cross-channel message leakage.
Thank you for maintaining OpenClaw! 🙏
Description
When
session.dmScopeis set to"per-channel-peer", the Web Control UI does not create an independent session key and instead reuses the global sessionagent:main:main. This causes all Web UI responses to be delivered to whichever channel last updated the session'sdeliveryContext, leading to message routing conflicts.Environment
{ "session": { "dmScope": "per-channel-peer" } }Steps to Reproduce
session.dmScope: "per-channel-peer"inopenclaw.jsonagent:main:telegram:direct:{user_id})Current Behavior
Session keys created:
{ "agent:main:telegram:direct:8658588041": { "deliveryContext": { "channel": "telegram", "to": "telegram:8658588041" } }, "agent:main:slack:direct:u049par1b98:thread:...": { "deliveryContext": { "channel": "slack", "to": "user:U049PAR1B98" } }, "agent:main:main": { "origin": { "provider": "telegram", // ❌ Wrong! "surface": "webchat" }, "deliveryContext": { "channel": "telegram", // ❌ Should be "webchat" "to": "telegram:8658588041" // ❌ Should be webchat target } } }Result: Web UI messages are delivered to Telegram instead of staying in the Web UI.
Expected Behavior
Web Control UI should create an independent session when
dmScope: "per-channel-peer":{ "agent:main:webchat:direct:{user_id}": { "deliveryContext": { "channel": "webchat", "to": "webchat:{user_id}" } } }OR if Web UI must remain global, its
deliveryContext.channelshould always be"webchat"regardless of other sessions.Root Cause Analysis
Code Location
File:
/app/dist/session-key-a6av96Fj.jsFunction:
buildAgentMainSessionKeyIssue: Web Control UI (
sender: "openclaw-control-ui") always uses this function, which returnsagent:main:maininstead of respectingdmScope: "per-channel-peer".Why Other Channels Work
Telegram, Slack, and WhatsApp use
buildAgentPeerSessionKey, which correctly implements per-channel-peer logic:Web UI Special Handling
File:
/app/dist/gateway-cli-*.jsThis suggests Web UI has intentional special handling, but it breaks channel isolation when multiple channels are active.
Impact
dmScope: "per-channel-peer"Proposed Fix
Option 1: Make Web UI respect dmScope (Recommended)
When
dmScope: "per-channel-peer", Web UI should:agent:main:webchat:direct:{user_id_or_device_id}deliveryContext.channel: "webchat"Option 2: Isolate Web UI deliveryContext
If Web UI must remain global (
agent:main:main), ensure:deliveryContext.channelis always"webchat"deliveryContextfrom other channelsOption 3: Document the limitation
If this is intentional behavior:
Workaround (Temporary)
For users affected by this bug:
session.dmScope: "main"(disables per-channel isolation)Additional Context
session.identityLinks(cross-channel identity mapping)Conclusion
This bug prevents users from safely running multi-channel setups with the Web Control UI. The fix should ensure Web UI creates an independent session key or at least isolates its deliveryContext to prevent cross-channel message leakage.
Thank you for maintaining OpenClaw! 🙏