feat(Phase 5 Sprint 5.1): Telegram callback_handler 接上 dispatcher
Some checks failed
CD Pipeline / build-and-deploy (push) Has been cancelled
Some checks failed
CD Pipeline / build-and-deploy (push) Has been cancelled
整合點: _handle_callback_query 未知 action fallback 路徑 變更: 1. Line 2601 原「⚠️ 未知操作」改呼叫 _dispatch_category_action() 2. 新增 _dispatch_category_action() method: - 查 callback_action_spec registry - 若 action 不存在 → 回「未知操作」(行為不變) - 若存在 → acknowledge + 從 incident 取 labels + dispatch + reply 原卡片 效果: - check_process / check_port / check_log_* / check_health / open_signoz / open_flywheel 等 10 個查類按鈕現在有完整 flow(雖 Sprint 5.2 還沒接 MCP,但 stub 會 reply) - 當 CD 部署 + Sprint 5.2 實裝 MCP 接線後,查類按鈕自動上線 Sprint 5.1 DOD: - ✅ callback_handler 接線 _dispatch_category_action - ✅ Dispatcher 讀 incident labels 替換模板變數 - ✅ Reply to 原告警卡片(Redis tg_msg lookup) - ⏳ MCP 實際執行(Sprint 5.2) 回歸測試: 109/109 Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -2598,7 +2598,14 @@ class TelegramGateway:
|
||||
await self._answer_callback(callback_query_id, action, text="🔄 重診排程中...")
|
||||
await self._send_reanalyze_result(incident_id)
|
||||
else:
|
||||
await self._answer_callback(callback_query_id, action, text="⚠️ 未知操作")
|
||||
# 2026-04-14 Claude Sonnet 4.6 (Phase 5 Sprint 5.1):
|
||||
# 未知 action → fallback dispatcher (查看 callback_action_spec.yaml 是否有註冊)
|
||||
await self._dispatch_category_action(
|
||||
callback_query_id=callback_query_id,
|
||||
action=action,
|
||||
incident_id=incident_id,
|
||||
user_id=user_id,
|
||||
)
|
||||
|
||||
return {
|
||||
"action": action,
|
||||
@@ -2608,7 +2615,11 @@ class TelegramGateway:
|
||||
"info_action": True,
|
||||
}
|
||||
|
||||
nonce = parsed["nonce"]
|
||||
nonce = parsed["nonce"] # 4-part nonce action
|
||||
|
||||
# 2026-04-14 Claude Sonnet 4.6 (Phase 5 Sprint 5.1):
|
||||
# 寫類 nonce action 先驗 nonce 再 fallback dispatcher(若 action 在 registry)
|
||||
# 這段邏輯在 Step 2 之後再處理,這裡只是佔位註解
|
||||
|
||||
# 驗證使用者 + Nonce
|
||||
user = await self._security.verify_callback(
|
||||
@@ -3445,6 +3456,86 @@ class TelegramGateway:
|
||||
)
|
||||
return True
|
||||
|
||||
async def _dispatch_category_action(
|
||||
self,
|
||||
callback_query_id: str,
|
||||
action: str,
|
||||
incident_id: str,
|
||||
user_id: int,
|
||||
) -> None:
|
||||
"""
|
||||
Phase 5 Sprint 5.1 (2026-04-14 Claude Sonnet 4.6):
|
||||
Fallback dispatcher — 未知 info action 查 callback_action_spec.yaml
|
||||
|
||||
流程:
|
||||
1. 查 action registry
|
||||
2. 若不存在 → 原「⚠️ 未知操作」回覆
|
||||
3. 若存在 → 從 incident 取 labels → dispatch_action → reply_to 原卡片
|
||||
|
||||
注意: 此方法只處理 info action (查類)。nonce action (寫類) 走另一路徑。
|
||||
"""
|
||||
from src.services.callback_dispatcher import dispatch_action, get_action_spec
|
||||
|
||||
spec = get_action_spec(action)
|
||||
if not spec:
|
||||
await self._answer_callback(callback_query_id, action, text="⚠️ 未知操作")
|
||||
return
|
||||
|
||||
# Acknowledge callback immediately(避免 Telegram 端 timeout)
|
||||
await self._answer_callback(
|
||||
callback_query_id, action, text=f"{spec.emoji} 執行中..."
|
||||
)
|
||||
|
||||
# 從 incident 取 labels (供模板替換)
|
||||
labels: dict = {}
|
||||
try:
|
||||
from src.repositories.incident_repository import get_incident_repository
|
||||
repo = get_incident_repository()
|
||||
incident = await repo.get_by_id(incident_id)
|
||||
if incident and incident.signals:
|
||||
labels = incident.signals[0].labels or {}
|
||||
except Exception as _e:
|
||||
logger.debug("dispatch_labels_lookup_failed", incident_id=incident_id, error=str(_e))
|
||||
|
||||
# Dispatch
|
||||
result = await dispatch_action(
|
||||
action_name=action,
|
||||
incident_id=incident_id,
|
||||
user_id=user_id,
|
||||
labels=labels,
|
||||
)
|
||||
|
||||
# Reply to 原卡片 — 從 Redis tg_msg 查 message_id
|
||||
try:
|
||||
from src.core.redis_client import get_redis
|
||||
redis = get_redis()
|
||||
msg_id_raw = await redis.get(f"tg_msg:{incident_id}")
|
||||
orig_msg_id = int(msg_id_raw) if msg_id_raw else None
|
||||
except Exception:
|
||||
orig_msg_id = None
|
||||
|
||||
try:
|
||||
payload: dict = {
|
||||
"chat_id": settings.OPENCLAW_TG_CHAT_ID,
|
||||
"text": result.result_text,
|
||||
"parse_mode": "HTML",
|
||||
}
|
||||
if orig_msg_id:
|
||||
payload["reply_to_message_id"] = orig_msg_id
|
||||
await self._http_client.post(
|
||||
f"https://api.telegram.org/bot{settings.OPENCLAW_TG_BOT_TOKEN}/sendMessage",
|
||||
json=payload,
|
||||
)
|
||||
logger.info(
|
||||
"category_action_reply_sent",
|
||||
action=action,
|
||||
incident_id=incident_id,
|
||||
success=result.success,
|
||||
duration_ms=round(result.duration_ms, 1),
|
||||
)
|
||||
except Exception as _e:
|
||||
logger.warning("category_action_reply_failed", action=action, error=str(_e))
|
||||
|
||||
async def _send_incident_detail(self, incident_id: str) -> None:
|
||||
"""
|
||||
ADR-050 P2: 傳送事件詳情訊息 (不修改原始簽核卡片)
|
||||
|
||||
Reference in New Issue
Block a user