Skip to main content

langgraph_prebuilt/
tools_condition.rs

1use serde_json::Value as JsonValue;
2use langgraph::constants::END;
3
4/// Routing function for determining whether to continue with tool execution
5/// or end the conversation.
6///
7/// This is a standard conditional edge function for ReAct-style agents.
8/// It checks if the last AI message contains tool calls:
9/// - If yes, route to the "tools" node
10/// - If no, route to END
11///
12/// Returns a string key that should be mapped in the conditional edges:
13/// - "tools" → route to ToolNode
14/// - END ("__end__") → route to END
15pub fn tools_condition(input: &JsonValue) -> String {
16    let messages = match input.get("messages") {
17        Some(JsonValue::Array(arr)) => arr,
18        _ => return END.to_string(),
19    };
20
21    // Check the last message for tool calls
22    if let Some(last_msg) = messages.last() {
23        if let Some(obj) = last_msg.as_object() {
24            if obj.get("type").and_then(|v| v.as_str()) == Some("ai") {
25                if let Some(JsonValue::Array(calls)) = obj.get("tool_calls") {
26                    if !calls.is_empty() {
27                        return "tools".to_string();
28                    }
29                }
30            }
31        }
32    }
33
34    END.to_string()
35}
36
37#[cfg(test)]
38mod tests {
39    use super::*;
40
41    #[test]
42    fn test_tools_condition_with_tool_calls() {
43        let input = serde_json::json!({
44            "messages": [
45                {"type": "human", "content": "Search for cats"},
46                {"type": "ai", "content": "", "tool_calls": [
47                    {"name": "search", "args": {"query": "cats"}, "id": "call_1"}
48                ]}
49            ]
50        });
51
52        assert_eq!(tools_condition(&input), "tools");
53    }
54
55    #[test]
56    fn test_tools_condition_without_tool_calls() {
57        let input = serde_json::json!({
58            "messages": [
59                {"type": "human", "content": "Hello"},
60                {"type": "ai", "content": "Hi there!"}
61            ]
62        });
63
64        assert_eq!(tools_condition(&input), "__end__");
65    }
66
67    #[test]
68    fn test_tools_condition_empty_messages() {
69        let input = serde_json::json!({
70            "messages": []
71        });
72
73        assert_eq!(tools_condition(&input), "__end__");
74    }
75
76    #[test]
77    fn test_tools_condition_no_messages_key() {
78        let input = serde_json::json!({});
79        assert_eq!(tools_condition(&input), "__end__");
80    }
81}