agent: Add use_modifier_to_send setting (#34709)

When `use_modifier_to_send` is turned on, holding `cmd`/`ctrl` is
necessary to send a message in the agent panel. Text threads already use
`cmd-enter` by default to submit a message, and it was done this way to
have the usual text editing bindings not taken over when writing a
prompt, sort of stimulating more thoughtful writing. While `enter` to
send is still somewhat a huge pattern in chat-like LLM UIs, it still
makes sense to allow this for the new agent panel... hence the existence
of this setting now!

Release Notes:

- agent: Added the `use_modifier_to_send` setting, which makes holding a
modifier (`cmd`/`ctrl`), together with `enter`, required to send a new
message.
This commit is contained in:
Danilo Leal 2025-07-18 15:03:31 -03:00 committed by GitHub
parent 64ce696aae
commit e1d28ff957
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 66 additions and 4 deletions

View file

@ -277,7 +277,7 @@
} }
}, },
{ {
"context": "MessageEditor > Editor", "context": "MessageEditor > Editor && !use_modifier_to_send",
"bindings": { "bindings": {
"enter": "agent::Chat", "enter": "agent::Chat",
"ctrl-enter": "agent::ChatWithFollow", "ctrl-enter": "agent::ChatWithFollow",
@ -287,6 +287,17 @@
"ctrl-shift-n": "agent::RejectAll" "ctrl-shift-n": "agent::RejectAll"
} }
}, },
{
"context": "MessageEditor > Editor && use_modifier_to_send",
"bindings": {
"ctrl-enter": "agent::Chat",
"enter": "editor::Newline",
"ctrl-i": "agent::ToggleProfileSelector",
"shift-ctrl-r": "agent::OpenAgentDiff",
"ctrl-shift-y": "agent::KeepAll",
"ctrl-shift-n": "agent::RejectAll"
}
},
{ {
"context": "EditMessageEditor > Editor", "context": "EditMessageEditor > Editor",
"bindings": { "bindings": {

View file

@ -318,7 +318,7 @@
} }
}, },
{ {
"context": "MessageEditor > Editor", "context": "MessageEditor > Editor && !use_modifier_to_send",
"use_key_equivalents": true, "use_key_equivalents": true,
"bindings": { "bindings": {
"enter": "agent::Chat", "enter": "agent::Chat",
@ -329,6 +329,18 @@
"cmd-shift-n": "agent::RejectAll" "cmd-shift-n": "agent::RejectAll"
} }
}, },
{
"context": "MessageEditor > Editor && use_modifier_to_send",
"use_key_equivalents": true,
"bindings": {
"cmd-enter": "agent::Chat",
"enter": "editor::Newline",
"cmd-i": "agent::ToggleProfileSelector",
"shift-ctrl-r": "agent::OpenAgentDiff",
"cmd-shift-y": "agent::KeepAll",
"cmd-shift-n": "agent::RejectAll"
}
},
{ {
"context": "EditMessageEditor > Editor", "context": "EditMessageEditor > Editor",
"use_key_equivalents": true, "use_key_equivalents": true,

View file

@ -69,6 +69,7 @@ pub struct AgentSettings {
pub enable_feedback: bool, pub enable_feedback: bool,
pub expand_edit_card: bool, pub expand_edit_card: bool,
pub expand_terminal_card: bool, pub expand_terminal_card: bool,
pub use_modifier_to_send: bool,
} }
impl AgentSettings { impl AgentSettings {
@ -174,6 +175,10 @@ impl AgentSettingsContent {
self.single_file_review = Some(allow); self.single_file_review = Some(allow);
} }
pub fn set_use_modifier_to_send(&mut self, always_use: bool) {
self.use_modifier_to_send = Some(always_use);
}
pub fn set_profile(&mut self, profile_id: AgentProfileId) { pub fn set_profile(&mut self, profile_id: AgentProfileId) {
self.default_profile = Some(profile_id); self.default_profile = Some(profile_id);
} }
@ -301,6 +306,10 @@ pub struct AgentSettingsContent {
/// ///
/// Default: true /// Default: true
expand_terminal_card: Option<bool>, expand_terminal_card: Option<bool>,
/// Whether to always use cmd-enter (or ctrl-enter on Linux) to send messages in the agent panel.
///
/// Default: false
use_modifier_to_send: Option<bool>,
} }
#[derive(Clone, Copy, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Default)] #[derive(Clone, Copy, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Default)]
@ -456,6 +465,10 @@ impl Settings for AgentSettings {
&mut settings.expand_terminal_card, &mut settings.expand_terminal_card,
value.expand_terminal_card, value.expand_terminal_card,
); );
merge(
&mut settings.use_modifier_to_send,
value.use_modifier_to_send,
);
settings settings
.model_parameters .model_parameters

View file

@ -28,8 +28,8 @@ use fs::Fs;
use futures::future::Shared; use futures::future::Shared;
use futures::{FutureExt as _, future}; use futures::{FutureExt as _, future};
use gpui::{ use gpui::{
Animation, AnimationExt, App, Entity, EventEmitter, Focusable, Subscription, Task, TextStyle, Animation, AnimationExt, App, Entity, EventEmitter, Focusable, KeyContext, Subscription, Task,
WeakEntity, linear_color_stop, linear_gradient, point, pulsating_between, TextStyle, WeakEntity, linear_color_stop, linear_gradient, point, pulsating_between,
}; };
use language::{Buffer, Language, Point}; use language::{Buffer, Language, Point};
use language_model::{ use language_model::{
@ -132,6 +132,7 @@ pub(crate) fn create_editor(
placement: Some(ContextMenuPlacement::Above), placement: Some(ContextMenuPlacement::Above),
}); });
editor.register_addon(ContextCreasesAddon::new()); editor.register_addon(ContextCreasesAddon::new());
editor.register_addon(MessageEditorAddon::new());
editor editor
}); });
@ -1494,6 +1495,31 @@ pub struct ContextCreasesAddon {
_subscription: Option<Subscription>, _subscription: Option<Subscription>,
} }
pub struct MessageEditorAddon {}
impl MessageEditorAddon {
pub fn new() -> Self {
Self {}
}
}
impl Addon for MessageEditorAddon {
fn to_any(&self) -> &dyn std::any::Any {
self
}
fn to_any_mut(&mut self) -> Option<&mut dyn std::any::Any> {
Some(self)
}
fn extend_key_context(&self, key_context: &mut KeyContext, cx: &App) {
let settings = agent_settings::AgentSettings::get_global(cx);
if settings.use_modifier_to_send {
key_context.add("use_modifier_to_send");
}
}
}
impl Addon for ContextCreasesAddon { impl Addon for ContextCreasesAddon {
fn to_any(&self) -> &dyn std::any::Any { fn to_any(&self) -> &dyn std::any::Any {
self self