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