From d5134062ac0afb8729c20ee8d353b7d6bb384536 Mon Sep 17 00:00:00 2001 From: Danilo Leal <67129314+danilo-leal@users.noreply.github.com> Date: Wed, 28 May 2025 18:08:58 -0300 Subject: [PATCH] agent: Add keybinding to toggle Burn Mode (#31630) One caveat with this PR is that the keybinding still doesn't work for text threads. Will do that in a follow-up. Release Notes: - agent: Added a keybinding to toggle Burn Mode on and off. --- assets/keymaps/default-linux.json | 3 +- assets/keymaps/default-macos.json | 3 +- crates/agent/src/agent.rs | 1 + crates/agent/src/agent_panel.rs | 23 ++++++- crates/agent/src/message_editor.rs | 28 ++++++--- crates/agent/src/ui/max_mode_tooltip.rs | 62 +++++++++++-------- .../src/max_mode_tooltip.rs | 51 +++++++-------- 7 files changed, 108 insertions(+), 63 deletions(-) diff --git a/assets/keymaps/default-linux.json b/assets/keymaps/default-linux.json index 243406277e..b407733a94 100644 --- a/assets/keymaps/default-linux.json +++ b/assets/keymaps/default-linux.json @@ -250,7 +250,8 @@ "ctrl-alt-e": "agent::RemoveAllContext", "ctrl-shift-e": "project_panel::ToggleFocus", "ctrl-shift-enter": "agent::ContinueThread", - "alt-enter": "agent::ContinueWithBurnMode" + "alt-enter": "agent::ContinueWithBurnMode", + "ctrl-alt-b": "agent::ToggleBurnMode" } }, { diff --git a/assets/keymaps/default-macos.json b/assets/keymaps/default-macos.json index 5afb6e97c4..a7b4319b94 100644 --- a/assets/keymaps/default-macos.json +++ b/assets/keymaps/default-macos.json @@ -285,7 +285,8 @@ "cmd-alt-e": "agent::RemoveAllContext", "cmd-shift-e": "project_panel::ToggleFocus", "cmd-shift-enter": "agent::ContinueThread", - "alt-enter": "agent::ContinueWithBurnMode" + "alt-enter": "agent::ContinueWithBurnMode", + "cmd-alt-b": "agent::ToggleBurnMode" } }, { diff --git a/crates/agent/src/agent.rs b/crates/agent/src/agent.rs index f5ae6097a5..1e26e42314 100644 --- a/crates/agent/src/agent.rs +++ b/crates/agent/src/agent.rs @@ -89,6 +89,7 @@ actions!( ResetTrialEndUpsell, ContinueThread, ContinueWithBurnMode, + ToggleBurnMode, ] ); diff --git a/crates/agent/src/agent_panel.rs b/crates/agent/src/agent_panel.rs index 324f98c2fd..9f9ddb5577 100644 --- a/crates/agent/src/agent_panel.rs +++ b/crates/agent/src/agent_panel.rs @@ -67,8 +67,8 @@ use crate::{ AddContextServer, AgentDiffPane, ContextStore, ContinueThread, ContinueWithBurnMode, DeleteRecentlyOpenThread, ExpandMessageEditor, Follow, InlineAssistant, NewTextThread, NewThread, OpenActiveThreadAsMarkdown, OpenAgentDiff, OpenHistory, ResetTrialEndUpsell, - ResetTrialUpsell, TextThreadStore, ThreadEvent, ToggleContextPicker, ToggleNavigationMenu, - ToggleOptionsMenu, + ResetTrialUpsell, TextThreadStore, ThreadEvent, ToggleBurnMode, ToggleContextPicker, + ToggleNavigationMenu, ToggleOptionsMenu, }; const AGENT_PANEL_KEY: &str = "agent_panel"; @@ -1304,6 +1304,24 @@ impl AgentPanel { } } + fn toggle_burn_mode( + &mut self, + _: &ToggleBurnMode, + _window: &mut Window, + cx: &mut Context, + ) { + self.thread.update(cx, |active_thread, cx| { + active_thread.thread().update(cx, |thread, _cx| { + let current_mode = thread.completion_mode(); + + thread.set_completion_mode(match current_mode { + CompletionMode::Max => CompletionMode::Normal, + CompletionMode::Normal => CompletionMode::Max, + }); + }); + }); + } + pub(crate) fn active_context_editor(&self) -> Option> { match &self.active_view { ActiveView::PromptEditor { context_editor, .. } => Some(context_editor.clone()), @@ -3065,6 +3083,7 @@ impl Render for AgentPanel { }); this.continue_conversation(window, cx); })) + .on_action(cx.listener(Self::toggle_burn_mode)) .child(self.render_toolbar(window, cx)) .children(self.render_upsell(window, cx)) .children(self.render_trial_end_upsell(window, cx)) diff --git a/crates/agent/src/message_editor.rs b/crates/agent/src/message_editor.rs index a53fc475f4..d5508ae8d4 100644 --- a/crates/agent/src/message_editor.rs +++ b/crates/agent/src/message_editor.rs @@ -51,7 +51,7 @@ use crate::thread::{MessageCrease, Thread, TokenUsageRatio}; use crate::thread_store::{TextThreadStore, ThreadStore}; use crate::{ ActiveThread, AgentDiffPane, Chat, ChatWithFollow, ExpandMessageEditor, Follow, NewThread, - OpenAgentDiff, RemoveAllContext, ToggleContextPicker, ToggleProfileSelector, + OpenAgentDiff, RemoveAllContext, ToggleBurnMode, ToggleContextPicker, ToggleProfileSelector, register_agent_preview, }; @@ -471,6 +471,22 @@ impl MessageEditor { } } + pub fn toggle_burn_mode( + &mut self, + _: &ToggleBurnMode, + _window: &mut Window, + cx: &mut Context, + ) { + self.thread.update(cx, |thread, _cx| { + let active_completion_mode = thread.completion_mode(); + + thread.set_completion_mode(match active_completion_mode { + CompletionMode::Max => CompletionMode::Normal, + CompletionMode::Normal => CompletionMode::Max, + }); + }); + } + fn render_max_mode_toggle(&self, cx: &mut Context) -> Option { let thread = self.thread.read(cx); let model = thread.configured_model(); @@ -492,13 +508,8 @@ impl MessageEditor { .icon_color(Color::Muted) .toggle_state(max_mode_enabled) .selected_icon_color(Color::Error) - .on_click(cx.listener(move |this, _event, _window, cx| { - this.thread.update(cx, |thread, _cx| { - thread.set_completion_mode(match active_completion_mode { - CompletionMode::Max => CompletionMode::Normal, - CompletionMode::Normal => CompletionMode::Max, - }); - }); + .on_click(cx.listener(|this, _event, window, cx| { + this.toggle_burn_mode(&ToggleBurnMode, window, cx); })) .tooltip(move |_window, cx| { cx.new(|_| MaxModeTooltip::new().selected(max_mode_enabled)) @@ -596,6 +607,7 @@ impl MessageEditor { .on_action(cx.listener(Self::remove_all_context)) .on_action(cx.listener(Self::move_up)) .on_action(cx.listener(Self::expand_message_editor)) + .on_action(cx.listener(Self::toggle_burn_mode)) .capture_action(cx.listener(Self::paste)) .gap_2() .p_2() diff --git a/crates/agent/src/ui/max_mode_tooltip.rs b/crates/agent/src/ui/max_mode_tooltip.rs index d1bd94c201..97f7853a61 100644 --- a/crates/agent/src/ui/max_mode_tooltip.rs +++ b/crates/agent/src/ui/max_mode_tooltip.rs @@ -1,5 +1,6 @@ -use gpui::{Context, IntoElement, Render, Window}; -use ui::{prelude::*, tooltip_container}; +use crate::ToggleBurnMode; +use gpui::{Context, FontWeight, IntoElement, Render, Window}; +use ui::{KeyBinding, prelude::*, tooltip_container}; pub struct MaxModeTooltip { selected: bool, @@ -18,39 +19,48 @@ impl MaxModeTooltip { impl Render for MaxModeTooltip { fn render(&mut self, window: &mut Window, cx: &mut Context) -> impl IntoElement { - let icon = if self.selected { - IconName::ZedBurnModeOn + let (icon, color) = if self.selected { + (IconName::ZedBurnModeOn, Color::Error) } else { - IconName::ZedBurnMode + (IconName::ZedBurnMode, Color::Default) }; + let turned_on = h_flex() + .h_4() + .px_1() + .border_1() + .border_color(cx.theme().colors().border) + .bg(cx.theme().colors().text_accent.opacity(0.1)) + .rounded_sm() + .child( + Label::new("ON") + .size(LabelSize::XSmall) + .weight(FontWeight::SEMIBOLD) + .color(Color::Accent), + ); + let title = h_flex() - .gap_1() - .child(Icon::new(icon).size(IconSize::Small)) - .child(Label::new("Burn Mode")); + .gap_1p5() + .child(Icon::new(icon).size(IconSize::Small).color(color)) + .child(Label::new("Burn Mode")) + .when(self.selected, |title| title.child(turned_on)); + + let keybinding = KeyBinding::for_action(&ToggleBurnMode, window, cx) + .map(|kb| kb.size(rems_from_px(12.))); tooltip_container(window, cx, |this, _, _| { - this.gap_0p5() - .map(|header| if self.selected { - header.child( - h_flex() - .justify_between() - .child(title) - .child( - h_flex() - .gap_0p5() - .child(Icon::new(IconName::Check).size(IconSize::XSmall).color(Color::Accent)) - .child(Label::new("Turned On").size(LabelSize::XSmall).color(Color::Accent)) - ) - ) - } else { - header.child(title) - }) + this + .child( + h_flex() + .justify_between() + .child(title) + .children(keybinding) + ) .child( div() - .max_w_72() + .max_w_64() .child( - Label::new("Enables models to use large context windows, unlimited tool calls, and other capabilities for expanded reasoning, offering an unfettered agentic experience.") + Label::new("Enables models to use large context windows, unlimited tool calls, and other capabilities for expanded reasoning.") .size(LabelSize::Small) .color(Color::Muted) ) diff --git a/crates/assistant_context_editor/src/max_mode_tooltip.rs b/crates/assistant_context_editor/src/max_mode_tooltip.rs index d1bd94c201..a3100d4367 100644 --- a/crates/assistant_context_editor/src/max_mode_tooltip.rs +++ b/crates/assistant_context_editor/src/max_mode_tooltip.rs @@ -1,4 +1,4 @@ -use gpui::{Context, IntoElement, Render, Window}; +use gpui::{Context, FontWeight, IntoElement, Render, Window}; use ui::{prelude::*, tooltip_container}; pub struct MaxModeTooltip { @@ -18,39 +18,40 @@ impl MaxModeTooltip { impl Render for MaxModeTooltip { fn render(&mut self, window: &mut Window, cx: &mut Context) -> impl IntoElement { - let icon = if self.selected { - IconName::ZedBurnModeOn + let (icon, color) = if self.selected { + (IconName::ZedBurnModeOn, Color::Error) } else { - IconName::ZedBurnMode + (IconName::ZedBurnMode, Color::Default) }; + let turned_on = h_flex() + .h_4() + .px_1() + .border_1() + .border_color(cx.theme().colors().border) + .bg(cx.theme().colors().text_accent.opacity(0.1)) + .rounded_sm() + .child( + Label::new("ON") + .size(LabelSize::XSmall) + .weight(FontWeight::SEMIBOLD) + .color(Color::Accent), + ); + let title = h_flex() - .gap_1() - .child(Icon::new(icon).size(IconSize::Small)) - .child(Label::new("Burn Mode")); + .gap_1p5() + .child(Icon::new(icon).size(IconSize::Small).color(color)) + .child(Label::new("Burn Mode")) + .when(self.selected, |title| title.child(turned_on)); tooltip_container(window, cx, |this, _, _| { - this.gap_0p5() - .map(|header| if self.selected { - header.child( - h_flex() - .justify_between() - .child(title) - .child( - h_flex() - .gap_0p5() - .child(Icon::new(IconName::Check).size(IconSize::XSmall).color(Color::Accent)) - .child(Label::new("Turned On").size(LabelSize::XSmall).color(Color::Accent)) - ) - ) - } else { - header.child(title) - }) + this + .child(title) .child( div() - .max_w_72() + .max_w_64() .child( - Label::new("Enables models to use large context windows, unlimited tool calls, and other capabilities for expanded reasoning, offering an unfettered agentic experience.") + Label::new("Enables models to use large context windows, unlimited tool calls, and other capabilities for expanded reasoning.") .size(LabelSize::Small) .color(Color::Muted) )