Skip to content

Slack: DM session fan-out when Agent/Assistant capability is enabled #87019

Description

@paulosxyz

Summary

When the Slack app has the 'Agent or Assistant' capability enabled, every DM from a user spawns a new sibling session instead of routing into the user's existing DM session. This makes DMs unusable for any agent that maintains continuous conversation context: messages land in isolated child sessions the user can't see, and the agent ends up with multiple parallel personas responding to the same DM channel.

Repro

  1. Configure a Slack app with 'Agent or Assistant' enabled (api.slack.com/apps → your app → Agent or Assistant → toggle on)
  2. Subscribe to bot events: message.im, assistant_thread_started, assistant_thread_context_changed
  3. Install/reinstall the app to the workspace
  4. Configure channels.slack in openclaw.json (socket or http mode both reproduce)
  5. DM the bot from Slack desktop
  6. Observe: a new session is created with a key like agent:<agent>:<uuid>-topic-<thread_ts>
  7. Send a second DM. Observe: another new session is created (different topic_ts)

Expected

All DMs from the same user should route into the user's existing DM session, regardless of which assistant_app_thread Slack wraps them in.

Root Cause

@openclaw/[email protected], file dist/prepare-BjlcuiLr.js around line 464:

const routedThreadId = (isDirectMessage ? assistantThreadTs : isRoomish ? isThreadReply && threadTs ? threadTs : void 0 : isThreadReply ? threadTs : autoThreadId) ?? ...

For DM channels, the plugin always routes to assistantThreadTs as the thread id. Slack's AI Apps feature wraps every DM in an assistant_app_thread with a unique thread_ts per message, so every inbound DM produces a different routedThreadId.

That routedThreadId is then passed to resolveThreadSessionKeys() (in openclaw core, dist/session-key-*.js):

function resolveThreadSessionKeys(params) {
  const threadId = (params.threadId ?? "").trim();
  if (!threadId) return { sessionKey: params.baseSessionKey, parentSessionKey: undefined };
  return {
    sessionKey: params.useSuffix ?? true ? `${params.baseSessionKey}:thread:${normalizedThread}` : params.baseSessionKey,
    parentSessionKey: params.parentSessionKey
  };
}

useSuffix defaults to true, and the Slack plugin doesn't pass false. So every assistant thread = new :thread:<ts> suffix = new session.

Why replyToModeByChatType.direct: "off" doesn't fix it

That config only controls outbound reply mode (whether the bot uses thread replies vs top-level when responding). It doesn't affect inbound session-key derivation — routedThreadId is set independently from replyToMode.

Proposed Fixes

Pick one of these:

  1. (Recommended) Treat DM assistant threads as the channel-level conversation by default. Change line 464 so isDirectMessage does NOT use assistantThreadTs for session routing. Per-thread context for the AI sidebar can still be tracked separately via the existing assistantThreadContexts map without forking the session key.

  2. Add a config flag like channels.slack.dm.collapseAssistantThreads: true (default true would be cleanest given the current UX is broken).

  3. Pass useSuffix: false to resolveThreadSessionKeys when isDirectMessage && !isExplicitUserReplyInThread.

Environment

  • OpenClaw: 2026.5.22
  • @openclaw/slack: 2026.5.18
  • macOS 24.6.0 (arm64), Node 26.0.0
  • Slack workspace with Agent/Assistant capability enabled

Workaround

Currently advising users to use webchat as the primary surface and treat Slack as outbound-only until this is fixed.

Happy to test a fix against my workspace if a PR lands.

Metadata

Metadata

Assignees

No one assigned

    Labels

    P1High-priority user-facing bug, regression, or broken workflow.clawsweeper:fix-shape-clearClawSweeper found a clear likely implementation shape for this issue.clawsweeper:linked-pr-openClawSweeper found an open linked pull request for this issue.clawsweeper:needs-maintainer-reviewClawSweeper marked this issue as needing maintainer review before automation.clawsweeper:needs-product-decisionClawSweeper marked this issue as needing a product or behavior decision.clawsweeper:no-new-fix-prClawSweeper does not recommend queueing a new automated fix PR for this issue.clawsweeper:source-reproClawSweeper found a high-confidence source-level issue reproduction.impact:message-lossChannel message delivery can be lost, duplicated, or misrouted.impact:session-stateSession, memory, transcript, context, or agent state can drift or corrupt.issue-rating: 🦞 diamond lobsterVery strong issue quality with high-confidence source-level or clear reproduction.

    Type

    No type

    Fields

    Priority

    None yet

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions