Боты со Slack
Приложение на Slack Bolt или slack_sdk переезжает в Kontext без переписывания обработчиков: меняются адрес API, токен и секрет подписи. События приходят по HTTP — режима Socket Mode нет.
Что работает
| В Slack | В Kontext |
|---|---|
| Бот-пользователь приложения | Бот пространства: «Интеграции → Боты → Новый бот», шаблон «Приложение Slack (Bolt)» |
Bot token xoxb-… | Токен бота ktx_b_… — в карточке бота, раздел «Токены» |
| Signing Secret | Секрет подписи — показывается при создании бота, сменить его можно в разделе «Секрет подписи» |
Web API: chat.*, reactions.*, conversations.*, users.*, auth.test | Те же методы по адресу https://app.kontext.su/api/slack/ |
Events API: message, app_mention, message_changed, message_deleted, reaction_added, reaction_removed, team_join, channel_created | Подписка бота на события в формате Slack — раздел карточки «События» |
Слеш-команды, ack(), respond(), response_url | Свои команды бота — раздел карточки «Команды» |
Block Kit и вложения в chat.* | Карточка с кнопками, списками, датами, «⋯» — как у Slack |
Interactivity: block_actions, respond(replace_original=True) | Адрес действий бота — раздел карточки «Интерактивность» |
views.open, views.update, views.push, view_submission, view_closed | Модальные окна по trigger_id — тем же кодом |
Shortcuts: app.shortcut(...) — глобальные и у сообщения | Ярлыки бота — «Интерактивность» → «Ярлыки»: глобальный ярлык виден в подсказке после «/», ярлык сообщения — значком молнии в панели действий сообщения |
external_select, app.options(...) | Список, варианты которого приложение подбирает по набранному тексту, — тем же кодом, через адрес действий |
User groups: usergroups.*, <!subteam^S…> | Группы людей пространства: @devs уведомляет участников группы в канале; бот дежурств по очереди меняет, кто входит в @oncall |
| Входящий вебхук | Входящий вебхук Kontext принимает формат Slack без переделок и может писать от имени бота |
Переезд за шесть шагов
- Заведите бота: «Пространство → Интеграции → Боты → Новый бот», шаблон «Приложение Slack (Bolt)». Скопируйте секрет подписи — он показывается один раз.
- Добавьте бота в каналы, где он работает (карточка бота → «Каналы»). Бот видит и получает события только там, где состоит, — как в Slack.
- Выпустите токен бота (карточка бота → «Токены») с нужными областями доступа (scopes).
- Поменяйте три строки в приложении:
Для Node (import os from slack_bolt import App from slack_sdk import WebClient app = App( client=WebClient( token=os.environ["KONTEXT_BOT_TOKEN"], base_url="https://app.kontext.su/api/slack/", ), signing_secret=os.environ["KONTEXT_SIGNING_SECRET"], )@slack/bolt):new App({ token, signingSecret, clientOptions: { slackApiUrl: "https://app.kontext.su/api/slack/" } }). - Направьте события и команды на адрес приложения (обычно
https://ваш-сервер/slack/events) в карточке бота: «События» — формат «Slack», «Команды» —/имяи тот же адрес. Kontext подписывает запросы так же, как Slack (X-Slack-Signature,X-Slack-Request-Timestamp), поэтому Bolt проверяет подпись сам. При сохранении подписки придёт запросurl_verification— на него Bolt тоже ответит сам.Отметьте только те события, которые приложение обрабатывает, — как «Subscribe to bot events» в настройках Slack: «Упомянули бота» — это
app_mention, «Сообщение или ответ в треде» —message. На событие без обработчика Bolt отвечает ошибкой404. Если приложение обрабатывает только упоминания, а подписка шлёт ему все сообщения, неудачные доставки будут копиться, пока подписка не выключится. - Кнопки и окна: карточка бота → «Интерактивность» → тот же адрес
https://ваш-сервер/slack/events(как Interactivity Request URL у Slack). Без него кнопки в карточках видны, но не нажимаются.
Отличия
- Идентификаторы другие:
C<число>,U<число>,B<число>,T<число>. Если идентификаторы Slack прописаны в коде или настройках, замените их на наши — их возвращаютconversations.list,users.list,auth.test. tsсообщения — номер, а не время ("12345.000000"). Треды, правка и реакции поtsработают, но вычислять поtsвремя отправки нельзя.- Блоки: нет
rich_text_input,file_input,video,file. Неподдерживаемый блок в сообщении заменяется пометкой, а в окне вызывает ошибкуinvalid_arguments. Нет вкладки App Home (views.publish), устаревших интерактивных вложений иdialog.*. - Ярлыки задаются не в манифесте, а в карточке бота («Интерактивность» → «Ярлыки»): вид, название,
callback_id. Ярлык сообщения люди видят только в каналах, которые бот может читать сам, — ведь приложению уходит всё сообщение целиком. У глобального ярлыка, как и в Slack, нет ни канала, ниresponse_url: приложение открывает окно поtrigger_id. external_select: варианты запрашиваются на тот же адрес действий (block_suggestion; отдельного «Options Load URL» нет), когда набраноmin_query_lengthзнаков (по умолчанию 3). Приложение должно ответить{"options"}или{"option_groups"}за 3 секунды. Выбрать можно только то, что приложение предложило этому человеку.- Группы: для
usergroups.listиusergroups.users.listнужна областьusers:read; дляusergroups.create,update,disable,enableиusers.update— областьusergroups:writeи роль бота «как участник» (у гостевой роли групп нет).<!subteam^S5>с нашим номером в сообщении бота уведомляет группу. Номер берите изusergroups.list— номера Slack у нас другие. - Нажатие не повторяется, а ответа приложения Kontext ждёт 3 секунды, как и Slack. Кнопка со ссылкой (
url) запроса приложению не отправляет. Значениеvalueкнопки доступно каждому, кто видит сообщение, — секреты туда не кладите. - Нет:
files.*(файлы загружаются черезPOST /api/v1/files),users.lookupByEmail(адресов почты в API нет), Socket Mode (события, команды и нажатия приходят только по HTTP: приложению на Socket Mode понадобятся адрес, доступный из интернета, и запуск в режиме HTTP), установки приложения через OAuth («Add to Slack») — токен выдаёт администратор пространства. username,icon_emoji,icon_urlне действуют: сообщение пишется от имени бота с его картинкой.- Событий задач в формате Slack нет (у Slack таких событий нет вовсе) — для них нужна подписка в формате Kontext.
- Команды:
ack("…")— ответ с пометкой «видно только вам». Если приложение не ответило за 3 секунды, вызвавший видит «ждём ответ…». Дольше 30 секунд команда не ждёт и не повторяется (Slack тоже не повторяет).respond()работает черезresponse_url: 30 минут, до пяти ответов.say()пишет черезchat.postMessage, поэтому бот должен состоять в канале.
Если что-то не так
invalid_auth— токен скопирован не целиком или это не токен бота Kontext.account_inactive— бот выключен или удалён.not_in_channel— добавьте бота в канал (карточка бота → «Каналы»).missing_scope— у токена нет нужной области, её название — в полеneededответа. Выпустите токен с этой областью.unknown_method— такого метода в Kontext нет; список — на странице API.
Полное описание API — Документация → API.