use serde::Serialize;
#[derive(Debug, Clone, Serialize)]
pub struct ToolMeta {
pub name: &'static str,
pub description_key: &'static str,
pub category: &'static str,
}
impl ToolMeta {
pub const fn new(
name: &'static str,
description_key: &'static str,
category: &'static str,
) -> Self {
Self {
name,
description_key,
category,
}
}
}
pub fn known_tools() -> &'static [ToolMeta] {
TOOL_CATALOG
}
const TOOL_CATALOG: &[ToolMeta] = &[
ToolMeta::new("read", "tools.read", "fs"),
ToolMeta::new("write", "tools.write", "fs"),
ToolMeta::new("edit", "tools.edit", "fs"),
ToolMeta::new("grep", "tools.grep", "fs"),
ToolMeta::new("find", "tools.find", "fs"),
ToolMeta::new("ls", "tools.ls", "fs"),
ToolMeta::new("web_search", "tools.webSearch", "comms"),
ToolMeta::new("get_search_results", "tools.getSearchResults", "comms"),
ToolMeta::new("exec", "tools.exec", "exec"),
ToolMeta::new("browse", "tools.browse", "comms"),
ToolMeta::new("memory_read", "tools.memoryRead", "memory"),
ToolMeta::new("memory_write", "tools.memoryWrite", "memory"),
ToolMeta::new("memory_search", "tools.memorySearch", "memory"),
ToolMeta::new("project", "tools.project", "system"),
ToolMeta::new("kernel_agent", "tools.kernelAgent", "system"),
ToolMeta::new("a2a_delegate", "tools.a2aDelegate", "a2a"),
ToolMeta::new("a2a_send", "tools.a2aSend", "a2a"),
ToolMeta::new("a2a_query", "tools.a2aQuery", "a2a"),
ToolMeta::new("persona", "tools.persona", "system"),
ToolMeta::new("cron", "tools.cron", "system"),
ToolMeta::new("security", "tools.security", "system"),
ToolMeta::new("budget", "tools.budget", "system"),
ToolMeta::new("resource", "tools.resource", "system"),
ToolMeta::new("knowledge", "tools.knowledge", "system"),
ToolMeta::new("calendar", "tools.calendar", "system"),
ToolMeta::new("send_email", "tools.sendEmail", "comms"),
];
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn catalog_is_populated() {
let tools = known_tools();
assert!(!tools.is_empty(), "tool catalog should not be empty");
assert!(
tools.iter().any(|t| t.name == "read"),
"read tool should be in catalog"
);
assert!(
tools.iter().any(|t| t.name == "exec"),
"exec tool should be in catalog"
);
assert!(
tools.iter().any(|t| t.name == "memory_read"),
"memory_read should be in catalog"
);
}
#[test]
fn all_tools_have_required_fields() {
for tool in known_tools() {
assert!(!tool.name.is_empty(), "tool name should not be empty");
assert!(
!tool.description_key.is_empty(),
"description_key should not be empty"
);
assert!(!tool.category.is_empty(), "category should not be empty");
}
}
#[test]
fn no_duplicate_names() {
let names: Vec<&str> = known_tools().iter().map(|t| t.name).collect();
let mut sorted = names.clone();
sorted.sort();
sorted.dedup();
assert_eq!(names.len(), sorted.len(), "duplicate tool names found");
}
}