--- name: slack-webhook description: Use when sending Slack alerts or notifications. Automatically uses the configured SLACK_WEBHOOK_URL from environment. --- # Slack Webhook Integration Send alerts and notifications to Slack using the configured webhook. ## Quick Start The webhook URL is automatically loaded from the `SLACK_WEBHOOK_URL` environment variable. ```python import os import json from urllib.request import Request, urlopen def send_slack_alert(message: dict) -> bool: """Send a message to Slack via webhook. Args: message: Slack Block Kit message payload Returns: True if sent successfully, False otherwise """ webhook_url = os.environ.get('SLACK_WEBHOOK_URL') if not webhook_url: raise ValueError("SLACK_WEBHOOK_URL environment variable not set") request = Request( webhook_url, data=json.dumps(message).encode('utf-8'), headers={'Content-Type': 'application/json'} ) with urlopen(request, timeout=10) as response: return response.status == 200 ``` ## Message Formats ### Simple Text Message ```python message = { "text": "Hello from the agent!" } send_slack_alert(message) ``` ### Alert with Block Kit (Recommended) ```python message = { "blocks": [ { "type": "header", "text": {"type": "plain_text", "text": "šŸ”“ Anomaly Detected"} }, { "type": "section", "fields": [ {"type": "mrkdwn", "text": "*Metric:*\nConversion Rate"}, {"type": "mrkdwn", "text": "*Severity:*\nCritical"} ] }, { "type": "section", "fields": [ {"type": "mrkdwn", "text": "*Expected:*\n4.2%"}, {"type": "mrkdwn", "text": "*Actual:*\n1.8%"} ] }, {"type": "divider"}, { "type": "section", "text": { "type": "mrkdwn", "text": "*Potential Causes:*\n• Checkout flow issue\n• Payment gateway error\n• Landing page test impact" } }, { "type": "context", "elements": [ {"type": "mrkdwn", "text": "šŸ¤– Alert generated by AI Agent"} ] } ] } ``` ### Anomaly Alert Template ```python def build_anomaly_alert( metric_name: str, date: str, expected: float, actual: float, severity: str = "Warning", potential_causes: list = None ) -> dict: """Build a formatted anomaly alert message. Args: metric_name: Name of the metric (e.g., "Conversion Rate") date: Date of the anomaly expected: Expected value actual: Actual value severity: "Critical" or "Warning" potential_causes: List of potential cause strings Returns: Slack Block Kit message payload """ emoji = "šŸ”“" if severity == "Critical" else "🟔" pct_change = ((actual - expected) / expected) * 100 direction = "drop" if pct_change < 0 else "spike" blocks = [ { "type": "header", "text": {"type": "plain_text", "text": f"{emoji} Anomaly Detected: {metric_name}"} }, { "type": "section", "fields": [ {"type": "mrkdwn", "text": f"*Date:*\n{date}"}, {"type": "mrkdwn", "text": f"*Severity:*\n{severity}"} ] }, { "type": "section", "fields": [ {"type": "mrkdwn", "text": f"*Expected:*\n{expected:,.2f}"}, {"type": "mrkdwn", "text": f"*Actual:*\n{actual:,.2f}"} ] }, { "type": "section", "text": { "type": "mrkdwn", "text": f"*Change:* {pct_change:+.1f}% {direction}" } } ] if potential_causes: causes_text = "\n".join([f"• {cause}" for cause in potential_causes]) blocks.extend([ {"type": "divider"}, { "type": "section", "text": { "type": "mrkdwn", "text": f"*Potential Causes:*\n{causes_text}" } } ]) blocks.append({ "type": "context", "elements": [ {"type": "mrkdwn", "text": "šŸ¤– Alert generated by AI Agent"} ] }) return {"blocks": blocks} ``` ## Usage Example ```python # Build and send an anomaly alert alert = build_anomaly_alert( metric_name="Trial Conversion Rate", date="2025-11-28", expected=37.6, actual=10.5, severity="Critical", potential_causes=[ "Onboarding flow broken", "Integration setup failing", "New user segment with different behavior" ] ) success = send_slack_alert(alert) if success: print("āœ… Alert sent to Slack") else: print("āŒ Failed to send alert") ``` ## Testing To test without sending (dry run): ```python import json print(json.dumps(alert, indent=2)) ``` ## Error Handling ```python from urllib.error import URLError, HTTPError try: send_slack_alert(message) except ValueError as e: print(f"Configuration error: {e}") except HTTPError as e: print(f"Slack API error: {e.code} - {e.reason}") except URLError as e: print(f"Network error: {e.reason}") ```