"""Build durable webhook events in the same transaction as domain updates.""" from __future__ import annotations from datetime import UTC, datetime import uuid from typing import Any from db.models import ConversationSession, SiteSetting, WebhookDelivery from sqlalchemy.ext.asyncio import AsyncSession ANALYSIS_WEBHOOK_KEY = "analysis_webhook" ANALYSIS_COMPLETED_EVENT = "call.analysis.completed" def analysis_completed_payload( conversation: ConversationSession, result: dict[str, Any], *, event_id: str, timestamp: datetime, ) -> dict[str, Any]: return { "id": event_id, "event": ANALYSIS_COMPLETED_EVENT, "timestamp": timestamp.isoformat(), "data": { "conversationId": conversation.id, "assistantId": conversation.assistant_id, "assistantName": conversation.assistant_name, "analysis": result, }, } async def enqueue_analysis_completed( session: AsyncSession, conversation: ConversationSession, result: dict[str, Any], ) -> WebhookDelivery | None: setting = await session.get(SiteSetting, ANALYSIS_WEBHOOK_KEY) values = dict(setting.value or {}) if setting else {} secrets = dict(setting.secrets or {}) if setting else {} url = str(values.get("url") or "") secret = str(secrets.get("secret") or "") if not values.get("enabled") or not url or not secret: return None event_id = f"evt_{uuid.uuid4().hex}" now = datetime.now(UTC) delivery = WebhookDelivery( id=f"dlv_{uuid.uuid4().hex}", event_id=event_id, event_type=ANALYSIS_COMPLETED_EVENT, conversation_id=conversation.id, payload=analysis_completed_payload( conversation, result, event_id=event_id, timestamp=now, ), url=url, secrets={"secret": secret}, status="pending", next_attempt_at=now, ) session.add(delivery) return delivery