From f3ab8066a70c72dfc9788f3f1c6ba912456133cd Mon Sep 17 00:00:00 2001 From: Re-bin Date: Mon, 9 Feb 2026 11:39:13 +0000 Subject: [PATCH] fix: use websockets backend, simplify subtype check, add Slack docs --- README.md | 43 +++++++++++++++++++++++++++++++++++++-- nanobot/agent/loop.py | 2 +- nanobot/channels/slack.py | 6 +++--- 3 files changed, 45 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 4106b2a..186fe35 100644 --- a/README.md +++ b/README.md @@ -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) |
@@ -374,6 +375,44 @@ nanobot gateway
+
+Slack + +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 +``` + +
+
Email @@ -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 diff --git a/nanobot/agent/loop.py b/nanobot/agent/loop.py index 64c95ba..b764c3d 100644 --- a/nanobot/agent/loop.py +++ b/nanobot/agent/loop.py @@ -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: diff --git a/nanobot/channels/slack.py b/nanobot/channels/slack.py index 32abe3b..be95dd2 100644 --- a/nanobot/channels/slack.py +++ b/nanobot/channels/slack.py @@ -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