mirror of
https://github.com/lobehub/lobehub
synced 2026-04-21 09:37:28 +00:00
✨ feat: discord support slash commands and DM (#13805)
* fix: slack not respond to text commands * feat: add slack slash commands instructions * chore: add slack validate in test connections * chore: update slack docs * chore: remove text commands for slack
This commit is contained in:
parent
0b490a7268
commit
f9fbd45fee
4 changed files with 89 additions and 17 deletions
|
|
@ -56,6 +56,13 @@ LobeHub supports two connection modes for Slack:
|
|||
bot_user:
|
||||
display_name: LobeHub Assistant
|
||||
always_online: true
|
||||
slash_commands:
|
||||
- command: /new
|
||||
description: Start a new conversation
|
||||
should_escape: false
|
||||
- command: /stop
|
||||
description: Stop the current execution
|
||||
should_escape: false
|
||||
oauth_config:
|
||||
scopes:
|
||||
bot:
|
||||
|
|
@ -63,6 +70,7 @@ LobeHub supports two connection modes for Slack:
|
|||
- channels:history
|
||||
- channels:read
|
||||
- chat:write
|
||||
- commands
|
||||
- groups:history
|
||||
- groups:read
|
||||
- im:history
|
||||
|
|
@ -84,12 +92,14 @@ LobeHub supports two connection modes for Slack:
|
|||
- member_joined_channel
|
||||
- assistant_thread_started
|
||||
- assistant_thread_context_changed
|
||||
interactivity:
|
||||
is_enabled: true
|
||||
org_deploy_enabled: false
|
||||
socket_mode_enabled: true
|
||||
token_rotation_enabled: false
|
||||
```
|
||||
|
||||
> **Note:** `socket_mode_enabled: true` means no Request URL is needed. Events are delivered via WebSocket.
|
||||
> **Note:** `socket_mode_enabled: true` means no Request URL is needed. Events (including Slash Commands) are delivered via WebSocket.
|
||||
|
||||
### Create the App
|
||||
|
||||
|
|
@ -154,6 +164,8 @@ LobeHub supports two connection modes for Slack:
|
|||
|
||||
Click **Test Connection** in LobeHub, then go to Slack, invite the bot to a channel, and mention it with `@LobeHub Assistant` to confirm it responds.
|
||||
|
||||
> **Slash Commands:** If you used the manifest template above, the `/new` and `/stop` commands are automatically configured. Type `/new` in Slack to reset the conversation, or `/stop` to stop the current execution. You can also use these commands via `@bot /new`.
|
||||
|
||||
---
|
||||
|
||||
## Webhook Setup (Alternative)
|
||||
|
|
@ -177,11 +189,28 @@ Use this method if your Slack app already has Event Subscriptions configured wit
|
|||
|
||||
Enter **Application ID**, **Bot Token**, and **Signing Secret** in LobeHub's Slack channel settings. Set **Connection Mode** to **Webhook** in Advanced Settings. Save and copy the displayed **Webhook URL**.
|
||||
|
||||
### Enable App Home Messaging
|
||||
|
||||
In the Slack API Dashboard → **App Home**, find the **Show Tabs** section, enable **Messages Tab**, and make sure **"Allow users to send Slash commands and messages from the messages tab"** is checked. This allows users to chat with the bot via direct messages.
|
||||
|
||||
### Configure Event Subscriptions
|
||||
|
||||
In the Slack API Dashboard → **Event Subscriptions**, enable events, paste the Webhook URL as the **Request URL**, and subscribe to bot events: `app_mention`, `message.channels`, `message.groups`, `message.im`, `message.mpim`, `member_joined_channel`.
|
||||
|
||||

|
||||
|
||||
### Configure Slash Commands (Optional)
|
||||
|
||||
In the Slack API Dashboard → **Slash Commands**, click **Create New Command** and add the following commands:
|
||||
|
||||
| Command | Request URL | Short Description |
|
||||
| ------- | ------------------------- | -------------------------- |
|
||||
| `/new` | Same Webhook URL as above | Start a new conversation |
|
||||
| `/stop` | Same Webhook URL as above | Stop the current execution |
|
||||
|
||||
> **Note:** The Request URL is required for Webhook mode. If you are using Socket Mode, we recommend creating the app from the Manifest template above, which automatically configures Slash Commands without manual setup.
|
||||
|
||||
Also ensure you add the `commands` scope under **OAuth & Permissions** → **Bot Token Scopes**, and enable **Interactivity & Shortcuts** with the same Webhook URL as the Request URL.
|
||||
</Steps>
|
||||
|
||||
## Configuration Reference
|
||||
|
|
@ -196,6 +225,7 @@ Use this method if your Slack app already has Event Subscriptions configured wit
|
|||
|
||||
## Troubleshooting
|
||||
|
||||
- **DM shows "Sending messages to this app has been turned off":** In the Slack API Dashboard → **App Home** → **Show Tabs**, make sure **Messages Tab** is enabled and "Allow users to send Slash commands and messages from the messages tab" is checked. This is already enabled if you created the app using the Manifest template.
|
||||
- **Bot not responding:** Confirm the bot has been invited to the channel. For Socket Mode, ensure the App-Level Token is correct and Socket Mode is enabled in Slack app settings.
|
||||
- **Test Connection failed:** Double-check the Application ID and Bot Token. Ensure the app is installed to the workspace.
|
||||
- **Webhook verification failed (Webhook mode):** Make sure the Signing Secret matches and the Webhook URL is correct.
|
||||
|
|
|
|||
|
|
@ -53,6 +53,13 @@ LobeHub 支持两种 Slack 连接模式:
|
|||
bot_user:
|
||||
display_name: LobeHub Assistant
|
||||
always_online: true
|
||||
slash_commands:
|
||||
- command: /new
|
||||
description: Start a new conversation
|
||||
should_escape: false
|
||||
- command: /stop
|
||||
description: Stop the current execution
|
||||
should_escape: false
|
||||
oauth_config:
|
||||
scopes:
|
||||
bot:
|
||||
|
|
@ -60,6 +67,7 @@ LobeHub 支持两种 Slack 连接模式:
|
|||
- channels:history
|
||||
- channels:read
|
||||
- chat:write
|
||||
- commands
|
||||
- groups:history
|
||||
- groups:read
|
||||
- im:history
|
||||
|
|
@ -81,12 +89,14 @@ LobeHub 支持两种 Slack 连接模式:
|
|||
- member_joined_channel
|
||||
- assistant_thread_started
|
||||
- assistant_thread_context_changed
|
||||
interactivity:
|
||||
is_enabled: true
|
||||
org_deploy_enabled: false
|
||||
socket_mode_enabled: true
|
||||
token_rotation_enabled: false
|
||||
```
|
||||
|
||||
> **注意:** `socket_mode_enabled: true` 表示无需配置 Request URL。事件通过 WebSocket 推送。
|
||||
> **注意:** `socket_mode_enabled: true` 表示无需配置 Request URL。事件(包括 Slash Commands)通过 WebSocket 推送。
|
||||
|
||||
### 创建应用
|
||||
|
||||
|
|
@ -151,6 +161,8 @@ LobeHub 支持两种 Slack 连接模式:
|
|||
|
||||
在 LobeHub 点击 **测试连接**,然后进入 Slack,将机器人邀请到频道,通过 `@LobeHub Assistant` 提及它,确认是否正常响应。
|
||||
|
||||
> **Slash Commands:** 如果您使用了上方的 Manifest 模板,`/new` 和 `/stop` 命令已自动配置。在 Slack 输入 `/new` 可以重置对话,输入 `/stop` 可以停止当前执行。您也可以通过 `@bot /new` 的方式使用这些命令。
|
||||
|
||||
---
|
||||
|
||||
## Webhook 设置(备选方案)
|
||||
|
|
@ -174,11 +186,28 @@ LobeHub 支持两种 Slack 连接模式:
|
|||
|
||||
在 LobeHub 的 Slack 渠道设置中输入 **应用 ID**、**Bot Token** 和 **签名密钥**。在高级设置中将 **连接模式** 设为 **Webhook**。保存后复制显示的 **Webhook URL**。
|
||||
|
||||
### 启用 App Home 消息功能
|
||||
|
||||
在 Slack API 控制台 → **App Home** 中,找到 **Show Tabs** 区域,勾选 **Messages Tab**,并确保 **"Allow users to send Slash commands and messages from the messages tab"** 已启用。这样用户才能在私信中与机器人对话。
|
||||
|
||||
### 配置事件订阅
|
||||
|
||||
在 Slack API 控制台 → **Event Subscriptions** 中,启用事件,将 Webhook URL 粘贴为 **Request URL**,订阅事件:`app_mention`、`message.channels`、`message.groups`、`message.im`、`message.mpim`、`member_joined_channel`。
|
||||
|
||||

|
||||
|
||||
### 配置 Slash Commands(可选)
|
||||
|
||||
在 Slack API 控制台 → **Slash Commands** 中,点击 **Create New Command**,添加以下命令:
|
||||
|
||||
| Command | Request URL | Short Description |
|
||||
| ------- | ------------------ | -------------------------- |
|
||||
| `/new` | 与上方相同的 Webhook URL | Start a new conversation |
|
||||
| `/stop` | 与上方相同的 Webhook URL | Stop the current execution |
|
||||
|
||||
> **注意:** Webhook 模式下 Request URL 为必填项。如果您使用 Socket Mode,推荐通过 Manifest 模板创建应用,Slash Commands 会自动配置,无需手动添加。
|
||||
|
||||
同时确保在 **OAuth & Permissions** → **Bot Token Scopes** 中添加 `commands` 权限,并在 **Interactivity & Shortcuts** 中启用 Interactivity,将 Request URL 设为相同的 Webhook URL。
|
||||
</Steps>
|
||||
|
||||
## 配置参考
|
||||
|
|
@ -193,6 +222,7 @@ LobeHub 支持两种 Slack 连接模式:
|
|||
|
||||
## 故障排除
|
||||
|
||||
- **私信显示 "Sending messages to this app has been turned off":** 在 Slack API 控制台 → **App Home** → **Show Tabs** 中,确保 **Messages Tab** 已启用,并勾选 "Allow users to send Slash commands and messages from the messages tab"。如果使用 Manifest 模板创建应用则默认已开启。
|
||||
- **机器人未响应:** 确认机器人已被邀请到频道。Socket Mode 下请确保应用级别 Token 正确且 Socket Mode 已在 Slack 应用设置中启用。
|
||||
- **测试连接失败:** 仔细检查应用 ID 和 Bot Token 是否正确。确保应用已安装到工作区。
|
||||
- **Webhook 验证失败(Webhook 模式):** 确保签名密钥匹配且 Webhook URL 正确。
|
||||
|
|
|
|||
|
|
@ -408,7 +408,9 @@ export class BotMessageRouter {
|
|||
const charLimit = (info.settings?.charLimit as number) || undefined;
|
||||
const displayToolCalls = info.settings?.displayToolCalls !== false;
|
||||
|
||||
/** Try dispatching a text command. Returns true if handled. */
|
||||
/** Try dispatching a text command. Returns true if handled.
|
||||
* Strips platform mention artifacts (e.g. Slack's `<@U123>`) before
|
||||
* checking so that "@bot /new" correctly resolves to the /new command. */
|
||||
const tryDispatch = async (
|
||||
thread: {
|
||||
id: string;
|
||||
|
|
@ -417,7 +419,8 @@ export class BotMessageRouter {
|
|||
},
|
||||
text: string | undefined,
|
||||
): Promise<boolean> => {
|
||||
const result = BotMessageRouter.dispatchTextCommand(text, commands);
|
||||
const sanitized = client.sanitizeUserInput?.(text ?? '') ?? text;
|
||||
const result = BotMessageRouter.dispatchTextCommand(sanitized, commands);
|
||||
if (!result) return false;
|
||||
await result.command.handler({
|
||||
args: result.args,
|
||||
|
|
@ -559,7 +562,7 @@ export class BotMessageRouter {
|
|||
});
|
||||
|
||||
// Register slash command handlers (native + text-based)
|
||||
this.registerCommands(bot, commands);
|
||||
this.registerCommands(bot, commands, client);
|
||||
|
||||
// Register onNewMessage handler based on platform config
|
||||
const dmEnabled = info.settings?.dm?.enabled ?? false;
|
||||
|
|
@ -712,7 +715,7 @@ export class BotMessageRouter {
|
|||
* To add a new command, add an entry to `buildCommands()` — it will be
|
||||
* automatically registered on all platforms.
|
||||
*/
|
||||
private registerCommands(bot: Chat<any>, commands: BotCommand[]): void {
|
||||
private registerCommands(bot: Chat<any>, commands: BotCommand[], client: PlatformClient): void {
|
||||
// --- Native slash commands (Slack, Discord) ---
|
||||
for (const cmd of commands) {
|
||||
bot.onSlashCommand(`/${cmd.name}`, async (event) => {
|
||||
|
|
@ -729,11 +732,14 @@ export class BotMessageRouter {
|
|||
// Platforms that don't support native onSlashCommand send /commands as
|
||||
// regular text messages. This handler intercepts them in unsubscribed
|
||||
// threads (e.g. first command in a group chat or DM).
|
||||
// The regex also matches mention-prefixed messages (e.g. "<@U123> /new")
|
||||
// so that platforms like Slack can dispatch commands from @-mentions.
|
||||
const namePattern = commands.map((c) => c.name).join('|');
|
||||
const regex = new RegExp(`^\\/(?:${namePattern})(?:\\s|$|@)`);
|
||||
const regex = new RegExp(`(?:^|\\s)\\/(?:${namePattern})(?:\\s|$|@)`);
|
||||
bot.onNewMessage(regex, async (thread, message) => {
|
||||
if (message.author.isBot === true) return;
|
||||
const result = BotMessageRouter.dispatchTextCommand(message.text, commands);
|
||||
const sanitized = client.sanitizeUserInput?.(message.text ?? '') ?? message.text;
|
||||
const result = BotMessageRouter.dispatchTextCommand(sanitized, commands);
|
||||
if (!result) return;
|
||||
await result.command.handler({
|
||||
args: result.args,
|
||||
|
|
|
|||
|
|
@ -215,10 +215,6 @@ class SlackWebhookClient implements PlatformClient {
|
|||
parseMessageId(compositeId: string): string {
|
||||
return compositeId;
|
||||
}
|
||||
|
||||
sanitizeUserInput(text: string): string {
|
||||
return text.replaceAll(/<@[A-Z\d]+>\s*/g, '').trim();
|
||||
}
|
||||
}
|
||||
|
||||
// ---------- Socket Mode Client (persistent) ----------
|
||||
|
|
@ -408,10 +404,6 @@ class SlackSocketModeClient implements PlatformClient {
|
|||
parseMessageId(compositeId: string): string {
|
||||
return compositeId;
|
||||
}
|
||||
|
||||
sanitizeUserInput(text: string): string {
|
||||
return text.replaceAll(/<@[A-Z\d]+>\s*/g, '').trim();
|
||||
}
|
||||
}
|
||||
|
||||
// ---------- Factory ----------
|
||||
|
|
@ -428,7 +420,10 @@ export class SlackClientFactory extends ClientFactory {
|
|||
return new SlackWebhookClient(config, context);
|
||||
}
|
||||
|
||||
async validateCredentials(credentials: Record<string, string>): Promise<ValidationResult> {
|
||||
async validateCredentials(
|
||||
credentials: Record<string, string>,
|
||||
settings?: Record<string, unknown>,
|
||||
): Promise<ValidationResult> {
|
||||
if (!credentials.botToken) {
|
||||
return { errors: [{ field: 'botToken', message: 'Bot Token is required' }], valid: false };
|
||||
}
|
||||
|
|
@ -438,6 +433,17 @@ export class SlackClientFactory extends ClientFactory {
|
|||
valid: false,
|
||||
};
|
||||
}
|
||||
if (settings?.connectionMode === 'websocket' && !credentials.appToken) {
|
||||
return {
|
||||
errors: [
|
||||
{
|
||||
field: 'appToken',
|
||||
message: 'App-Level Token is required for WebSocket (Socket Mode)',
|
||||
},
|
||||
],
|
||||
valid: false,
|
||||
};
|
||||
}
|
||||
|
||||
try {
|
||||
const res = await fetch(`${SLACK_API_BASE}/auth.test`, {
|
||||
|
|
|
|||
Loading…
Reference in a new issue