From 47eaf274d6b688eae7302c3e4b8289b084765755 Mon Sep 17 00:00:00 2001 From: Bennet Bo Fenner Date: Tue, 8 Apr 2025 15:37:10 -0600 Subject: [PATCH] agent: Only require confirmation for batch tool when subset of tool calls require confirmation (#28363) Release Notes: - agent: Only require confirmation for batch tool when subset of tool calls require confirmation --- crates/agent/src/thread.rs | 2 +- crates/agent/src/tool_use.rs | 2 +- crates/assistant_tool/src/assistant_tool.rs | 2 +- crates/assistant_tools/src/bash_tool.rs | 2 +- crates/assistant_tools/src/batch_tool.rs | 13 +++++++++++-- crates/assistant_tools/src/code_symbols_tool.rs | 2 +- crates/assistant_tools/src/copy_path_tool.rs | 2 +- crates/assistant_tools/src/create_directory_tool.rs | 2 +- crates/assistant_tools/src/create_file_tool.rs | 2 +- crates/assistant_tools/src/delete_path_tool.rs | 2 +- crates/assistant_tools/src/diagnostics_tool.rs | 2 +- crates/assistant_tools/src/fetch_tool.rs | 2 +- .../assistant_tools/src/find_replace_file_tool.rs | 2 +- crates/assistant_tools/src/list_directory_tool.rs | 2 +- crates/assistant_tools/src/move_path_tool.rs | 2 +- crates/assistant_tools/src/now_tool.rs | 2 +- crates/assistant_tools/src/open_tool.rs | 2 +- crates/assistant_tools/src/path_search_tool.rs | 2 +- crates/assistant_tools/src/read_file_tool.rs | 2 +- crates/assistant_tools/src/regex_search_tool.rs | 2 +- crates/assistant_tools/src/symbol_info_tool.rs | 2 +- crates/assistant_tools/src/thinking_tool.rs | 2 +- crates/context_server/src/context_server_tool.rs | 2 +- 23 files changed, 33 insertions(+), 24 deletions(-) diff --git a/crates/agent/src/thread.rs b/crates/agent/src/thread.rs index fd3192bdf043294224bce443cedafd963067579e..3b5cd98d0991a676e78d5b9d1f9eb94336d9e166 100644 --- a/crates/agent/src/thread.rs +++ b/crates/agent/src/thread.rs @@ -1414,7 +1414,7 @@ impl Thread { for tool_use in pending_tool_uses.iter() { if let Some(tool) = self.tools.tool(&tool_use.name, cx) { - if tool.needs_confirmation() + if tool.needs_confirmation(&tool_use.input, cx) && !AssistantSettings::get_global(cx).always_allow_tool_actions { self.tool_use.confirm_tool_use( diff --git a/crates/agent/src/tool_use.rs b/crates/agent/src/tool_use.rs index b71c0348c39188bebb59e9eaf36481f425ca1323..8fce4ac67a1799f1d9b731543f003f5e50c5d3f7 100644 --- a/crates/agent/src/tool_use.rs +++ b/crates/agent/src/tool_use.rs @@ -201,7 +201,7 @@ impl ToolUseState { let (icon, needs_confirmation) = if let Some(tool) = self.tools.tool(&tool_use.name, cx) { - (tool.icon(), tool.needs_confirmation()) + (tool.icon(), tool.needs_confirmation(&tool_use.input, cx)) } else { (IconName::Cog, false) }; diff --git a/crates/assistant_tool/src/assistant_tool.rs b/crates/assistant_tool/src/assistant_tool.rs index 65c844e554187f30e4d56a34a441b88dcb55a325..59879b80d3ce34193e255720e35e75c561d04bd3 100644 --- a/crates/assistant_tool/src/assistant_tool.rs +++ b/crates/assistant_tool/src/assistant_tool.rs @@ -48,7 +48,7 @@ pub trait Tool: 'static + Send + Sync { /// Returns true iff the tool needs the users's confirmation /// before having permission to run. - fn needs_confirmation(&self) -> bool; + fn needs_confirmation(&self, input: &serde_json::Value, cx: &App) -> bool; /// Returns the JSON schema that describes the tool's input. fn input_schema(&self, _: LanguageModelToolSchemaFormat) -> serde_json::Value { diff --git a/crates/assistant_tools/src/bash_tool.rs b/crates/assistant_tools/src/bash_tool.rs index e010e81113a044bfb9b7418d9a61ab255453acdd..d0b6b885d6618619a21c52364f720d9dbde16f16 100644 --- a/crates/assistant_tools/src/bash_tool.rs +++ b/crates/assistant_tools/src/bash_tool.rs @@ -29,7 +29,7 @@ impl Tool for BashTool { "bash".to_string() } - fn needs_confirmation(&self) -> bool { + fn needs_confirmation(&self, _: &serde_json::Value, _: &App) -> bool { true } diff --git a/crates/assistant_tools/src/batch_tool.rs b/crates/assistant_tools/src/batch_tool.rs index 30d436f9e8fa4048fa8272f82ea003439bb46d35..751d2f8272c068748b88fc8f886fcc027ec37f08 100644 --- a/crates/assistant_tools/src/batch_tool.rs +++ b/crates/assistant_tools/src/batch_tool.rs @@ -151,8 +151,17 @@ impl Tool for BatchTool { "batch_tool".into() } - fn needs_confirmation(&self) -> bool { - true + fn needs_confirmation(&self, input: &serde_json::Value, cx: &App) -> bool { + serde_json::from_value::(input.clone()) + .map(|input| { + let working_set = ToolWorkingSet::default(); + input.invocations.iter().any(|invocation| { + working_set + .tool(&invocation.name, cx) + .map_or(false, |tool| tool.needs_confirmation(&invocation.input, cx)) + }) + }) + .unwrap_or(false) } fn description(&self) -> String { diff --git a/crates/assistant_tools/src/code_symbols_tool.rs b/crates/assistant_tools/src/code_symbols_tool.rs index f6f6dc28552d0830a7a3cba2a9431b0db2bddb04..dccff43fbf399a729ad757ed39829358bd4a0a10 100644 --- a/crates/assistant_tools/src/code_symbols_tool.rs +++ b/crates/assistant_tools/src/code_symbols_tool.rs @@ -79,7 +79,7 @@ impl Tool for CodeSymbolsTool { "code_symbols".into() } - fn needs_confirmation(&self) -> bool { + fn needs_confirmation(&self, _: &serde_json::Value, _: &App) -> bool { false } diff --git a/crates/assistant_tools/src/copy_path_tool.rs b/crates/assistant_tools/src/copy_path_tool.rs index 7a77b3257b4cebe67f5ff71fc64baaa58b015a19..c5995d6ff95867f7ff78ca2495c00c817102d203 100644 --- a/crates/assistant_tools/src/copy_path_tool.rs +++ b/crates/assistant_tools/src/copy_path_tool.rs @@ -43,7 +43,7 @@ impl Tool for CopyPathTool { "copy_path".into() } - fn needs_confirmation(&self) -> bool { + fn needs_confirmation(&self, _: &serde_json::Value, _: &App) -> bool { true } diff --git a/crates/assistant_tools/src/create_directory_tool.rs b/crates/assistant_tools/src/create_directory_tool.rs index d7d80e1f2db94cdfbf6d9be4991f6ca2a7291a8d..2ca7b2730357889ad36d269701800d7b76f1494d 100644 --- a/crates/assistant_tools/src/create_directory_tool.rs +++ b/crates/assistant_tools/src/create_directory_tool.rs @@ -33,7 +33,7 @@ impl Tool for CreateDirectoryTool { "create_directory".into() } - fn needs_confirmation(&self) -> bool { + fn needs_confirmation(&self, _: &serde_json::Value, _: &App) -> bool { true } diff --git a/crates/assistant_tools/src/create_file_tool.rs b/crates/assistant_tools/src/create_file_tool.rs index b4f72a5f5ab766ff3ea83771dd67952baabf0f97..26dd12b6c86cb2a5ebff33e84ad79edffd0b7745 100644 --- a/crates/assistant_tools/src/create_file_tool.rs +++ b/crates/assistant_tools/src/create_file_tool.rs @@ -40,7 +40,7 @@ impl Tool for CreateFileTool { "create_file".into() } - fn needs_confirmation(&self) -> bool { + fn needs_confirmation(&self, _: &serde_json::Value, _: &App) -> bool { false } diff --git a/crates/assistant_tools/src/delete_path_tool.rs b/crates/assistant_tools/src/delete_path_tool.rs index 22b1b45e50c958d98d0c95377d3842acead1213c..b831f14b42abb677cd706194e5c53942bad5d386 100644 --- a/crates/assistant_tools/src/delete_path_tool.rs +++ b/crates/assistant_tools/src/delete_path_tool.rs @@ -33,7 +33,7 @@ impl Tool for DeletePathTool { "delete_path".into() } - fn needs_confirmation(&self) -> bool { + fn needs_confirmation(&self, _: &serde_json::Value, _: &App) -> bool { true } diff --git a/crates/assistant_tools/src/diagnostics_tool.rs b/crates/assistant_tools/src/diagnostics_tool.rs index 2882cbefc614fe7bfec3576bd8e770fa62295e11..704e1e6d57614a03f439a216fa8188df48bbc54e 100644 --- a/crates/assistant_tools/src/diagnostics_tool.rs +++ b/crates/assistant_tools/src/diagnostics_tool.rs @@ -46,7 +46,7 @@ impl Tool for DiagnosticsTool { "diagnostics".into() } - fn needs_confirmation(&self) -> bool { + fn needs_confirmation(&self, _: &serde_json::Value, _: &App) -> bool { false } diff --git a/crates/assistant_tools/src/fetch_tool.rs b/crates/assistant_tools/src/fetch_tool.rs index 6c24bf3ba1fb647759c552ee8a2f029df99241ea..90a4c0ca0500d108b6f78d657221fc6672a8bc14 100644 --- a/crates/assistant_tools/src/fetch_tool.rs +++ b/crates/assistant_tools/src/fetch_tool.rs @@ -116,7 +116,7 @@ impl Tool for FetchTool { "fetch".to_string() } - fn needs_confirmation(&self) -> bool { + fn needs_confirmation(&self, _: &serde_json::Value, _: &App) -> bool { true } diff --git a/crates/assistant_tools/src/find_replace_file_tool.rs b/crates/assistant_tools/src/find_replace_file_tool.rs index e18763be208be36247c8c8af4d3a144056c9188c..dfcceb90fe4e675afce564bc7fea0190ef10edc7 100644 --- a/crates/assistant_tools/src/find_replace_file_tool.rs +++ b/crates/assistant_tools/src/find_replace_file_tool.rs @@ -129,7 +129,7 @@ impl Tool for FindReplaceFileTool { "find_replace_file".into() } - fn needs_confirmation(&self) -> bool { + fn needs_confirmation(&self, _: &serde_json::Value, _: &App) -> bool { false } diff --git a/crates/assistant_tools/src/list_directory_tool.rs b/crates/assistant_tools/src/list_directory_tool.rs index 4d76653dfd9bfa2361036de39f0e94d0f4fd17c6..2a0615fa54f337c85dc50a38c0b15d205177f20a 100644 --- a/crates/assistant_tools/src/list_directory_tool.rs +++ b/crates/assistant_tools/src/list_directory_tool.rs @@ -44,7 +44,7 @@ impl Tool for ListDirectoryTool { "list_directory".into() } - fn needs_confirmation(&self) -> bool { + fn needs_confirmation(&self, _: &serde_json::Value, _: &App) -> bool { false } diff --git a/crates/assistant_tools/src/move_path_tool.rs b/crates/assistant_tools/src/move_path_tool.rs index 5dbbc2373eb734cbd0b4612350c6fdb4f8ffecc1..b44023f122abcbf10eb865e26c6a1ef24c38c827 100644 --- a/crates/assistant_tools/src/move_path_tool.rs +++ b/crates/assistant_tools/src/move_path_tool.rs @@ -42,7 +42,7 @@ impl Tool for MovePathTool { "move_path".into() } - fn needs_confirmation(&self) -> bool { + fn needs_confirmation(&self, _: &serde_json::Value, _: &App) -> bool { true } diff --git a/crates/assistant_tools/src/now_tool.rs b/crates/assistant_tools/src/now_tool.rs index e793899855e3fdfc84c00b6ee1b88a1e07df238f..45279daa3ad5bdfb0dc57e73ae1394c1adf0ad73 100644 --- a/crates/assistant_tools/src/now_tool.rs +++ b/crates/assistant_tools/src/now_tool.rs @@ -33,7 +33,7 @@ impl Tool for NowTool { "now".into() } - fn needs_confirmation(&self) -> bool { + fn needs_confirmation(&self, _: &serde_json::Value, _: &App) -> bool { false } diff --git a/crates/assistant_tools/src/open_tool.rs b/crates/assistant_tools/src/open_tool.rs index 8aa336e2648ef92bed9d365b480142586ad81535..a64a50edbfd49dc28d6a5fd1462c9220233f5e04 100644 --- a/crates/assistant_tools/src/open_tool.rs +++ b/crates/assistant_tools/src/open_tool.rs @@ -23,7 +23,7 @@ impl Tool for OpenTool { "open".to_string() } - fn needs_confirmation(&self) -> bool { + fn needs_confirmation(&self, _: &serde_json::Value, _: &App) -> bool { true } diff --git a/crates/assistant_tools/src/path_search_tool.rs b/crates/assistant_tools/src/path_search_tool.rs index 78662a604f4ca3c4e948b716731370f8208d0005..604084395c1b3e420402831b1cd1f8b2d9475f87 100644 --- a/crates/assistant_tools/src/path_search_tool.rs +++ b/crates/assistant_tools/src/path_search_tool.rs @@ -41,7 +41,7 @@ impl Tool for PathSearchTool { "path_search".into() } - fn needs_confirmation(&self) -> bool { + fn needs_confirmation(&self, _: &serde_json::Value, _: &App) -> bool { false } diff --git a/crates/assistant_tools/src/read_file_tool.rs b/crates/assistant_tools/src/read_file_tool.rs index b0823ee70fe423f95a741e7c41ff70bdf6c7af9c..eb4f5c7a771ead180392b3ac7387d87599bfda2e 100644 --- a/crates/assistant_tools/src/read_file_tool.rs +++ b/crates/assistant_tools/src/read_file_tool.rs @@ -51,7 +51,7 @@ impl Tool for ReadFileTool { "read_file".into() } - fn needs_confirmation(&self) -> bool { + fn needs_confirmation(&self, _: &serde_json::Value, _: &App) -> bool { false } diff --git a/crates/assistant_tools/src/regex_search_tool.rs b/crates/assistant_tools/src/regex_search_tool.rs index 948afcf1fd83f11f83df48810ce89e149025c0f4..809b40754782eea99581be35b1edbfc3f31c53ef 100644 --- a/crates/assistant_tools/src/regex_search_tool.rs +++ b/crates/assistant_tools/src/regex_search_tool.rs @@ -44,7 +44,7 @@ impl Tool for RegexSearchTool { "regex_search".into() } - fn needs_confirmation(&self) -> bool { + fn needs_confirmation(&self, _: &serde_json::Value, _: &App) -> bool { false } diff --git a/crates/assistant_tools/src/symbol_info_tool.rs b/crates/assistant_tools/src/symbol_info_tool.rs index d04cce22ed8bdc2d2439ad9c445346ab40c99fa9..6d86679b384436f75949c85db46425cc26201e7a 100644 --- a/crates/assistant_tools/src/symbol_info_tool.rs +++ b/crates/assistant_tools/src/symbol_info_tool.rs @@ -72,7 +72,7 @@ impl Tool for SymbolInfoTool { "symbol_info".into() } - fn needs_confirmation(&self) -> bool { + fn needs_confirmation(&self, _: &serde_json::Value, _: &App) -> bool { false } diff --git a/crates/assistant_tools/src/thinking_tool.rs b/crates/assistant_tools/src/thinking_tool.rs index b189edc0b6ab0f20e96ea60fd15fb35673a7e4ec..4a5800a6ad7a2e1770edf181563ae67c3e1a4dcf 100644 --- a/crates/assistant_tools/src/thinking_tool.rs +++ b/crates/assistant_tools/src/thinking_tool.rs @@ -24,7 +24,7 @@ impl Tool for ThinkingTool { "thinking".to_string() } - fn needs_confirmation(&self) -> bool { + fn needs_confirmation(&self, _: &serde_json::Value, _: &App) -> bool { false } diff --git a/crates/context_server/src/context_server_tool.rs b/crates/context_server/src/context_server_tool.rs index 31801ddfc715dd634a30076a05a72c1cebe3805c..ac952e4bd2c4e0510f735980a828fc255d7adbbe 100644 --- a/crates/context_server/src/context_server_tool.rs +++ b/crates/context_server/src/context_server_tool.rs @@ -49,7 +49,7 @@ impl Tool for ContextServerTool { } } - fn needs_confirmation(&self) -> bool { + fn needs_confirmation(&self, _: &serde_json::Value, _: &App) -> bool { true }