1use roder_api::dynamic_workflows::{
2 WorkflowAgentRun, WorkflowAgentRunId, WorkflowApproval, WorkflowApprovalDecision, WorkflowRun,
3 WorkflowRunId, WorkflowRunSummary, WorkflowScript, WorkflowScriptId, WorkflowScriptSourceKind,
4};
5use roder_api::events::{ThreadId, TurnId};
6use serde::{Deserialize, Serialize};
7
8#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
9#[serde(rename_all = "camelCase")]
10pub struct WorkflowsPlanParams {
11 #[serde(default, skip_serializing_if = "Option::is_none")]
12 pub thread_id: Option<ThreadId>,
13 #[serde(default, skip_serializing_if = "Option::is_none")]
14 pub turn_id: Option<TurnId>,
15 pub prompt: String,
16 #[serde(default, skip_serializing_if = "Option::is_none")]
17 pub workspace: Option<String>,
18 #[serde(default)]
19 pub arguments: serde_json::Value,
20 #[serde(default, skip_serializing_if = "Option::is_none")]
21 pub script: Option<String>,
22}
23
24#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
25#[serde(rename_all = "camelCase")]
26pub struct WorkflowsPlanResult {
27 pub run: WorkflowRun,
28 pub approval_required: bool,
29}
30
31#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
32#[serde(rename_all = "camelCase")]
33pub struct WorkflowsApproveParams {
34 pub run_id: WorkflowRunId,
35 pub decision: WorkflowApprovalDecision,
36 #[serde(default, skip_serializing_if = "Option::is_none")]
37 pub reason: Option<String>,
38}
39
40#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
41#[serde(rename_all = "camelCase")]
42pub struct WorkflowsApproveResult {
43 pub run: WorkflowRun,
44 pub approval: WorkflowApproval,
45}
46
47#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
48#[serde(rename_all = "camelCase")]
49pub struct WorkflowsListParams {
50 #[serde(default, skip_serializing_if = "Option::is_none")]
51 pub thread_id: Option<ThreadId>,
52 #[serde(default)]
53 pub include_terminal: bool,
54}
55
56#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
57#[serde(rename_all = "camelCase")]
58pub struct WorkflowsListResult {
59 pub runs: Vec<WorkflowRunSummary>,
60}
61
62#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
63#[serde(rename_all = "camelCase")]
64pub struct WorkflowsGetParams {
65 pub run_id: WorkflowRunId,
66 #[serde(default)]
67 pub include_script_body: bool,
68 #[serde(default)]
69 pub include_agents: bool,
70}
71
72#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
73#[serde(rename_all = "camelCase")]
74pub struct WorkflowsGetResult {
75 pub run: WorkflowRun,
76}
77
78#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
79#[serde(rename_all = "camelCase")]
80pub struct WorkflowsPauseParams {
81 pub run_id: WorkflowRunId,
82 #[serde(default)]
83 pub cancel_running_agents: bool,
84 #[serde(default, skip_serializing_if = "Option::is_none")]
85 pub reason: Option<String>,
86}
87
88#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
89#[serde(rename_all = "camelCase")]
90pub struct WorkflowsPauseResult {
91 pub run: WorkflowRun,
92}
93
94#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
95#[serde(rename_all = "camelCase")]
96pub struct WorkflowsResumeParams {
97 pub run_id: WorkflowRunId,
98}
99
100#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
101#[serde(rename_all = "camelCase")]
102pub struct WorkflowsResumeResult {
103 pub run: WorkflowRun,
104}
105
106#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
107#[serde(rename_all = "camelCase")]
108pub struct WorkflowsStopParams {
109 pub run_id: WorkflowRunId,
110 #[serde(default, skip_serializing_if = "Option::is_none")]
111 pub reason: Option<String>,
112}
113
114#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
115#[serde(rename_all = "camelCase")]
116pub struct WorkflowsStopResult {
117 pub run: WorkflowRun,
118}
119
120#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
121#[serde(rename_all = "camelCase")]
122pub struct WorkflowsRestartAgentParams {
123 pub run_id: WorkflowRunId,
124 pub agent_id: WorkflowAgentRunId,
125}
126
127#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
128#[serde(rename_all = "camelCase")]
129pub struct WorkflowsRestartAgentResult {
130 pub run: WorkflowRun,
131 pub agent: WorkflowAgentRun,
132}
133
134#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
135#[serde(rename_all = "camelCase")]
136pub enum WorkflowsSaveScope {
137 User,
138 Workspace,
139}
140
141#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
142#[serde(rename_all = "camelCase")]
143pub struct WorkflowsSaveParams {
144 pub run_id: WorkflowRunId,
145 pub name: String,
146 pub scope: WorkflowsSaveScope,
147 #[serde(default)]
148 pub overwrite: bool,
149}
150
151#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
152#[serde(rename_all = "camelCase")]
153pub struct WorkflowsSaveResult {
154 pub script: WorkflowScript,
155}
156
157#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
158#[serde(rename_all = "camelCase")]
159pub struct WorkflowsScriptsListParams {
160 #[serde(default, skip_serializing_if = "Option::is_none")]
161 pub workspace: Option<String>,
162 #[serde(default)]
163 pub include_user: bool,
164 #[serde(default)]
165 pub include_builtin: bool,
166}
167
168#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
169#[serde(rename_all = "camelCase")]
170pub struct WorkflowsScriptsListResult {
171 pub scripts: Vec<WorkflowScript>,
172}
173
174#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
175#[serde(rename_all = "camelCase")]
176pub struct WorkflowsScriptsReadParams {
177 #[serde(default, skip_serializing_if = "Option::is_none")]
178 pub script_id: Option<WorkflowScriptId>,
179 #[serde(default, skip_serializing_if = "Option::is_none")]
180 pub name: Option<String>,
181 #[serde(default, skip_serializing_if = "Option::is_none")]
182 pub source: Option<WorkflowScriptSourceKind>,
183 #[serde(default)]
184 pub include_body: bool,
185}
186
187#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
188#[serde(rename_all = "camelCase")]
189pub struct WorkflowsScriptsReadResult {
190 pub script: WorkflowScript,
191}
192
193#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
194#[serde(rename_all = "camelCase")]
195pub struct WorkflowsScriptsDeleteParams {
196 pub script_id: WorkflowScriptId,
197 #[serde(default)]
198 pub delete_file: bool,
199}
200
201#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
202#[serde(rename_all = "camelCase")]
203pub struct WorkflowsScriptsDeleteResult {
204 pub script_id: WorkflowScriptId,
205 pub deleted: bool,
206}
207
208#[cfg(test)]
209mod tests {
210 use super::*;
211
212 #[test]
213 fn workflow_protocol_params_use_camel_case_fields() {
214 let plan: WorkflowsPlanParams = serde_json::from_value(serde_json::json!({
215 "threadId": "thread-1",
216 "turnId": "turn-1",
217 "prompt": "use a workflow to audit auth",
218 "workspace": "/tmp/repo",
219 "arguments": { "scope": "auth" }
220 }))
221 .unwrap();
222 assert_eq!(plan.thread_id.as_deref(), Some("thread-1"));
223 assert_eq!(plan.turn_id.as_deref(), Some("turn-1"));
224
225 let approve: WorkflowsApproveParams = serde_json::from_value(serde_json::json!({
226 "runId": "run-1",
227 "decision": "alwaysForScriptAndWorkspace",
228 "reason": "trusted generated workflow"
229 }))
230 .unwrap();
231 assert_eq!(
232 approve.decision,
233 WorkflowApprovalDecision::AlwaysForScriptAndWorkspace
234 );
235
236 let restart: WorkflowsRestartAgentParams = serde_json::from_value(serde_json::json!({
237 "runId": "run-1",
238 "agentId": "agent-1"
239 }))
240 .unwrap();
241 assert_eq!(restart.agent_id, "agent-1");
242
243 let read: WorkflowsScriptsReadParams = serde_json::from_value(serde_json::json!({
244 "name": "deep-research",
245 "source": "builtIn",
246 "includeBody": true
247 }))
248 .unwrap();
249 assert_eq!(read.source, Some(WorkflowScriptSourceKind::BuiltIn));
250 assert!(read.include_body);
251
252 let delete = serde_json::to_value(WorkflowsScriptsDeleteResult {
253 script_id: "script-1".to_string(),
254 deleted: true,
255 })
256 .unwrap();
257 assert_eq!(delete["scriptId"], "script-1");
258 }
259}