0Pricing
AI Agents · درس

الاستماع إلى الأحداث وأوامر الشرطة المائلة

app_mention وأوامر الشرطة المائلة ومعالجات الإجراءات في Slack Bolt

الاستماع إلى الأحداث وأوامر الشرطة المائلة درس مجاني في AI Agents على CoddyKit. هذا هو الدرس 2 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في AI Agents، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة AI Agents 4 دروس في المجموع.

نظرة عامة على اشتراكات أحداث Slack

يرسل Slack إلى تطبيقكم أحداثًا عند وقوع أمور معينة — مثل نشر رسالة، أو ذكر أحدهم لروبوتكم، أو انضمام مستخدم إلى قناة. تشتركون في أنواع أحداث محددة من لوحة Slack App، ثم تسجّلون معالجات الأحداث في Bolt باستخدام المزيّن @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"]}')

التعامل مع أحداث 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)

الوصول إلى حمولة الحدث

يتلقى كل معالج أحداث قاموس event الذي يحتوي على حمولة حدث Slack الخام. الحقول الرئيسية هي: event['user'] (معرّف المستخدم)، وevent['channel'] (معرّف القناة)، وevent['text'] (محتوى الرسالة)، وevent['ts'] (الطابع الزمني/معرّف الرسالة).

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

تسجيل أوامر الشرطة المائلة والاستجابة لها

تتيح أوامر الشرطة المائلة للمستخدمين تشغيل إجراءات الوكيل من أي قناة في Slack. سجّلوا عنوان URL للأمر في لوحة Slack App (ضمن Slash Commands)، ثم عالجوه باستخدام @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() — قاعدة الثواني الثلاث

يتطلب Slack من تطبيقكم استدعاء ack() (لإقرار الاستلام) لكل أمر شرطة مائلة وحمولة تفاعلية واردة خلال 3 ثوانٍ. إذا لم تفعلوا ذلك، يعرض 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 out

say() أم respond() — متى تستخدمون كلًّا منهما

توجد دالتان لنشر الرسائل إلى Slack:

  • say() — تنشر في القناة التي وقع فيها الحدث؛ وتكون الرسالة مرئية للجميع
  • respond() — تتوفر فقط في معالجات أوامر الشرطة المائلة؛ ويمكنها نشر رسائل مؤقتة لا يراها سوى مستخدم الأمر

استخدموا 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 العام لجميع الرسائل، بما في ذلك رسائل الروبوتات والتعديلات وعمليات الحذف. استخدموا الحقل 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'). ومعرّف الإجراء هو السلسلة النصية التي تحددونها عند إنشاء مكوّن 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]}')

دعم الردود ضمن سلاسل المحادثات

للرد ضمن سلسلة محادثات بدلًا من القناة الرئيسية، مرّروا thread_ts إلى say(). استخدموا 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.

مراجعة الأحداث وأوامر الشرطة المائلة

يمكن لوكيل Slack الخاص بكم الآن الاستجابة لأي تفاعل من المستخدم:

  • @app.event('app_mention') — التعامل مع إشارات @bot؛ وإزالة بادئة الإشارة باستخدام تعبير نمطي
  • @app.command('/cmd') — التعامل مع أوامر الشرطة المائلة؛ واستدعاء ack() دائمًا خلال 3 ثوانٍ
  • say() — النشر علنًا في القناة؛ وrespond() — الرد على أمر شرطة مائلة، ويمكن أن يكون مؤقتًا
  • @app.action('id') — التعامل مع نقرات الأزرار وتفاعلات المكوّنات التفاعلية
  • @app.event('reaction_added') — التشغيل عند إضافة تفاعلات باستخدام الرموز التعبيرية
  • استخدموا thread_ts في say() لإبقاء الردود ضمن سلاسل المحادثات
  • أجروا التصفية حسب القناة/المستخدم مبكرًا لتجنب معالجة الأحداث غير ذات الصلة

الأسئلة الشائعة

هل درس «الاستماع إلى الأحداث وأوامر الشرطة المائلة» مجاني؟

نعم — نص درس «الاستماع إلى الأحداث وأوامر الشرطة المائلة» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة AI Agents، انتقل إلى CoddyKit PRO. تتضمن دورة AI Agents 4 دروس في المجموع.

ماذا ستتعلم في «الاستماع إلى الأحداث وأوامر الشرطة المائلة»؟

app_mention وأوامر الشرطة المائلة ومعالجات الإجراءات في Slack Bolt تتمرن على AI Agents مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.

هل أحتاج إلى خبرة سابقة لأبدأ AI Agents؟

لا تُشترط خبرة سابقة. AI Agents على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 2 من أصل 4.

كم من الوقت يستغرق درس «الاستماع إلى الأحداث وأوامر الشرطة المائلة»؟

معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.

هل يمكنني كتابة وتشغيل أكواد في درس AI Agents هذا؟

نعم. كل درس في AI Agents يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.

جميع الدروس في هذه الدورة

  1. أساسيات Slack Bolt SDK
  2. الاستماع إلى الأحداث وأوامر الشرطة المائلة
  3. إرسال الرسائل والكتل المنسقة
  4. بناء bot لإشعارات الفريق
← العودة إلى AI Agents