0Pricing
AI Agents · Aula

Ouvindo eventos e comandos de barra

app_mention, comandos de barra e manipuladores de ações no Slack Bolt.

Ouvindo eventos e comandos de barra é uma aula grátis de AI Agents no CoddyKit. Esta é a aula 2 de 4. Você pode ler a aula completa abaixo gratuitamente — depois pratica ao vivo no navegador com um editor de código integrado e um tutor de IA 24/7. Faz parte do caminho de aprendizado de AI Agents, e seu progresso é sincronizado entre a web e o app CoddyKit. O curso de AI Agents inclui 4 aulas no total.

Visão geral das assinaturas de eventos do Slack

O Slack envia eventos para seu aplicativo quando algo acontece — uma mensagem é publicada, alguém menciona seu bot ou um usuário entra em um canal. Você se inscreve em tipos de eventos específicos no painel do aplicativo do Slack e, em seguida, registra manipuladores no Bolt usando o decorador @app.event().

from slack_bolt import App
import os

app = App(
    token=os.environ['SLACK_BOT_TOKEN'],
    signing_secret=os.environ['SLACK_SIGNING_SECRET']
)

# Register event handlers with @app.event()
# The string argument must match the Slack event type exactly

@app.event('app_mention')
def handle_mention(event, say, logger):
    logger.info(f'Mention event: {event}')
    say(f'Hello <@{event["user"]}>!')

@app.event('message')
def handle_message(event, say):
    # Fires for every message in subscribed channels
    if event.get('subtype') is None:  # ignore bot messages
        print(f'Message: {event["text"]}')

Tratamento de eventos app_mention

O evento app_mention é acionado quando alguém digita @YourBot em um canal. O event['text'] contém a mensagem completa, incluindo a menção. Remova o prefixo da menção para obter a consulta real do usuário.

import re

@app.event('app_mention')
def handle_mention(event, say, client):
    # event['text'] example: '<@U0123BOT> summarize this'
    text = event.get('text', '')
    user_id = event['user']
    channel = event['channel']

    # Remove the @mention to get the clean query
    clean_text = re.sub(r'<@[A-Z0-9]+>', '', text).strip()
    print(f'User {user_id} asked: {clean_text}')

    if not clean_text:
        say(f'Hi <@{user_id}>! How can I help you today?')
        return

    # Process the query
    response = process_user_query(clean_text, user_id)
    say(response)

Acessando os dados do evento

Cada manipulador de eventos recebe o dicionário event, que contém os dados brutos do evento do Slack. Campos principais: event['user'] (ID do usuário), event['channel'] (ID do canal), event['text'] (conteúdo da mensagem), event['ts'] (carimbo de data e hora/ID da mensagem).

@app.event('app_mention')
def handle_mention(event, say, client):
    print('Event type:', event.get('type'))
    print('User ID:', event.get('user'))     # e.g. 'U0123ABC'
    print('Channel:', event.get('channel'))   # e.g. 'C0456DEF'
    print('Text:', event.get('text'))          # full message text
    print('Timestamp:', event.get('ts'))       # '1234567890.123456'
    print('Thread TS:', event.get('thread_ts')) # if in a thread

    # Get full user info from the user ID
    user_info = client.users_info(user=event['user'])
    real_name = user_info['user']['real_name']
    email = user_info['user']['profile'].get('email', '')
    say(f'Hello {real_name}!')

Comandos de barra — registro e resposta

Os comandos de barra permitem que os usuários acionem ações do agente a partir de qualquer canal do Slack. Registre a URL do comando no painel do aplicativo do Slack (em Comandos de barra) e trate-o com @app.command('/command-name'). Sempre chame ack() imediatamente — o Slack encerra a solicitação por tempo limite após 3 segundos se você não fizer isso.

@app.command('/summarize')
def handle_summarize(ack, body, say, respond):
    # CRITICAL: ack() must be called within 3 seconds
    ack()  # acknowledge the command immediately

    # body contains the command payload
    user_id = body['user_id']
    channel_id = body['channel_id']
    text = body.get('text', '').strip()  # text after the command

    print(f'User {user_id} ran /summarize with: "{text}"')

    if not text:
        respond('Usage: /summarize <text or URL to summarize>')
        return

    # Process and respond
    summary = generate_summary(text)
    say(f'Summary by <@{user_id}>:\n{summary}')

ack() — a regra dos 3 segundos

O Slack exige que seu aplicativo chame ack() (confirme o recebimento de) cada comando de barra e carga útil interativa recebidos em até 3 segundos. Se você não fizer isso, o Slack exibirá um erro ao usuário. Para operações demoradas, confirme o recebimento imediatamente, inicie o processamento em segundo plano e responda usando respond() com o resultado.

import threading

@app.command('/analyze')
def handle_analyze(ack, body, respond):
    ack()  # Must be within 3 seconds!

    text = body.get('text', '').strip()
    if not text:
        respond('Please provide text to analyze.')
        return

    # For slow operations: run in background thread
    def process_in_background():
        result = slow_ai_analysis(text)  # may take 10+ seconds
        respond(f'Analysis complete:\n{result}')

    thread = threading.Thread(target=process_in_background)
    thread.daemon = True
    thread.start()

    # respond() is safe to call from a different thread
    # ack() already sent, Slack won't time out

say() versus respond() — quando usar cada um

Duas funções publicam mensagens de volta no Slack:

  • say() — publica no canal onde o evento ocorreu; fica visível para todos
  • respond() — disponível somente em manipuladores de comandos de barra; pode publicar mensagens efêmeras, visíveis apenas para o usuário que executou o comando

Use respond(response_type='in_channel') para respostas públicas e respond(response_type='ephemeral') para respostas privadas.

@app.command('/status')
def handle_status(ack, respond, body):
    ack()

    # Ephemeral: only visible to the user who ran the command
    respond(
        text='Agent status: Running | Queue: 3 tasks | Uptime: 4h 22m',
        response_type='ephemeral'  # private to command user
    )

@app.command('/broadcast')
def handle_broadcast(ack, say, respond, body):
    ack()
    text = body.get('text', '')

    # Public: visible to everyone in the channel
    say(
        text=f'<@{body["user_id"]}> broadcast: {text}',
        channel=body['channel_id']
    )

    # Confirm privately to the sender
    respond('Broadcast sent!', response_type='ephemeral')

Eventos de mensagens e subtipos

O evento genérico message é acionado para todas as mensagens, incluindo mensagens de bots, edições e exclusões. Use o campo subtype para filtrar. Subtipos comuns: bot_message, message_changed, message_deleted. Se subtype estiver ausente, trata-se de uma mensagem comum de usuário.

@app.event('message')
def handle_message(event, say, client):
    subtype = event.get('subtype')

    # Ignore bot messages to prevent loops
    if subtype == 'bot_message':
        return

    # Ignore message edits and deletes
    if subtype in ('message_changed', 'message_deleted'):
        return

    # Only process direct messages (DMs) to the bot
    channel_type = event.get('channel_type', '')
    if channel_type == 'im':
        text = event.get('text', '').strip()
        user = event['user']
        print(f'DM from {user}: {text}')
        say(f'You said: {text}')

Ouvindo reações

O evento reaction_added é acionado quando alguém adiciona uma reação com emoji a uma mensagem. Você pode usá-lo para acionar ações do agente — por exemplo, adicionar a reação 📌 para salvar uma mensagem ou ✅ para marcar uma tarefa como concluída.

@app.event('reaction_added')
def handle_reaction(event, client, say):
    reaction = event['reaction']  # e.g. 'thumbsup', 'white_check_mark'
    user_id = event['user']  # who reacted
    item = event['item']  # what was reacted to

    print(f'User {user_id} reacted :{reaction}: to {item["type"]}')

    if reaction == 'white_check_mark' and item['type'] == 'message':
        # Fetch the original message
        result = client.conversations_history(
            channel=item['channel'],
            oldest=item['ts'],
            latest=item['ts'],
            inclusive=True,
            limit=1
        )
        messages = result.get('messages', [])
        if messages:
            text = messages[0].get('text', '')
            print(f'Task completed: {text[:100]}')

Cargas úteis de ações de componentes interativos

Quando um usuário clica em um botão ou seleciona um item de menu, o Slack envia uma carga útil de ação. Trate-a com @app.action('action_id'). O ID da ação é a cadeia de caracteres definida ao criar o componente do Block Kit. Sempre chame ack() imediatamente.

@app.action('approve_task')
def handle_approve(ack, body, respond, client):
    ack()  # acknowledge within 3 seconds

    action = body['actions'][0]  # the button that was clicked
    action_id = action['action_id']  # 'approve_task'
    value = action.get('value', '')  # data attached to the button
    user_id = body['user']['id']

    print(f'User {user_id} clicked {action_id} with value: {value}')

    # Update the original message to show it was approved
    client.chat_update(
        channel=body['container']['channel_id'],
        ts=body['container']['message_ts'],
        text=f'Task approved by <@{user_id}>',
        blocks=[]  # remove buttons after action
    )
    respond('Task approved!', response_type='ephemeral')

Filtrando eventos por canal ou usuário

Em espaços de trabalho grandes, seu bot pode receber eventos de muitos canais. Filtre-os logo no início do manipulador para processar apenas os eventos relevantes. Verifique event['channel'] em relação a uma lista permitida ou use event['user'] para ignorar determinados usuários, como outros bots.

import os

# Only respond in designated channels
ALLOWED_CHANNELS = set(
    os.environ.get('ALLOWED_CHANNELS', '').split(',')
)

BOT_USER_IDS = set()  # will be populated at startup

@app.event('app_mention')
def handle_mention(event, say, client):
    channel = event.get('channel', '')
    user = event.get('user', '')

    # Skip if channel not in allowed list (if list is configured)
    if ALLOWED_CHANNELS and channel not in ALLOWED_CHANNELS:
        return

    # Skip if the 'user' is actually a bot
    if user in BOT_USER_IDS:
        return

    text = event.get('text', '').strip()
    say(f'Processing: {text[:50]}')

Suporte a respostas em tópicos

Para responder em um tópico (em vez de no canal principal), passe thread_ts para say(). Use event.get('thread_ts', event['ts']) para obter o carimbo de data e hora do tópico — thread_ts existe somente se a mensagem já estiver em um tópico; caso contrário, use o próprio ts da mensagem para iniciar um novo tópico.

@app.event('app_mention')
def handle_mention_in_thread(event, say):
    user = event['user']
    text = event.get('text', '').strip()

    # Reply in the same thread (or start a new one)
    thread_ts = event.get('thread_ts') or event.get('ts')

    response_text = f'<@{user}>, processing your request...'

    say(
        text=response_text,
        thread_ts=thread_ts  # keeps the reply in the thread
    )

    # Do the actual work
    result = do_agent_work(text)

    say(
        text=f'Done! Result:\n{result}',
        thread_ts=thread_ts
    )

Verificação rápida: tempo de ack()

Teste sua compreensão sobre o tratamento de eventos do Slack.

Recapitulação de eventos e comandos de barra

Agora seu agente do Slack pode responder a qualquer interação do usuário:

  • @app.event('app_mention') — trata menções a @bot; remova o prefixo da menção com uma expressão regular
  • @app.command('/cmd') — trata comandos de barra; sempre chame ack() em até 3 segundos
  • say() — publica no canal; respond() — responde ao comando de barra e pode ser efêmero
  • @app.action('id') — trata cliques em botões e interações com componentes interativos
  • @app.event('reaction_added') — é acionado por reações com emoji
  • Use thread_ts em say() para manter as respostas em tópicos
  • Filtre por canal ou usuário logo no início para evitar o processamento de eventos irrelevantes

Perguntas Frequentes

A aula “Ouvindo eventos e comandos de barra” é grátis?

Sim — o texto completo de “Ouvindo eventos e comandos de barra” é grátis para ler aqui na web. Para praticá-la interativamente (um editor de código integrado e um tutor de IA 24/7) e desbloquear o restante do curso de AI Agents, atualize para CoddyKit PRO. O curso de AI Agents inclui 4 aulas no total.

O que vou aprender em “Ouvindo eventos e comandos de barra”?

app_mention, comandos de barra e manipuladores de ações no Slack Bolt. Você pratica AI Agents com código prático que executa diretamente no navegador, e um tutor de IA 24/7 responde suas dúvidas enquanto trabalha na aula.

Preciso ter experiência prévia para começar AI Agents?

Nenhuma experiência prévia é necessária. AI Agents no CoddyKit é estruturado para alunos iniciantes até avançados, então você pode começar aqui ou desde o início e aprender no seu ritmo. Esta é a aula 2 de 4.

Quanto tempo leva a aula “Ouvindo eventos e comandos de barra”?

A maioria das aulas CoddyKit leva cerca de 5–10 minutos. Cada uma é compacta e interativa, então você faz progresso constante e retoma exatamente de onde parou entre web e app.

Posso escrever e executar código nesta aula de AI Agents?

Sim. Cada aula de AI Agents inclui um editor de código integrado, então você escreve e executa código real direto no navegador e recebe feedback de IA instantaneamente — nenhuma configuração local necessária.

Todas as aulas deste curso

  1. Fundamentos do Slack Bolt SDK
  2. Ouvindo eventos e comandos de barra
  3. Enviando mensagens e blocos avançados
  4. Criando um bot de notificações para equipes
← Voltar para AI Agents