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