Skip to main content

ironflow_engine/config/
mod.rs

1//! Serializable step configurations — one per operation type.
2//!
3//! These types mirror the builder options in [`ironflow_core`] operations but
4//! are fully serializable, allowing them to be stored as JSON in the database
5//! and reconstructed by the executor at runtime.
6
7mod agent;
8mod approval;
9mod artifact;
10mod http;
11mod shell;
12mod workflow;
13
14pub use agent::AgentStepConfig;
15pub use approval::ApprovalConfig;
16pub use artifact::{ArtifactInput, ArtifactOutput};
17pub use http::HttpConfig;
18pub use shell::ShellConfig;
19pub use workflow::WorkflowStepConfig;
20
21use ironflow_store::entities::StepKind;
22use serde::{Deserialize, Serialize};
23
24/// A serializable step configuration, wrapping one of the operation-specific configs.
25///
26/// Stored as JSON in the `steps.input` column and reconstructed by the
27/// executor at runtime.
28///
29/// # Examples
30///
31/// ```
32/// use ironflow_engine::config::{StepConfig, ShellConfig};
33///
34/// let config = StepConfig::Shell(ShellConfig::new("echo hello"));
35/// let json = serde_json::to_string(&config).unwrap();
36/// assert!(json.contains("echo hello"));
37/// ```
38#[derive(Debug, Clone, Serialize, Deserialize)]
39#[serde(tag = "type", rename_all = "snake_case")]
40pub enum StepConfig {
41    /// A shell command step.
42    Shell(ShellConfig),
43    /// An HTTP request step.
44    Http(HttpConfig),
45    /// An AI agent step.
46    Agent(AgentStepConfig),
47    /// A sub-workflow invocation step.
48    Workflow(WorkflowStepConfig),
49    /// A human approval gate step.
50    Approval(ApprovalConfig),
51}
52
53impl StepConfig {
54    /// Whether this step is allowed to fail without stopping the run.
55    ///
56    /// # Examples
57    ///
58    /// ```
59    /// use ironflow_engine::config::{StepConfig, ShellConfig};
60    ///
61    /// let config = StepConfig::Shell(ShellConfig::new("cargo clippy").allow_failure());
62    /// assert!(config.allow_failure());
63    ///
64    /// let config = StepConfig::Shell(ShellConfig::new("cargo build"));
65    /// assert!(!config.allow_failure());
66    /// ```
67    pub fn allow_failure(&self) -> bool {
68        match self {
69            StepConfig::Shell(c) => c.allow_failure,
70            StepConfig::Http(c) => c.allow_failure,
71            StepConfig::Agent(c) => c.allow_failure,
72            StepConfig::Workflow(_) | StepConfig::Approval(_) => false,
73        }
74    }
75
76    /// Get the kind of step this configuration represents.
77    ///
78    /// # Examples
79    ///
80    /// ```
81    /// use ironflow_engine::config::{StepConfig, ShellConfig};
82    /// use ironflow_store::entities::StepKind;
83    ///
84    /// let config = StepConfig::Shell(ShellConfig::new("echo test"));
85    /// assert_eq!(config.kind(), StepKind::Shell);
86    /// ```
87    pub fn kind(&self) -> StepKind {
88        match self {
89            StepConfig::Shell(_) => StepKind::Shell,
90            StepConfig::Http(_) => StepKind::Http,
91            StepConfig::Agent(_) => StepKind::Agent,
92            StepConfig::Workflow(_) => StepKind::Workflow,
93            StepConfig::Approval(_) => StepKind::Approval,
94        }
95    }
96}
97
98impl From<ShellConfig> for StepConfig {
99    fn from(c: ShellConfig) -> Self {
100        StepConfig::Shell(c)
101    }
102}
103
104impl From<HttpConfig> for StepConfig {
105    fn from(c: HttpConfig) -> Self {
106        StepConfig::Http(c)
107    }
108}
109
110impl From<AgentStepConfig> for StepConfig {
111    fn from(c: AgentStepConfig) -> Self {
112        StepConfig::Agent(c)
113    }
114}
115
116#[cfg(test)]
117mod tests {
118    use super::*;
119
120    #[test]
121    fn serde_roundtrip() {
122        let configs = vec![
123            StepConfig::Shell(ShellConfig::new("echo test")),
124            StepConfig::Http(HttpConfig::get("http://example.com")),
125            StepConfig::Agent(AgentStepConfig::new("summarize")),
126            StepConfig::Workflow(WorkflowStepConfig::new("build", serde_json::json!({}))),
127            StepConfig::Approval(ApprovalConfig::new("Deploy to production?")),
128        ];
129
130        for config in configs {
131            let json = serde_json::to_string(&config).expect("serialize");
132            let back: StepConfig = serde_json::from_str(&json).expect("deserialize");
133            let json2 = serde_json::to_string(&back).expect("serialize2");
134            assert_eq!(json, json2);
135        }
136    }
137}