langgraph_core_rs/runnable/
seq.rs1use std::sync::Arc;
2use async_trait::async_trait;
3use serde_json::Value as JsonValue;
4use langgraph_checkpoint::config::RunnableConfig;
5use super::base::{Runnable, RunnableError};
6
7pub struct RunnableSeq {
15 name: String,
16 steps: Vec<Arc<dyn Runnable>>,
17}
18
19impl RunnableSeq {
20 pub fn new(name: impl Into<String>, steps: Vec<Arc<dyn Runnable>>) -> Self {
22 assert!(steps.len() >= 2, "RunnableSeq requires at least 2 steps");
23 Self {
24 name: name.into(),
25 steps,
26 }
27 }
28
29 pub fn new_relaxed(name: impl Into<String>, steps: Vec<Arc<dyn Runnable>>) -> Self {
31 Self {
32 name: name.into(),
33 steps,
34 }
35 }
36
37 pub fn len(&self) -> usize {
39 self.steps.len()
40 }
41
42 pub fn is_empty(&self) -> bool {
44 self.steps.is_empty()
45 }
46}
47
48#[async_trait]
49impl Runnable for RunnableSeq {
50 fn invoke(&self, input: &JsonValue, config: &RunnableConfig) -> Result<JsonValue, RunnableError> {
51 let mut current = input.clone();
52 for step in &self.steps {
53 current = step.invoke(¤t, config)?;
54 }
55 Ok(current)
56 }
57
58 async fn ainvoke(&self, input: &JsonValue, config: &RunnableConfig) -> Result<JsonValue, RunnableError> {
59 let mut current = input.clone();
60 for step in &self.steps {
61 current = step.ainvoke(¤t, config).await?;
62 }
63 Ok(current)
64 }
65
66 fn name(&self) -> &str {
67 &self.name
68 }
69}
70
71pub fn pipe(first: Arc<dyn Runnable>, second: Arc<dyn Runnable>) -> RunnableSeq {
79 let name = format!("{}|{}", first.name(), second.name());
80 RunnableSeq::new_relaxed(name, vec![first, second])
81}