イベントとスラッシュコマンドの受信
Slack Boltでのapp_mention、スラッシュコマンド、アクションハンドラーを学びます。
「イベントとスラッシュコマンドの受信」はCoddyKit上の無料AI Agentsレッスンです。 これはレッスン2/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはAI Agents学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 AI Agentsコースには全4レッスンが含まれています。
Slack イベントサブスクリプションの概要
Slack は、何かが起きるたびにアプリへ イベント を送信します — メッセージの投稿、誰かによるボットのメンション、ユーザーのチャンネル参加などです。Slack App ダッシュボードで特定のイベントタイプを購読し、続いて @app.event() デコレーターを使って Bolt にハンドラーを登録します。
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"]}')app_mention イベントの処理
app_mention イベントは、チャンネルで誰かが @YourBot と入力したときに発生します。event['text'] にはメンションを含むメッセージ全体が格納されます。メンションのプレフィックスを取り除くと、ユーザーが実際に入力したクエリを取得できます。
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)イベントペイロードへのアクセス
すべてのイベントハンドラーは、Slack イベントの生のペイロードを含む event 辞書を受け取ります。主なフィールドは次のとおりです。event['user'](ユーザー ID)、event['channel'](チャンネル ID)、event['text'](メッセージの内容)、event['ts'](タイムスタンプ/メッセージ ID)。
@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 コマンドの登録と応答
Slash コマンドを使うと、ユーザーは Slack の任意のチャンネルからエージェントのアクションを実行できます。Slack App ダッシュボードの Slash Commands でコマンド URL を登録し、@app.command('/command-name') で処理します。必ずすぐに ack() を呼び出してください。呼び出さない場合、Slack は 3 秒でタイムアウトします。
@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() — 3 秒ルール
Slack では、受信したすべての Slash コマンドとインタラクティブペイロードについて、3 秒以内 にアプリが ack()(受信確認)を返す必要があります。返さない場合、Slack はユーザーにエラーを表示します。時間のかかる処理では、すぐに ack してバックグラウンドスレッドで処理を開始し、完了したら respond() で結果を返します。
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() と respond() — 使い分け
Slack にメッセージを投稿する関数は 2 つあります。
say()— イベントが発生したチャンネルに投稿します。全員に表示されますrespond()— Slash コマンドのハンドラーでのみ使用できます。エフェメラルメッセージを投稿でき、コマンドを実行したユーザーだけに表示されます
公開応答には respond(response_type='in_channel') を使用し、非公開の応答には respond(response_type='ephemeral') を使用します。
@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')message イベントとサブタイプ
汎用の message イベントは、ボットのメッセージ、編集、削除を含むすべてのメッセージに対して発生します。subtype フィールドを使って絞り込みます。一般的なサブタイプには、bot_message、message_changed、message_deleted があります。subtype が存在しない場合は、通常のユーザーメッセージです。
@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}')リアクションの監視
reaction_added イベントは、誰かがメッセージに絵文字リアクションを追加したときに発生します。これを使ってエージェントのアクションを実行できます。たとえば、📌 リアクションを追加してメッセージを保存したり、✅ を追加してタスクの完了を示したりできます。
@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]}')インタラクティブコンポーネントからのアクションペイロード
ユーザーがボタンをクリックしたりメニュー項目を選択したりすると、Slack は アクションペイロード を送信します。@app.action('action_id') で処理します。アクション ID は、Block Kit コンポーネントの作成時に設定した文字列です。必ずすぐに ack() を呼び出してください。
@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')チャンネルまたはユーザーによるイベントの絞り込み
大規模なワークスペースでは、ボットが多くのチャンネルからイベントを受け取ることがあります。ハンドラーの早い段階で絞り込み、関連するイベントだけを処理してください。event['channel'] を許可リストと照合するか、event['user'] を確認して、特定のユーザー(他のボットなど)を無視します。
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]}')スレッド返信への対応
メインチャンネルではなくスレッドに返信するには、say() に thread_ts を渡します。スレッドのタイムスタンプを取得するには event.get('thread_ts', event['ts']) を使用します。thread_ts はメッセージがすでにスレッド内にある場合にのみ存在するため、そうでなければメッセージ自身の ts を使って新しいスレッドを開始します。
@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
)クイックチェック: ack() のタイミング
Slack のイベント処理についての理解度を確認します。
イベントと Slash コマンドのまとめ
これで Slack エージェントは、あらゆるユーザー操作に応答できるようになりました。
- @app.event('app_mention') — @bot のメンションを処理します。正規表現でメンションのプレフィックスを取り除きます
- @app.command('/cmd') — Slash コマンドを処理します。必ず 3 秒以内に
ack()を呼び出します - say() — チャンネルに公開投稿します。respond() — Slash コマンドに応答します(エフェメラルにもできます)
- @app.action('id') — ボタンのクリックやインタラクティブコンポーネントの操作を処理します
- @app.event('reaction_added') — 絵文字リアクションをトリガーにします
- say() で
thread_tsを使用すると、返信をスレッド内に保持できます - チャンネルやユーザーで早い段階に絞り込み、無関係なイベントの処理を避けます
よくある質問
「イベントとスラッシュコマンドの受信」レッスンは無料ですか?
はい。「イベントとスラッシュコマンドの受信」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、AI Agentsコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 AI Agentsコースには全4レッスンが含まれています。
「イベントとスラッシュコマンドの受信」で何を学びますか?
Slack Boltでのapp_mention、スラッシュコマンド、アクションハンドラーを学びます。 ブラウザで直接実行するハンズオンコードでAI Agentsを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。
AI Agentsを始めるのに経験は必要ですか?
事前経験は必要ありません。CoddyKitのAI Agentsは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン2/4です。
「イベントとスラッシュコマンドの受信」レッスンにはどのくらい時間がかかりますか?
ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。
このAI Agentsレッスンでコードを書いて実行できますか?
はい。すべてのAI Agentsレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。
このコースのすべてのレッスン
- Slack Bolt SDKの基礎
- イベントとスラッシュコマンドの受信
- メッセージとリッチブロックの送信
- チーム通知ボットの構築