lc_langgraph/compiled/
stream.rs1use super::graph::CompiledGraph;
6use super::types::{GraphInvocation, StreamEvent};
7use crate::edge::GraphEdge;
8use crate::errors::{GraphError, GraphResult};
9use crate::graph::END;
10use crate::node::NodeConfig;
11use crate::state::StateSchema;
12use futures_util::future::join_all;
13use futures_util::Stream;
14use std::collections::HashMap;
15use std::pin::Pin;
16use tokio_stream::wrappers::ReceiverStream;
17
18impl<S: StateSchema + Send + Sync + 'static> CompiledGraph<S> {
19 pub fn stream(
27 &self,
28 input: S,
29 ) -> Pin<Box<dyn Stream<Item = Result<StreamEvent<S>, GraphError>> + Send>> {
30 let (tx, rx) = tokio::sync::mpsc::channel(64);
31
32 let graph = self.clone();
33 tokio::spawn(async move {
34 let mut state = input;
35 let mut current_node = graph.entry_point.clone();
36 let mut recursion_count = 0;
37
38 if tx
39 .send(Ok(StreamEvent::start(state.clone())))
40 .await
41 .is_err()
42 {
43 return;
44 }
45
46 if let Some(ref checkpointer) = graph.checkpointer {
47 match checkpointer.lock().await.save(&state, 0).await {
48 Ok(_) => {}
49 Err(e) => {
50 let _ = tx.send(Err(e)).await;
51 return;
52 }
53 }
54 }
55
56 while current_node != END && recursion_count < graph.recursion_limit {
57 if graph.interrupt_before.contains(¤t_node) {
58 let _ = tx
59 .send(Err(GraphError::ExecutionInterrupted(current_node.clone())))
60 .await;
61 return;
62 }
63
64 recursion_count += 1;
65
66 if tx
67 .send(Ok(StreamEvent::enter_node(
68 current_node.clone(),
69 state.clone(),
70 )))
71 .await
72 .is_err()
73 {
74 return;
75 }
76
77 let node = match graph.get_node(¤t_node).await {
78 Ok(n) => n,
79 Err(e) => {
80 let _ = tx.send(Err(e)).await;
81 return;
82 }
83 };
84
85 let config = NodeConfig {
86 recursion_limit: graph.recursion_limit,
87 debug: false,
88 metadata: HashMap::new(),
89 };
90
91 let update = match node.execute(&state, Some(config)).await {
92 Ok(u) => u,
93 Err(e) => {
94 let _ = tx.send(Err(e)).await;
95 return;
96 }
97 };
98
99 if tx
100 .send(Ok(StreamEvent::node_complete(
101 current_node.clone(),
102 update.clone(),
103 )))
104 .await
105 .is_err()
106 {
107 return;
108 }
109
110 if let Some(new_state) = update.update {
111 state = graph.default_reducer.reduce(&state, &new_state);
112 if tx
113 .send(Ok(StreamEvent::state_update(state.clone())))
114 .await
115 .is_err()
116 {
117 return;
118 }
119 }
120
121 if graph.interrupt_after.contains(¤t_node) {
122 if let Some(ref checkpointer) = graph.checkpointer {
123 let _ = checkpointer
124 .lock()
125 .await
126 .save(&state, recursion_count)
127 .await;
128 }
129 let _ = tx
130 .send(Err(GraphError::ExecutionInterrupted(format!(
131 "after_{}",
132 current_node
133 ))))
134 .await;
135 return;
136 }
137
138 let next_node = match graph.find_next_node(¤t_node, &state).await {
139 Ok(n) => n,
140 Err(e) => {
141 let _ = tx.send(Err(e)).await;
142 return;
143 }
144 };
145
146 if let Some(ref checkpointer) = graph.checkpointer {
147 let _ = checkpointer
148 .lock()
149 .await
150 .save(&state, recursion_count)
151 .await;
152 }
153
154 current_node = next_node;
155 }
156
157 if current_node != END {
160 let _ = tx
161 .send(Err(GraphError::RecursionLimitReached(
162 graph.recursion_limit,
163 )))
164 .await;
165 return;
166 }
167
168 let _ = tx.send(Ok(StreamEvent::end(state))).await;
169 });
170
171 Box::pin(ReceiverStream::new(rx))
172 }
173
174 pub async fn stream_collected(&self, input: S) -> GraphResult<Vec<StreamEvent<S>>> {
179 let mut events = Vec::new();
180 let mut stream = self.stream(input);
181 use futures_util::StreamExt;
182 while let Some(event) = stream.next().await {
183 events.push(event?);
184 }
185 Ok(events)
186 }
187
188 pub(super) async fn find_next_node(&self, current: &str, state: &S) -> GraphResult<String> {
189 'rt: {
191 let edge = {
192 let re = self.runtime_edges.read().await;
193 match re.iter().find(|e| e.source() == current) {
194 Some(e) => e.clone(),
195 None => break 'rt,
196 }
197 }; match edge {
199 GraphEdge::Fixed { target, .. } => return Ok(target),
200 GraphEdge::Conditional {
201 router_name,
202 targets,
203 default_target,
204 ..
205 } => {
206 let router = self
207 .conditional_routers
208 .get(&router_name)
209 .cloned()
210 .or_else(|| {
211 self.runtime_conditional_routers
212 .try_read()
213 .ok()
214 .and_then(|guard| guard.get(&router_name).cloned())
215 })
216 .ok_or_else(|| {
217 GraphError::ExecutionError(format!(
218 "Router '{}' not found (runtime)",
219 router_name
220 ))
221 })?;
222 let route_key = router.route(state).await?;
223 let target = targets
224 .get(&route_key)
225 .or(default_target.as_ref())
226 .ok_or_else(|| {
227 GraphError::RoutingError(format!(
228 "No target for route '{}' (runtime)",
229 route_key
230 ))
231 })?;
232 return Ok(target.clone());
233 }
234 GraphEdge::FanOut { targets, .. } => {
235 if targets.is_empty() {
236 return Err(GraphError::RoutingError(
237 "FanOut has no targets (runtime)".to_string(),
238 ));
239 }
240 return Ok(targets[0].clone());
241 }
242 GraphEdge::FanIn { .. } => {}
243 }
244 }
245
246 for edge in &self.edges {
248 if edge.source() == current {
249 match edge {
250 GraphEdge::Fixed { target, .. } => {
251 return Ok(target.clone());
252 }
253 GraphEdge::Conditional {
254 router_name,
255 targets,
256 default_target,
257 ..
258 } => {
259 let router = self
260 .conditional_routers
261 .get(router_name)
262 .cloned()
263 .or_else(|| {
264 self.runtime_conditional_routers
265 .try_read()
266 .ok()
267 .and_then(|guard| guard.get(router_name).cloned())
268 })
269 .ok_or_else(|| {
270 GraphError::ExecutionError(format!(
271 "Router '{}' not found",
272 router_name
273 ))
274 })?;
275
276 let route_key = router.route(state).await?;
277
278 let target = targets
279 .get(&route_key)
280 .or(default_target.as_ref())
281 .ok_or_else(|| {
282 GraphError::RoutingError(format!(
283 "No target for route '{}'",
284 route_key
285 ))
286 })?;
287
288 return Ok(target.clone());
289 }
290 GraphEdge::FanOut { targets, .. } => {
291 if targets.is_empty() {
292 return Err(GraphError::RoutingError(
293 "FanOut has no targets".to_string(),
294 ));
295 }
296 return Ok(targets[0].clone());
297 }
298 GraphEdge::FanIn { .. } => {
299 continue;
300 }
301 }
302 }
303 }
304
305 if current == self.entry_point && self.nodes.len() == 1 {
306 return Ok(END.to_string());
307 }
308
309 Err(GraphError::RoutingError(format!(
310 "No outgoing edge from node '{}'",
311 current
312 )))
313 }
314
315 pub(super) async fn find_fan_out_targets(&self, current: &str) -> Option<Vec<String>> {
316 {
317 let re = self.runtime_edges.read().await;
318 if let Some(GraphEdge::FanOut { targets, .. }) =
319 re.iter().find(|e| e.source() == current)
320 {
321 return Some(targets.clone());
322 }
323 }
324 for edge in &self.edges {
325 if edge.source() == current {
326 if let GraphEdge::FanOut { targets, .. } = edge {
327 return Some(targets.clone());
328 }
329 }
330 }
331 None
332 }
333
334 pub(super) async fn find_fan_in_target(&self, sources: &[String]) -> Option<String> {
335 {
336 let re = self.runtime_edges.read().await;
337 if let Some(GraphEdge::FanIn {
338 sources: edge_sources,
339 target,
340 }) = re.iter().find(|e| matches!(e, GraphEdge::FanIn { .. }))
341 {
342 if edge_sources.iter().all(|s| sources.contains(s)) {
343 return Some(target.clone());
344 }
345 }
346 }
347 for edge in &self.edges {
348 if let GraphEdge::FanIn {
349 sources: edge_sources,
350 target,
351 } = edge
352 {
353 if edge_sources.iter().all(|s| sources.contains(s)) {
354 return Some(target.clone());
355 }
356 }
357 }
358 None
359 }
360
361 pub(super) async fn execute_parallel_branches(
362 &self,
363 targets: &[String],
364 state: &S,
365 recursion_count: usize,
366 ) -> GraphResult<Vec<(String, GraphInvocation<S>)>> {
367 let futures: Vec<_> = targets
372 .iter()
373 .filter(|t| *t != END)
374 .map(|target| {
375 let target = target.clone();
376 let state_clone = state.clone();
377 async move {
378 let result = self
379 .invoke_from_node_with_count(target.clone(), state_clone, recursion_count)
380 .await;
381 result.map(|inv| (target, inv))
382 }
383 })
384 .collect();
385
386 let results = join_all(futures).await;
387
388 let mut successful = Vec::new();
389 for result in results {
390 match result {
391 Ok((name, inv)) => successful.push((name, inv)),
392 Err(e) => return Err(e),
393 }
394 }
395
396 Ok(successful)
397 }
398}