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 0000000000..1f50219418
--- /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 0b463266f5..9012c1b092 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 75d35f3ed3..05aa67f8a7 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 68ffefb126..e4461f94de 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 9e3467cca6..484e91abfd 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)
+ })),
)
- .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)
+ })),
+ )
+ .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 f907766759..daa7d5726f 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 c26968949f..da6adc07f0 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 ecda105f6d..6c08a61cf4 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 a27209b0d1..28d6bef9dd 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 5d4b36c2e8..b3e198c1b5 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 275161840b..e45c1976d1 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 2cac59c2d9..3b6d38fc06 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 c4768934db..bde904abb5 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 2c593407b6..82b15b7a86 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 1bf19d8d98..86e67a8f58 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 202e7620f2..1b0c69b744 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 cfd0247514..2c8bf0f6cf 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 ec079b6a56..27ae10151d 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 8587c9f7e6..b6b1cf90a4 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 34d4a8bd07..97a4769e19 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 0be0b53d66..39cc3165d8 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 91a2d994ed..4059eac2cf 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 1a8b6103ee..4641b7359e 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 7478d2ba75..9430ac9d9e 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 adfbe1e52d..c7ea321dce 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,