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 outsay() 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 todosrespond()— 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_tsem 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
- Fundamentos do Slack Bolt SDK
- Ouvindo eventos e comandos de barra
- Enviando mensagens e blocos avançados
- Criando um bot de notificações para equipes