Escucha de eventos y comandos de barra
app_mention, comandos de barra y gestores de acciones en Slack Bolt.
Escucha de eventos y comandos de barra es una lección gratuita de AI Agents en CoddyKit. Esta es la lección 2 de 4. Puedes leer la lección completa abajo gratuitamente — luego la practicas en el navegador con un editor de código integrado y un tutor de IA 24/7. Forma parte de la ruta de aprendizaje de AI Agents, y tu progreso se sincroniza en la web y la app de CoddyKit. El curso de AI Agents incluye 4 lecciones en total.
Descripción general de las suscripciones a eventos de Slack
Slack envía eventos a su aplicación cuando ocurren determinadas acciones: se publica un mensaje, alguien menciona su bot o un usuario se une a un canal. Suscríbase a tipos de eventos específicos en el panel de Slack App y, después, registre los controladores en Bolt mediante el 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"]}')Gestión de eventos app_mention
El evento app_mention se activa cuando alguien escribe @YourBot en un canal. event['text'] contiene el mensaje completo, incluida la mención. Elimine el prefijo de la mención para obtener la consulta real del usuario.
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)Acceso al payload del evento
Cada controlador de eventos recibe el diccionario event, que contiene el payload sin procesar del evento de Slack. Campos clave: event['user'] (ID de usuario), event['channel'] (ID de canal), event['text'] (contenido del mensaje) y event['ts'] (marca de tiempo o ID del mensaje).
@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 slash: registro y respuesta
Los comandos slash permiten que los usuarios activen acciones del agente desde cualquier canal de Slack. Registre la URL del comando en el panel de Slack App, en Slash Commands, y después gestiónelo con @app.command('/command-name'). Llame siempre a ack() de inmediato: Slack agota el tiempo de espera en 3 segundos si no lo hace.
@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(): la regla de los 3 segundos
Slack requiere que su aplicación llame a ack() (acuse de recibo) para cada comando slash y payload interactivo entrante en un plazo de 3 segundos. Si no lo hace, Slack muestra un error al usuario. Para operaciones de larga duración, llame a ack() de inmediato, inicie el procesamiento en un hilo en segundo plano y, después, responda mediante respond() con el 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() frente a respond(): cuándo usar cada uno
Dos funciones publican mensajes de vuelta en Slack:
say(): publica en el canal donde ocurrió el evento; todos pueden verlorespond(): solo está disponible en los controladores de comandos slash; puede publicar mensajes efímeros visibles únicamente para el usuario que ejecutó el comando
Use respond(response_type='in_channel') para las respuestas públicas y respond(response_type='ephemeral') para las 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 mensajes y subtipos
El evento genérico message se activa para todos los mensajes, incluidos los mensajes de bots, las ediciones y las eliminaciones. Use el campo subtype para filtrarlos. Subtipos comunes: bot_message, message_changed y message_deleted. Si subtype está ausente, se trata de un mensaje normal de un usuario.
@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}')Escucha de reacciones
El evento reaction_added se activa cuando alguien añade una reacción con emoji a un mensaje. Puede usarlo para activar acciones del agente; por ejemplo, añadir una reacción 📌 para guardar un mensaje o una ✅ para marcar una tarea como completada.
@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]}')Payloads de acciones de componentes interactivos
Cuando un usuario hace clic en un botón o selecciona un elemento de menú, Slack envía un payload de acción. Gestiónelo con @app.action('action_id'). El ID de acción es la cadena que estableció al crear el componente de Block Kit. Llame siempre a ack() de inmediato.
@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')Filtrado de eventos por canal o usuario
En los espacios de trabajo grandes, su bot puede recibir eventos de muchos canales. Filtre al principio del controlador para procesar únicamente los eventos relevantes. Compruebe event['channel'] con una lista de elementos permitidos o use event['user'] para ignorar determinados usuarios, como otros 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]}')Compatibilidad con respuestas en hilos
Para responder en un hilo, en lugar de hacerlo en el canal principal, pase thread_ts a say(). Use event.get('thread_ts', event['ts']) para obtener la marca de tiempo del hilo: thread_ts solo existe si el mensaje ya está en un hilo; de lo contrario, use el ts del propio mensaje para iniciar un hilo nuevo.
@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
)Comprobación rápida: tiempo de respuesta de ack()
Compruebe sus conocimientos sobre la gestión de eventos de Slack.
Repaso de eventos y comandos slash
Su agente de Slack ahora puede responder a cualquier interacción del usuario:
- @app.event('app_mention'): gestione las menciones a @bot; elimine el prefijo de la mención con una expresión regular
- @app.command('/cmd'): gestione los comandos slash; llame siempre a
ack()en un plazo de 3 segundos - say(): publique en el canal para que todos lo vean; respond(): responda al comando slash, con la posibilidad de hacerlo de forma efímera
- @app.action('id'): gestione los clics en botones y las interacciones con componentes interactivos
- @app.event('reaction_added'): active acciones cuando se añadan reacciones con emoji
- Use
thread_tsen say() para mantener las respuestas en hilos - Filtre pronto por canal o usuario para evitar procesar eventos irrelevantes
Preguntas frecuentes
¿La lección «Escucha de eventos y comandos de barra» es gratis?
Sí — el texto completo de «Escucha de eventos y comandos de barra» es gratis para leer aquí en la web. Para practicarla de forma interactiva (editor de código integrado y tutor de IA 24/7) y desbloquear el resto del curso de AI Agents, actualiza a CoddyKit PRO. El curso de AI Agents incluye 4 lecciones en total.
¿Qué aprenderé en «Escucha de eventos y comandos de barra»?
app_mention, comandos de barra y gestores de acciones en Slack Bolt. Practicas AI Agents con código real que ejecutas directamente en el navegador, y un tutor de IA 24/7 responde tus preguntas mientras trabajas en la lección.
¿Necesito experiencia previa para empezar AI Agents?
No se requiere experiencia previa. AI Agents en CoddyKit está estructurado para principiantes hasta estudiantes avanzados, así que puedes empezar aquí o desde el inicio y avanzar a tu ritmo. Esta es la lección 2 de 4.
¿Cuánto tiempo toma la lección «Escucha de eventos y comandos de barra»?
La mayoría de las lecciones de CoddyKit toman alrededor de 5–10 minutos. Cada una es compacta e interactiva, así que avanzas constantemente y retomas exactamente por donde dejaste en la web y la app.
¿Puedo escribir y ejecutar código en esta lección de AI Agents?
Sí. Cada lección de AI Agents incluye un editor de código integrado, así que escribes y ejecutas código real directamente en tu navegador y obtienes retroalimentación instantánea de IA — sin configuración local necesaria.
Todas las lecciones de este curso
- Fundamentos del SDK Slack Bolt
- Escucha de eventos y comandos de barra
- Envío de mensajes y bloques enriquecidos
- Creación de un bot de notificaciones para equipos