vtcode_core/tools/registry/
dual_output.rs1use anyhow::Result;
4use serde_json::Value;
5use tracing::{debug, warn};
6use vtcode_commons::serde_helpers::json_to_string_pretty;
7
8use crate::config::constants::tools;
9use crate::tools::summarizers::{
10 Summarizer,
11 execution::BashSummarizer,
12 file_ops::{EditSummarizer, ReadSummarizer},
13 search::{GrepSummarizer, ListSummarizer},
14};
15use crate::tools::tool_intent;
16
17use super::{SplitToolResult, ToolRegistry};
18
19impl ToolRegistry {
20 pub async fn execute_tool_dual(&self, name: &str, args: Value) -> Result<SplitToolResult> {
37 let result = self.execute_tool_ref(name, &args).await?;
39
40 let ui_content = if result.is_string() {
42 result.as_str().unwrap_or("").to_string()
43 } else {
44 json_to_string_pretty(&result)
45 };
46
47 let tool_name = if let Some(registration) = self.inventory.registration_for(name) {
50 registration.name().to_string()
51 } else {
52 name.to_string() };
54
55 match tool_name.as_str() {
57 tools::UNIFIED_SEARCH => {
58 match tool_intent::unified_search_action(&args).unwrap_or("grep") {
59 "grep" => {
60 let summarizer = GrepSummarizer::default();
61 match summarizer.summarize(&ui_content, None) {
62 Ok(llm_content) => {
63 debug!(
64 tool = tools::UNIFIED_SEARCH,
65 action = "grep",
66 ui_tokens = %summarizer.estimate_savings(&ui_content, &llm_content).1,
67 llm_tokens = %summarizer.estimate_savings(&ui_content, &llm_content).0,
68 savings_pct = %summarizer.estimate_savings(&ui_content, &llm_content).2,
69 "Applied grep summarization"
70 );
71 Ok(SplitToolResult::new(
72 tool_name.as_str(),
73 llm_content,
74 ui_content,
75 ))
76 }
77 Err(e) => {
78 warn!(
79 tool = tools::UNIFIED_SEARCH,
80 action = "grep",
81 error = %e,
82 "Failed to summarize grep output, using simple result"
83 );
84 Ok(SplitToolResult::simple(tool_name.as_str(), ui_content))
85 }
86 }
87 }
88 "list" => {
89 let summarizer = ListSummarizer::default();
90 match summarizer.summarize(&ui_content, None) {
91 Ok(llm_content) => {
92 debug!(
93 tool = tools::UNIFIED_SEARCH,
94 action = "list",
95 ui_tokens = %summarizer.estimate_savings(&ui_content, &llm_content).1,
96 llm_tokens = %summarizer.estimate_savings(&ui_content, &llm_content).0,
97 savings_pct = %summarizer.estimate_savings(&ui_content, &llm_content).2,
98 "Applied list summarization"
99 );
100 Ok(SplitToolResult::new(
101 tool_name.as_str(),
102 llm_content,
103 ui_content,
104 ))
105 }
106 Err(e) => {
107 warn!(
108 tool = tools::UNIFIED_SEARCH,
109 action = "list",
110 error = %e,
111 "Failed to summarize list output, using simple result"
112 );
113 Ok(SplitToolResult::simple(tool_name.as_str(), ui_content))
114 }
115 }
116 }
117 _ => Ok(SplitToolResult::simple(tool_name.as_str(), ui_content)),
118 }
119 }
120 tools::UNIFIED_FILE => {
121 match tool_intent::unified_file_action(&args).unwrap_or("read") {
122 "read" => {
123 let mut metadata = args.clone();
124 if let Value::Object(map) = &mut metadata
125 && !map.contains_key("file_path")
126 {
127 let inferred_path = args
128 .get("path")
129 .or_else(|| args.get("file_path"))
130 .or_else(|| args.get("filepath"))
131 .or_else(|| args.get("target_path"))
132 .and_then(Value::as_str)
133 .map(str::to_string);
134 if let Some(path) = inferred_path {
135 map.insert("file_path".to_string(), Value::String(path));
136 }
137 }
138
139 let summarizer = ReadSummarizer::default();
140 match summarizer.summarize(&ui_content, Some(&metadata)) {
141 Ok(llm_content) => {
142 debug!(
143 tool = tools::UNIFIED_FILE,
144 action = "read",
145 ui_tokens = %summarizer.estimate_savings(&ui_content, &llm_content).1,
146 llm_tokens = %summarizer.estimate_savings(&ui_content, &llm_content).0,
147 savings_pct = %summarizer.estimate_savings(&ui_content, &llm_content).2,
148 "Applied unified_file read summarization"
149 );
150 Ok(SplitToolResult::new(
151 tool_name.as_str(),
152 llm_content,
153 ui_content,
154 ))
155 }
156 Err(e) => {
157 warn!(
158 tool = tools::UNIFIED_FILE,
159 action = "read",
160 error = %e,
161 "Failed to summarize unified_file read output, using simple result"
162 );
163 Ok(SplitToolResult::simple(tool_name.as_str(), ui_content))
164 }
165 }
166 }
167 "write" | "edit" | "patch" | "move" | "copy" | "delete" => {
168 let summarizer = EditSummarizer::default();
169 match summarizer.summarize(&ui_content, None) {
170 Ok(llm_content) => {
171 debug!(
172 tool = tools::UNIFIED_FILE,
173 action = "mutate",
174 ui_tokens = %summarizer.estimate_savings(&ui_content, &llm_content).1,
175 llm_tokens = %summarizer.estimate_savings(&ui_content, &llm_content).0,
176 savings_pct = %summarizer.estimate_savings(&ui_content, &llm_content).2,
177 "Applied unified_file mutation summarization"
178 );
179 Ok(SplitToolResult::new(
180 tool_name.as_str(),
181 llm_content,
182 ui_content,
183 ))
184 }
185 Err(e) => {
186 warn!(
187 tool = tools::UNIFIED_FILE,
188 action = "mutate",
189 error = %e,
190 "Failed to summarize unified_file mutation output, using simple result"
191 );
192 Ok(SplitToolResult::simple(tool_name.as_str(), ui_content))
193 }
194 }
195 }
196 _ => Ok(SplitToolResult::simple(tool_name.as_str(), ui_content)),
197 }
198 }
199 tools::UNIFIED_EXEC => match tool_intent::unified_exec_action(&args).unwrap_or("run") {
200 "run" | "code" => {
201 let summarizer = BashSummarizer::default();
202 let metadata = args.as_object().map(|_| args.clone());
203 match summarizer.summarize(&ui_content, metadata.as_ref()) {
204 Ok(llm_content) => {
205 debug!(
206 tool = tools::UNIFIED_EXEC,
207 action = "run",
208 ui_tokens = %summarizer.estimate_savings(&ui_content, &llm_content).1,
209 llm_tokens = %summarizer.estimate_savings(&ui_content, &llm_content).0,
210 savings_pct = %summarizer.estimate_savings(&ui_content, &llm_content).2,
211 "Applied unified_exec summarization"
212 );
213 Ok(SplitToolResult::new(
214 tool_name.as_str(),
215 llm_content,
216 ui_content,
217 ))
218 }
219 Err(e) => {
220 warn!(
221 tool = tools::UNIFIED_EXEC,
222 action = "run",
223 error = %e,
224 "Failed to summarize unified_exec output, using simple result"
225 );
226 Ok(SplitToolResult::simple(tool_name.as_str(), ui_content))
227 }
228 }
229 }
230 _ => Ok(SplitToolResult::simple(tool_name.as_str(), ui_content)),
231 },
232 tools::READ_FILE => {
233 let summarizer = ReadSummarizer::default();
235 let metadata = args.as_object().map(|_| args.clone());
237 match summarizer.summarize(&ui_content, metadata.as_ref()) {
238 Ok(llm_content) => {
239 debug!(
240 tool = tools::READ_FILE,
241 ui_tokens = %summarizer.estimate_savings(&ui_content, &llm_content).1,
242 llm_tokens = %summarizer.estimate_savings(&ui_content, &llm_content).0,
243 savings_pct = %summarizer.estimate_savings(&ui_content, &llm_content).2,
244 "Applied read file summarization"
245 );
246 Ok(SplitToolResult::new(
247 tool_name.as_str(),
248 llm_content,
249 ui_content,
250 ))
251 }
252 Err(e) => {
253 warn!(
254 tool = tools::READ_FILE,
255 error = %e,
256 "Failed to summarize read output, using simple result"
257 );
258 Ok(SplitToolResult::simple(tool_name.as_str(), ui_content))
259 }
260 }
261 }
262 tools::RUN_PTY_CMD => {
263 let summarizer = BashSummarizer::default();
265 let metadata = args.as_object().map(|_| args.clone());
267 match summarizer.summarize(&ui_content, metadata.as_ref()) {
268 Ok(llm_content) => {
269 debug!(
270 tool = tools::RUN_PTY_CMD,
271 ui_tokens = %summarizer.estimate_savings(&ui_content, &llm_content).1,
272 llm_tokens = %summarizer.estimate_savings(&ui_content, &llm_content).0,
273 savings_pct = %summarizer.estimate_savings(&ui_content, &llm_content).2,
274 "Applied bash summarization"
275 );
276 Ok(SplitToolResult::new(
277 tool_name.as_str(),
278 llm_content,
279 ui_content,
280 ))
281 }
282 Err(e) => {
283 warn!(
284 tool = tools::RUN_PTY_CMD,
285 error = %e,
286 "Failed to summarize bash output, using simple result"
287 );
288 Ok(SplitToolResult::simple(tool_name.as_str(), ui_content))
289 }
290 }
291 }
292 tools::WRITE_FILE | tools::EDIT_FILE | tools::APPLY_PATCH => {
293 let summarizer = EditSummarizer::default();
295 match summarizer.summarize(&ui_content, None) {
296 Ok(llm_content) => {
297 debug!(
298 tool = tool_name.as_str(),
299 ui_tokens = %summarizer.estimate_savings(&ui_content, &llm_content).1,
300 llm_tokens = %summarizer.estimate_savings(&ui_content, &llm_content).0,
301 savings_pct = %summarizer.estimate_savings(&ui_content, &llm_content).2,
302 "Applied edit summarization"
303 );
304 Ok(SplitToolResult::new(
305 tool_name.as_str(),
306 llm_content,
307 ui_content,
308 ))
309 }
310 Err(e) => {
311 warn!(
312 tool = tool_name.as_str(),
313 error = %e,
314 "Failed to summarize edit output, using simple result"
315 );
316 Ok(SplitToolResult::simple(tool_name.as_str(), ui_content))
317 }
318 }
319 }
320 _ => {
321 Ok(SplitToolResult::simple(tool_name.as_str(), ui_content))
323 }
324 }
325 }
326}