from __future__ import annotations from datetime import datetime from typing import Any from pydantic import BaseModel, Field class NormalizedEvent(BaseModel): source: str = "zabbix" correlation_id: str received_at: datetime remote_addr: str | None = None event_id: str | None = None problem_id: str | None = None event_type: str = "problem" timestamp: datetime | None = None severity: str | None = None severity_code: int | None = None host: str | None = None host_id: str | None = None service: str | None = None trigger_name: str | None = None trigger_id: str | None = None item_id: str | None = None value: str | None = None opdata: str | None = None zabbix_url: str | None = None event_url: str | None = None graph_url: str | None = None graph_image_path: str | None = None zabbix_context: dict[str, Any] = Field(default_factory=dict) tags: dict[str, str] = Field(default_factory=dict) raw_payload: dict[str, Any] class ProcessorForwardEnvelope(BaseModel): event: NormalizedEvent class NotificationDecision(BaseModel): notify: bool severity: str | None = None channels: list[str] = Field(default_factory=list) reason: str routing_class: str fingerprint: str | None = None repeat_count: int = 1 suppressed: bool = False suppress_reason: str | None = None event_phase: str = "problem" open_incident_found: bool = False recovered_from_severity: str | None = None flap_detected: bool = False flap_event_count: int = 0 flap_reason: str | None = None triage_applied: bool = False triage_source: str | None = None triage_verdict: str | None = None triage_reason: str | None = None triage_classification: str | None = None correlation_applied: bool = False correlation_role: str | None = None correlation_group_id: str | None = None correlation_kind: str | None = None correlation_reason: str | None = None correlation_source: str | None = None correlation_confidence: str | None = None parent_event_id: str | None = None parent_correlation_id: str | None = None root_cause_candidate: bool = False correlated_event_count: int = 0 llm_enriched: bool = False remediation_summary: str | None = None remediation_steps: list[str] = Field(default_factory=list) remediation_commands: list[str] = Field(default_factory=list) class ProcessorAck(BaseModel): accepted: bool correlation_id: str decision: NotificationDecision message: str class IngestAck(BaseModel): accepted: bool correlation_id: str queued: bool job_id: str message: str