pub const BUILTIN_TOOL_NAMES: [&str; 21] = [
"conclusion_with_options",
"Bash",
"BashOutput",
"Edit",
"EnterPlanMode",
"ExitPlanMode",
"GetFileInfo",
"Glob",
"Grep",
"js_repl",
"KillShell",
"session_note",
"NotebookEdit",
"Read",
"request_permissions",
"Sleep",
"Task",
"WebFetch",
"WebSearch",
"Workspace",
"Write",
];
pub const BUILTIN_TOOL_ALIASES: [(&str, &str); 9] = [
("apply_patch", "Edit"),
("FileExists", "GetFileInfo"),
("GetCurrentDir", "Workspace"),
("SetWorkspace", "Workspace"),
("memory_note", "session_note"),
("recall", "session_history"),
("session_inspector", "session_history"),
("schedule_tasks", "scheduler"),
("sub_session_manager", "SubSession"),
];
pub const SERVER_TOOL_NAMES: [&str; 7] = [
"SubSession",
"compact_context",
"scheduler",
"session_history",
"memory",
"load_skill",
"read_skill_resource",
];
pub fn normalize_tool_ref(value: &str) -> Option<String> {
let trimmed = value.trim();
if trimmed.is_empty() {
return None;
}
let raw_tool_name = trimmed.split("::").last().unwrap_or(trimmed);
let normalized = normalize_builtin_alias(raw_tool_name);
if let Some(name) = BUILTIN_TOOL_NAMES
.iter()
.chain(SERVER_TOOL_NAMES.iter())
.find(|name| name.eq_ignore_ascii_case(normalized))
{
return Some((*name).to_string());
}
BUILTIN_TOOL_ALIASES
.iter()
.find(|(alias, _)| alias.eq_ignore_ascii_case(normalized))
.map(|(alias, _)| (*alias).to_string())
}
pub fn resolve_alias(name: &str) -> Option<&'static str> {
BUILTIN_TOOL_ALIASES
.iter()
.find(|(alias, _)| alias.eq_ignore_ascii_case(name))
.map(|(_, canonical)| *canonical)
}
pub fn normalize_builtin_alias(name: &str) -> &str {
match name {
"conclusionWithOptions" => "conclusion_with_options",
"execute_command" => "Bash",
"file_exists" => "FileExists",
"fileExists" => "FileExists",
"get_current_dir" => "GetCurrentDir",
"getCurrentDir" => "GetCurrentDir",
"get_file_info" => "GetFileInfo",
"getFileInfo" => "GetFileInfo",
"list_directory" => "Glob",
"memory_note" => "memory_note",
"read_file" => "Read",
"set_workspace" => "SetWorkspace",
"setWorkspace" => "SetWorkspace",
"sleep" => "Sleep",
"applyPatch" => "apply_patch",
"spawn_session" => "SubSession",
"spawnSession" => "SubSession",
"sub_session" => "SubSession",
"subSession" => "SubSession",
"sub_task" => "SubSession",
"subTask" => "SubSession",
"team_agent" => "SubSession",
"teamAgent" => "SubSession",
"child_session" => "SubSession",
"childSession" => "SubSession",
"sub_session_manager" => "SubSession",
"write_file" => "Write",
"sessionInspector" => "session_inspector",
"scheduleTasks" => "schedule_tasks",
_ => name,
}
}
pub fn is_builtin_tool(value: &str) -> bool {
normalize_tool_ref(value).is_some()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_normalize_tool_ref_accepts_claude_style_names() {
assert_eq!(
normalize_tool_ref("default::Bash"),
Some("Bash".to_string())
);
}
#[test]
fn test_normalize_tool_ref_accepts_legacy_camel_aliases() {
assert_eq!(
normalize_tool_ref("default::fileExists"),
Some("FileExists".to_string())
);
assert_eq!(
normalize_tool_ref("default::getCurrentDir"),
Some("GetCurrentDir".to_string())
);
assert_eq!(
normalize_tool_ref("default::getFileInfo"),
Some("GetFileInfo".to_string())
);
assert_eq!(
normalize_tool_ref("default::setWorkspace"),
Some("SetWorkspace".to_string())
);
assert_eq!(
normalize_tool_ref("default::sleep"),
Some("Sleep".to_string())
);
}
#[test]
fn test_normalize_tool_ref_accepts_legacy_snake_case_aliases() {
assert_eq!(
normalize_tool_ref("default::execute_command"),
Some("Bash".to_string())
);
assert_eq!(
normalize_tool_ref("default::file_exists"),
Some("FileExists".to_string())
);
assert_eq!(
normalize_tool_ref("default::get_current_dir"),
Some("GetCurrentDir".to_string())
);
assert_eq!(
normalize_tool_ref("default::get_file_info"),
Some("GetFileInfo".to_string())
);
assert_eq!(
normalize_tool_ref("default::list_directory"),
Some("Glob".to_string())
);
assert_eq!(
normalize_tool_ref("default::memory_note"),
Some("memory_note".to_string())
);
assert_eq!(
normalize_tool_ref("default::read_file"),
Some("Read".to_string())
);
assert_eq!(
normalize_tool_ref("default::set_workspace"),
Some("SetWorkspace".to_string())
);
assert_eq!(
normalize_tool_ref("default::write_file"),
Some("Write".to_string())
);
}
#[test]
fn test_normalize_tool_ref_accepts_spawn_task_aliases() {
for alias in [
"default::spawn_session",
"default::sub_session",
"default::sub_task",
"default::team_agent",
"default::child_session",
] {
assert_eq!(normalize_tool_ref(alias), Some("SubSession".to_string()));
}
}
#[test]
fn test_normalize_tool_ref_accepts_server_overlay_tools() {
assert_eq!(normalize_tool_ref("compress_context"), None);
assert_eq!(
normalize_tool_ref("default::read_skill_resource"),
Some("read_skill_resource".to_string())
);
}
#[test]
fn test_normalize_tool_ref_rejects_unknown_tool() {
assert_eq!(normalize_tool_ref("default::search"), None);
}
#[test]
fn test_is_builtin_tool() {
assert!(is_builtin_tool("Bash"));
assert!(is_builtin_tool("default::Bash"));
assert!(!is_builtin_tool("unknown_tool"));
assert!(!is_builtin_tool("compress_context"));
}
#[test]
fn test_resolve_alias() {
assert_eq!(resolve_alias("apply_patch"), Some("Edit"));
assert_eq!(resolve_alias("FileExists"), Some("GetFileInfo"));
assert_eq!(resolve_alias("Bash"), None);
}
}