fix: use websockets backend, simplify subtype check, add Slack docs
This commit is contained in:
parent
74e3c411a1
commit
f3ab8066a7
43
README.md
43
README.md
@ -166,7 +166,7 @@ nanobot agent -m "Hello from my local LLM!"
|
|||||||
|
|
||||||
## 💬 Chat Apps
|
## 💬 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 |
|
| Channel | Setup |
|
||||||
|---------|-------|
|
|---------|-------|
|
||||||
@ -175,6 +175,7 @@ Talk to your nanobot through Telegram, Discord, WhatsApp, Feishu, DingTalk, or E
|
|||||||
| **WhatsApp** | Medium (scan QR) |
|
| **WhatsApp** | Medium (scan QR) |
|
||||||
| **Feishu** | Medium (app credentials) |
|
| **Feishu** | Medium (app credentials) |
|
||||||
| **DingTalk** | Medium (app credentials) |
|
| **DingTalk** | Medium (app credentials) |
|
||||||
|
| **Slack** | Medium (bot + app tokens) |
|
||||||
| **Email** | Medium (IMAP/SMTP credentials) |
|
| **Email** | Medium (IMAP/SMTP credentials) |
|
||||||
|
|
||||||
<details>
|
<details>
|
||||||
@ -374,6 +375,44 @@ nanobot gateway
|
|||||||
|
|
||||||
</details>
|
</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>
|
<details>
|
||||||
<summary><b>Email</b></summary>
|
<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)
|
- [ ] **Multi-modal** — See and hear (images, voice, video)
|
||||||
- [ ] **Long-term memory** — Never forget important context
|
- [ ] **Long-term memory** — Never forget important context
|
||||||
- [ ] **Better reasoning** — Multi-step planning and reflection
|
- [ ] **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
|
- [ ] **Self-improvement** — Learn from feedback and mistakes
|
||||||
|
|
||||||
### Contributors
|
### Contributors
|
||||||
|
|||||||
@ -246,7 +246,7 @@ class AgentLoop:
|
|||||||
channel=msg.channel,
|
channel=msg.channel,
|
||||||
chat_id=msg.chat_id,
|
chat_id=msg.chat_id,
|
||||||
content=final_content,
|
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:
|
async def _process_system_message(self, msg: InboundMessage) -> OutboundMessage | None:
|
||||||
|
|||||||
@ -5,7 +5,7 @@ import re
|
|||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
from loguru import logger
|
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.request import SocketModeRequest
|
||||||
from slack_sdk.socket_mode.response import SocketModeResponse
|
from slack_sdk.socket_mode.response import SocketModeResponse
|
||||||
from slack_sdk.web.async_client import AsyncWebClient
|
from slack_sdk.web.async_client import AsyncWebClient
|
||||||
@ -115,8 +115,8 @@ class SlackChannel(BaseChannel):
|
|||||||
sender_id = event.get("user")
|
sender_id = event.get("user")
|
||||||
chat_id = event.get("channel")
|
chat_id = event.get("channel")
|
||||||
|
|
||||||
# Ignore bot/system messages to prevent loops
|
# Ignore bot/system messages (any subtype = not a normal user message)
|
||||||
if event.get("subtype") == "bot_message" or event.get("subtype"):
|
if event.get("subtype"):
|
||||||
return
|
return
|
||||||
if self._bot_user_id and sender_id == self._bot_user_id:
|
if self._bot_user_id and sender_id == self._bot_user_id:
|
||||||
return
|
return
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user