use serde::{Deserialize, Serialize};
use super::message::A2AMessage;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum TaskStatus {
#[serde(rename = "submitted")]
Submitted,
#[serde(rename = "working")]
Working,
#[serde(rename = "input-required")]
InputRequired,
#[serde(rename = "completed")]
Completed,
#[serde(rename = "failed")]
Failed,
#[serde(rename = "cancelled")]
Cancelled,
#[serde(rename = "rejected")]
Rejected,
#[serde(rename = "auth-required")]
AuthRequired,
#[serde(rename = "expired")]
Expired,
}
impl TaskStatus {
pub fn can_transition_to(&self, target: &TaskStatus) -> bool {
use TaskStatus::*;
matches!(
(self, target),
(Submitted, Working)
| (Submitted, Rejected)
| (Submitted, Cancelled)
| (Submitted, Expired)
| (Working, Completed)
| (Working, Failed)
| (Working, InputRequired)
| (Working, Cancelled)
| (Working, Expired)
| (InputRequired, Working)
| (InputRequired, Cancelled)
| (InputRequired, Expired)
| (AuthRequired, Submitted)
| (AuthRequired, Expired)
)
}
pub fn is_terminal(&self) -> bool {
matches!(
self,
TaskStatus::Completed
| TaskStatus::Failed
| TaskStatus::Cancelled
| TaskStatus::Rejected
| TaskStatus::Expired
)
}
}
impl std::fmt::Display for TaskStatus {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let s = match self {
TaskStatus::Submitted => "submitted",
TaskStatus::Working => "working",
TaskStatus::InputRequired => "input-required",
TaskStatus::Completed => "completed",
TaskStatus::Failed => "failed",
TaskStatus::Cancelled => "cancelled",
TaskStatus::Rejected => "rejected",
TaskStatus::AuthRequired => "auth-required",
TaskStatus::Expired => "expired",
};
f.write_str(s)
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct A2ATask {
pub id: String,
pub message: A2AMessage,
pub status: TaskStatus,
#[serde(skip_serializing_if = "Option::is_none")]
pub owner: Option<String>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub messages: Vec<A2AMessage>,
}
impl A2ATask {
pub fn new(id: impl Into<String>, message: A2AMessage) -> Self {
let id = id.into();
Self {
messages: vec![message.clone()],
id,
message,
status: TaskStatus::Submitted,
owner: None,
}
}
pub fn with_status(mut self, status: TaskStatus) -> Self {
self.status = status;
self
}
pub fn with_owner(mut self, owner: impl Into<String>) -> Self {
self.owner = Some(owner.into());
self
}
pub fn push_message(&mut self, msg: A2AMessage) {
self.messages.push(msg);
}
pub fn message_history(&self) -> std::borrow::Cow<'_, [A2AMessage]> {
if self.messages.is_empty() {
std::borrow::Cow::Owned(vec![self.message.clone()])
} else {
std::borrow::Cow::Borrowed(&self.messages)
}
}
}