diff --git a/apps/api/src/services/telegram_gateway.py b/apps/api/src/services/telegram_gateway.py
index d7544c30..304b8cf6 100644
--- a/apps/api/src/services/telegram_gateway.py
+++ b/apps/api/src/services/telegram_gateway.py
@@ -1860,6 +1860,8 @@ class TelegramGateway:
nemotron_validation=nemotron_validation,
nemotron_latency_ms=nemotron_latency_ms,
incident_id=incident_id,
+ alert_category=alert_category,
+ notification_type=notification_type,
)
)
@@ -1893,6 +1895,8 @@ class TelegramGateway:
nemotron_validation: str = "",
nemotron_latency_ms: float = 0.0,
incident_id: str = "",
+ alert_category: str = "",
+ notification_type: str = "",
) -> None:
"""
發送告警卡片到 SRE 群組 — 與個人 chat 相同的完整 v7.0 格式
@@ -1940,7 +1944,16 @@ class TelegramGateway:
nemotron_latency_ms=nemotron_latency_ms,
)
text = message.format_with_nemotron() if nemotron_enabled else message.format()
- resp = await self.send_to_group(text=text)
+
+ # 2026-04-25 ogt + Claude Sonnet 4.6: 群組卡片使用完整 _build_inline_keyboard
+ # 統帥決策: 群組成員為受信任 SRE,完整批准/拒絕/暫默/詳情/重診/歷史按鈕從 DM 移植至群組
+ _group_keyboard = self._build_inline_keyboard(
+ approval_id=approval_id,
+ incident_id=incident_id,
+ alert_category=alert_category,
+ notification_type=notification_type,
+ )
+ resp = await self.send_to_group(text=text, reply_markup=_group_keyboard)
# 2026-04-10 Claude Sonnet 4.6: 儲存 message_id 到 Redis,供 append_incident_update 使用
# tg_msg:{incident_id} → Telegram message_id (TTL 24h)
@@ -1967,10 +1980,13 @@ class TelegramGateway:
severity: str = "info",
) -> dict:
"""
- TYPE-1 純資訊通知 — 無按鈕,FYI 類告警
+ TYPE-1 純資訊通知 — FYI 類告警
用於: severity=info 成功類 / Backup 完成 / AlertChainHealthy 等
- 格式: 簡潔文字,無 InlineKeyboard
+ 格式: 簡潔文字 + [詳情][歷史] 查類按鈕(read-only,2-part info 格式,ADR-050)
+
+ 2026-04-25 ogt + Claude Sonnet 4.6: 補充 read-only 按鈕(鬼魂按鈕鐵律:
+ detail/history 已有 handler 且無副作用,符合三條件才加)
Args:
incident_id: 事件 ID
@@ -1987,16 +2003,23 @@ class TelegramGateway:
)
if alertname:
text += f"🔔 告警: {html.escape(alertname)}\n"
- text += (
- f"\n{html.escape(message)}\n"
- f"\n此為純資訊通知,無需操作。"
- )
+ text += f"\n{html.escape(message)}"
+
+ # read-only 查類按鈕(2-part info 格式,handler 已在 handle_callback 實作)
+ # detail/history 均在 INFO_ACTIONS 白名單,無 nonce 無副作用
+ keyboard = {
+ "inline_keyboard": [[
+ {"text": "📋 詳情", "callback_data": f"detail:{incident_id}"},
+ {"text": "📊 歷史", "callback_data": f"history:{incident_id}"},
+ ]]
+ }
return await self._send_request(
"sendMessage",
{
"chat_id": settings.OPENCLAW_TG_CHAT_ID,
"text": text,
"parse_mode": "HTML",
+ "reply_markup": keyboard,
},
)