Skip to main content

babelforce_manager_sdk/resources/
tasks.rs

1use crate::error::{map_task_automation_err as map_err, ManagerError};
2use crate::gen::task_automation::apis::configuration::Configuration;
3use crate::gen::task_automation::apis::{
4    account_configuration_api as cfg_api, action_test_api, agent_api, logs_api, manager_api,
5    metrics_api, scripts_api, secrets_api, usage_api,
6};
7use crate::gen::task_automation::models;
8use crate::retry::{with_retry, RetryPolicy};
9use crate::token::SharedCfg;
10use std::collections::HashMap;
11
12/// Task automation (v3) — `/api/v3/tasks`, with nested `scripts`, `secrets`, `selection_config`,
13/// and `metrics` sub-resources.
14pub struct TasksResource {
15    pub(crate) cfg: SharedCfg<Configuration>,
16    pub(crate) retry: RetryPolicy,
17    /// Custom scripts by type.
18    pub scripts: TaskScriptsResource,
19    /// Account secrets, grouped by prefix.
20    pub secrets: TaskSecretsResource,
21    /// Account task-selection configuration.
22    pub selection_config: TaskSelectionConfigResource,
23    /// Task & agent metrics.
24    pub metrics: TaskMetricsResource,
25}
26
27impl TasksResource {
28    /// List tasks (one page), optionally filtered.
29    pub async fn list(&self, filter: Option<&str>) -> Result<models::TaskList, ManagerError> {
30        let cfg = self.cfg.get().await?;
31        let cfg = cfg.as_ref();
32        with_retry(&self.retry, true, || {
33            manager_api::tasks(cfg, filter, None, None)
34        })
35        .await
36        .map_err(map_err)
37    }
38
39    /// Submit a new task.
40    pub async fn create(&self, body: models::SubmitTask) -> Result<models::Task, ManagerError> {
41        let cfg = self.cfg.get().await?;
42        let cfg = cfg.as_ref();
43        with_retry(&self.retry, false, || {
44            manager_api::submit_task(cfg, body.clone())
45        })
46        .await
47        .map_err(map_err)
48    }
49
50    /// Submit a task from a named template, supplying the template variables.
51    pub async fn create_from_template(
52        &self,
53        template: &str,
54        variables: serde_json::Value,
55    ) -> Result<models::Task, ManagerError> {
56        let cfg = self.cfg.get().await?;
57        let cfg = cfg.as_ref();
58        with_retry(&self.retry, false, || {
59            manager_api::submit_task_template(cfg, template, variables.clone(), None)
60        })
61        .await
62        .map_err(map_err)
63    }
64
65    /// Get a task by id.
66    pub async fn get(&self, task_id: &str) -> Result<models::Task, ManagerError> {
67        let cfg = self.cfg.get().await?;
68        let cfg = cfg.as_ref();
69        with_retry(&self.retry, true, || manager_api::task(cfg, task_id))
70            .await
71            .map_err(map_err)
72    }
73
74    /// Update a task.
75    pub async fn update(
76        &self,
77        task_id: &str,
78        body: models::Task,
79    ) -> Result<models::Task, ManagerError> {
80        let cfg = self.cfg.get().await?;
81        let cfg = cfg.as_ref();
82        with_retry(&self.retry, false, || {
83            manager_api::update_task(cfg, task_id, body.clone())
84        })
85        .await
86        .map_err(map_err)
87    }
88
89    /// Interrupt a task, moving it to a target state.
90    pub async fn interrupt(
91        &self,
92        task_id: &str,
93        interrupt_to: models::InterruptionTargetStates,
94        action: Option<models::ManualActionRequest>,
95    ) -> Result<(), ManagerError> {
96        let cfg = self.cfg.get().await?;
97        let cfg = cfg.as_ref();
98        with_retry(&self.retry, false, || {
99            manager_api::manager_interrupt_on_task(cfg, task_id, interrupt_to, action.clone())
100        })
101        .await
102        .map_err(map_err)
103    }
104
105    /// Change a task's state.
106    ///
107    /// The underlying generated operation is marked deprecated upstream, but it remains part of the
108    /// spec and is wrapped here for parity with the TypeScript/Go SDKs.
109    #[allow(deprecated)]
110    pub async fn change_state(
111        &self,
112        task_id: &str,
113        state: models::TaskState,
114    ) -> Result<(), ManagerError> {
115        let cfg = self.cfg.get().await?;
116        let cfg = cfg.as_ref();
117        with_retry(&self.retry, false, || {
118            manager_api::change_task_state(cfg, task_id, state)
119        })
120        .await
121        .map_err(map_err)
122    }
123
124    /// Perform an agent action on a task (accept/reject/complete, …).
125    pub async fn agent_action(
126        &self,
127        task_id: &str,
128        action: models::AgentActions,
129        manual_action: Option<models::ManualActionRequest>,
130    ) -> Result<models::Task, ManagerError> {
131        let cfg = self.cfg.get().await?;
132        let cfg = cfg.as_ref();
133        with_retry(&self.retry, false, || {
134            agent_api::agent_action_on_task(cfg, task_id, action, manual_action.clone())
135        })
136        .await
137        .map_err(map_err)
138    }
139
140    /// Lock or unlock the current agent.
141    pub async fn set_agent_lock(
142        &self,
143        lock_state: models::AgentLocking,
144    ) -> Result<models::AgentLockState, ManagerError> {
145        let cfg = self.cfg.get().await?;
146        let cfg = cfg.as_ref();
147        with_retry(&self.retry, false, || {
148            agent_api::change_agent_lock(cfg, lock_state)
149        })
150        .await
151        .map_err(map_err)
152    }
153
154    /// Task usage (time series).
155    pub async fn usage(&self) -> Result<models::TaskTimeSeries, ManagerError> {
156        let cfg = self.cfg.get().await?;
157        let cfg = cfg.as_ref();
158        with_retry(&self.retry, true, || {
159            usage_api::task_usage(cfg, None, None, None, None)
160        })
161        .await
162        .map_err(map_err)
163    }
164
165    /// The set of task usage types.
166    pub async fn usage_types(&self) -> Result<Vec<String>, ManagerError> {
167        let cfg = self.cfg.get().await?;
168        let cfg = cfg.as_ref();
169        with_retry(&self.retry, true, || {
170            usage_api::task_usage_types(cfg, None, None)
171        })
172        .await
173        .map_err(map_err)
174    }
175
176    /// Read the customer task logs.
177    pub async fn logs(&self) -> Result<models::LogsResponse, ManagerError> {
178        let cfg = self.cfg.get().await?;
179        let cfg = cfg.as_ref();
180        with_retry(&self.retry, true, || {
181            logs_api::list(cfg, None, None, None, None, None, None)
182        })
183        .await
184        .map_err(map_err)
185    }
186
187    /// Test an action without dispatching it.
188    pub async fn test_action(
189        &self,
190        body: models::TestAction,
191    ) -> Result<models::TestActionResult, ManagerError> {
192        let cfg = self.cfg.get().await?;
193        let cfg = cfg.as_ref();
194        with_retry(&self.retry, false, || {
195            action_test_api::testing(cfg, body.clone())
196        })
197        .await
198        .map_err(map_err)
199    }
200}
201
202/// Custom scripts by type — `/api/v3/scripts`.
203pub struct TaskScriptsResource {
204    pub(crate) cfg: SharedCfg<Configuration>,
205    pub(crate) retry: RetryPolicy,
206}
207
208impl TaskScriptsResource {
209    /// List scripts of a type.
210    pub async fn list(
211        &self,
212        script_type: models::ScriptType,
213    ) -> Result<models::ScriptList, ManagerError> {
214        let cfg = self.cfg.get().await?;
215        let cfg = cfg.as_ref();
216        with_retry(&self.retry, true, || {
217            scripts_api::list_scripts(cfg, script_type, None, None, None)
218        })
219        .await
220        .map_err(map_err)
221    }
222
223    /// Get a script by id.
224    pub async fn get(
225        &self,
226        script_type: models::ScriptType,
227        code_id: &str,
228    ) -> Result<models::ScriptResponses, ManagerError> {
229        let cfg = self.cfg.get().await?;
230        let cfg = cfg.as_ref();
231        with_retry(&self.retry, true, || {
232            scripts_api::get_script(cfg, code_id, script_type, None)
233        })
234        .await
235        .map_err(map_err)
236    }
237
238    /// Submit a new script.
239    pub async fn submit(
240        &self,
241        script_type: models::ScriptType,
242        body: models::Script,
243    ) -> Result<models::ScriptResponses, ManagerError> {
244        let cfg = self.cfg.get().await?;
245        let cfg = cfg.as_ref();
246        with_retry(&self.retry, false, || {
247            scripts_api::submit_script(cfg, script_type, body.clone())
248        })
249        .await
250        .map_err(map_err)
251    }
252
253    /// Update a script.
254    pub async fn update(
255        &self,
256        script_type: models::ScriptType,
257        code_id: &str,
258        body: models::Script,
259    ) -> Result<models::ScriptResponses, ManagerError> {
260        let cfg = self.cfg.get().await?;
261        let cfg = cfg.as_ref();
262        with_retry(&self.retry, false, || {
263            scripts_api::update_script(cfg, code_id, script_type, body.clone())
264        })
265        .await
266        .map_err(map_err)
267    }
268
269    /// Delete a script.
270    pub async fn delete(
271        &self,
272        script_type: models::ScriptType,
273        code_id: &str,
274    ) -> Result<(), ManagerError> {
275        let cfg = self.cfg.get().await?;
276        let cfg = cfg.as_ref();
277        with_retry(&self.retry, false, || {
278            scripts_api::delete_script(cfg, code_id, script_type)
279        })
280        .await
281        .map_err(map_err)
282    }
283}
284
285/// Account secrets, grouped by prefix — `/api/v3/secrets`.
286pub struct TaskSecretsResource {
287    pub(crate) cfg: SharedCfg<Configuration>,
288    pub(crate) retry: RetryPolicy,
289}
290
291impl TaskSecretsResource {
292    /// List the secret prefixes.
293    pub async fn list_prefixes(&self) -> Result<Vec<String>, ManagerError> {
294        let cfg = self.cfg.get().await?;
295        let cfg = cfg.as_ref();
296        with_retry(&self.retry, true, || secrets_api::list_secret_prefixes(cfg))
297            .await
298            .map_err(map_err)
299    }
300
301    /// List the keys under a prefix.
302    pub async fn list_keys(&self, prefix: &str) -> Result<Vec<String>, ManagerError> {
303        let cfg = self.cfg.get().await?;
304        let cfg = cfg.as_ref();
305        with_retry(&self.retry, true, || {
306            secrets_api::list_secret_keys(cfg, prefix)
307        })
308        .await
309        .map_err(map_err)
310    }
311
312    /// Create secrets under a prefix.
313    pub async fn create(
314        &self,
315        prefix: &str,
316        secrets: HashMap<String, serde_json::Value>,
317    ) -> Result<(), ManagerError> {
318        let cfg = self.cfg.get().await?;
319        let cfg = cfg.as_ref();
320        with_retry(&self.retry, false, || {
321            secrets_api::create_secrets(cfg, prefix, Some(secrets.clone()))
322        })
323        .await
324        .map_err(map_err)
325    }
326
327    /// Patch (merge) secrets under a prefix.
328    pub async fn patch(
329        &self,
330        prefix: &str,
331        secrets: HashMap<String, serde_json::Value>,
332    ) -> Result<(), ManagerError> {
333        let cfg = self.cfg.get().await?;
334        let cfg = cfg.as_ref();
335        with_retry(&self.retry, false, || {
336            secrets_api::patch_secrets(cfg, prefix, Some(secrets.clone()))
337        })
338        .await
339        .map_err(map_err)
340    }
341
342    /// Delete keys under a prefix.
343    pub async fn delete_keys(&self, prefix: &str, keys: Vec<String>) -> Result<(), ManagerError> {
344        let cfg = self.cfg.get().await?;
345        let cfg = cfg.as_ref();
346        with_retry(&self.retry, false, || {
347            secrets_api::delete_secret_keys(cfg, prefix, Some(keys.clone()))
348        })
349        .await
350        .map_err(map_err)
351    }
352}
353
354/// Account task-selection configuration — `/api/v3/account/selection`.
355pub struct TaskSelectionConfigResource {
356    pub(crate) cfg: SharedCfg<Configuration>,
357    pub(crate) retry: RetryPolicy,
358}
359
360impl TaskSelectionConfigResource {
361    /// Read the selection configuration.
362    pub async fn read(&self) -> Result<models::AccountSelectionConfiguration, ManagerError> {
363        let cfg = self.cfg.get().await?;
364        let cfg = cfg.as_ref();
365        with_retry(&self.retry, true, || {
366            cfg_api::read_selection_configuration(cfg)
367        })
368        .await
369        .map_err(map_err)
370    }
371
372    /// Create the selection configuration.
373    pub async fn create(
374        &self,
375        body: models::AccountSelectionConfiguration,
376    ) -> Result<models::AccountSelectionConfiguration, ManagerError> {
377        let cfg = self.cfg.get().await?;
378        let cfg = cfg.as_ref();
379        with_retry(&self.retry, false, || {
380            cfg_api::create_selection_configuration(cfg, Some(body.clone()))
381        })
382        .await
383        .map_err(map_err)
384    }
385
386    /// Update the selection configuration.
387    pub async fn update(
388        &self,
389        body: models::AccountSelectionConfiguration,
390    ) -> Result<models::AccountSelectionConfiguration, ManagerError> {
391        let cfg = self.cfg.get().await?;
392        let cfg = cfg.as_ref();
393        with_retry(&self.retry, false, || {
394            cfg_api::update_selection_configuration(cfg, Some(body.clone()))
395        })
396        .await
397        .map_err(map_err)
398    }
399
400    /// Delete the selection configuration.
401    pub async fn delete(&self) -> Result<(), ManagerError> {
402        let cfg = self.cfg.get().await?;
403        let cfg = cfg.as_ref();
404        with_retry(&self.retry, false, || {
405            cfg_api::delete_selection_configuration(cfg)
406        })
407        .await
408        .map_err(map_err)
409    }
410}
411
412/// Task & agent metrics — `/api/v3/metrics`.
413pub struct TaskMetricsResource {
414    pub(crate) cfg: SharedCfg<Configuration>,
415    pub(crate) retry: RetryPolicy,
416}
417
418impl TaskMetricsResource {
419    /// The journal for a task.
420    pub async fn task_journal(&self, task_id: &str) -> Result<models::TaskJournal, ManagerError> {
421        let cfg = self.cfg.get().await?;
422        let cfg = cfg.as_ref();
423        with_retry(&self.retry, true, || {
424            metrics_api::task_journal(cfg, task_id)
425        })
426        .await
427        .map_err(map_err)
428    }
429
430    /// The interaction journal for an agent.
431    pub async fn agent_journal(
432        &self,
433        agent_id: &str,
434    ) -> Result<models::AgentJournal, ManagerError> {
435        let cfg = self.cfg.get().await?;
436        let cfg = cfg.as_ref();
437        with_retry(&self.retry, true, || {
438            metrics_api::agent_interactions(cfg, agent_id)
439        })
440        .await
441        .map_err(map_err)
442    }
443
444    /// An agent's interaction durations.
445    pub async fn agent_interaction_durations(
446        &self,
447        agent_id: &str,
448    ) -> Result<models::InteractionDurations, ManagerError> {
449        let cfg = self.cfg.get().await?;
450        let cfg = cfg.as_ref();
451        with_retry(&self.retry, true, || {
452            metrics_api::agent_interaction_duration(cfg, agent_id)
453        })
454        .await
455        .map_err(map_err)
456    }
457}