"""Telegram Notification Provider — 接線 TelegramGateway 到 NotificationManager 2026-04-25 修復 L2:系統執行反饋完全丟失 根本原因:執行完成後的推送通知未配置任何 provider,Telegram 曾有 Gateway 實作 但從未註冊為 NotificationProvider,導致執行失敗的卡片無法推送回 Telegram 本模組:直接複用既有 TelegramGateway.send_alert_notification(),將執行結果格式化並推送 """ from src.core.config import settings from src.core.logging import get_logger from .base import ( ExecutionStatus, NotificationMessage, NotificationProvider, NotificationResult, NotificationStatus, ) logger = get_logger("awoooi.notifications.telegram") class TelegramWebhookProvider(NotificationProvider): """透過既有 TelegramGateway 發送執行結果卡片""" @property def name(self) -> str: return "telegram" @property def enabled(self) -> bool: """檢查 Telegram bot token 與 AwoooI SRE 戰情室是否配置。""" return bool(settings.OPENCLAW_TG_BOT_TOKEN) and bool(settings.SRE_GROUP_CHAT_ID) def _format(self, msg: NotificationMessage) -> str: """格式化執行結果為 Telegram 訊息""" title = f"{msg.status_emoji} {msg.status_text}" lines = [ title, "━━━━━━━━━━━━━━━━━━━", f"🎯 {msg.action_title[:120]}", f"🧭 Namespace: {msg.namespace} | Op: {msg.operation_type}", f"{msg.risk_emoji} 風險: {msg.risk_level.upper()} | Pods: {msg.affected_pods}", f"📝 Approval: {msg.approval_id[:12]}", ] if msg.duration_ms is not None: lines.append(f"⏱️ 耗時: {msg.duration_ms}ms") if msg.error_message: lines.append(f"❗ 錯誤: {msg.error_message[:200]}") if msg.signers: lines.append(f"👥 簽核: {msg.signers_display}") return "\n".join(lines) async def send(self, message: NotificationMessage) -> NotificationResult: """推送執行結果到 Telegram""" if not self.enabled: return NotificationResult( status=NotificationStatus.SKIPPED, provider=self.name, message="Telegram bot token or chat_id not configured", ) try: from src.services.telegram_gateway import get_telegram_gateway gateway = get_telegram_gateway() text = self._format(message) resp = await gateway.send_alert_notification(text=text, parse_mode="HTML") return NotificationResult( status=NotificationStatus.SUCCESS, provider=self.name, message="Telegram notification sent", response_data=resp if isinstance(resp, dict) else None, ) except Exception as e: logger.exception("telegram_notification_exception", error=str(e)) return NotificationResult( status=NotificationStatus.FAILED, provider=self.name, message="Exception during send", error=str(e)[:300], ) async def test_connection(self) -> bool: """測試 Telegram 連接""" if not self.enabled: return False try: from src.services.telegram_gateway import get_telegram_gateway gw = get_telegram_gateway() await gw.send_alert_notification(text="🔔 AWOOOI Telegram provider 連線測試") return True except Exception as e: logger.error("telegram_connection_test_failed", error=str(e)) return False