fix: use websockets backend, simplify subtype check, add Slack docs

This commit is contained in:
Re-bin 2026-02-09 11:39:13 +00:00
parent 74e3c411a1
commit f3ab8066a7
3 changed files with 45 additions and 6 deletions

View File

@ -166,7 +166,7 @@ nanobot agent -m "Hello from my local LLM!"
## 💬 Chat Apps
Talk to your nanobot through Telegram, Discord, WhatsApp, Feishu, DingTalk, or Email — anytime, anywhere.
Talk to your nanobot through Telegram, Discord, WhatsApp, Feishu, DingTalk, Slack, or Email — anytime, anywhere.
| Channel | Setup |
|---------|-------|
@ -175,6 +175,7 @@ Talk to your nanobot through Telegram, Discord, WhatsApp, Feishu, DingTalk, or E
| **WhatsApp** | Medium (scan QR) |
| **Feishu** | Medium (app credentials) |
| **DingTalk** | Medium (app credentials) |
| **Slack** | Medium (bot + app tokens) |
| **Email** | Medium (IMAP/SMTP credentials) |
<details>
@ -374,6 +375,44 @@ nanobot gateway
</details>
<details>
<summary><b>Slack</b></summary>
Uses **Socket Mode** — no public URL required.
**1. Create a Slack app**
- Go to [Slack API](https://api.slack.com/apps) → Create New App
- **OAuth & Permissions**: Add bot scopes: `chat:write`, `reactions:write`, `app_mentions:read`
- Install to your workspace and copy the **Bot Token** (`xoxb-...`)
- **Socket Mode**: Enable it and generate an **App-Level Token** (`xapp-...`) with `connections:write` scope
- **Event Subscriptions**: Subscribe to `message.im`, `message.channels`, `app_mention`
**2. Configure**
```json
{
"channels": {
"slack": {
"enabled": true,
"botToken": "xoxb-...",
"appToken": "xapp-...",
"groupPolicy": "mention"
}
}
}
```
> `groupPolicy`: `"mention"` (respond only when @mentioned), `"open"` (respond to all messages), or `"allowlist"` (restrict to specific channels).
> DM policy defaults to open. Set `"dm": {"enabled": false}` to disable DMs.
**3. Run**
```bash
nanobot gateway
```
</details>
<details>
<summary><b>Email</b></summary>
@ -592,7 +631,7 @@ PRs welcome! The codebase is intentionally small and readable. 🤗
- [ ] **Multi-modal** — See and hear (images, voice, video)
- [ ] **Long-term memory** — Never forget important context
- [ ] **Better reasoning** — Multi-step planning and reflection
- [ ] **More integrations**Slack, calendar, and more
- [ ] **More integrations**Calendar and more
- [ ] **Self-improvement** — Learn from feedback and mistakes
### Contributors

View File

@ -246,7 +246,7 @@ class AgentLoop:
channel=msg.channel,
chat_id=msg.chat_id,
content=final_content,
metadata=msg.metadata or {},
metadata=msg.metadata or {}, # Pass through for channel-specific needs (e.g. Slack thread_ts)
)
async def _process_system_message(self, msg: InboundMessage) -> OutboundMessage | None:

View File

@ -5,7 +5,7 @@ import re
from typing import Any
from loguru import logger
from slack_sdk.socket_mode.aiohttp import SocketModeClient
from slack_sdk.socket_mode.websockets import SocketModeClient
from slack_sdk.socket_mode.request import SocketModeRequest
from slack_sdk.socket_mode.response import SocketModeResponse
from slack_sdk.web.async_client import AsyncWebClient
@ -115,8 +115,8 @@ class SlackChannel(BaseChannel):
sender_id = event.get("user")
chat_id = event.get("channel")
# Ignore bot/system messages to prevent loops
if event.get("subtype") == "bot_message" or event.get("subtype"):
# Ignore bot/system messages (any subtype = not a normal user message)
if event.get("subtype"):
return
if self._bot_user_id and sender_id == self._bot_user_id:
return