Skip to main content

agent_runtime/
step.rs

1use crate::event::EventStream;
2use crate::types::JsonValue;
3use async_trait::async_trait;
4use serde::{Deserialize, Serialize};
5
6/// Types of steps that can be in a workflow
7#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
8#[serde(rename_all = "snake_case")]
9pub enum StepType {
10    Agent,
11    Transform,
12    Conditional,
13    Parallel,
14    SubWorkflow,
15    Custom(String),
16}
17
18/// Input data passed to a step
19#[derive(Debug, Clone, Serialize, Deserialize)]
20pub struct StepInput {
21    pub data: JsonValue,
22    pub metadata: StepInputMetadata,
23}
24
25#[derive(Debug, Clone, Serialize, Deserialize)]
26pub struct StepInputMetadata {
27    pub step_index: usize,
28    pub previous_step: Option<String>,
29    pub workflow_id: String,
30}
31
32/// Output data produced by a step
33#[derive(Debug, Clone, Serialize, Deserialize)]
34pub struct StepOutput {
35    pub data: JsonValue,
36    pub metadata: StepOutputMetadata,
37}
38
39#[derive(Debug, Clone, Serialize, Deserialize)]
40pub struct StepOutputMetadata {
41    pub step_name: String,
42    pub step_type: StepType,
43    pub execution_time_ms: u64,
44}
45
46/// Result type for step execution
47pub type StepResult = Result<StepOutput, StepError>;
48
49/// Errors that can occur during step execution
50#[derive(Debug, Clone, Serialize, Deserialize, thiserror::Error)]
51pub enum StepError {
52    #[error("Execution failed: {0}")]
53    ExecutionFailed(String),
54
55    #[error("Invalid input: {0}")]
56    InvalidInput(String),
57
58    #[error("Agent error: {0}")]
59    AgentError(String),
60
61    #[error("Step not found: {0}")]
62    StepNotFound(String),
63}
64
65/// Execution context passed to steps
66pub struct ExecutionContext<'a> {
67    pub event_stream: Option<&'a EventStream>,
68}
69
70impl<'a> Default for ExecutionContext<'a> {
71    fn default() -> Self {
72        Self::new()
73    }
74}
75
76impl<'a> ExecutionContext<'a> {
77    pub fn new() -> Self {
78        Self { event_stream: None }
79    }
80
81    pub fn with_event_stream(event_stream: &'a EventStream) -> Self {
82        Self {
83            event_stream: Some(event_stream),
84        }
85    }
86}
87
88/// Step trait - all workflow steps must implement this
89#[async_trait]
90pub trait Step: Send + Sync {
91    /// Execute the step with the given input
92    async fn execute(&self, input: StepInput) -> StepResult {
93        self.execute_with_context(input, ExecutionContext::new())
94            .await
95    }
96
97    /// Execute with execution context (for event streaming, etc.)
98    async fn execute_with_context(&self, input: StepInput, ctx: ExecutionContext<'_>)
99        -> StepResult;
100
101    /// Unique name for this step
102    fn name(&self) -> &str;
103
104    /// Type of step
105    fn step_type(&self) -> StepType;
106
107    /// Optional: Get a description of what this step does
108    fn description(&self) -> Option<&str> {
109        None
110    }
111
112    /// For conditional steps: get the branches (then, else)
113    fn get_branches(&self) -> Option<(&dyn Step, &dyn Step)> {
114        None
115    }
116
117    /// For sub-workflow steps: get the workflow
118    fn get_sub_workflow(&self) -> Option<crate::workflow::Workflow> {
119        None
120    }
121}