acp: Add Reauthenticate to dropdown (#36878)

Bennet Bo Fenner and Conrad Irwin created

Release Notes:

- N/A

Co-authored-by: Conrad Irwin <conrad.irwin@gmail.com>

Change summary

crates/agent_ui/src/acp/thread_view.rs | 18 ++++++++++++++++++
crates/agent_ui/src/agent_panel.rs     | 13 +++++++++++++
crates/zed_actions/src/lib.rs          |  4 +++-
3 files changed, 34 insertions(+), 1 deletion(-)

Detailed changes

crates/agent_ui/src/acp/thread_view.rs 🔗

@@ -4746,6 +4746,24 @@ impl AcpThreadView {
             }))
     }
 
+    pub(crate) fn reauthenticate(&mut self, window: &mut Window, cx: &mut Context<Self>) {
+        let agent = self.agent.clone();
+        let ThreadState::Ready { thread, .. } = &self.thread_state else {
+            return;
+        };
+
+        let connection = thread.read(cx).connection().clone();
+        let err = AuthRequired {
+            description: None,
+            provider_id: None,
+        };
+        self.clear_thread_error(cx);
+        let this = cx.weak_entity();
+        window.defer(cx, |window, cx| {
+            Self::handle_auth_required(this, err, agent, connection, window, cx);
+        })
+    }
+
     fn upgrade_button(&self, cx: &mut Context<Self>) -> impl IntoElement {
         Button::new("upgrade", "Upgrade")
             .label_size(LabelSize::Small)

crates/agent_ui/src/agent_panel.rs 🔗

@@ -9,6 +9,7 @@ use agent_servers::AgentServerSettings;
 use agent2::{DbThreadMetadata, HistoryEntry};
 use db::kvp::{Dismissable, KEY_VALUE_STORE};
 use serde::{Deserialize, Serialize};
+use zed_actions::agent::ReauthenticateAgent;
 
 use crate::acp::{AcpThreadHistory, ThreadHistoryEvent};
 use crate::agent_diff::AgentDiffThread;
@@ -2204,6 +2205,8 @@ impl AgentPanel {
             "Enable Full Screen"
         };
 
+        let selected_agent = self.selected_agent.clone();
+
         PopoverMenu::new("agent-options-menu")
             .trigger_with_tooltip(
                 IconButton::new("agent-options-menu", IconName::Ellipsis)
@@ -2283,6 +2286,11 @@ impl AgentPanel {
                             .action("Settings", Box::new(OpenSettings))
                             .separator()
                             .action(full_screen_label, Box::new(ToggleZoom));
+
+                        if selected_agent == AgentType::Gemini {
+                            menu = menu.action("Reauthenticate", Box::new(ReauthenticateAgent))
+                        }
+
                         menu
                     }))
                 }
@@ -3751,6 +3759,11 @@ impl Render for AgentPanel {
                 }
             }))
             .on_action(cx.listener(Self::toggle_burn_mode))
+            .on_action(cx.listener(|this, _: &ReauthenticateAgent, window, cx| {
+                if let Some(thread_view) = this.active_thread_view() {
+                    thread_view.update(cx, |thread_view, cx| thread_view.reauthenticate(window, cx))
+                }
+            }))
             .child(self.render_toolbar(window, cx))
             .children(self.render_onboarding(window, cx))
             .map(|parent| match &self.active_view {

crates/zed_actions/src/lib.rs 🔗

@@ -290,7 +290,9 @@ pub mod agent {
             Chat,
             /// Toggles the language model selector dropdown.
             #[action(deprecated_aliases = ["assistant::ToggleModelSelector", "assistant2::ToggleModelSelector"])]
-            ToggleModelSelector
+            ToggleModelSelector,
+            /// Triggers re-authentication on Gemini
+            ReauthenticateAgent
         ]
     );
 }