lellm_agent/runtime/react/
graph_builder.rs1use std::sync::Arc;
16
17use lellm_graph::{Graph, GraphBuilder, NodeKind, TaskNode};
18
19use super::super::typed_state::{AgentState, AgentStateMerge};
20use super::guards::{BudgetCondition, CompactorNode, PostLLMGuard, StopConfig};
21use super::llm_node::LLMNode;
22use super::tool_node::ToolNode;
23
24pub fn build_react_graph(
28 llm_node: LLMNode,
29 tool_node: ToolNode,
30 compactor_node: CompactorNode,
31) -> Graph<AgentState, AgentStateMerge> {
32 let llm_name = llm_node.name.clone();
33 let budget = llm_node.config.context_budget.clone();
34 let stop_config = StopConfig::from_tool_use_config(&llm_node.config);
35
36 let mut builder =
37 GraphBuilder::<AgentState, AgentStateMerge>::new(format!("react_{}", llm_name));
38 builder.start("budget_check");
39 builder.end("end");
40
41 builder.node("llm", NodeKind::ExternalLeaf(Arc::new(llm_node)));
43 builder.node("tool", NodeKind::ExternalLeaf(Arc::new(tool_node)));
44 builder.node(
45 "post_llm_check",
46 NodeKind::ExternalLeaf(Arc::new(PostLLMGuard::new(
47 format!("{}_post_llm", llm_name),
48 stop_config,
49 ))),
50 );
51 builder.node(
52 "budget_check",
53 NodeKind::ExternalLeaf(Arc::new(BudgetCondition::new(
54 format!("{}_budget", llm_name),
55 budget,
56 ))),
57 );
58 builder.node(
59 "compactor",
60 NodeKind::ExternalLeaf(Arc::new(compactor_node)),
61 );
62 builder.node(
64 "end",
65 NodeKind::Task(TaskNode::<AgentState>::new("end", |_| Ok(()))),
66 );
67
68 builder.edge("budget_check", "llm");
80 builder.edge_fallback("budget_check", "compactor");
81 builder.edge("compactor", "llm");
82 builder.edge("llm", "post_llm_check");
83 builder.edge("post_llm_check", "tool");
84 builder.edge_fallback("post_llm_check", "end");
85 builder.edge("tool", "budget_check");
86
87 builder.build().expect("ReAct graph should be valid")
88}