Skip to main content

systemprompt_models/a2a/
task.rs

1use super::artifact::Artifact;
2use super::message::Message;
3use super::task_metadata::TaskMetadata;
4use serde::{Deserialize, Serialize};
5use systemprompt_identifiers::{ContextId, TaskId};
6
7#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
8#[serde(rename_all = "camelCase")]
9pub struct Task {
10    pub id: TaskId,
11    pub context_id: ContextId,
12    pub status: TaskStatus,
13    pub history: Option<Vec<Message>>,
14    pub artifacts: Option<Vec<Artifact>>,
15    pub metadata: Option<TaskMetadata>,
16    #[serde(skip_serializing_if = "Option::is_none")]
17    pub created_at: Option<chrono::DateTime<chrono::Utc>>,
18    #[serde(skip_serializing_if = "Option::is_none")]
19    pub last_modified: Option<chrono::DateTime<chrono::Utc>>,
20}
21
22impl Default for Task {
23    fn default() -> Self {
24        let now = chrono::Utc::now();
25        Self {
26            id: TaskId::generate(),
27            context_id: ContextId::generate(),
28            status: TaskStatus::default(),
29            history: None,
30            artifacts: None,
31            metadata: None,
32            created_at: Some(now),
33            last_modified: Some(now),
34        }
35    }
36}
37
38#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
39pub struct TaskStatus {
40    pub state: TaskState,
41    pub message: Option<Message>,
42    pub timestamp: Option<chrono::DateTime<chrono::Utc>>,
43}
44
45impl Default for TaskStatus {
46    fn default() -> Self {
47        Self {
48            state: TaskState::Submitted,
49            message: None,
50            timestamp: None,
51        }
52    }
53}
54
55#[derive(Debug, Serialize, Deserialize, Clone, Copy, PartialEq, Eq)]
56pub enum TaskState {
57    #[serde(rename = "TASK_STATE_PENDING")]
58    Pending,
59    #[serde(rename = "TASK_STATE_SUBMITTED")]
60    Submitted,
61    #[serde(rename = "TASK_STATE_WORKING")]
62    Working,
63    #[serde(rename = "TASK_STATE_COMPLETED")]
64    Completed,
65    #[serde(rename = "TASK_STATE_FAILED")]
66    Failed,
67    #[serde(rename = "TASK_STATE_CANCELED")]
68    Canceled,
69    #[serde(rename = "TASK_STATE_REJECTED")]
70    Rejected,
71    #[serde(rename = "TASK_STATE_INPUT_REQUIRED")]
72    InputRequired,
73    #[serde(rename = "TASK_STATE_AUTH_REQUIRED")]
74    AuthRequired,
75    #[serde(rename = "TASK_STATE_UNKNOWN")]
76    Unknown,
77}
78
79impl TaskState {
80    pub const fn is_terminal(&self) -> bool {
81        matches!(
82            self,
83            Self::Completed | Self::Failed | Self::Canceled | Self::Rejected
84        )
85    }
86
87    pub const fn can_transition_to(&self, target: &Self) -> bool {
88        if self.is_terminal() {
89            return false;
90        }
91        match self {
92            Self::Pending => matches!(target, Self::Submitted),
93            Self::Submitted => matches!(
94                target,
95                Self::Working
96                    | Self::Completed
97                    | Self::Failed
98                    | Self::Canceled
99                    | Self::Rejected
100                    | Self::AuthRequired
101            ),
102            Self::Working => matches!(
103                target,
104                Self::Completed | Self::Failed | Self::Canceled | Self::InputRequired
105            ),
106            Self::InputRequired => matches!(
107                target,
108                Self::Working | Self::Completed | Self::Failed | Self::Canceled
109            ),
110            Self::AuthRequired => matches!(target, Self::Working | Self::Failed | Self::Canceled),
111            _ => false,
112        }
113    }
114}
115
116impl std::str::FromStr for TaskState {
117    type Err = String;
118
119    fn from_str(s: &str) -> Result<Self, Self::Err> {
120        match s {
121            "TASK_STATE_PENDING" | "pending" => Ok(Self::Pending),
122            "TASK_STATE_SUBMITTED" | "submitted" => Ok(Self::Submitted),
123            "TASK_STATE_WORKING" | "working" => Ok(Self::Working),
124            "TASK_STATE_COMPLETED" | "completed" => Ok(Self::Completed),
125            "TASK_STATE_FAILED" | "failed" => Ok(Self::Failed),
126            "TASK_STATE_CANCELED" | "canceled" => Ok(Self::Canceled),
127            "TASK_STATE_REJECTED" | "rejected" => Ok(Self::Rejected),
128            "TASK_STATE_INPUT_REQUIRED" | "input-required" => Ok(Self::InputRequired),
129            "TASK_STATE_AUTH_REQUIRED" | "auth-required" => Ok(Self::AuthRequired),
130            "TASK_STATE_UNKNOWN" | "unknown" => Ok(Self::Unknown),
131            _ => Err(format!("Invalid task state: {s}")),
132        }
133    }
134}