Files
awoooi/apps/api/src/services/agent99_telegram_lifecycle.py

115 lines
4.1 KiB
Python
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""Canonical, durable Telegram lifecycle delivery for Windows Agent99."""
from __future__ import annotations
import html
from typing import Any
from src.models.agent99_completion import Agent99TelegramLifecycleRequest
from src.services.telegram_gateway import get_telegram_gateway
_LIFECYCLE_LABELS = {
"detected": "已偵測 / DETECTED",
"investigating": "調查中 / INVESTIGATING",
"remediating": "修復中 / REMEDIATING",
"verifying": "驗證中 / VERIFYING",
"recovered": "已恢復 / RECOVERED",
"blocked": "需介入 / ACTION REQUIRED",
"unknown": "狀態未知 / UNKNOWN",
}
_SEVERITY_LABELS = {
"critical": "重大 / CRITICAL",
"warning": "警告 / WARNING",
"info": "資訊 / INFO",
}
def _format_lifecycle_card(payload: Agent99TelegramLifecycleRequest) -> str:
def esc(value: object) -> str:
return html.escape(str(value or ""))
return "\n".join(
[
f"<b>Agent99 事件|{esc(payload.title)}</b>",
(
f"狀態:<b>{esc(_LIFECYCLE_LABELS[payload.lifecycle])}</b>"
f" 等級:<b>{esc(_SEVERITY_LABELS[payload.severity])}</b>"
),
"────────────────────",
f"<b>資產</b> {esc(payload.target)}",
f"<b>影響</b> {esc(payload.impact)}",
f"<b>AI 處置</b> {esc(payload.action)}",
f"<b>驗證</b> {esc(payload.verification)}",
"────────────────────",
(
f"事件:<code>{esc(payload.incident_id)}</code> "
f"發生:{payload.occurrences} 次 耗時:{esc(payload.duration_text)}"
),
f"下一次更新:{esc(payload.next_update)}",
f"時間:{esc(payload.occurred_at.isoformat())}",
]
)[:4096]
async def deliver_agent99_telegram_lifecycle(
payload: Agent99TelegramLifecycleRequest,
) -> dict[str, Any]:
"""Send once through the registered AWOOOI SRE route and verify its ack."""
response = await get_telegram_gateway().send_agent99_lifecycle_receipt(
delivery_id=payload.delivery_id,
incident_id=payload.incident_id,
state_key=payload.state_key,
text=_format_lifecycle_card(payload),
priority="P0" if payload.severity == "critical" else "P1",
project_id=payload.project_id,
reply_to_message_id=payload.reply_to_message_id,
)
result = response.get("result") if isinstance(response, dict) else None
message_id = str(result.get("message_id") or "") if isinstance(result, dict) else ""
delivery_context = (
response.get("_awooop_delivery_context")
if isinstance(response, dict)
and isinstance(response.get("_awooop_delivery_context"), dict)
else {}
)
delivery_status = (
str(response.get("_awooop_delivery_status") or "")
if isinstance(response, dict)
else ""
)
durable_ack = bool(
isinstance(response, dict)
and response.get("_awooop_outbound_mirror_acknowledged") is True
)
destination_verified = bool(
delivery_status == "sent_reused"
or delivery_context.get("destination_binding_verified") is True
)
ok = bool(
durable_ack
and destination_verified
and message_id
and delivery_status in {"sent", "sent_reused"}
)
return {
"schema_version": "agent99_telegram_lifecycle_receipt_v1",
"ok": ok,
"delivery_id": payload.delivery_id,
"incident_id": payload.incident_id,
"event_type": payload.event_type,
"lifecycle": payload.lifecycle,
"provider_message_id": message_id or None,
"delivery_status": delivery_status or "unknown",
"durable_outbound_acknowledged": durable_ack,
"destination_binding_verified": destination_verified,
"provider_send_performed": bool(
isinstance(response, dict)
and response.get("_awooop_provider_send_performed") is True
),
"stores_secret": False,
"raw_response_stored": False,
}