use ri_agent_graph::prelude::*;
#[tokio::main]
async fn main() -> Result<()> {
println!("=== Fan-Out / Fan-In Parallel Execution Example ===\n");
let graph = AgentGraph::builder()
.add_node(
"init",
node!("init", |state| async move {
println!("[init] Setting up initial data...");
state.set("title", "Parallel Workflow").await?;
state.set("results", Vec::<String>::new()).await?;
state.set("total_score", 0i64).await?;
println!("[init] Initial data ready.");
Ok(())
}),
)
.add_node(
"branch_a",
node!("branch_a", |state| async move {
println!("[branch_a] Starting text analysis...");
tokio::time::sleep(std::time::Duration::from_millis(80)).await;
let title: String = state.get("title").await?;
let finding = format!(
"Text analysis of '{}': 42 tokens, positive sentiment",
title
);
println!("[branch_a] Done: {}", finding);
state.set("results", vec![finding]).await?;
state.set("total_score", 85i64).await?;
Ok(())
}),
)
.add_node(
"branch_b",
node!("branch_b", |state| async move {
println!("[branch_b] Starting keyword extraction...");
tokio::time::sleep(std::time::Duration::from_millis(60)).await;
let title: String = state.get("title").await?;
let finding = format!(
"Keyword extraction of '{}': [parallel, workflow, rust]",
title
);
println!("[branch_b] Done: {}", finding);
state.set("results", vec![finding]).await?;
state.set("total_score", 72i64).await?;
Ok(())
}),
)
.add_node(
"merge",
node!("merge", |state| async move {
println!("[merge] Combining results from parallel branches...");
let results: Vec<String> = state.get("results").await?;
let total_score: f64 = state.get("total_score").await?;
println!("[merge] Received {} results:", results.len());
for (i, result) in results.iter().enumerate() {
println!(" {}. {}", i + 1, result);
}
println!("[merge] Combined score: {}", total_score);
state
.set(
"summary",
format!(
"{} analyses completed, combined score: {}",
results.len(),
total_score
),
)
.await?;
Ok(())
}),
)
.add_edge("init", "branch_a")
.add_edge("init", "branch_b")
.add_edge("branch_a", "merge")
.add_edge("branch_b", "merge")
.with_reducer("results", AppendReducer)
.with_reducer("total_score", AddReducer)
.build()?;
let state = AgentState::new();
let start = std::time::Instant::now();
let result = graph.execute("init", state).await?;
let elapsed = start.elapsed();
println!("\n=== Final State ===");
let title: String = result.get("title").await?;
let results: Vec<String> = result.get("results").await?;
let total_score: f64 = result.get("total_score").await?;
let summary: String = result.get("summary").await?;
println!(" title: {}", title);
println!(" results: {:?}", results);
println!(" total_score: {}", total_score);
println!(" summary: {}", summary);
println!(" elapsed: {:?}", elapsed);
assert!(
elapsed.as_millis() < 200,
"Expected parallel execution but took {:?}",
elapsed
);
println!("\nParallel execution verified (branches ran concurrently).");
Ok(())
}