use serde::{Deserialize, Serialize}; use serde_json::Value; use uuid::Uuid; /// One gateway event with its journal sequence number. The wire contract /// with the frontend (`frontend/src/lib/gateway/events.ts` mirrors it). #[derive(Debug, Clone, Serialize, Deserialize)] pub struct RunEventEnvelope { pub seq: i64, #[serde(flatten)] pub event: RunEventBody, } #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(tag = "type", rename_all = "snake_case")] pub enum RunEventBody { RunStarted { run_id: Uuid, }, TextDelta { delta: String, }, StepStarted { step_seq: i32, tool: String, input: Value, }, StepFinished { step_seq: i32, status: String, output: Value, }, /// A gated action awaits human review (§15): carries the exact preview /// of what will execute, surfaced as the approval card (§10). ApprovalRequired { approval_id: Uuid, category: String, action_type: String, preview: Value, }, /// The run is blocked until the pending approval is decided. RunSuspended { approval_id: Uuid, }, RunCompleted { message_id: String, }, Error { message: String, }, } impl RunEventBody { /// Stable name stored in `run_events.event_type`. pub fn type_name(&self) -> &'static str { match self { RunEventBody::RunStarted { .. } => "run_started", RunEventBody::TextDelta { .. } => "text_delta", RunEventBody::StepStarted { .. } => "step_started", RunEventBody::StepFinished { .. } => "step_finished", RunEventBody::ApprovalRequired { .. } => "approval_required", RunEventBody::RunSuspended { .. } => "run_suspended", RunEventBody::RunCompleted { .. } => "run_completed", RunEventBody::Error { .. } => "error", } } }