diff options
Diffstat (limited to 'makima/src/db/models.rs')
| -rw-r--r-- | makima/src/db/models.rs | 212 |
1 files changed, 211 insertions, 1 deletions
diff --git a/makima/src/db/models.rs b/makima/src/db/models.rs index 636d81a..a7d2cda 100644 --- a/makima/src/db/models.rs +++ b/makima/src/db/models.rs @@ -1949,6 +1949,64 @@ pub struct CheckpointListResponse { // Supervisor State (for supervisor resumability) // ============================================================================ +/// Supervisor activity state enum +/// Tracks the current operational state of the supervisor +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, ToSchema)] +#[serde(rename_all = "snake_case")] +pub enum SupervisorActivityState { + /// Supervisor is initializing + Initializing, + /// Supervisor is in planning phase + Planning, + /// Supervisor is actively executing work + Executing, + /// Supervisor is waiting for spawned tasks to complete + WaitingForTask, + /// Supervisor is waiting for user input + WaitingForUser, + /// Supervisor encountered an error + Error, + /// Supervisor has completed its work + Completed, +} + +impl Default for SupervisorActivityState { + fn default() -> Self { + Self::Initializing + } +} + +impl std::fmt::Display for SupervisorActivityState { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::Initializing => write!(f, "initializing"), + Self::Planning => write!(f, "planning"), + Self::Executing => write!(f, "executing"), + Self::WaitingForTask => write!(f, "waiting_for_task"), + Self::WaitingForUser => write!(f, "waiting_for_user"), + Self::Error => write!(f, "error"), + Self::Completed => write!(f, "completed"), + } + } +} + +impl std::str::FromStr for SupervisorActivityState { + type Err = String; + + fn from_str(s: &str) -> Result<Self, Self::Err> { + match s { + "initializing" => Ok(Self::Initializing), + "planning" => Ok(Self::Planning), + "executing" => Ok(Self::Executing), + "waiting_for_task" => Ok(Self::WaitingForTask), + "waiting_for_user" => Ok(Self::WaitingForUser), + "error" => Ok(Self::Error), + "completed" => Ok(Self::Completed), + _ => Err(format!("Unknown supervisor state: {}", s)), + } + } +} + /// Supervisor state for contract supervisor tasks /// Enables resumption after interruption #[derive(Debug, Clone, FromRow, Serialize, ToSchema)] @@ -1971,10 +2029,59 @@ pub struct SupervisorState { pub last_activity: DateTime<Utc>, pub created_at: DateTime<Utc>, pub updated_at: DateTime<Utc>, + + // Enhanced fields for Phase 3 crash recovery + /// Current supervisor activity state + pub state: String, + /// Human-readable current activity description + pub current_activity: Option<String>, + /// Progress percentage (0-100) + pub progress: Option<i32>, + /// Error message if in error state + pub error_message: Option<String>, + /// All task UUIDs spawned by this supervisor + #[sqlx(try_from = "Vec<Uuid>")] + pub spawned_task_ids: Vec<Uuid>, + /// Pending question UUID if waiting for user input + pub pending_question_id: Option<Uuid>, + /// Last LLM response for context restoration + pub last_llm_response: Option<String>, + /// Number of times this supervisor has been restored + pub restoration_count: Option<i32>, + /// Timestamp of last restoration + pub last_restored_at: Option<DateTime<Utc>>, +} + +impl SupervisorState { + /// Get the parsed supervisor activity state + pub fn activity_state(&self) -> SupervisorActivityState { + self.state.parse().unwrap_or(SupervisorActivityState::Initializing) + } + + /// Check if this supervisor state is restorable + pub fn is_restorable(&self) -> bool { + let state = self.activity_state(); + // Can restore if not in a terminal or error state + !matches!(state, SupervisorActivityState::Completed | SupervisorActivityState::Error) + } + + /// Check if supervisor is waiting for something + pub fn is_waiting(&self) -> bool { + let state = self.activity_state(); + matches!( + state, + SupervisorActivityState::WaitingForTask | SupervisorActivityState::WaitingForUser + ) + } + + /// Check if supervisor has pending questions + pub fn has_pending_question(&self) -> bool { + self.pending_question_id.is_some() + } } /// Request to update supervisor state -#[derive(Debug, Deserialize, ToSchema)] +#[derive(Debug, Default, Deserialize, ToSchema)] #[serde(rename_all = "camelCase")] pub struct UpdateSupervisorStateRequest { /// Updated conversation history @@ -1983,6 +2090,109 @@ pub struct UpdateSupervisorStateRequest { pub pending_task_ids: Option<Vec<Uuid>>, /// Current contract phase pub phase: Option<String>, + /// Current supervisor activity state + pub state: Option<String>, + /// Human-readable current activity description + pub current_activity: Option<String>, + /// Progress percentage (0-100) + pub progress: Option<i32>, + /// Error message if in error state + pub error_message: Option<String>, + /// All spawned task IDs + pub spawned_task_ids: Option<Vec<Uuid>>, + /// Pending question UUID + pub pending_question_id: Option<Uuid>, + /// Clear the pending question (set to None) + #[serde(default)] + pub clear_pending_question: bool, + /// Last LLM response + pub last_llm_response: Option<String>, +} + +/// Request to save supervisor state at specific save points +#[derive(Debug, Deserialize, Serialize, ToSchema)] +#[serde(rename_all = "camelCase")] +pub struct SaveSupervisorStateRequest { + /// The save point type that triggered this save + pub save_point: SupervisorSavePoint, + /// Updated conversation history (if available) + pub conversation_history: Option<serde_json::Value>, + /// Current state + pub state: Option<String>, + /// Current activity description + pub current_activity: Option<String>, + /// Progress percentage + pub progress: Option<i32>, + /// Last LLM response + pub last_llm_response: Option<String>, + /// Task that was spawned (for task_spawn save point) + pub spawned_task_id: Option<Uuid>, + /// Question that was asked (for question_asked save point) + pub question_id: Option<Uuid>, + /// Error message (for error save point) + pub error_message: Option<String>, +} + +/// Types of save points for supervisor state persistence +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, ToSchema)] +#[serde(rename_all = "snake_case")] +pub enum SupervisorSavePoint { + /// Save on every LLM response + LlmResponse, + /// Save when spawning a new task + TaskSpawn, + /// Save when asking a question to user + QuestionAsked, + /// Save when phase changes + PhaseChange, + /// Lightweight heartbeat update + Heartbeat, + /// Save when an error occurs + Error, + /// Save when task completes + TaskComplete, +} + +/// Supervisor restoration context +/// Contains all information needed to restore a supervisor after crash +#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)] +#[serde(rename_all = "camelCase")] +pub struct SupervisorRestorationContext { + /// The restored supervisor state + pub state: SupervisorState, + /// Tasks that were pending when the crash occurred + pub pending_tasks: Vec<TaskSummary>, + /// Pending question that needs re-delivery (if any) + pub pending_question: Option<PendingQuestionInfo>, + /// Whether state was fully valid or partially recovered + pub restoration_type: RestorationResult, + /// Human-readable restoration message + pub message: String, +} + +/// Information about a pending question for restoration +#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)] +#[serde(rename_all = "camelCase")] +pub struct PendingQuestionInfo { + pub question_id: Uuid, + pub question: String, + pub choices: Vec<String>, + pub context: Option<String>, + pub multi_select: bool, +} + +/// Result of restoration attempt +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, ToSchema)] +#[serde(rename_all = "snake_case")] +pub enum RestorationResult { + /// State was fully valid and restored + FullRestore, + /// State was valid but restored from last checkpoint + CheckpointRestore, + /// Started fresh due to invalid/missing state + FreshStart, + /// Partial restoration with some context lost + PartialRestore, } // ============================================================================ |
