From 2645591cd5f4f13cc0e180e53068d940ce34505b Mon Sep 17 00:00:00 2001 From: Danilo Leal <67129314+danilo-leal@users.noreply.github.com> Date: Tue, 3 Jun 2025 15:20:25 -0300 Subject: [PATCH] agent: Allow to accept and reject all via the panel (#31971) This PR introduces the "Reject All" and "Accept All" buttons in the panel's edit bar, which appears as soon as the agent starts editing a file. I'm also adding here a new method to the thread called `has_pending_edit_tool_uses`, which is a more specific way of knowing, in comparison to the `is_generating` method, whether or not the reject/accept all actions can be triggered. Previously, without this new method, you'd be waiting for the whole generation to end (e.g., the agent would be generating markdown with things like change summary) to be able to click those buttons, when the edit was already there, ready for you. It always felt like waiting for the whole thing was unnecessary when you really wanted to just wait for the _edits_ to be done, as so to avoid any potential conflicting state. --- Release Notes: - agent: Added ability to reject and accept all changes from the agent panel. --------- Co-authored-by: Agus Zubiaga --- assets/icons/list_todo.svg | 1 + assets/keymaps/default-linux.json | 4 +- assets/keymaps/default-macos.json | 4 +- crates/agent/src/context_server_tool.rs | 4 + crates/agent/src/message_editor.rs | 174 ++++++++++++++---- crates/agent/src/thread.rs | 11 +- crates/agent/src/tool_use.rs | 8 + crates/assistant_tool/src/assistant_tool.rs | 3 + crates/assistant_tools/src/copy_path_tool.rs | 4 + .../src/create_directory_tool.rs | 8 +- .../assistant_tools/src/delete_path_tool.rs | 4 + .../assistant_tools/src/diagnostics_tool.rs | 4 + crates/assistant_tools/src/edit_file_tool.rs | 4 + crates/assistant_tools/src/fetch_tool.rs | 6 +- crates/assistant_tools/src/find_path_tool.rs | 4 + crates/assistant_tools/src/grep_tool.rs | 4 + .../src/list_directory_tool.rs | 4 + crates/assistant_tools/src/move_path_tool.rs | 4 + crates/assistant_tools/src/now_tool.rs | 4 + crates/assistant_tools/src/open_tool.rs | 4 +- crates/assistant_tools/src/read_file_tool.rs | 4 + crates/assistant_tools/src/terminal_tool.rs | 4 + crates/assistant_tools/src/thinking_tool.rs | 4 + crates/assistant_tools/src/web_search_tool.rs | 4 + crates/icons/src/icons.rs | 1 + 25 files changed, 240 insertions(+), 40 deletions(-) create mode 100644 assets/icons/list_todo.svg diff --git a/assets/icons/list_todo.svg b/assets/icons/list_todo.svg new file mode 100644 index 0000000000000000000000000000000000000000..1f50219418231e9d25fe9441ae1e4ae445abfcee --- /dev/null +++ b/assets/icons/list_todo.svg @@ -0,0 +1 @@ + diff --git a/assets/keymaps/default-linux.json b/assets/keymaps/default-linux.json index 0b463266f54c3d607cd582c0b0426f8d494225d8..9012c1b0922ed99ac6e5a534f759b8a968b2f049 100644 --- a/assets/keymaps/default-linux.json +++ b/assets/keymaps/default-linux.json @@ -278,7 +278,9 @@ "enter": "agent::Chat", "ctrl-enter": "agent::ChatWithFollow", "ctrl-i": "agent::ToggleProfileSelector", - "shift-ctrl-r": "agent::OpenAgentDiff" + "shift-ctrl-r": "agent::OpenAgentDiff", + "ctrl-shift-y": "agent::KeepAll", + "ctrl-shift-n": "agent::RejectAll" } }, { diff --git a/assets/keymaps/default-macos.json b/assets/keymaps/default-macos.json index 75d35f3ed3a8b16d0b13895b27db85461740dd44..05aa67f8a71f6654862eeb00c408176e98106f6c 100644 --- a/assets/keymaps/default-macos.json +++ b/assets/keymaps/default-macos.json @@ -315,7 +315,9 @@ "enter": "agent::Chat", "cmd-enter": "agent::ChatWithFollow", "cmd-i": "agent::ToggleProfileSelector", - "shift-ctrl-r": "agent::OpenAgentDiff" + "shift-ctrl-r": "agent::OpenAgentDiff", + "cmd-shift-y": "agent::KeepAll", + "cmd-shift-n": "agent::RejectAll" } }, { diff --git a/crates/agent/src/context_server_tool.rs b/crates/agent/src/context_server_tool.rs index 68ffefb126468b114878e0ed8857425a31fc1dbc..e4461f94de3ced9c13431de6e0eb02b7ffe646e4 100644 --- a/crates/agent/src/context_server_tool.rs +++ b/crates/agent/src/context_server_tool.rs @@ -51,6 +51,10 @@ impl Tool for ContextServerTool { true } + fn may_perform_edits(&self) -> bool { + true + } + fn input_schema(&self, format: LanguageModelToolSchemaFormat) -> Result { let mut schema = self.tool.input_schema.clone(); assistant_tool::adapt_schema_to_format(&mut schema, format)?; diff --git a/crates/agent/src/message_editor.rs b/crates/agent/src/message_editor.rs index 9e3467cca6676d6ecfb3c5d542b8df5af7c8e407..484e91abfd69f55e5ea3b6e66140bc09e3e9dde2 100644 --- a/crates/agent/src/message_editor.rs +++ b/crates/agent/src/message_editor.rs @@ -6,7 +6,7 @@ use crate::agent_model_selector::{AgentModelSelector, ModelType}; use crate::context::{AgentContextKey, ContextCreasesAddon, ContextLoadResult, load_context}; use crate::tool_compatibility::{IncompatibleToolsState, IncompatibleToolsTooltip}; use crate::ui::{ - AnimatedLabel, MaxModeTooltip, + MaxModeTooltip, preview::{AgentPreview, UsageCallout}, }; use agent_settings::{AgentSettings, CompletionMode}; @@ -27,7 +27,7 @@ use gpui::{ Animation, AnimationExt, App, ClipboardEntry, Entity, EventEmitter, Focusable, Subscription, Task, TextStyle, WeakEntity, linear_color_stop, linear_gradient, point, pulsating_between, }; -use language::{Buffer, Language}; +use language::{Buffer, Language, Point}; use language_model::{ ConfiguredModel, LanguageModelRequestMessage, MessageContent, RequestUsage, ZED_CLOUD_PROVIDER_ID, @@ -51,9 +51,9 @@ use crate::profile_selector::ProfileSelector; use crate::thread::{MessageCrease, Thread, TokenUsageRatio}; use crate::thread_store::{TextThreadStore, ThreadStore}; use crate::{ - ActiveThread, AgentDiffPane, Chat, ChatWithFollow, ExpandMessageEditor, Follow, NewThread, - OpenAgentDiff, RemoveAllContext, ToggleBurnMode, ToggleContextPicker, ToggleProfileSelector, - register_agent_preview, + ActiveThread, AgentDiffPane, Chat, ChatWithFollow, ExpandMessageEditor, Follow, KeepAll, + NewThread, OpenAgentDiff, RejectAll, RemoveAllContext, ToggleBurnMode, ToggleContextPicker, + ToggleProfileSelector, register_agent_preview, }; #[derive(RegisterComponent)] @@ -459,11 +459,20 @@ impl MessageEditor { } fn handle_review_click(&mut self, window: &mut Window, cx: &mut Context) { + if self.thread.read(cx).has_pending_edit_tool_uses() { + return; + } + self.edits_expanded = true; AgentDiffPane::deploy(self.thread.clone(), self.workspace.clone(), window, cx).log_err(); cx.notify(); } + fn handle_edit_bar_expand(&mut self, cx: &mut Context) { + self.edits_expanded = !self.edits_expanded; + cx.notify(); + } + fn handle_file_click( &self, buffer: Entity, @@ -494,6 +503,40 @@ impl MessageEditor { }); } + fn handle_accept_all(&mut self, _window: &mut Window, cx: &mut Context) { + if self.thread.read(cx).has_pending_edit_tool_uses() { + return; + } + + self.thread.update(cx, |thread, cx| { + thread.keep_all_edits(cx); + }); + cx.notify(); + } + + fn handle_reject_all(&mut self, _window: &mut Window, cx: &mut Context) { + if self.thread.read(cx).has_pending_edit_tool_uses() { + return; + } + + // Since there's no reject_all_edits method in the thread API, + // we need to iterate through all buffers and reject their edits + let action_log = self.thread.read(cx).action_log().clone(); + let changed_buffers = action_log.read(cx).changed_buffers(cx); + + for (buffer, _) in changed_buffers { + self.thread.update(cx, |thread, cx| { + let buffer_snapshot = buffer.read(cx); + let start = buffer_snapshot.anchor_before(Point::new(0, 0)); + let end = buffer_snapshot.anchor_after(buffer_snapshot.max_point()); + thread + .reject_edits_in_ranges(buffer, vec![start..end], cx) + .detach(); + }); + } + cx.notify(); + } + fn render_max_mode_toggle(&self, cx: &mut Context) -> Option { let thread = self.thread.read(cx); let model = thread.configured_model(); @@ -615,6 +658,12 @@ impl MessageEditor { .on_action(cx.listener(Self::move_up)) .on_action(cx.listener(Self::expand_message_editor)) .on_action(cx.listener(Self::toggle_burn_mode)) + .on_action( + cx.listener(|this, _: &KeepAll, window, cx| this.handle_accept_all(window, cx)), + ) + .on_action( + cx.listener(|this, _: &RejectAll, window, cx| this.handle_reject_all(window, cx)), + ) .capture_action(cx.listener(Self::paste)) .gap_2() .p_2() @@ -870,7 +919,10 @@ impl MessageEditor { let bg_edit_files_disclosure = editor_bg_color.blend(active_color.opacity(0.3)); let is_edit_changes_expanded = self.edits_expanded; - let is_generating = self.thread.read(cx).is_generating(); + let thread = self.thread.read(cx); + let pending_edits = thread.has_pending_edit_tool_uses(); + + const EDIT_NOT_READY_TOOLTIP_LABEL: &str = "Wait until file edits are complete."; v_flex() .mt_1() @@ -888,31 +940,28 @@ impl MessageEditor { }]) .child( h_flex() - .id("edits-container") - .cursor_pointer() - .p_1p5() + .p_1() .justify_between() .when(is_edit_changes_expanded, |this| { this.border_b_1().border_color(border_color) }) - .on_click( - cx.listener(|this, _, window, cx| this.handle_review_click(window, cx)), - ) .child( h_flex() + .id("edits-container") + .cursor_pointer() + .w_full() .gap_1() .child( Disclosure::new("edits-disclosure", is_edit_changes_expanded) - .on_click(cx.listener(|this, _ev, _window, cx| { - this.edits_expanded = !this.edits_expanded; - cx.notify(); + .on_click(cx.listener(|this, _, _, cx| { + this.handle_edit_bar_expand(cx) })), ) .map(|this| { - if is_generating { + if pending_edits { this.child( - AnimatedLabel::new(format!( - "Editing {} {}", + Label::new(format!( + "Editing {} {}…", changed_buffers.len(), if changed_buffers.len() == 1 { "file" @@ -920,7 +969,15 @@ impl MessageEditor { "files" } )) - .size(LabelSize::Small), + .color(Color::Muted) + .size(LabelSize::Small) + .with_animation( + "edit-label", + Animation::new(Duration::from_secs(2)) + .repeat() + .with_easing(pulsating_between(0.3, 0.7)), + |label, delta| label.alpha(delta), + ), ) } else { this.child( @@ -945,23 +1002,74 @@ impl MessageEditor { .color(Color::Muted), ) } - }), + }) + .on_click( + cx.listener(|this, _, _, cx| this.handle_edit_bar_expand(cx)), + ), ) .child( - Button::new("review", "Review Changes") - .label_size(LabelSize::Small) - .key_binding( - KeyBinding::for_action_in( - &OpenAgentDiff, - &focus_handle, - window, - cx, - ) - .map(|kb| kb.size(rems_from_px(12.))), + h_flex() + .gap_1() + .child( + IconButton::new("review-changes", IconName::ListTodo) + .icon_size(IconSize::Small) + .tooltip({ + let focus_handle = focus_handle.clone(); + move |window, cx| { + Tooltip::for_action_in( + "Review Changes", + &OpenAgentDiff, + &focus_handle, + window, + cx, + ) + } + }) + .on_click(cx.listener(|this, _, window, cx| { + this.handle_review_click(window, cx) + })), + ) + .child(ui::Divider::vertical().color(ui::DividerColor::Border)) + .child( + Button::new("reject-all-changes", "Reject All") + .label_size(LabelSize::Small) + .disabled(pending_edits) + .when(pending_edits, |this| { + this.tooltip(Tooltip::text(EDIT_NOT_READY_TOOLTIP_LABEL)) + }) + .key_binding( + KeyBinding::for_action_in( + &RejectAll, + &focus_handle.clone(), + window, + cx, + ) + .map(|kb| kb.size(rems_from_px(10.))), + ) + .on_click(cx.listener(|this, _, window, cx| { + this.handle_reject_all(window, cx) + })), ) - .on_click(cx.listener(|this, _, window, cx| { - this.handle_review_click(window, cx) - })), + .child( + Button::new("accept-all-changes", "Accept All") + .label_size(LabelSize::Small) + .disabled(pending_edits) + .when(pending_edits, |this| { + this.tooltip(Tooltip::text(EDIT_NOT_READY_TOOLTIP_LABEL)) + }) + .key_binding( + KeyBinding::for_action_in( + &KeepAll, + &focus_handle, + window, + cx, + ) + .map(|kb| kb.size(rems_from_px(10.))), + ) + .on_click(cx.listener(|this, _, window, cx| { + this.handle_accept_all(window, cx) + })), + ), ), ) .when(is_edit_changes_expanded, |parent| { diff --git a/crates/agent/src/thread.rs b/crates/agent/src/thread.rs index f907766759d54bc2250ee8820c961958feafb30d..daa7d5726f959f18cad65fc2af7d5c5a91571d9c 100644 --- a/crates/agent/src/thread.rs +++ b/crates/agent/src/thread.rs @@ -871,7 +871,16 @@ impl Thread { self.tool_use .pending_tool_uses() .iter() - .all(|tool_use| tool_use.status.is_error()) + .all(|pending_tool_use| pending_tool_use.status.is_error()) + } + + /// Returns whether any pending tool uses may perform edits + pub fn has_pending_edit_tool_uses(&self) -> bool { + self.tool_use + .pending_tool_uses() + .iter() + .filter(|pending_tool_use| !pending_tool_use.status.is_error()) + .any(|pending_tool_use| pending_tool_use.may_perform_edits) } pub fn tool_uses_for_message(&self, id: MessageId, cx: &App) -> Vec { diff --git a/crates/agent/src/tool_use.rs b/crates/agent/src/tool_use.rs index c26968949f19283873e7ee61e84cf3e4c59f0aaf..da6adc07f0c3c81ed4033c9d25e04438f440277a 100644 --- a/crates/agent/src/tool_use.rs +++ b/crates/agent/src/tool_use.rs @@ -337,6 +337,12 @@ impl ToolUseState { ) .into(); + let may_perform_edits = self + .tools + .read(cx) + .tool(&tool_use.name, cx) + .is_some_and(|tool| tool.may_perform_edits()); + self.pending_tool_uses_by_id.insert( tool_use.id.clone(), PendingToolUse { @@ -345,6 +351,7 @@ impl ToolUseState { name: tool_use.name.clone(), ui_text: ui_text.clone(), input: tool_use.input, + may_perform_edits, status, }, ); @@ -518,6 +525,7 @@ pub struct PendingToolUse { pub ui_text: Arc, pub input: serde_json::Value, pub status: PendingToolUseStatus, + pub may_perform_edits: bool, } #[derive(Debug, Clone)] diff --git a/crates/assistant_tool/src/assistant_tool.rs b/crates/assistant_tool/src/assistant_tool.rs index ecda105f6dcb2bb3f3a6b7a530c6dfe4399b9a89..6c08a61cf4479dec6c643020dbcadb642e02cdd7 100644 --- a/crates/assistant_tool/src/assistant_tool.rs +++ b/crates/assistant_tool/src/assistant_tool.rs @@ -218,6 +218,9 @@ pub trait Tool: 'static + Send + Sync { /// before having permission to run. fn needs_confirmation(&self, input: &serde_json::Value, cx: &App) -> bool; + /// Returns true if the tool may perform edits. + fn may_perform_edits(&self) -> bool; + /// Returns the JSON schema that describes the tool's input. fn input_schema(&self, _: LanguageModelToolSchemaFormat) -> Result { Ok(serde_json::Value::Object(serde_json::Map::default())) diff --git a/crates/assistant_tools/src/copy_path_tool.rs b/crates/assistant_tools/src/copy_path_tool.rs index a27209b0d167b96b07c7426aa01043972911f6f0..28d6bef9dd899360cd08e28b876830f81a5bb50a 100644 --- a/crates/assistant_tools/src/copy_path_tool.rs +++ b/crates/assistant_tools/src/copy_path_tool.rs @@ -48,6 +48,10 @@ impl Tool for CopyPathTool { false } + fn may_perform_edits(&self) -> bool { + true + } + fn description(&self) -> String { include_str!("./copy_path_tool/description.md").into() } diff --git a/crates/assistant_tools/src/create_directory_tool.rs b/crates/assistant_tools/src/create_directory_tool.rs index 5d4b36c2e8b8828db92b18c179e82dfddd600a50..b3e198c1b5e276032846dc8a6c2b67b02c917379 100644 --- a/crates/assistant_tools/src/create_directory_tool.rs +++ b/crates/assistant_tools/src/create_directory_tool.rs @@ -33,12 +33,16 @@ impl Tool for CreateDirectoryTool { "create_directory".into() } + fn description(&self) -> String { + include_str!("./create_directory_tool/description.md").into() + } + fn needs_confirmation(&self, _: &serde_json::Value, _: &App) -> bool { false } - fn description(&self) -> String { - include_str!("./create_directory_tool/description.md").into() + fn may_perform_edits(&self) -> bool { + false } fn icon(&self) -> IconName { diff --git a/crates/assistant_tools/src/delete_path_tool.rs b/crates/assistant_tools/src/delete_path_tool.rs index 275161840b0998e8d76f108eaac86b910d079c3c..e45c1976d1f32642b4091e9fad75385a5b4a7c93 100644 --- a/crates/assistant_tools/src/delete_path_tool.rs +++ b/crates/assistant_tools/src/delete_path_tool.rs @@ -37,6 +37,10 @@ impl Tool for DeletePathTool { false } + fn may_perform_edits(&self) -> bool { + true + } + fn description(&self) -> String { include_str!("./delete_path_tool/description.md").into() } diff --git a/crates/assistant_tools/src/diagnostics_tool.rs b/crates/assistant_tools/src/diagnostics_tool.rs index 2cac59c2d97bfac38d9c86163e7bca787ff00994..3b6d38fc06c0e9f8b95f031cb900ace74c5c6b04 100644 --- a/crates/assistant_tools/src/diagnostics_tool.rs +++ b/crates/assistant_tools/src/diagnostics_tool.rs @@ -50,6 +50,10 @@ impl Tool for DiagnosticsTool { false } + fn may_perform_edits(&self) -> bool { + false + } + fn description(&self) -> String { include_str!("./diagnostics_tool/description.md").into() } diff --git a/crates/assistant_tools/src/edit_file_tool.rs b/crates/assistant_tools/src/edit_file_tool.rs index c4768934db21aaf4b257efd17a152778062203d4..bde904abb53bd28dfdcd25ea20ed7032b487bdb0 100644 --- a/crates/assistant_tools/src/edit_file_tool.rs +++ b/crates/assistant_tools/src/edit_file_tool.rs @@ -129,6 +129,10 @@ impl Tool for EditFileTool { false } + fn may_perform_edits(&self) -> bool { + true + } + fn description(&self) -> String { include_str!("edit_file_tool/description.md").to_string() } diff --git a/crates/assistant_tools/src/fetch_tool.rs b/crates/assistant_tools/src/fetch_tool.rs index 2c593407b6aa9c488769f539a6bd1aa83c630356..82b15b7a86905219167d4f4fb630e6c9bab2c79d 100644 --- a/crates/assistant_tools/src/fetch_tool.rs +++ b/crates/assistant_tools/src/fetch_tool.rs @@ -118,7 +118,11 @@ impl Tool for FetchTool { } fn needs_confirmation(&self, _: &serde_json::Value, _: &App) -> bool { - true + false + } + + fn may_perform_edits(&self) -> bool { + false } fn description(&self) -> String { diff --git a/crates/assistant_tools/src/find_path_tool.rs b/crates/assistant_tools/src/find_path_tool.rs index 1bf19d8d984bc154445c5a85d7e330bba3e0824c..86e67a8f58cd71aedd163e15cb95aeb9e3357a87 100644 --- a/crates/assistant_tools/src/find_path_tool.rs +++ b/crates/assistant_tools/src/find_path_tool.rs @@ -59,6 +59,10 @@ impl Tool for FindPathTool { false } + fn may_perform_edits(&self) -> bool { + false + } + fn description(&self) -> String { include_str!("./find_path_tool/description.md").into() } diff --git a/crates/assistant_tools/src/grep_tool.rs b/crates/assistant_tools/src/grep_tool.rs index 202e7620f29f9fe4b13bceec53b610354cca3cc6..1b0c69b74417f3a7659255571ffa5bafdbb1a5b1 100644 --- a/crates/assistant_tools/src/grep_tool.rs +++ b/crates/assistant_tools/src/grep_tool.rs @@ -60,6 +60,10 @@ impl Tool for GrepTool { false } + fn may_perform_edits(&self) -> bool { + false + } + fn description(&self) -> String { include_str!("./grep_tool/description.md").into() } diff --git a/crates/assistant_tools/src/list_directory_tool.rs b/crates/assistant_tools/src/list_directory_tool.rs index cfd024751415d4d7bef87cf5c72929d55bea1341..2c8bf0f6cf037b3267c64d6ecb96a52cbc29d933 100644 --- a/crates/assistant_tools/src/list_directory_tool.rs +++ b/crates/assistant_tools/src/list_directory_tool.rs @@ -48,6 +48,10 @@ impl Tool for ListDirectoryTool { false } + fn may_perform_edits(&self) -> bool { + false + } + fn description(&self) -> String { include_str!("./list_directory_tool/description.md").into() } diff --git a/crates/assistant_tools/src/move_path_tool.rs b/crates/assistant_tools/src/move_path_tool.rs index ec079b6a56ffe3f10d1877be0a5d6ac11f13a863..27ae10151d4e91f951e198e850e5ff6fc2fb331b 100644 --- a/crates/assistant_tools/src/move_path_tool.rs +++ b/crates/assistant_tools/src/move_path_tool.rs @@ -46,6 +46,10 @@ impl Tool for MovePathTool { false } + fn may_perform_edits(&self) -> bool { + true + } + fn description(&self) -> String { include_str!("./move_path_tool/description.md").into() } diff --git a/crates/assistant_tools/src/now_tool.rs b/crates/assistant_tools/src/now_tool.rs index 8587c9f7e686c3fbad735cfa5914a66ea1e125b5..b6b1cf90a43b487684b9c8f0d4f6a69a14af6455 100644 --- a/crates/assistant_tools/src/now_tool.rs +++ b/crates/assistant_tools/src/now_tool.rs @@ -37,6 +37,10 @@ impl Tool for NowTool { false } + fn may_perform_edits(&self) -> bool { + false + } + fn description(&self) -> String { "Returns the current datetime in RFC 3339 format. Only use this tool when the user specifically asks for it or the current task would benefit from knowing the current datetime.".into() } diff --git a/crates/assistant_tools/src/open_tool.rs b/crates/assistant_tools/src/open_tool.rs index 34d4a8bd075af03920f0905fcfb6b62d0ec56ffc..97a4769e19e60758fe509fab56bf7329ac7f30b6 100644 --- a/crates/assistant_tools/src/open_tool.rs +++ b/crates/assistant_tools/src/open_tool.rs @@ -26,7 +26,9 @@ impl Tool for OpenTool { fn needs_confirmation(&self, _: &serde_json::Value, _: &App) -> bool { true } - + fn may_perform_edits(&self) -> bool { + false + } fn description(&self) -> String { include_str!("./open_tool/description.md").to_string() } diff --git a/crates/assistant_tools/src/read_file_tool.rs b/crates/assistant_tools/src/read_file_tool.rs index 0be0b53d66bb0c7ace1c45d651e1e2f06363bf47..39cc3165d836f42c1fba6871ed1b2d13026e7096 100644 --- a/crates/assistant_tools/src/read_file_tool.rs +++ b/crates/assistant_tools/src/read_file_tool.rs @@ -58,6 +58,10 @@ impl Tool for ReadFileTool { false } + fn may_perform_edits(&self) -> bool { + false + } + fn description(&self) -> String { include_str!("./read_file_tool/description.md").into() } diff --git a/crates/assistant_tools/src/terminal_tool.rs b/crates/assistant_tools/src/terminal_tool.rs index 91a2d994eda499f7e5970201acf583eb711792d3..4059eac2cf53df80308841bd622e76f5998f58cf 100644 --- a/crates/assistant_tools/src/terminal_tool.rs +++ b/crates/assistant_tools/src/terminal_tool.rs @@ -80,6 +80,10 @@ impl Tool for TerminalTool { true } + fn may_perform_edits(&self) -> bool { + false + } + fn description(&self) -> String { include_str!("./terminal_tool/description.md").to_string() } diff --git a/crates/assistant_tools/src/thinking_tool.rs b/crates/assistant_tools/src/thinking_tool.rs index 1a8b6103ee6432787933b91fb8f5601b6df18f72..4641b7359e1039cefb80e2a4f97ec5db94bfd90e 100644 --- a/crates/assistant_tools/src/thinking_tool.rs +++ b/crates/assistant_tools/src/thinking_tool.rs @@ -28,6 +28,10 @@ impl Tool for ThinkingTool { false } + fn may_perform_edits(&self) -> bool { + false + } + fn description(&self) -> String { include_str!("./thinking_tool/description.md").to_string() } diff --git a/crates/assistant_tools/src/web_search_tool.rs b/crates/assistant_tools/src/web_search_tool.rs index 7478d2ba75754ffebba216e9842db9c845fac7f3..9430ac9d9e245d4f8871fcf120cba9ed48a5ba97 100644 --- a/crates/assistant_tools/src/web_search_tool.rs +++ b/crates/assistant_tools/src/web_search_tool.rs @@ -36,6 +36,10 @@ impl Tool for WebSearchTool { false } + fn may_perform_edits(&self) -> bool { + false + } + fn description(&self) -> String { "Search the web for information using your query. Use this when you need real-time information, facts, or data that might not be in your training. Results will include snippets and links from relevant web pages.".into() } diff --git a/crates/icons/src/icons.rs b/crates/icons/src/icons.rs index adfbe1e52d8a250214e2178228b6155cf08b8afd..c7ea321dce539fab7b4fc78f2994f91c3d31795b 100644 --- a/crates/icons/src/icons.rs +++ b/crates/icons/src/icons.rs @@ -155,6 +155,7 @@ pub enum IconName { LineHeight, Link, ListCollapse, + ListTodo, ListTree, ListX, LoadCircle,