systemprompt_models/a2a/
task.rs1use 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}