vtcode_core/tools/registry/
labels.rs1use std::borrow::Cow;
2
3use serde_json::Value;
4
5use crate::config::constants::tools as tool_names;
6use crate::tools::mcp::legacy_mcp_tool_name;
7use crate::tools::tool_intent;
8
9pub fn tool_action_label(tool_name: &str, args: &Value) -> Cow<'static, str> {
10 let actual_tool_name = normalize_tool_name(tool_name);
11
12 match actual_tool_name {
13 name if name == tool_names::EXEC_COMMAND => Cow::Borrowed("Run command"),
14 name if name == tool_names::WRITE_STDIN => Cow::Borrowed("Send command input"),
15 name if name == tool_names::RUN_PTY_CMD => Cow::Borrowed("Run command"),
16 name if name == tool_names::EXECUTE_CODE => Cow::Borrowed("Run code"),
17 name if name == tool_names::GET_ERRORS => Cow::Borrowed("List errors"),
18 name if name == tool_names::MCP_SEARCH_TOOLS => Cow::Borrowed("Search MCP tools"),
19 name if name == tool_names::MCP_GET_TOOL_DETAILS => Cow::Borrowed("Inspect MCP tool"),
20 name if name == tool_names::MCP_LIST_SERVERS => Cow::Borrowed("List MCP servers"),
21 name if name == tool_names::MCP_CONNECT_SERVER => Cow::Borrowed("Connect MCP server"),
22 name if name == tool_names::MCP_DISCONNECT_SERVER => Cow::Borrowed("Disconnect MCP server"),
23 name if name == tool_names::LIST_SKILLS => Cow::Borrowed("List skills"),
24 name if name == tool_names::LOAD_SKILL => Cow::Borrowed("Load skill"),
25 name if name == tool_names::LOAD_SKILL_RESOURCE => Cow::Borrowed("Load skill resource"),
26 name if name == tool_names::READ_FILE => Cow::Borrowed("Read file"),
27 name if name == tool_names::WRITE_FILE => Cow::Borrowed("Write file"),
28 name if name == tool_names::EDIT_FILE => Cow::Borrowed("Edit file"),
29 name if name == tool_names::CREATE_FILE => Cow::Borrowed("Create file"),
30 name if name == tool_names::DELETE_FILE => Cow::Borrowed("Delete file"),
31 name if name == tool_names::APPLY_PATCH => Cow::Borrowed("Apply patch"),
32 name if name == tool_names::SEARCH_REPLACE => Cow::Borrowed("Search/replace"),
33 name if name == tool_names::CREATE_PTY_SESSION => Cow::Borrowed("Create command session"),
34 name if name == tool_names::READ_PTY_SESSION => Cow::Borrowed("Read command session"),
35 name if name == tool_names::LIST_PTY_SESSIONS => Cow::Borrowed("List command sessions"),
36 name if name == tool_names::SEND_PTY_INPUT => Cow::Borrowed("Send command input"),
37 name if name == tool_names::CLOSE_PTY_SESSION => Cow::Borrowed("Close command session"),
38 name if name == tool_names::RESIZE_PTY_SESSION => Cow::Borrowed("Resize command session"),
39 name if name == tool_names::UNIFIED_EXEC => {
40 match tool_intent::unified_exec_action(args).unwrap_or("run") {
41 "run" => Cow::Borrowed("Run command"),
42 "write" => Cow::Borrowed("Send command input"),
43 "poll" => Cow::Borrowed("Read command session"),
44 "continue" => Cow::Borrowed("Continue command session"),
45 "inspect" => Cow::Borrowed("Inspect command output"),
46 "list" => Cow::Borrowed("List command sessions"),
47 "close" => Cow::Borrowed("Close command session"),
48 "code" => Cow::Borrowed("Run code"),
49 _ => Cow::Borrowed("Exec action"),
50 }
51 }
52 name if name == tool_names::UNIFIED_SEARCH => {
53 let normalized = tool_intent::normalize_unified_search_args(args);
54 let workflow = normalized
55 .get("workflow")
56 .and_then(Value::as_str)
57 .unwrap_or("query");
58
59 match tool_intent::unified_search_action(&normalized).unwrap_or("grep") {
60 "grep" => Cow::Borrowed("Search text"),
61 "list" => Cow::Borrowed("List files"),
62 "structural" => match workflow {
63 "scan" => Cow::Borrowed("Structural scan"),
64 "test" => Cow::Borrowed("Structural test"),
65 "new" => Cow::Borrowed("Structural new"),
66 "apply" => Cow::Borrowed("Structural apply"),
67 _ => Cow::Borrowed("Structural search"),
68 },
69 "tools" => Cow::Borrowed("List tools"),
70 "errors" => Cow::Borrowed("List errors"),
71 "agent" => Cow::Borrowed("Show agent info"),
72 "web" => Cow::Borrowed("Fetch"),
73 "skill" => Cow::Borrowed("Load skill"),
74 _ => Cow::Borrowed("Search"),
75 }
76 }
77 name if name == tool_names::UNIFIED_FILE => {
78 match tool_intent::unified_file_action(args).unwrap_or("read") {
79 "read" => Cow::Borrowed("Read file"),
80 "write" => Cow::Borrowed("Write file"),
81 "edit" => Cow::Borrowed("Edit file"),
82 "patch" | tool_names::APPLY_PATCH => Cow::Borrowed("Apply patch"),
83 "delete" => Cow::Borrowed("Delete file"),
84 "move" => Cow::Borrowed("Move file"),
85 "copy" => Cow::Borrowed("Copy file"),
86 _ => Cow::Borrowed("File operation"),
87 }
88 }
89 "fetch" => Cow::Borrowed("Fetch"),
90 _ => Cow::Owned(humanize_tool_name(actual_tool_name)),
91 }
92}
93
94fn normalize_tool_name(tool_name: &str) -> &str {
95 if let Some(stripped) = legacy_mcp_tool_name(tool_name) {
96 return stripped;
97 }
98 if tool_name.starts_with("mcp__") {
99 return tool_name.split("__").last().unwrap_or(tool_name);
100 }
101 if tool_name.starts_with("mcp::") {
102 return tool_name.split("::").last().unwrap_or(tool_name);
103 }
104 tool_name
105}
106
107fn humanize_tool_name(name: &str) -> String {
108 let replaced = name.replace('_', " ");
109 if replaced.is_empty() {
110 return replaced;
111 }
112 let mut chars = replaced.chars();
113 let Some(first) = chars.next() else {
114 return String::new();
115 };
116 let mut result = first.to_uppercase().collect::<String>();
117 result.push_str(&chars.collect::<String>());
118 result
119}
120
121#[cfg(test)]
122mod tests {
123 use super::tool_action_label;
124 use crate::config::constants::tools;
125 use serde_json::json;
126
127 #[test]
128 fn unified_search_structural_query_uses_default_label() {
129 let label = tool_action_label(
130 tools::UNIFIED_SEARCH,
131 &json!({"action": "structural", "pattern": "fn $NAME() {}"}),
132 );
133
134 assert_eq!(label, "Structural search");
135 }
136
137 #[test]
138 fn unified_search_structural_scan_uses_distinct_label() {
139 let label = tool_action_label(
140 tools::UNIFIED_SEARCH,
141 &json!({"action": "structural", "workflow": "scan"}),
142 );
143
144 assert_eq!(label, "Structural scan");
145 }
146
147 #[test]
148 fn unified_search_structural_test_uses_distinct_label() {
149 let label = tool_action_label(
150 tools::UNIFIED_SEARCH,
151 &json!({"workflow": "test", "config_path": "sgconfig.yml"}),
152 );
153
154 assert_eq!(label, "Structural test");
155 }
156}