0Pricing
AI Agents · Lezione

Ascolto degli eventi e dei comandi slash

app_mention, comandi slash e gestori delle azioni in Slack Bolt

Ascolto degli eventi e dei comandi slash è una lezione AI Agents gratuita su CoddyKit. Questa è la lezione 2 di 4. Puoi leggere la lezione completa qui gratuitamente — poi esercitati direttamente nel browser con un editor di codice integrato e un tutor IA disponibile 24/7. Fa parte del percorso di apprendimento AI Agents, e i tuoi progressi si sincronizzano tra il web e l'app CoddyKit. Il corso AI Agents include 4 lezioni in totale.

Panoramica delle sottoscrizioni agli eventi di Slack

Slack invia alla Sua app degli eventi quando accadono determinate cose: quando viene pubblicato un messaggio, qualcuno menziona il Suo bot o un utente entra in un canale. Sottoscriva tipi di evento specifici nella dashboard di Slack, quindi registri i gestori in Bolt usando il decoratore @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"]}')

Gestione degli eventi app_mention

L'evento app_mention viene attivato quando qualcuno scrive @YourBot in un canale. event['text'] contiene il messaggio completo, inclusa la menzione. Rimuova il prefisso della menzione per ottenere la query effettiva dell'utente.

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)

Accesso al payload dell'evento

Ogni gestore di eventi riceve il dizionario event, che contiene il payload grezzo dell'evento Slack. Campi principali: event['user'] (ID utente), event['channel'] (ID del canale), event['text'] (contenuto del messaggio), event['ts'] (timestamp/ID del messaggio).

@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}!')

Slash Commands — Registrazione e risposta

Gli slash command consentono agli utenti di attivare azioni dell'agente da qualsiasi canale Slack. Registri l'URL del comando nella dashboard di Slack, nella sezione Slash Commands, quindi lo gestisca con @app.command('/command-name'). Esegua sempre ack() immediatamente: Slack interrompe l'attesa dopo 3 secondi se non lo fa.

@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 regola dei 3 secondi

Slack richiede che la Sua app esegua ack() (confermi la ricezione) di ogni slash command e payload interattivo entro 3 secondi. In caso contrario, Slack mostra un errore all'utente. Per le operazioni di lunga durata, esegua subito ack, avvii l'elaborazione in un thread in background, quindi risponda usando respond() con il risultato.

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() vs respond() — Quando usare ciascuno

Due funzioni pubblicano messaggi su Slack:

  • say() — pubblica nel canale in cui si è verificato l'evento; è visibile a tutti
  • respond() — è disponibile solo nei gestori degli slash command; può pubblicare messaggi effimeri visibili solo all'utente che ha eseguito il comando

Utilizzi respond(response_type='in_channel') per le risposte pubbliche e respond(response_type='ephemeral') per quelle private.

@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')

Eventi message e sottotipi

L'evento generico message viene attivato per tutti i messaggi, inclusi quelli dei bot, le modifiche e le eliminazioni. Utilizzi il campo subtype per filtrare. Sottotipi comuni: bot_message, message_changed, message_deleted. Se subtype è assente, si tratta di un normale messaggio di un utente.

@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}')

Ascolto delle reazioni

L'evento reaction_added viene attivato quando qualcuno aggiunge una reazione con emoji a un messaggio. Può utilizzarlo per attivare azioni dell'agente, ad esempio aggiungendo una reazione 📌 per salvare un messaggio o una ✅ per contrassegnare un'attività come completata.

@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]}')

Payload delle azioni dei componenti interattivi

Quando un utente fa clic su un pulsante o seleziona una voce di menu, Slack invia un payload dell'azione. Lo gestisca con @app.action('action_id'). L'ID dell'azione è la stringa impostata durante la creazione del componente Block Kit. Esegua sempre ack() immediatamente.

@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')

Filtraggio degli eventi per canale o utente

Negli workspace di grandi dimensioni, il Suo bot potrebbe ricevere eventi da molti canali. Filtri all'inizio del gestore per elaborare solo gli eventi pertinenti. Verifichi event['channel'] rispetto a un elenco di canali consentiti oppure utilizzi event['user'] per ignorare determinati utenti, ad esempio altri bot.

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]}')

Supporto alle risposte nei thread

Per rispondere in un thread, invece che nel canale principale, passi thread_ts a say(). Utilizzi event.get('thread_ts', event['ts']) per ottenere il timestamp del thread: thread_ts esiste solo se il messaggio si trova già in un thread; in caso contrario, utilizzi il ts del messaggio stesso per avviare un nuovo thread.

@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 rapida: tempistica di ack()

Verifichi la Sua comprensione della gestione degli eventi Slack.

Riepilogo di eventi e Slash Commands

Ora il Suo agente Slack può rispondere a qualsiasi interazione dell'utente:

  • @app.event('app_mention') — gestisce le menzioni di @bot; rimuova il prefisso della menzione con un'espressione regolare
  • @app.command('/cmd') — gestisce gli slash command; esegua sempre ack() entro 3 secondi
  • say() — pubblica nel canale in modo pubblico; respond() — risponde allo slash command e può inviare messaggi effimeri
  • @app.action('id') — gestisce i clic sui pulsanti e le interazioni con i componenti interattivi
  • @app.event('reaction_added') — si attiva in caso di reazioni con emoji
  • Utilizzi thread_ts in say() per mantenere le risposte nei thread
  • Filtri tempestivamente per canale o utente per evitare di elaborare eventi non pertinenti

Domande Frequenti

La lezione «Ascolto degli eventi e dei comandi slash» è gratuita?

Sì — il testo completo di «Ascolto degli eventi e dei comandi slash» è gratuito qui sul web. Per esercitarvi in modo interattivo (un editor di codice integrato e un tutor IA 24/7) e sbloccare il resto del corso AI Agents, passa a CoddyKit PRO. Il corso AI Agents include 4 lezioni in totale.

Cosa imparerò in «Ascolto degli eventi e dei comandi slash»?

app_mention, comandi slash e gestori delle azioni in Slack Bolt Eserciti AI Agents con codice pratico che esegui direttamente nel browser, e un tutor IA 24/7 risponde alle tue domande mentre lavori sulla lezione.

Ho bisogno di esperienza per iniziare AI Agents?

Non è richiesta alcuna esperienza precedente. AI Agents su CoddyKit è strutturato per principianti e studenti avanzati, quindi puoi iniziare da qui o dall'inizio e procedere al tuo ritmo. Questa è la lezione 2 di 4.

Quanto tempo richiede la lezione «Ascolto degli eventi e dei comandi slash»?

La maggior parte delle lezioni CoddyKit richiede circa 5–10 minuti. Ogni lezione è breve e interattiva, quindi fai progressi costanti e riprendi esattamente da dove hai lasciato su web e app.

Posso scrivere ed eseguire codice in questa lezione AI Agents?

Sì. Ogni lezione AI Agents include un editor di codice integrato, quindi scrivi ed esegui codice reale direttamente nel tuo browser e ricevi feedback istantaneo dall'IA — nessuna configurazione locale necessaria.

Tutte le lezioni di questo corso

  1. Nozioni di base di Slack Bolt SDK
  2. Ascolto degli eventi e dei comandi slash
  3. Invio di messaggi e blocchi avanzati
  4. Creazione di un bot per le notifiche del team
← Torna a AI Agents