fix(slack): subscribe to message.mpim + mpim scopes so group DMs work

Group DMs (multi-person DMs, channel_type=mpim) were never delivered to
the Slack bot. The adapter already classifies mpim as a DM and replies
ambiently (adapter.py:2526, is_dm = channel_type in {im, mpim}), but the
generated app manifest only subscribed to message.im / im:history — the
1:1 DM pair. Without the message.mpim event subscription Slack drops
group-DM messages before the adapter ever sees them, so 1:1 DMs worked
while group-DM ambient mode was dead.

Add message.mpim to bot_events and mpim:history (the scope that event
requires per Slack docs) + mpim:read (mirrors im:read for the
conversations.info classification call) to bot_scopes. Update the
SLACK_BOT_TOKEN / SLACK_APP_TOKEN setup-help strings and the Slack docs
(EN + zh-Hans: scope table, event table, troubleshooting) so existing
installs are told to add the new scopes and reinstall.

Reported by an enterprise customer. Note: this is a manifest/scope
change, so it only takes effect after the app is reinstalled and the
new scopes are accepted.

Tests: assert message.mpim + mpim:history + mpim:read are in the
manifest (with and without assistant mode); both fail on current main
and pass with this change.
This commit is contained in:
Ben 2026-06-29 14:44:59 +10:00 committed by Teknium
parent 29f0968275
commit 4125cc3b7c
5 changed files with 41 additions and 2 deletions

View file

@ -3795,7 +3795,7 @@ OPTIONAL_ENV_VARS = {
"SLACK_BOT_TOKEN": {
"description": "Slack bot token (xoxb-). Get from OAuth & Permissions after installing your app. "
"Required scopes: chat:write, app_mentions:read, channels:history, groups:history, "
"im:history, im:read, im:write, users:read, files:read, files:write",
"im:history, im:read, im:write, mpim:history, mpim:read, users:read, files:read, files:write",
"prompt": "Slack Bot Token (xoxb-...)",
"help": "In your Slack app, add the required bot scopes, install the app to the workspace, then copy OAuth & Permissions > Bot User OAuth Token.",
"url": "https://api.slack.com/apps",
@ -3805,7 +3805,7 @@ OPTIONAL_ENV_VARS = {
"SLACK_APP_TOKEN": {
"description": "Slack app-level token (xapp-) for Socket Mode. Get from Basic Information → "
"App-Level Tokens. Also ensure Event Subscriptions include: message.im, "
"message.channels, message.groups, app_mention",
"message.channels, message.groups, message.mpim, app_mention",
"prompt": "Slack App Token (xapp-...)",
"help": "In your Slack app, enable Socket Mode, then create Basic Information > App-Level Tokens with the connections:write scope.",
"url": "https://api.slack.com/apps",

View file

@ -76,6 +76,8 @@ def _build_full_manifest(
"im:history",
"im:read",
"im:write",
"mpim:history",
"mpim:read",
"users:read",
]
@ -84,6 +86,7 @@ def _build_full_manifest(
"message.channels",
"message.groups",
"message.im",
"message.mpim",
]
if include_assistant:

View file

@ -45,6 +45,34 @@ class TestSlackFullManifest:
bot_scopes = manifest["oauth_config"]["scopes"]["bot"]
assert "groups:read" in bot_scopes
def test_group_dm_scopes_and_event_are_included(self):
"""Group DMs (mpim) need message.mpim + mpim:history or Slack never
delivers them the adapter classifies mpim as a DM and replies
ambiently, but only if the event reaches the bot at all."""
manifest = _build_full_manifest("Hermes", "Your Hermes agent on Slack")
bot_scopes = manifest["oauth_config"]["scopes"]["bot"]
bot_events = manifest["settings"]["event_subscriptions"]["bot_events"]
# The event is the load-bearing piece: without message.mpim Slack
# drops group-DM messages before the adapter sees them.
assert "message.mpim" in bot_events
# mpim:history is the scope message.mpim requires (per Slack docs);
# mpim:read mirrors im:read for conversations.info classification.
assert "mpim:history" in bot_scopes
assert "mpim:read" in bot_scopes
def test_group_dm_surface_present_without_assistant_mode(self):
"""Dropping assistant mode must not strip the group-DM surface."""
manifest = _build_full_manifest(
"Hermes", "Your Hermes agent on Slack", include_assistant=False
)
bot_scopes = manifest["oauth_config"]["scopes"]["bot"]
bot_events = manifest["settings"]["event_subscriptions"]["bot_events"]
assert "message.mpim" in bot_events
assert "mpim:history" in bot_scopes
def test_assistant_features_remain_enabled(self):
manifest = _build_full_manifest("Hermes", "Your Hermes agent on Slack")

View file

@ -76,6 +76,8 @@ Navigate to **Features → OAuth & Permissions** in the sidebar. Scroll to **Sco
| `im:history` | Read direct message history |
| `im:read` | View basic DM info |
| `im:write` | Open and manage DMs |
| `mpim:history` | Read group direct message (multi-person DM) history |
| `mpim:read` | View basic group DM info |
| `users:read` | Look up user information |
| `files:read` | Read and download attached files, including voice notes/audio |
| `files:write` | Upload files (images, audio, documents) |
@ -124,6 +126,7 @@ This step is critical — it controls what messages the bot can see.
| Event | Required? | Purpose |
|-------|-----------|---------|
| `message.im` | **Yes** | Bot receives direct messages |
| `message.mpim` | **Recommended** | Bot receives messages in **group DMs** (multi-person DMs) it's added to |
| `message.channels` | **Yes** | Bot receives messages in **public** channels it's added to |
| `message.groups` | **Recommended** | Bot receives messages in **private** channels it's invited to |
| `app_mention` | **Yes** | Prevents Bolt SDK errors when bot is @mentioned |
@ -606,6 +609,7 @@ Notes:
| Bot works in DMs but not in channels | **Most common issue.** Add `message.channels` and `message.groups` to event subscriptions, reinstall the app, and invite the bot to the channel with `/invite @Hermes Agent` |
| Bot doesn't respond to @mentions in channels | 1) Check `message.channels` event is subscribed. 2) Bot must be invited to the channel. 3) Ensure `channels:history` scope is added. 4) Reinstall the app after scope/event changes |
| Bot ignores messages in private channels | Add both the `message.groups` event subscription and `groups:history` scope, then reinstall the app and `/invite` the bot |
| Bot doesn't respond in group DMs (multi-person DMs) | Add the `message.mpim` event subscription and the `mpim:history` scope (plus `mpim:read`), then **reinstall** the app. Without `message.mpim`, Slack never delivers group-DM messages to the bot — even though 1:1 DMs work. |
| "Sending messages to this app has been turned off" in DMs | Enable the **Messages Tab** in App Home settings (see Step 5) |
| "not_authed" or "invalid_auth" errors | Regenerate your Bot Token and App Token, update `.env` |
| Bot responds but can't post in a channel | Invite the bot to the channel with `/invite @Hermes Agent` |

View file

@ -65,6 +65,8 @@ description: "使用 Socket Mode 将 Hermes Agent 设置为 Slack 机器人"
| `im:history` | 读取私信历史记录 |
| `im:read` | 查看基本私信信息 |
| `im:write` | 打开并管理私信 |
| `mpim:history` | 读取群组私信(多人私信)历史记录 |
| `mpim:read` | 查看基本群组私信信息 |
| `users:read` | 查询用户信息 |
| `files:read` | 读取并下载附件文件,包括语音备忘录/音频 |
| `files:write` | 上传文件(图片、音频、文档) |
@ -110,6 +112,7 @@ Socket Mode 让机器人通过 WebSocket 连接,无需公开 URL。
| 事件 | 是否必需 | 用途 |
|-------|-----------|---------|
| `message.im` | **必需** | 机器人接收私信 |
| `message.mpim` | **推荐** | 机器人接收其加入的**群组私信**(多人私信)消息 |
| `message.channels` | **必需** | 机器人接收其加入的**公开**频道消息 |
| `message.groups` | **推荐** | 机器人接收被邀请加入的**私有**频道消息 |
| `app_mention` | **必需** | 防止机器人被 @ 提及时出现 Bolt SDK 错误 |
@ -558,6 +561,7 @@ slack:
| 机器人在私信中正常但在频道中不响应 | **最常见问题。**`message.channels``message.groups` 添加到事件订阅,重新安装应用,并用 `/invite @Hermes Agent` 邀请机器人加入频道 |
| 机器人不响应频道中的 @mention | 1) 检查 `message.channels` 事件是否已订阅。2) 机器人必须被邀请到频道。3) 确保已添加 `channels:history` 权限范围。4) 更改权限范围/事件后重新安装应用 |
| 机器人忽略私有频道中的消息 | 添加 `message.groups` 事件订阅和 `groups:history` 权限范围,然后重新安装应用并 `/invite` 机器人 |
| 机器人不响应群组私信(多人私信) | 添加 `message.mpim` 事件订阅和 `mpim:history` 权限范围(以及 `mpim:read`),然后**重新安装**应用。没有 `message.mpim`,即使 1:1 私信正常Slack 也永远不会向机器人投递群组私信消息。 |
| 私信中出现"向此应用发送消息已被关闭" | 在 App Home 设置中启用 **Messages Tab**(见第五步) |
| "not_authed" 或 "invalid_auth" 错误 | 重新生成 Bot Token 和 App Token更新 `.env` |
| 机器人响应但无法在频道中发帖 | 用 `/invite @Hermes Agent` 邀请机器人加入频道 |