1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
//! Agent step for [`WorkflowContext`].
use ironflow_store::models::StepKind;
use crate::config::{AgentStep, StepConfig};
use crate::context::WorkflowContext;
use crate::error::EngineError;
impl WorkflowContext {
/// Execute an agent step.
///
/// With [`output::<T>()`](crate::config::AgentStepConfig::output) on the
/// config, the step returns the `T` the agent answered; otherwise it
/// returns the raw [`StepOutput`](crate::executor::StepOutput). See
/// [`AgentStep`].
///
/// # Errors
///
/// Returns [`EngineError`] if the agent invocation fails or the store
/// errors, and [`EngineError::Serialization`] if a typed answer does not
/// match its type.
///
/// # Examples
///
/// ```no_run
/// use ironflow_engine::context::WorkflowContext;
/// use ironflow_engine::config::AgentStepConfig;
/// use ironflow_engine::error::EngineError;
/// use schemars::JsonSchema;
/// use serde::Deserialize;
///
/// #[derive(Deserialize, JsonSchema)]
/// struct Review {
/// approved: bool,
/// comments: Vec<String>,
/// }
///
/// # async fn example(ctx: &mut WorkflowContext) -> Result<(), EngineError> {
/// let review = ctx
/// .agent(
/// "review",
/// AgentStepConfig::new("Review the code").max_turns(2).output::<Review>(),
/// )
/// .await?;
/// if !review.approved {
/// println!("{} comments", review.comments.len());
/// }
/// # Ok(())
/// # }
/// ```
pub async fn agent<C: AgentStep>(
&mut self,
name: &str,
config: C,
) -> Result<C::Answer, EngineError> {
let output = self
.execute_step(
name,
StepKind::Agent,
StepConfig::Agent(config.into_config()),
)
.await?;
C::answer(output)
}
}