import { z } from "zod"; import type { JsonObject } from "../core/json.js"; import type { ThoughtEvent } from "../events/types.js"; export const OPERATIONAL_INCIDENT_EVENT_TYPE = "stream.thought.runtime.incident"; export const OPERATIONAL_INCIDENT_SOURCE = "system:operational-incidents"; export const OPERATIONAL_INCIDENT_ACTOR = "system:incident-projector"; export const OPERATIONAL_INCIDENT_CATEGORIES = [ "connector-failure", "connector-terminal", "connector-recovered", "scheduler-exhausted", "agent-run-failed", "agent-run-blocked", "agent-run-abandoned", "telegram-delivery-failed", ] as const; export const DEFAULT_ALERT_INCIDENT_CATEGORIES = [ "connector-terminal", "scheduler-exhausted", "agent-run-failed", "agent-run-blocked", ] as const; const boundedId = z.string().min(1).max(500); const boundedToken = z.string().min(1).max(120).regex(/^[A-Za-z0-9._:-]+$/); export const operationalIncidentPayloadSchema = z.object({ incidentVersion: z.literal(1), incidentId: boundedId, state: z.enum(["open", "recovered"]), category: z.enum(OPERATIONAL_INCIDENT_CATEGORIES), severity: z.enum(["info", "warning", "error", "critical"]), component: boundedId, code: boundedToken, stage: boundedToken.optional(), fingerprint: z.string().regex(/^[a-f0-9]{64}$/), occurredAt: z.string().datetime({ offset: true }), retryable: z.boolean(), progress: z.enum(["advanced", "unchanged", "unknown", "not-applicable"]), source: boundedId.optional(), agentId: boundedId.optional(), agentVersion: z.number().int().positive().optional(), attempt: z.number().int().positive().optional(), references: z.object({ originEventId: boundedId.optional(), runId: boundedId.optional(), triggerEventId: boundedId.optional(), deliveryId: boundedId.optional(), }).strict(), }).strict(); export type OperationalIncident = z.infer; export type OperationalIncidentCategory = OperationalIncident["category"]; export function parseOperationalIncidentEvent(event: ThoughtEvent): OperationalIncident | undefined { if (event.type !== OPERATIONAL_INCIDENT_EVENT_TYPE || event.schemaVersion !== 1) return undefined; const parsed = operationalIncidentPayloadSchema.safeParse(event.payload); return parsed.success ? parsed.data : undefined; } export function incidentPayloadJson(incident: OperationalIncident): JsonObject { return operationalIncidentPayloadSchema.parse(incident) as JsonObject; }