gestura_core/tools/
registry.rs1use crate::config::AppConfig;
12
13pub use gestura_core_tools::registry::{
17 ToolDefinition, all_tools, code_tool_names, find_tool, is_code_tool_name,
18 looks_like_capabilities_question, looks_like_tools_question, render_tool_detail,
19 render_tools_overview,
20};
21
22pub fn render_capabilities(config: &AppConfig) -> String {
25 let mut out = String::new();
26
27 out.push_str("## Built-in Tools\n\n");
29 for t in all_tools() {
30 out.push_str(&format!("• **{}** - {}\n", t.name, t.summary));
31 }
32
33 out.push_str("\n## MCP Servers & Tools\n\n");
35 if config.mcp_servers.is_empty() {
36 out.push_str("_No MCP servers configured._\n");
37 } else {
38 for srv in &config.mcp_servers {
39 let status = if srv.enabled { "✓" } else { "○" };
40 out.push_str(&format!(
41 "• {} **{}** ({}) → `{}`\n",
42 status,
43 srv.name,
44 srv.transport,
45 srv.effective_uri()
46 ));
47 }
48 }
49
50 if !config.mdh_pointers.is_empty() {
52 out.push_str("\n## MDH Data Resources\n\n");
53 for (alias, uri) in &config.mdh_pointers {
54 out.push_str(&format!("• **{}** → `{}`\n", alias, uri));
55 }
56 }
57
58 out.push_str("\n## LLM Configuration\n\n");
60 out.push_str(&format!("• **Primary Provider:** {}\n", config.llm.primary));
61 if let Some(ref openai) = config.llm.openai {
62 out.push_str(&format!("• **OpenAI Model:** {}\n", openai.model));
63 }
64 if let Some(ref anthropic) = config.llm.anthropic {
65 out.push_str(&format!("• **Anthropic Model:** {}\n", anthropic.model));
66 }
67 if let Some(ref grok) = config.llm.grok {
68 out.push_str(&format!("• **Grok Model:** {}\n", grok.model));
69 }
70 if let Some(ref ollama) = config.llm.ollama {
71 out.push_str(&format!(
72 "• **Ollama:** {} @ {}\n",
73 ollama.model, ollama.base_url
74 ));
75 }
76
77 out.push_str("\n## Voice Configuration\n\n");
79 out.push_str(&format!("• **Provider:** {}\n", config.voice.provider));
80 if let Some(ref device) = config.voice.audio_device {
81 out.push_str(&format!("• **Audio Device:** {}\n", device));
82 }
83 if let Some(ref model_path) = config.voice.local_model_path {
84 out.push_str(&format!("• **Local Model:** {}\n", model_path));
85 }
86
87 out.push_str("\n## Device & Simulator Settings\n\n");
89 out.push_str(&format!(
90 "• **Developer Mode:** {}\n",
91 if config.developer.developer_mode {
92 "enabled"
93 } else {
94 "disabled"
95 }
96 ));
97 out.push_str(&format!(
98 "• **Simulators:** {}\n",
99 if config.developer.enable_simulators {
100 "enabled"
101 } else {
102 "disabled"
103 }
104 ));
105 if config.developer.enable_simulators {
106 out.push_str(&format!(
107 "• **Auto-discover Simulators:** {}\n",
108 config.developer.auto_discover_simulators
109 ));
110 out.push_str(&format!(
111 "• **Simulator Pattern:** {}\n",
112 config.developer.simulator.device_name_pattern
113 ));
114 }
115
116 out.push_str("\n## System\n\n");
118 out.push_str(&format!("• **Hotkey:** {}\n", config.hotkey_listen));
119 out.push_str(&format!(
120 "• **Grace Period:** {}s\n",
121 config.grace_period_secs
122 ));
123
124 out.push_str("\n---\nUse `/tools <name>` for details on a specific tool.");
125 out
126}
127
128#[cfg(test)]
129mod tests {
130 use super::*;
131
132 #[test]
133 fn registry_contains_expected_tools() {
134 assert!(find_tool("file").is_some());
135 assert!(find_tool("shell").is_some());
136 assert!(find_tool("git").is_some());
137 }
138
139 #[test]
140 fn looks_like_tools_question_matches_common_phrases() {
141 assert!(looks_like_tools_question("what tools do you have?"));
142 assert!(looks_like_tools_question("list tools"));
143 assert!(looks_like_tools_question("/tools"));
144 assert!(!looks_like_tools_question("tell me a joke"));
145 }
146}