use crate::config::constants::tools;
use crate::llm::provider::ToolDefinition;
const PRIORITY_TOOLS: &[&str] = &[
tools::EXEC_COMMAND,
tools::CODE_SEARCH,
tools::APPLY_PATCH,
tools::WRITE_STDIN,
tools::REQUEST_USER_INPUT,
tools::TASK_TRACKER,
tools::FINISH_PLANNING,
];
pub fn sort_tool_definitions(mut tools: Vec<ToolDefinition>) -> Vec<ToolDefinition> {
tools.sort_by(|a, b| {
let a_name = a.function.as_ref().map(|func| func.name.as_str()).unwrap_or("");
let b_name = b.function.as_ref().map(|func| func.name.as_str()).unwrap_or("");
let a_priority = PRIORITY_TOOLS.iter().position(|&p| p == a_name);
let b_priority = PRIORITY_TOOLS.iter().position(|&p| p == b_name);
match (a_priority, b_priority) {
(Some(a_pos), Some(b_pos)) => a_pos.cmp(&b_pos),
(Some(_), None) => std::cmp::Ordering::Less,
(None, Some(_)) => std::cmp::Ordering::Greater,
(None, None) => {
let name_cmp = a_name.cmp(b_name);
if name_cmp != std::cmp::Ordering::Equal {
return name_cmp;
}
a.tool_type.cmp(&b.tool_type)
}
}
});
tools
}
#[cfg(test)]
mod tests {
use hashbrown::HashSet;
use super::PRIORITY_TOOLS;
use super::sort_tool_definitions;
use crate::llm::provider::ToolDefinition;
#[test]
fn sort_tool_definitions_orders_by_name() {
let tools = vec![
ToolDefinition::function("b_tool".to_string(), "b".to_string(), serde_json::json!({})),
ToolDefinition::function("a_tool".to_string(), "a".to_string(), serde_json::json!({})),
];
let sorted = sort_tool_definitions(tools);
let names: Vec<&str> = sorted
.iter()
.filter_map(|tool| tool.function.as_ref().map(|func| func.name.as_str()))
.collect();
assert_eq!(names, vec!["a_tool", "b_tool"]);
}
#[test]
fn sort_tool_definitions_prioritizes_current_core_tools() {
let tools = vec![
ToolDefinition::function("zebra_tool".to_string(), "z".to_string(), serde_json::json!({})),
ToolDefinition::function("code_search".to_string(), "search".to_string(), serde_json::json!({})),
ToolDefinition::function("request_user_input".to_string(), "ask".to_string(), serde_json::json!({})),
ToolDefinition::function("alpha_tool".to_string(), "a".to_string(), serde_json::json!({})),
ToolDefinition::function("exec_command".to_string(), "shell".to_string(), serde_json::json!({})),
];
let sorted = sort_tool_definitions(tools);
let names: Vec<&str> = sorted
.iter()
.filter_map(|tool| tool.function.as_ref().map(|func| func.name.as_str()))
.collect();
assert_eq!(
names,
vec![
"exec_command",
"code_search",
"request_user_input",
"alpha_tool",
"zebra_tool"
]
);
}
#[test]
fn priority_tools_are_unique() {
let unique: HashSet<&str> = PRIORITY_TOOLS.iter().copied().collect();
assert_eq!(unique.len(), PRIORITY_TOOLS.len());
}
}