Боты со 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 — раздел карточки «События»
Slash-команды, 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 — тем же кодом
Входящий вебхукВходящий вебхук Kontext понимает формат Slack как есть; писать может от имени бота

Переезд за шесть шагов

  1. Заведите бота: «Пространство → Интеграции → Боты → Новый бот», шаблон «Приложение Slack (Bolt)». Скопируйте секрет подписи — он показывается один раз.
  2. Добавьте бота в каналы, где он работает (карточка бота → «Каналы»). Бот видит и получает события только там, где состоит, — как в Slack.
  3. Выпустите токен бота (карточка бота → «Токены») с нужными областями.
  4. Поменяйте три строки в приложении:
    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"],
    )
    Для Node (@slack/bolt): new App({ token, signingSecret, clientOptions: { slackApiUrl: "https://app.kontext.su/api/slack/" } }).
  5. Направьте события и команды на адрес приложения (обычно 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, и подписка на «все сообщения» у приложения, которое слушает только упоминания, копила бы неудачи, пока не выключится.

  6. Кнопки и окна: карточка бота → «Интерактивность» → тот же адрес https://ваш-сервер/slack/events (как Interactivity Request URL у Slack). Без него кнопки карточек рисуются, но нажать их нельзя.

Отличия

  • Id другие: C<число>, U<число>, B<число>, T<число>. Если id Slack зашиты в код или настройки — замените на наши (их отдают conversations.list, users.list, auth.test).
  • ts сообщения — номер, а не время ("12345.000000"). Треды, правка и реакции по ts работают; возраст сообщения по ts не вычисляйте.
  • Блоки: нет external_select, rich_text_input, file_input, video, file; неподдержанный блок в сообщении показан пометкой, в окне — ошибка invalid_arguments. Нет домашней вкладки (views.publish), ярлыков (shortcut, message_action), устаревших интерактивных вложений и dialog.*.
  • Нажатие не повторяется и ждёт ответа 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.