Bots e mensagens interativas

Uma conta de bot é um utilizador criado para um programa. Tem o seu próprio nome, imagem e tokens, e exibe a etiqueta BOT junto ao nome. Esta página também abrange as partes interativas das mensagens: botões, menus e diálogos, que qualquer integração pode utilizar.

Porquê uma conta de bot

  • As suas mensagens provêm de uma identidade clara, com a etiqueta BOT, em vez de virem da conta de um colega.
  • Os seus tokens continuam a funcionar quando a pessoa que os configurou muda de função ou sai (a menos que o servidor desative os bots de proprietários desativados, ver abaixo).
  • Os bots não podem iniciar sessão com uma palavra-passe e nunca veem a aplicação web.

As aplicações criam os seus próprios bots, como os bots de Tarefas ou Playbooks, através da API de plugins (EnsureBotUser).

Ativar contas de bot

Um administrador do sistema ativa Ativar a criação de contas de bot em Consola do sistema › Integrações › Contas de bot (ServiceSettings.EnableBotAccountCreation, AM_SERVICESETTINGS_ENABLEBOTACCOUNTCREATION). A opção está desativada por omissão. Apenas administradores do sistema podem criar bots, a menos que concedam esse direito a outros papéis nas definições de permissões.

Na mesma página, Desativar contas de bot quando o proprietário é desativado (ServiceSettings.DisableBotsWhenOwnerIsDeactivated, ativado por omissão) desativa um bot quando a conta do seu proprietário é desativada.

Criar um bot

  1. Abra o seu avatar no canto superior direito, depois Integrações › Contas de bot, e depois Adicionar conta de bot.
  2. Introduza um Nome de utilizador (letras minúsculas, números, pontos, traços e sublinhados) e, opcionalmente, um Ícone do bot, um Nome de apresentação e uma Descrição.
  3. Escolha o Papel: Membro, ou Administrador do sistema para um bot que gere o servidor. Atribua a um bot apenas o mínimo necessário.
  4. Marque post:channels para permitir que publique em todos os canais públicos, ou post:all para todos os canais, incluindo privados e mensagens diretas, sem ser membro.
  5. Defina quando o token predefinido expira e, em seguida, escolha Criar conta de bot.
  6. Copie o token de acesso apresentado. Não será mostrado novamente.

Mais tarde, Criar novo token na linha do bot adiciona um token, e cada token pode ser desativado ou eliminado. Os tokens de bot funcionam mesmo quando os tokens de acesso pessoal estão desativados para os utilizadores.

Com a API:

# create the bot (you become its owner)
curl -X POST https://chat.example.com/api/v4/bots \
  -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
  -d '{"username": "deploy-bot", "display_name": "Deploy", "description": "Posts deployments"}'

# give it a token
curl -X POST https://chat.example.com/api/v4/users/$BOT_USER_ID/tokens \
  -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
  -d '{"description": "deploy pipeline"}'

A partir da linha de comandos, autenticado como administrador (não em modo local): amctl bot create deploy-bot --display-name Deploy --with-token --expires-in 90d. Outros endpoints: GET /api/v4/bots, PUT /api/v4/bots/{bot_user_id}, POST /api/v4/bots/{bot_user_id}/disable e /enable, POST /api/v4/bots/{bot_user_id}/assign/{user_id} para alterar o respetivo proprietário.

Adicionar o bot a comunidades e canais

Um novo bot não pertence a nenhuma comunidade. Adicione-o como uma pessoa, através da gestão de membros da comunidade ou com a API:

curl -X POST https://chat.example.com/api/v4/teams/$TEAM_ID/members \
  -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
  -d '{"team_id": "'$TEAM_ID'", "user_id": "'$BOT_USER_ID'"}'

curl -X POST https://chat.example.com/api/v4/channels/$CHANNEL_ID/members \
  -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
  -d '{"user_id": "'$BOT_USER_ID'"}'

Um bot com post:channels ou post:all pode publicar sem ser membro, mas apenas recebe eventos WebSocket para os canais em que está.

Publicar como o bot

Utilize o token do bot com qualquer chamada de API; POST /api/v4/posts é a mais comum (ver Recursos principais). Para escrever diretamente a alguém, abra primeiro o canal de mensagem direta:

# returns the channel; use its "id" as channel_id
curl -X POST https://chat.example.com/api/v4/channels/direct \
  -H "Authorization: Bearer $BOT_TOKEN" -H 'Content-Type: application/json' \
  -d '["'$BOT_USER_ID'", "'$USER_ID'"]'

Para reagir ao que as pessoas dizem, siga o WebSocket com o token do bot e responda aos eventos posted que lhe interessam. Ignore as mensagens do próprio bot para evitar ciclos.

Uma mensagem que apenas uma pessoa pode ver (uma mensagem efémera) é enviada com POST /api/v4/posts/ephemeral e {"user_id", "post": {"channel_id", "message"}}. Requer a permissão create_post_ephemeral, que por omissão apenas os administradores do sistema possuem. As integrações enviam normalmente mensagens efémeras como respostas a comandos de barra e botões.

Mensagens interativas: botões e menus

Qualquer mensagem com anexos pode conter ações: botões e menus para seleção. Funcionam em mensagens publicadas com a API, webhooks e respostas a comandos de barra. Quando alguém utiliza uma, o Antimatter chama o URL da sua integração.

{
  "channel_id": "…",
  "message": "Deploy **api 2.4.0** to production?",
  "props": {
    "attachments": [{
      "actions": [
        {
          "id": "approve",
          "type": "button",
          "name": "Approve",
          "style": "primary",
          "integration": {"url": "https://deploy.example.com/actions", "context": {"release": "2.4.0", "action": "approve"}}
        },
        {
          "id": "env",
          "type": "select",
          "name": "Pick an environment",
          "options": [{"text": "Staging", "value": "staging"}, {"text": "Production", "value": "production"}],
          "integration": {"url": "https://deploy.example.com/actions", "context": {"release": "2.4.0", "action": "env"}}
        }
      ]
    }]
  }
}
  • type: button ou select.
  • id: letras, números, traços e sublinhados, diferentes para cada ação da mensagem. É gerado quando o omite.
  • style (botões): default, primary, success, good, warning, danger, ou uma cor em hexadecimal.
  • options (menus), ou data_source: users ou channels para selecionar uma pessoa ou um canal. default_option pré-seleciona um valor.
  • integration.url: o destino do clique. Uma aplicação (plugin) pode usar a sua própria rota, como /plugins/com.example.deploy/actions. integration.context é seu: é devolvido com o clique e os clientes nunca o veem.

A solicitação que a sua integração recebe

{
  "user_id": "…",
  "user_name": "priya",
  "channel_id": "…",
  "channel_name": "releases",
  "team_id": "…",
  "team_domain": "lumen-labs",
  "post_id": "…",
  "trigger_id": "…",
  "type": "button",
  "context": {"release": "2.4.0", "action": "approve"}
}

Para um menu, type é select e context.selected_option contém o valor selecionado.

A sua resposta

{
  "update": {"message": "Deploy of **api 2.4.0** approved by @priya", "props": {}},
  "ephemeral_text": "Done. The deploy starts in a minute."
}
  • update: substitui o texto e as propriedades da mensagem, por exemplo, para remover os botões após o uso (um props vazio).
  • ephemeral_text: uma mensagem visível apenas para a pessoa que clicou.
  • goto_location: um URL para abrir.
  • Um corpo vazio não altera nada.

O servidor aguarda até ao limite permitido pelo Tempo limite de pedido de integração (30 segundos por omissão). Os URLs de integração em endereços de rede privada devem ser autorizados por um administrador do sistema, tal como os webhooks.

Diálogos

Um diálogo é um formulário que abre sobre o chat. Pode ser aberto apenas em resposta a algo que a pessoa acabou de fazer, como um comando de barra ou um botão, pois necessita do trigger_id dessa solicitação. O trigger_id é válido durante o tempo limite de solicitação de integração.

curl -X POST https://chat.example.com/api/v4/actions/dialogs/open \
  -H 'Content-Type: application/json' \
  -d '{
    "trigger_id": "'$TRIGGER_ID'",
    "url": "https://deploy.example.com/dialog",
    "dialog": {
      "callback_id": "new-release",
      "title": "New release",
      "introduction_text": "Fill in the release details.",
      "submit_label": "Create",
      "notify_on_cancel": false,
      "state": "anything you want back",
      "elements": [
        {"display_name": "Version", "name": "version", "type": "text", "placeholder": "2.4.0"},
        {"display_name": "Notes", "name": "notes", "type": "textarea", "optional": true},
        {"display_name": "Environment", "name": "env", "type": "select",
         "options": [{"text": "Staging", "value": "staging"}, {"text": "Production", "value": "production"}]},
        {"display_name": "Owner", "name": "owner", "type": "select", "data_source": "users"},
        {"display_name": "Notify the channel", "name": "notify", "type": "bool", "default": "true"}
      ]
    }
  }'
Tipo de elementoO que exibe
textUm campo de uma linha. subtype: text, email, number, password, tel ou url. min_length e max_length limitam-no.
textareaUm campo de várias linhas.
selectUma lista: options, ou data_source users, channels, ou dynamic com um data_source_url. multiselect permite vários valores.
boolUma caixa de seleção.
radioUma escolha entre options.
date, datetimeUma data, ou uma data e hora.

Cada elemento aceita display_name, name, help_text, placeholder, default e optional.

Quando a pessoa submete, o Antimatter envia uma solicitação POST para o url do diálogo:

{
  "type": "dialog_submission",
  "callback_id": "new-release",
  "state": "anything you want back",
  "user_id": "…",
  "channel_id": "…",
  "team_id": "…",
  "submission": {"version": "2.4.0", "notes": "", "env": "staging", "owner": "…", "notify": true},
  "cancelled": false
}

Responda com um corpo vazio para fechar o diálogo, ou mantenha-o aberto e indique o que está errado:

{"errors": {"version": "This version already exists."}}

{"error": "…"} exibe uma mensagem para o formulário inteiro. Com notify_on_cancel, o fecho do diálogo envia "cancelled": true. Os diálogos funcionam da mesma forma nas aplicações: o OpenInteractiveDialog da API de plugins aceita a mesma solicitação.