systemprompt-models 0.1.22

Shared data models and types for systemprompt.io OS
Documentation
use super::artifact::Artifact;
use super::message::Message;
use super::task_metadata::TaskMetadata;
use serde::{Deserialize, Serialize};
use systemprompt_identifiers::{ContextId, TaskId};

#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct Task {
    pub id: TaskId,
    pub context_id: ContextId,
    pub status: TaskStatus,
    pub history: Option<Vec<Message>>,
    pub artifacts: Option<Vec<Artifact>>,
    pub metadata: Option<TaskMetadata>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub created_at: Option<chrono::DateTime<chrono::Utc>>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub last_modified: Option<chrono::DateTime<chrono::Utc>>,
}

impl Default for Task {
    fn default() -> Self {
        let now = chrono::Utc::now();
        Self {
            id: TaskId::generate(),
            context_id: ContextId::generate(),
            status: TaskStatus::default(),
            history: None,
            artifacts: None,
            metadata: None,
            created_at: Some(now),
            last_modified: Some(now),
        }
    }
}

#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
pub struct TaskStatus {
    pub state: TaskState,
    pub message: Option<Message>,
    pub timestamp: Option<chrono::DateTime<chrono::Utc>>,
}

impl Default for TaskStatus {
    fn default() -> Self {
        Self {
            state: TaskState::Submitted,
            message: None,
            timestamp: None,
        }
    }
}

#[derive(Debug, Serialize, Deserialize, Clone, Copy, PartialEq, Eq)]
pub enum TaskState {
    #[serde(rename = "TASK_STATE_PENDING")]
    Pending,
    #[serde(rename = "TASK_STATE_SUBMITTED")]
    Submitted,
    #[serde(rename = "TASK_STATE_WORKING")]
    Working,
    #[serde(rename = "TASK_STATE_COMPLETED")]
    Completed,
    #[serde(rename = "TASK_STATE_FAILED")]
    Failed,
    #[serde(rename = "TASK_STATE_CANCELED")]
    Canceled,
    #[serde(rename = "TASK_STATE_REJECTED")]
    Rejected,
    #[serde(rename = "TASK_STATE_INPUT_REQUIRED")]
    InputRequired,
    #[serde(rename = "TASK_STATE_AUTH_REQUIRED")]
    AuthRequired,
    #[serde(rename = "TASK_STATE_UNKNOWN")]
    Unknown,
}

impl TaskState {
    pub const fn is_terminal(&self) -> bool {
        matches!(
            self,
            Self::Completed | Self::Failed | Self::Canceled | Self::Rejected
        )
    }

    pub const fn can_transition_to(&self, target: &Self) -> bool {
        if self.is_terminal() {
            return false;
        }
        match self {
            Self::Pending => matches!(target, Self::Submitted),
            Self::Submitted => matches!(
                target,
                Self::Working
                    | Self::Completed
                    | Self::Failed
                    | Self::Canceled
                    | Self::Rejected
                    | Self::AuthRequired
            ),
            Self::Working => matches!(
                target,
                Self::Completed | Self::Failed | Self::Canceled | Self::InputRequired
            ),
            Self::InputRequired => matches!(
                target,
                Self::Working | Self::Completed | Self::Failed | Self::Canceled
            ),
            Self::AuthRequired => matches!(target, Self::Working | Self::Failed | Self::Canceled),
            _ => false,
        }
    }
}

impl std::str::FromStr for TaskState {
    type Err = String;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s {
            "TASK_STATE_PENDING" | "pending" => Ok(Self::Pending),
            "TASK_STATE_SUBMITTED" | "submitted" => Ok(Self::Submitted),
            "TASK_STATE_WORKING" | "working" => Ok(Self::Working),
            "TASK_STATE_COMPLETED" | "completed" => Ok(Self::Completed),
            "TASK_STATE_FAILED" | "failed" => Ok(Self::Failed),
            "TASK_STATE_CANCELED" | "canceled" => Ok(Self::Canceled),
            "TASK_STATE_REJECTED" | "rejected" => Ok(Self::Rejected),
            "TASK_STATE_INPUT_REQUIRED" | "input-required" => Ok(Self::InputRequired),
            "TASK_STATE_AUTH_REQUIRED" | "auth-required" => Ok(Self::AuthRequired),
            "TASK_STATE_UNKNOWN" | "unknown" => Ok(Self::Unknown),
            _ => Err(format!("Invalid task state: {s}")),
        }
    }
}