| 1169 | } |
| 1170 | |
| 1171 | async fn execute_condition_node( |
| 1172 | node: &WorkflowNode, |
| 1173 | handler_id: &str, |
| 1174 | context: Arc<Mutex<WorkflowContext>>, |
| 1175 | parents_map: Arc<HashMap<NodeId, Vec<NodeId>>>, |
| 1176 | handlers: Arc<HashMap<String, ConditionalRouteFn>>, |
| 1177 | graph: Arc<WorkflowGraph>, |
| 1178 | ) -> GraphBitResult<serde_json::Value> { |
| 1179 | let parents = parents_map.get(&node.id).cloned().unwrap_or_default(); |
| 1180 | if parents.len() != 1 { |
| 1181 | return Err(GraphBitError::workflow_execution(format!( |
| 1182 | "Condition node '{}' must have exactly one incoming dependency, found {}", |
| 1183 | node.name, |
| 1184 | parents.len() |
| 1185 | ))); |
| 1186 | } |
| 1187 | let parent_id = parents[0].clone(); |
| 1188 | let parent_key = parent_id.to_string(); |
| 1189 | let routing_input = { |
| 1190 | let ctx = context.lock().await; |
| 1191 | let parent_output = ctx.get_node_output(&parent_key).ok_or_else(|| { |
| 1192 | GraphBitError::workflow_execution(format!( |
| 1193 | "Condition node '{}': parent output not found for {}", |
| 1194 | node.name, parent_key |
| 1195 | )) |
| 1196 | })?; |
| 1197 | ConditionRoutingInput { |
| 1198 | parent_node_id: parent_key.clone(), |
| 1199 | parent_output: parent_output.clone(), |
| 1200 | variables: ctx.variables.clone(), |
| 1201 | node_outputs: ctx.node_outputs.clone(), |
| 1202 | metadata: ctx.metadata.clone(), |
| 1203 | } |
| 1204 | }; |
| 1205 | let handler = handlers.get(handler_id).ok_or_else(|| { |
| 1206 | GraphBitError::workflow_execution(format!( |
| 1207 | "Condition node '{}': no handler registered for handler_id '{handler_id}'", |
| 1208 | node.name |
| 1209 | )) |
| 1210 | })?; |
| 1211 | let out = handler(routing_input)?; |
| 1212 | let trimmed = out.trim().to_string(); |
| 1213 | if trimmed.is_empty() { |
| 1214 | return Err(GraphBitError::workflow_execution(format!( |
| 1215 | "Condition handler returned an empty next-node name for node '{}'", |
| 1216 | node.name |
| 1217 | ))); |
| 1218 | } |
| 1219 | Self::resolve_condition_branch_target(graph.as_ref(), &node.id, &trimmed)?; |
| 1220 | Ok(serde_json::Value::String(trimmed)) |
| 1221 | } |
| 1222 | |
| 1223 | fn is_tool_calls_required_output(value: &serde_json::Value) -> bool { |
| 1224 | if let Some(obj) = value.as_object() { |