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};
14use crate::tools::tool_intent;
15
16use super::{SplitToolResult, ToolRegistry};
17
18impl ToolRegistry {
19 pub async fn execute_tool_dual(&self, name: &str, args: Value) -> Result<SplitToolResult> {
38 let result = self.execute_tool_ref(name, &args).await?;
40
41 let ui_content = if result.is_string() {
43 result.as_str().unwrap_or("").to_string()
44 } else {
45 json_to_string_pretty(&result)
46 };
47
48 let tool_name = if let Some(registration) = self.inventory.registration_for(name) {
51 registration.name().to_string()
52 } else {
53 name.to_string() };
55
56 match tool_name.as_str() {
58 tools::CODE_SEARCH => Ok(SplitToolResult::simple(tool_name.as_str(), ui_content)),
59 tools::UNIFIED_FILE => match tool_intent::file_operation_action(&args).unwrap_or("read") {
60 "read" => {
61 let mut metadata = args.clone();
62 if let Value::Object(map) = &mut metadata
63 && !map.contains_key("file_path")
64 {
65 let inferred_path = args
66 .get("path")
67 .or_else(|| args.get("file_path"))
68 .or_else(|| args.get("filepath"))
69 .or_else(|| args.get("target_path"))
70 .and_then(Value::as_str)
71 .map(str::to_string);
72 if let Some(path) = inferred_path {
73 map.insert("file_path".to_string(), Value::String(path));
74 }
75 }
76
77 let summarizer = ReadSummarizer::default();
78 match summarizer.summarize(&ui_content, Some(&metadata)) {
79 Ok(llm_content) => {
80 let savings = summarizer.estimate_savings(&ui_content, &llm_content);
81 debug!(
82 tool = tools::UNIFIED_FILE,
83 action = "read",
84 ui_tokens = %savings.ui_tokens,
85 llm_tokens = %savings.llm_tokens,
86 savings_pct = %savings.savings_percent,
87 "Applied file_operation read summarization"
88 );
89 Ok(SplitToolResult::new(tool_name.as_str(), llm_content, ui_content))
90 }
91 Err(e) => {
92 warn!(
93 tool = tools::UNIFIED_FILE,
94 action = "read",
95 error = %e,
96 "Failed to summarize file_operation read output, using simple result"
97 );
98 Ok(SplitToolResult::simple(tool_name.as_str(), ui_content))
99 }
100 }
101 }
102 "write" | "edit" | "patch" | "move" | "copy" | "delete" => {
103 let summarizer = EditSummarizer::default();
104 match summarizer.summarize(&ui_content, None) {
105 Ok(llm_content) => {
106 let savings = summarizer.estimate_savings(&ui_content, &llm_content);
107 debug!(
108 tool = tools::UNIFIED_FILE,
109 action = "mutate",
110 ui_tokens = %savings.ui_tokens,
111 llm_tokens = %savings.llm_tokens,
112 savings_pct = %savings.savings_percent,
113 "Applied file_operation mutation summarization"
114 );
115 Ok(SplitToolResult::new(tool_name.as_str(), llm_content, ui_content))
116 }
117 Err(e) => {
118 warn!(
119 tool = tools::UNIFIED_FILE,
120 action = "mutate",
121 error = %e,
122 "Failed to summarize file_operation mutation output, using simple result"
123 );
124 Ok(SplitToolResult::simple(tool_name.as_str(), ui_content))
125 }
126 }
127 }
128 _ => Ok(SplitToolResult::simple(tool_name.as_str(), ui_content)),
129 },
130 tools::UNIFIED_EXEC | tools::EXEC_COMMAND => {
131 match tool_intent::command_session_action(&args).unwrap_or("run") {
132 "run" | "code" => {
133 let summarizer = BashSummarizer::default();
134 let metadata = args.as_object().map(|_| args.clone());
135 match summarizer.summarize(&ui_content, metadata.as_ref()) {
136 Ok(llm_content) => {
137 let savings = summarizer.estimate_savings(&ui_content, &llm_content);
138 debug!(
139 tool = tools::UNIFIED_EXEC,
140 action = "run",
141 ui_tokens = %savings.ui_tokens,
142 llm_tokens = %savings.llm_tokens,
143 savings_pct = %savings.savings_percent,
144 "Applied command_session summarization"
145 );
146 Ok(SplitToolResult::new(tool_name.as_str(), llm_content, ui_content))
147 }
148 Err(e) => {
149 warn!(
150 tool = tools::UNIFIED_EXEC,
151 action = "run",
152 error = %e,
153 "Failed to summarize command_session output, using simple result"
154 );
155 Ok(SplitToolResult::simple(tool_name.as_str(), ui_content))
156 }
157 }
158 }
159 _ => Ok(SplitToolResult::simple(tool_name.as_str(), ui_content)),
160 }
161 }
162 tools::READ_FILE => {
163 let summarizer = ReadSummarizer::default();
165 let metadata = args.as_object().map(|_| args.clone());
167 match summarizer.summarize(&ui_content, metadata.as_ref()) {
168 Ok(llm_content) => {
169 let savings = summarizer.estimate_savings(&ui_content, &llm_content);
170 debug!(
171 tool = tools::READ_FILE,
172 ui_tokens = %savings.ui_tokens,
173 llm_tokens = %savings.llm_tokens,
174 savings_pct = %savings.savings_percent,
175 "Applied read file summarization"
176 );
177 Ok(SplitToolResult::new(tool_name.as_str(), llm_content, ui_content))
178 }
179 Err(e) => {
180 warn!(
181 tool = tools::READ_FILE,
182 error = %e,
183 "Failed to summarize read output, using simple result"
184 );
185 Ok(SplitToolResult::simple(tool_name.as_str(), ui_content))
186 }
187 }
188 }
189 tools::RUN_PTY_CMD => {
190 let summarizer = BashSummarizer::default();
192 let metadata = args.as_object().map(|_| args.clone());
194 match summarizer.summarize(&ui_content, metadata.as_ref()) {
195 Ok(llm_content) => {
196 let savings = summarizer.estimate_savings(&ui_content, &llm_content);
197 debug!(
198 tool = tools::RUN_PTY_CMD,
199 ui_tokens = %savings.ui_tokens,
200 llm_tokens = %savings.llm_tokens,
201 savings_pct = %savings.savings_percent,
202 "Applied bash summarization"
203 );
204 Ok(SplitToolResult::new(tool_name.as_str(), llm_content, ui_content))
205 }
206 Err(e) => {
207 warn!(
208 tool = tools::RUN_PTY_CMD,
209 error = %e,
210 "Failed to summarize bash output, using simple result"
211 );
212 Ok(SplitToolResult::simple(tool_name.as_str(), ui_content))
213 }
214 }
215 }
216 tools::WRITE_FILE | tools::EDIT_FILE | tools::APPLY_PATCH => {
217 let summarizer = EditSummarizer::default();
219 match summarizer.summarize(&ui_content, None) {
220 Ok(llm_content) => {
221 let savings = summarizer.estimate_savings(&ui_content, &llm_content);
222 debug!(
223 tool = tool_name.as_str(),
224 ui_tokens = %savings.ui_tokens,
225 llm_tokens = %savings.llm_tokens,
226 savings_pct = %savings.savings_percent,
227 "Applied edit summarization"
228 );
229 Ok(SplitToolResult::new(tool_name.as_str(), llm_content, ui_content))
230 }
231 Err(e) => {
232 warn!(
233 tool = tool_name.as_str(),
234 error = %e,
235 "Failed to summarize edit output, using simple result"
236 );
237 Ok(SplitToolResult::simple(tool_name.as_str(), ui_content))
238 }
239 }
240 }
241 _ => {
242 Ok(SplitToolResult::simple(tool_name.as_str(), ui_content))
244 }
245 }
246 }
247}