From 4e482288cb42fc998e6af18b87d643940c5fa3bf Mon Sep 17 00:00:00 2001
From: Danilo Leal <67129314+danilo-leal@users.noreply.github.com>
Date: Tue, 16 Dec 2025 09:15:08 -0300
Subject: [PATCH] agent_ui: Add keybinding to cycle through profiles (#44979)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Similar to the mode selector in external agents, it will now be possible
to use `shift-tab` to cycle through profiles.
Release Notes:
- Added the ability to use `shift-tab` to cycle through profiles for the
built-in Zed agent.
---
crates/agent_ui/src/acp/thread_view.rs | 6 ++-
crates/agent_ui/src/profile_selector.rs | 56 +++++++++++++++++++++----
2 files changed, 52 insertions(+), 10 deletions(-)
diff --git a/crates/agent_ui/src/acp/thread_view.rs b/crates/agent_ui/src/acp/thread_view.rs
index 6cd2ec2fa3442bbf4961dffb0c4538ac9615d982..bc449c3c3a0238a5989c52abec029a708bf9f0ba 100644
--- a/crates/agent_ui/src/acp/thread_view.rs
+++ b/crates/agent_ui/src/acp/thread_view.rs
@@ -4208,7 +4208,11 @@ impl AcpThreadView {
}
}))
.on_action(cx.listener(|this, _: &CycleModeSelector, window, cx| {
- if let Some(mode_selector) = this.mode_selector() {
+ if let Some(profile_selector) = this.profile_selector.as_ref() {
+ profile_selector.update(cx, |profile_selector, cx| {
+ profile_selector.cycle_profile(cx);
+ });
+ } else if let Some(mode_selector) = this.mode_selector() {
mode_selector.update(cx, |mode_selector, cx| {
mode_selector.cycle_mode(window, cx);
});
diff --git a/crates/agent_ui/src/profile_selector.rs b/crates/agent_ui/src/profile_selector.rs
index 0182be0912d3b8a8a046371ce725e7d21a0ddb58..ac08070fcefa92854b51bc8a66d4d388d08e087d 100644
--- a/crates/agent_ui/src/profile_selector.rs
+++ b/crates/agent_ui/src/profile_selector.rs
@@ -1,4 +1,4 @@
-use crate::{ManageProfiles, ToggleProfileSelector};
+use crate::{CycleModeSelector, ManageProfiles, ToggleProfileSelector};
use agent_settings::{
AgentProfile, AgentProfileId, AgentSettings, AvailableProfiles, builtin_profiles,
};
@@ -70,6 +70,29 @@ impl ProfileSelector {
self.picker_handle.clone()
}
+ pub fn cycle_profile(&mut self, cx: &mut Context) {
+ if !self.provider.profiles_supported(cx) {
+ return;
+ }
+
+ let profiles = AgentProfile::available_profiles(cx);
+ if profiles.is_empty() {
+ return;
+ }
+
+ let current_profile_id = self.provider.profile_id(cx);
+ let current_index = profiles
+ .keys()
+ .position(|id| id == ¤t_profile_id)
+ .unwrap_or(0);
+
+ let next_index = (current_index + 1) % profiles.len();
+
+ if let Some((next_profile_id, _)) = profiles.get_index(next_index) {
+ self.provider.set_profile(next_profile_id.clone(), cx);
+ }
+ }
+
fn ensure_picker(
&mut self,
window: &mut Window,
@@ -163,14 +186,29 @@ impl Render for ProfileSelector {
PickerPopoverMenu::new(
picker,
trigger_button,
- move |_window, cx| {
- Tooltip::for_action_in(
- "Toggle Profile Menu",
- &ToggleProfileSelector,
- &focus_handle,
- cx,
- )
- },
+ Tooltip::element({
+ move |_window, cx| {
+ let container = || h_flex().gap_1().justify_between();
+ v_flex()
+ .gap_1()
+ .child(
+ container()
+ .pb_1()
+ .border_b_1()
+ .border_color(cx.theme().colors().border_variant)
+ .child(Label::new("Cycle Through Profiles"))
+ .child(KeyBinding::for_action_in(
+ &CycleModeSelector,
+ &focus_handle,
+ cx,
+ )),
+ )
+ .child(container().child(Label::new("Toggle Profile Menu")).child(
+ KeyBinding::for_action_in(&ToggleProfileSelector, &focus_handle, cx),
+ ))
+ .into_any()
+ }
+ }),
gpui::Corner::BottomRight,
cx,
)