Skip to main content

routa_server/api/tasks/
dto.rs

1use serde::{Deserialize, Deserializer, Serialize};
2use std::collections::BTreeMap;
3
4fn deserialize_explicit_nullable_string<'de, D>(
5    deserializer: D,
6) -> Result<Option<Option<String>>, D::Error>
7where
8    D: Deserializer<'de>,
9{
10    let value = serde_json::Value::deserialize(deserializer)?;
11    match value {
12        serde_json::Value::Null => Ok(Some(None)),
13        serde_json::Value::String(value) => Ok(Some(Some(value))),
14        other => Err(serde::de::Error::custom(format!(
15            "expected string or null, received {other}"
16        ))),
17    }
18}
19
20/// Task artifact summary for evidence aggregation
21#[derive(Debug, Serialize)]
22#[serde(rename_all = "camelCase")]
23pub struct TaskArtifactSummary {
24    pub total: usize,
25    pub by_type: BTreeMap<String, usize>,
26    pub required_satisfied: bool,
27    pub missing_required: Vec<String>,
28}
29
30/// Task verification summary
31#[derive(Debug, Serialize)]
32#[serde(rename_all = "camelCase")]
33pub struct TaskVerificationSummary {
34    pub has_verdict: bool,
35    #[serde(skip_serializing_if = "Option::is_none")]
36    pub verdict: Option<String>,
37    pub has_report: bool,
38}
39
40/// Task completion summary
41#[derive(Debug, Serialize)]
42#[serde(rename_all = "camelCase")]
43pub struct TaskCompletionSummary {
44    pub has_summary: bool,
45}
46
47/// Task run summary
48#[derive(Debug, Serialize)]
49#[serde(rename_all = "camelCase")]
50pub struct TaskRunSummary {
51    pub total: usize,
52    pub latest_status: String,
53}
54
55/// Combined task evidence summary
56#[derive(Debug, Serialize)]
57#[serde(rename_all = "camelCase")]
58pub struct TaskEvidenceSummary {
59    pub artifact: TaskArtifactSummary,
60    pub verification: TaskVerificationSummary,
61    pub completion: TaskCompletionSummary,
62    pub runs: TaskRunSummary,
63}
64
65/// Task run resume target
66#[derive(Debug, Serialize)]
67#[serde(rename_all = "camelCase")]
68pub struct TaskRunResumeTarget {
69    pub r#type: String,
70    pub id: String,
71}
72
73/// Task run ledger entry
74#[derive(Debug, Serialize)]
75#[serde(rename_all = "camelCase")]
76pub struct TaskRunLedgerEntry {
77    pub id: String,
78    pub kind: String,
79    pub status: String,
80    #[serde(skip_serializing_if = "Option::is_none")]
81    pub session_id: Option<String>,
82    #[serde(skip_serializing_if = "Option::is_none")]
83    pub external_task_id: Option<String>,
84    #[serde(skip_serializing_if = "Option::is_none")]
85    pub context_id: Option<String>,
86    #[serde(skip_serializing_if = "Option::is_none")]
87    pub column_id: Option<String>,
88    #[serde(skip_serializing_if = "Option::is_none")]
89    pub step_id: Option<String>,
90    #[serde(skip_serializing_if = "Option::is_none")]
91    pub step_name: Option<String>,
92    #[serde(skip_serializing_if = "Option::is_none")]
93    pub provider: Option<String>,
94    #[serde(skip_serializing_if = "Option::is_none")]
95    pub specialist_name: Option<String>,
96    #[serde(skip_serializing_if = "Option::is_none")]
97    pub started_at: Option<String>,
98    #[serde(skip_serializing_if = "Option::is_none")]
99    pub completed_at: Option<String>,
100    #[serde(skip_serializing_if = "Option::is_none")]
101    pub owner_instance_id: Option<String>,
102    #[serde(skip_serializing_if = "Option::is_none")]
103    pub resume_target: Option<TaskRunResumeTarget>,
104}
105
106/// Request to create a task artifact
107#[derive(Debug, Deserialize)]
108#[serde(rename_all = "camelCase")]
109pub struct CreateTaskArtifactRequest {
110    pub agent_id: Option<String>,
111    #[serde(rename = "type")]
112    pub artifact_type: Option<String>,
113    pub content: Option<String>,
114    pub context: Option<String>,
115    pub request_id: Option<String>,
116    pub metadata: Option<std::collections::BTreeMap<String, String>>,
117}
118
119/// Query params for listing tasks
120#[derive(Debug, Deserialize)]
121#[serde(rename_all = "camelCase")]
122pub struct ListTasksQuery {
123    pub workspace_id: Option<String>,
124    pub session_id: Option<String>,
125    pub status: Option<String>,
126    pub assigned_to: Option<String>,
127}
128
129/// Query params for task file change
130#[derive(Debug, Deserialize)]
131pub struct TaskChangeFileQuery {
132    pub path: Option<String>,
133    pub status: Option<String>,
134    #[serde(rename = "previousPath")]
135    pub previous_path: Option<String>,
136}
137
138/// Query params for task commit change
139#[derive(Debug, Deserialize)]
140pub struct TaskChangeCommitQuery {
141    pub sha: Option<String>,
142}
143
144/// Query params for task change stats
145#[derive(Debug, Deserialize)]
146pub struct TaskChangeStatsQuery {
147    pub paths: Option<String>,
148    pub statuses: Option<String>,
149}
150
151/// Request to update task status
152#[derive(Debug, Deserialize)]
153pub struct UpdateStatusRequest {
154    pub status: String,
155}
156
157/// Request to create a new task
158#[derive(Debug, Deserialize)]
159#[serde(rename_all = "camelCase")]
160pub struct CreateTaskRequest {
161    pub title: String,
162    pub objective: String,
163    pub workspace_id: Option<String>,
164    pub session_id: Option<String>,
165    pub scope: Option<String>,
166    pub acceptance_criteria: Option<Vec<String>>,
167    pub verification_commands: Option<Vec<String>>,
168    pub test_cases: Option<Vec<String>>,
169    pub dependencies: Option<Vec<String>>,
170    pub parallel_group: Option<String>,
171    pub board_id: Option<String>,
172    pub column_id: Option<String>,
173    pub position: Option<i64>,
174    pub priority: Option<String>,
175    pub labels: Option<Vec<String>>,
176    pub assignee: Option<String>,
177    pub assigned_provider: Option<String>,
178    pub assigned_role: Option<String>,
179    pub assigned_specialist_id: Option<String>,
180    pub assigned_specialist_name: Option<String>,
181    pub create_github_issue: Option<bool>,
182    pub repo_path: Option<String>,
183    pub codebase_ids: Option<Vec<String>>,
184    pub worktree_id: Option<serde_json::Value>,
185    pub github_id: Option<String>,
186    pub github_number: Option<i64>,
187    pub github_url: Option<String>,
188    pub github_repo: Option<String>,
189    pub github_state: Option<String>,
190}
191
192/// Request to update an existing task
193#[derive(Debug, Deserialize)]
194#[serde(rename_all = "camelCase")]
195pub struct UpdateTaskRequest {
196    pub title: Option<String>,
197    pub objective: Option<String>,
198    pub comment: Option<String>,
199    pub scope: Option<String>,
200    pub acceptance_criteria: Option<Vec<String>>,
201    pub verification_commands: Option<Vec<String>>,
202    pub test_cases: Option<Vec<String>>,
203    pub assigned_to: Option<String>,
204    pub status: Option<String>,
205    pub board_id: Option<String>,
206    pub column_id: Option<String>,
207    pub position: Option<i64>,
208    pub priority: Option<String>,
209    pub labels: Option<Vec<String>>,
210    pub assignee: Option<String>,
211    pub assigned_provider: Option<String>,
212    pub assigned_role: Option<String>,
213    pub assigned_specialist_id: Option<String>,
214    pub assigned_specialist_name: Option<String>,
215    pub trigger_session_id: Option<String>,
216    pub codebase_ids: Option<Vec<String>>,
217    pub verification_plan: Option<String>,
218    pub verification_verdict: Option<String>,
219    pub github_id: Option<String>,
220    pub github_number: Option<i64>,
221    pub github_url: Option<String>,
222    pub github_repo: Option<String>,
223    pub github_state: Option<String>,
224    pub last_sync_error: Option<String>,
225    pub dependencies: Option<Vec<String>>,
226    pub parallel_group: Option<String>,
227    pub completion_summary: Option<String>,
228    pub verification_report: Option<String>,
229    pub sync_to_github: Option<bool>,
230    pub retry_trigger: Option<bool>,
231    pub repo_path: Option<String>,
232    #[serde(default, deserialize_with = "deserialize_explicit_nullable_string")]
233    pub worktree_id: Option<Option<String>>,
234}