pub const CORE_TOOLS: &[&str] = &[
"web_search",
"web_extract",
"web_crawl",
"terminal",
"run_process",
"list_processes",
"kill_process",
"get_process_output",
"wait_for_process",
"write_stdin",
"read_file",
"write_file",
"patch",
"search_files",
"pdf_to_markdown",
"skills_list",
"skills_categories",
"skill_view",
"skill_manage",
"skills_hub",
"browser_navigate",
"browser_snapshot",
"browser_screenshot",
"browser_click",
"browser_type",
"browser_scroll",
"browser_console",
"browser_back",
"browser_press",
"browser_close",
"browser_get_images",
"browser_vision",
"browser_wait_for",
"browser_select",
"browser_hover",
"text_to_speech",
"vision_analyze",
"transcribe_audio",
"manage_todo_list",
"memory_read",
"memory_write",
"honcho_conclude",
"honcho_search",
"honcho_list",
"honcho_remove",
"honcho_profile",
"honcho_context",
"ha_list_entities",
"ha_get_state",
"ha_list_services",
"ha_call_service",
"session_search",
"checkpoint",
"clarify",
"execute_code",
"delegate_task",
"mixture_of_agents",
"manage_cron_jobs",
"mcp_list_tools",
"mcp_call_tool",
"mcp_list_resources",
"mcp_read_resource",
"mcp_list_prompts",
"mcp_get_prompt",
"send_message",
"generate_image",
];
pub const ACP_TOOLS: &[&str] = &[
"web_search",
"web_extract",
"web_crawl",
"terminal",
"run_process",
"list_processes",
"kill_process",
"get_process_output",
"wait_for_process",
"write_stdin",
"read_file",
"write_file",
"patch",
"search_files",
"pdf_to_markdown",
"skills_list",
"skills_categories",
"skill_view",
"skill_manage",
"skills_hub",
"browser_navigate",
"browser_snapshot",
"browser_screenshot",
"browser_click",
"browser_type",
"browser_scroll",
"browser_console",
"browser_back",
"browser_press",
"browser_close",
"browser_get_images",
"browser_vision",
"browser_wait_for",
"browser_select",
"browser_hover",
"manage_todo_list",
"memory_read",
"memory_write",
"honcho_conclude",
"honcho_search",
"honcho_list",
"honcho_remove",
"honcho_profile",
"honcho_context",
"session_search",
"checkpoint",
"execute_code",
"delegate_task",
"mixture_of_agents",
"mcp_list_tools",
"mcp_call_tool",
"mcp_list_resources",
"mcp_read_resource",
"mcp_list_prompts",
"mcp_get_prompt",
];
pub fn resolve_alias(alias: &str) -> Option<&'static [&'static str]> {
match alias {
"core" => Some(&[
"core", "file", "meta", "scheduling", "delegation", "code_execution", "session", "mcp", "messaging", "media", "browser", ]),
"coding" => Some(&["file", "terminal", "search", "code_execution"]),
"research" => Some(&["web", "browser", "vision"]),
"debugging" => Some(&["terminal", "web", "file"]),
"safe" => Some(&["web", "vision", "image_gen", "moa"]),
"all" => Some(&[]), "minimal" => Some(&["file", "terminal"]),
"data_gen" => Some(&["file", "terminal", "web", "code_execution"]),
_ => None, }
}
pub fn expand_toolset_names(names: &[String]) -> Vec<String> {
let mut result: Vec<String> = names
.iter()
.flat_map(|s| match resolve_alias(s) {
Some(expanded) if !expanded.is_empty() => {
expanded.iter().map(|e| e.to_string()).collect::<Vec<_>>()
}
Some(_empty) => vec![], None => vec![s.clone()], })
.collect();
result.sort();
result.dedup();
result
}
pub fn contains_all_sentinel(names: &[String]) -> bool {
names
.iter()
.any(|n| n == "all" || resolve_alias(n) == Some(&[]))
}
pub fn resolve_active_toolsets(
enabled: &[String],
disabled: &[String],
all_toolsets: &[&str],
) -> Vec<String> {
let expand = |names: &[String]| -> Vec<String> {
names
.iter()
.flat_map(|s| match resolve_alias(s) {
Some(expanded) => expanded.iter().map(|e| e.to_string()).collect::<Vec<_>>(),
None => vec![s.clone()], })
.collect()
};
let enabled_expanded = if enabled.is_empty() {
all_toolsets.iter().map(|s| s.to_string()).collect()
} else {
expand(enabled)
};
let disabled_expanded = expand(disabled);
enabled_expanded
.into_iter()
.filter(|s| !disabled_expanded.contains(s))
.collect()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn core_tools_not_empty() {
assert!(!CORE_TOOLS.is_empty());
assert!(CORE_TOOLS.contains(&"read_file"));
assert!(CORE_TOOLS.contains(&"terminal"));
assert!(CORE_TOOLS.contains(&"web_search"));
assert!(CORE_TOOLS.contains(&"web_crawl"));
assert!(CORE_TOOLS.contains(&"clarify"));
assert!(CORE_TOOLS.contains(&"memory_read"));
assert!(CORE_TOOLS.contains(&"manage_todo_list"));
assert!(CORE_TOOLS.contains(&"checkpoint"));
assert!(CORE_TOOLS.contains(&"mcp_list_tools"));
assert!(CORE_TOOLS.contains(&"browser_wait_for"));
assert!(CORE_TOOLS.contains(&"browser_select"));
assert!(CORE_TOOLS.contains(&"browser_hover"));
}
#[test]
fn acp_tools_no_interactive() {
assert!(!ACP_TOOLS.contains(&"clarify"));
assert!(!ACP_TOOLS.contains(&"send_message"));
assert!(!ACP_TOOLS.contains(&"generate_image"));
assert!(!ACP_TOOLS.contains(&"text_to_speech"));
assert!(ACP_TOOLS.contains(&"web_crawl"));
assert!(ACP_TOOLS.contains(&"checkpoint"));
assert!(ACP_TOOLS.contains(&"mcp_list_tools"));
assert!(ACP_TOOLS.contains(&"browser_wait_for"));
assert!(ACP_TOOLS.contains(&"browser_select"));
assert!(ACP_TOOLS.contains(&"browser_hover"));
}
#[test]
fn resolve_alias_coding() {
let result = resolve_alias("coding").expect("should be known alias");
assert!(result.contains(&"file"));
assert!(result.contains(&"terminal"));
}
#[test]
fn resolve_alias_unknown_is_none() {
assert!(resolve_alias("custom_toolset").is_none());
}
#[test]
fn resolve_alias_all_is_empty_sentinel() {
let result = resolve_alias("all").expect("should be known alias");
assert!(result.is_empty());
}
#[test]
fn resolve_active_toolsets_whitelist() {
let all = vec!["file", "terminal", "web", "browser"];
let enabled = vec!["coding".to_string()];
let disabled = vec![];
let result = resolve_active_toolsets(&enabled, &disabled, &all);
assert!(result.contains(&"file".to_string()));
assert!(result.contains(&"terminal".to_string()));
assert!(!result.contains(&"web".to_string()));
}
#[test]
fn resolve_active_toolsets_blacklist() {
let all = vec!["file", "terminal", "web", "browser"];
let enabled = vec![];
let disabled = vec!["web".to_string()];
let result = resolve_active_toolsets(&enabled, &disabled, &all);
assert!(result.contains(&"file".to_string()));
assert!(!result.contains(&"web".to_string()));
}
#[test]
fn resolve_alias_core_includes_file_toolset() {
let expanded = resolve_alias("core").expect("'core' must be a registered alias");
assert!(
expanded.contains(&"file"),
"'core' alias must include 'file' toolset (read_file, write_file, patch)"
);
}
#[test]
fn resolve_alias_core_includes_meta_toolset() {
let expanded = resolve_alias("core").expect("'core' must be a registered alias");
assert!(
expanded.contains(&"meta"),
"'core' alias must include 'meta' toolset (manage_todo_list, clarify)"
);
}
#[test]
fn resolve_alias_core_includes_scheduling() {
let expanded = resolve_alias("core").expect("'core' must be a registered alias");
assert!(
expanded.contains(&"scheduling"),
"'core' alias must include 'scheduling' toolset (manage_cron_jobs)"
);
}
#[test]
fn resolve_alias_core_includes_browser_toolset() {
let expanded = resolve_alias("core").expect("'core' must be a registered alias");
assert!(
expanded.contains(&"browser"),
"'core' alias must include 'browser' toolset so browser_navigate is available when CDP is connected"
);
}
#[test]
fn resolve_alias_core_includes_messaging_toolset() {
let expanded = resolve_alias("core").expect("'core' must be a registered alias");
assert!(
expanded.contains(&"messaging"),
"'core' alias must include 'messaging' so send_message is visible when gateway delivery is wired"
);
}
#[test]
fn resolve_alias_core_includes_media_toolset() {
let expanded = resolve_alias("core").expect("'core' must be a registered alias");
assert!(
expanded.contains(&"media"),
"'core' alias must include 'media' so inbound images/audio are usable in default sessions"
);
}
#[test]
fn expand_toolset_names_expands_core_alias() {
let config_toolsets = vec![
"core".to_string(),
"web".to_string(),
"terminal".to_string(),
"memory".to_string(),
"skills".to_string(),
];
let expanded = expand_toolset_names(&config_toolsets);
assert!(
expanded.contains(&"file".to_string()),
"file must be in expanded list"
);
assert!(
expanded.contains(&"meta".to_string()),
"meta must be in expanded list"
);
assert!(
expanded.contains(&"scheduling".to_string()),
"scheduling must be in expanded list"
);
assert!(
expanded.contains(&"messaging".to_string()),
"messaging must be in expanded list"
);
assert!(
expanded.contains(&"media".to_string()),
"media must be in expanded list"
);
assert!(expanded.contains(&"web".to_string()));
assert!(expanded.contains(&"terminal".to_string()));
assert!(expanded.contains(&"memory".to_string()));
assert!(expanded.contains(&"skills".to_string()));
let mut sorted = expanded.clone();
sorted.sort();
sorted.dedup();
assert_eq!(
expanded.len(),
sorted.len(),
"expanded list must be deduplicated"
);
}
#[test]
fn expand_toolset_names_passes_through_literal() {
let names = vec!["terminal".to_string(), "web".to_string()];
let expanded = expand_toolset_names(&names);
assert_eq!(expanded, vec!["terminal".to_string(), "web".to_string()]);
}
#[test]
fn expand_toolset_names_empty_input() {
let expanded = expand_toolset_names(&[]);
assert!(expanded.is_empty());
}
#[test]
fn contains_all_sentinel_detects_all_alias() {
let names = vec!["core".to_string(), "all".to_string()];
assert!(contains_all_sentinel(&names));
}
#[test]
fn contains_all_sentinel_false_for_normal_list() {
let names = vec!["core".to_string(), "web".to_string()];
assert!(!contains_all_sentinel(&names));
}
}