Skip to main content

systemprompt_agent/services/a2a_server/processing/task_builder/
mod.rs

1//! Assembly of A2A [`Task`] values for the various completion paths.
2//!
3//! [`TaskBuilder`] is the general builder; the free functions cover the common
4//! shapes (completed, canceled, mock, submitted, multi-turn) used across the
5//! processing pipeline.
6
7mod builders;
8pub mod helpers;
9
10pub use builders::{
11    BuildMultiturnTaskParams, build_canceled_task, build_completed_task, build_mock_task,
12    build_multiturn_task, build_submitted_task,
13};
14
15use crate::models::a2a::{
16    Artifact, Message, MessageRole, Part, Task, TaskState, TaskStatus, TextPart,
17};
18use systemprompt_identifiers::{ContextId, MessageId, TaskId};
19use systemprompt_models::a2a::TaskMetadata;
20
21#[derive(Debug)]
22pub struct TaskBuilder {
23    task_id: TaskId,
24    context_id: ContextId,
25    state: TaskState,
26    response_text: String,
27    id: MessageId,
28    user_message: Option<Message>,
29    artifacts: Vec<Artifact>,
30    metadata: Option<TaskMetadata>,
31}
32
33impl TaskBuilder {
34    pub fn new(context_id: ContextId) -> Self {
35        Self {
36            task_id: TaskId::generate(),
37            context_id,
38            state: TaskState::Completed,
39            response_text: String::new(),
40            id: MessageId::generate(),
41            user_message: None,
42            artifacts: Vec::new(),
43            metadata: None,
44        }
45    }
46
47    pub fn with_task_id(mut self, task_id: TaskId) -> Self {
48        self.task_id = task_id;
49        self
50    }
51
52    pub const fn with_state(mut self, state: TaskState) -> Self {
53        self.state = state;
54        self
55    }
56
57    pub fn with_response_text(mut self, text: String) -> Self {
58        self.response_text = text;
59        self
60    }
61
62    pub fn with_message_id(mut self, id: impl Into<MessageId>) -> Self {
63        self.id = id.into();
64        self
65    }
66
67    pub fn with_user_message(mut self, message: Message) -> Self {
68        self.user_message = Some(message);
69        self
70    }
71
72    pub fn with_artifacts(mut self, artifacts: Vec<Artifact>) -> Self {
73        self.artifacts = artifacts;
74        self
75    }
76
77    pub fn with_metadata(mut self, metadata: TaskMetadata) -> Self {
78        self.metadata = Some(metadata);
79        self
80    }
81
82    pub fn build(self) -> Task {
83        let agent_message = Message {
84            role: MessageRole::Agent,
85            parts: vec![Part::Text(TextPart {
86                text: self.response_text.clone(),
87            })],
88            message_id: self.id.clone(),
89            task_id: Some(self.task_id.clone()),
90            context_id: self.context_id.clone(),
91            metadata: None,
92            extensions: None,
93            reference_task_ids: None,
94        };
95
96        let history = if let Some(user_msg) = self.user_message {
97            Some(vec![
98                user_msg,
99                Message {
100                    role: MessageRole::Agent,
101                    parts: vec![Part::Text(TextPart {
102                        text: self.response_text.clone(),
103                    })],
104                    message_id: MessageId::generate(),
105                    task_id: Some(self.task_id.clone()),
106                    context_id: self.context_id.clone(),
107                    metadata: None,
108                    extensions: None,
109                    reference_task_ids: None,
110                },
111            ])
112        } else {
113            None
114        };
115
116        Task {
117            id: self.task_id.clone(),
118            context_id: self.context_id.clone(),
119            status: TaskStatus {
120                state: self.state,
121                message: Some(agent_message),
122                timestamp: Some(chrono::Utc::now()),
123            },
124            history,
125            artifacts: if self.artifacts.is_empty() {
126                None
127            } else {
128                Some(self.artifacts)
129            },
130            metadata: self.metadata,
131            created_at: Some(chrono::Utc::now()),
132            last_modified: Some(chrono::Utc::now()),
133        }
134    }
135}