Skip to content

Slack: preserve explicit mention targets and distinguish implicit thread wakes from bot mentions #79025

Description

@bek91

Bug

Slack thread messages can wake/route an agent as was_mentioned: true even when the only explicit Slack user mention in the message targets someone else. The prompt/runtime context then exposes only the collapsed boolean was_mentioned: true, so the agent has no structured way to distinguish:

  • explicitly mentioned this bot, vs
  • explicitly mentioned another user, vs
  • implicit thread participation / reply-to-bot wakeup.

This causes agents to answer questions addressed to another human in a thread the bot has participated in.

This is related to #62066, but not identical: #62066 is about strict mention gating. This issue is about preserving explicit mention target/source metadata and avoiding a misleading was_mentioned: true prompt signal when the explicit mention is someone else.

Repro from a real Slack incident

OpenClaw version: 2026.5.5
Channel: Slack socket mode
Config excerpt:

{
  "channels": {
    "slack": {
      "requireMention": false,
      "replyToMode": "all",
      "replyToModeByChatType": {
        "direct": "all",
        "group": "all",
        "channel": "all"
      },
      "thread": {
        "historyScope": "thread",
        "inheritParent": false
      }
    }
  }
}

In a Slack thread where the bot had already participated, user Nico sent:

<@U09FU0EL0JD> (Bek) what do you think of bill’s plan for Matt ^?

The mentioned user was Bek (U09FU0EL0JD), not the bot (U0AAV2LB402).

The agent session received this runtime context:

{
  "chat_id": "channel:C0B13UKQSH5",
  "message_id": "1778167895.095549",
  "reply_to_id": "1778025086.423309",
  "sender_id": "U0B1ERUFUAZ",
  "conversation_label": "#client-development",
  "sender": "Nico",
  "thread_label": "Slack thread #client-development: <@U0AAV2LB402> based on our commitment to Matt on coming back to him with concre",
  "topic_id": "1778025086.423309",
  "is_group_chat": true,
  "was_mentioned": true
}

That was_mentioned: true was prompt-visible, but the prompt did not include any structured metadata like:

{
  "explicitly_mentioned_bot": false,
  "explicitly_mentioned_user_ids": ["U09FU0EL0JD"],
  "mention_source": "implicit_thread_participation"
}

The model responded as if the request was addressed to the bot.

Code path

Relevant installed dist files in 2026.5.5:

  • dist/provider-BA774vIf.js

    • registerSlackMessageEvents() handles both message and app_mention.
    • app_mention passes { source: "app_mention", wasMentioned: true } to handleSlackMessage().
    • createSlackMessageHandler() debounces entries and computes combinedMentioned = entries.some((entry) => Boolean(entry.opts.wasMentioned)), then passes wasMentioned: combinedMentioned || last.opts.wasMentioned into prepareSlackMessage().
  • dist/prepare-CD7Ym2Zf.js

    • prepareSlackMessage() computes:
      const hasAnyMention = /<@[^>]+>|<!subteam\^[^>]+>/.test(message.text ?? "");
      const explicitlyMentioned = Boolean(ctx.botUserId && (message.text?.includes(`<@${ctx.botUserId}>`) || await isSlackSubteamMentionForBot(...)));
      const resolveWasMentioned = (mentionRegexes) => opts.wasMentioned ?? (!isDirectMessage && matchesMentionWithExplicit({
        text: message.text ?? "",
        mentionRegexes,
        explicit: { hasAnyMention, isExplicitlyMentioned: explicitlyMentioned, canResolveExplicit: Boolean(ctx.botUserId) }
      }));
    • It also computes implicit thread mention kinds:
      const implicitMentionKinds = isDirectMessage || !ctx.botUserId || !message.thread_ts ? [] : [
        ...implicitMentionKindWhen("reply_to_bot", message.parent_user_id === ctx.botUserId),
        ...implicitMentionKindWhen("bot_thread_participant", await hasSlackThreadParticipationWithPersistence(...))
      ];
    • resolveInboundMentionDecision() collapses explicit and implicit mention state into effectiveWasMentioned.
    • ctxPayload.WasMentioned is set from effectiveWasMentioned.
  • dist/mention-gating-Dj8peKO5.js

    • resolveMentionDecisionCore() collapses source detail:
      const effectiveWasMentioned = params.wasMentioned || implicitMention || params.shouldBypassMention;
  • dist/get-reply-CQW0ur-n.js

    • buildInboundUserContextPrefix() only exposes:
      was_mentioned: ctx.WasMentioned === true ? true : void 0
    • It does not expose explicit mention target IDs or the mention source/kinds.

Docs acknowledge the implicit behavior:

  • docs/channels/slack.md says mention sources include implicit reply-to-bot thread behavior, and channels.slack.thread.requireExplicitMention suppresses implicit thread mentions.

Why this is a bug

The boolean name and prompt-facing semantics imply “the current agent was mentioned.” In this case, the explicit Slack mention was another user. The agent may have been activated because of implicit thread participation, but the prompt gets only was_mentioned: true, which is materially misleading in group chat.

Even if implicit thread activation remains supported, the runtime context should preserve enough source detail for agents and policies to avoid answering messages explicitly addressed to someone else.

Expected behavior

OpenClaw should distinguish activation/mention sources in Slack inbound context and/or gating, for example:

type MentionContext = {
  wasMentioned: boolean;                 // existing compat/effective boolean
  explicitlyMentionedBot: boolean;
  explicitMentionedUserIds: string[];
  explicitMentionedSubteamIds?: string[];
  implicitMentionKinds: Array<"reply_to_bot" | "bot_thread_participant">;
  mentionSource: "explicit_bot" | "mention_pattern" | "subteam" | "implicit_thread" | "none";
};

Prompt/runtime context could include:

{
  "was_mentioned": true,
  "explicitly_mentioned_bot": false,
  "mentioned_user_ids": ["U09FU0EL0JD"],
  "implicit_mention_kinds": ["bot_thread_participant"]
}

A stronger policy option: if a Slack message contains explicit user mentions and none target the bot, implicit thread participation should not mark it as WasMentioned=true unless explicitly configured. That would prevent “question addressed to Bek wakes Bill and looks like Bill was mentioned.”

Relationship to #62066

channels.slack.thread.requireExplicitMention=true may mitigate some cases by suppressing implicit thread mention kinds. But the core metadata problem remains: OpenClaw currently collapses explicit/implicit mention sources into one boolean and drops explicit mention targets before prompt construction.

So this issue can be fixed either alongside #62066 or separately by carrying mention-source metadata through Slack prepare -> ctxPayload -> runtime context prompt.

Metadata

Metadata

Assignees

No one assigned

    Labels

    maintainerMaintainer-authored PR

    Type

    No type

    Fields

    Priority

    None yet

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions