Fix language model selector (#26138)

Marshall Bowers created

This PR fixes the language model selector.

I tried to piece together the state prior to #25697 (the state it was in
at 11838cf89e0b96531f90f22432b3df6859587871) while retaining unrelated
changes that happened since then.

Release Notes:

- Fixed an issue where language models would not be authenticated until
after the model selector was opened (Preview only).

Change summary

crates/assistant/src/inline_assistant.rs                      |  50 +
crates/assistant/src/terminal_inline_assistant.rs             |  50 +
crates/assistant2/src/assistant_model_selector.rs             |  83 +
crates/assistant2/src/inline_prompt_editor.rs                 |  18 
crates/assistant2/src/message_editor.rs                       |  12 
crates/assistant_context_editor/src/context_editor.rs         |  86 +
crates/language_model_selector/src/language_model_selector.rs | 190 +---
7 files changed, 289 insertions(+), 200 deletions(-)

Detailed changes

crates/assistant/src/inline_assistant.rs 🔗

@@ -35,7 +35,7 @@ use language_model::{
     report_assistant_event, LanguageModel, LanguageModelRegistry, LanguageModelRequest,
     LanguageModelRequestMessage, LanguageModelTextStream, Role,
 };
-use language_model_selector::inline_language_model_selector;
+use language_model_selector::{LanguageModelSelector, LanguageModelSelectorPopoverMenu};
 use multi_buffer::MultiBufferRow;
 use parking_lot::Mutex;
 use project::{CodeAction, ProjectTransaction};
@@ -1425,6 +1425,7 @@ enum PromptEditorEvent {
 struct PromptEditor {
     id: InlineAssistId,
     editor: Entity<Editor>,
+    language_model_selector: Entity<LanguageModelSelector>,
     edited_since_done: bool,
     gutter_dimensions: Arc<Mutex<GutterDimensions>>,
     prompt_history: VecDeque<String>,
@@ -1438,7 +1439,6 @@ struct PromptEditor {
     _token_count_subscriptions: Vec<Subscription>,
     workspace: Option<WeakEntity<Workspace>>,
     show_rate_limit_notice: bool,
-    fs: Arc<dyn Fs>,
 }
 
 #[derive(Copy, Clone)]
@@ -1589,16 +1589,29 @@ impl Render for PromptEditor {
                     .w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0))
                     .justify_center()
                     .gap_2()
-                    .child(inline_language_model_selector({
-                        let fs = self.fs.clone();
-                        move |model, cx| {
-                            update_settings_file::<AssistantSettings>(
-                                fs.clone(),
+                    .child(LanguageModelSelectorPopoverMenu::new(
+                        self.language_model_selector.clone(),
+                        IconButton::new("context", IconName::SettingsAlt)
+                            .shape(IconButtonShape::Square)
+                            .icon_size(IconSize::Small)
+                            .icon_color(Color::Muted),
+                        move |window, cx| {
+                            Tooltip::with_meta(
+                                format!(
+                                    "Using {}",
+                                    LanguageModelRegistry::read_global(cx)
+                                        .active_model()
+                                        .map(|model| model.name().0)
+                                        .unwrap_or_else(|| "No model selected".into()),
+                                ),
+                                None,
+                                "Change Model",
+                                window,
                                 cx,
-                                move |settings, _| settings.set_model(model.clone()),
-                            );
-                        }
-                    }))
+                            )
+                        },
+                        gpui::Corner::TopRight,
+                    ))
                     .map(|el| {
                         let CodegenStatus::Error(error) = self.codegen.read(cx).status(cx) else {
                             return el;
@@ -1711,8 +1724,21 @@ impl PromptEditor {
 
         let mut this = Self {
             id,
-            fs,
             editor: prompt_editor,
+            language_model_selector: cx.new(|cx| {
+                let fs = fs.clone();
+                LanguageModelSelector::new(
+                    move |model, cx| {
+                        update_settings_file::<AssistantSettings>(
+                            fs.clone(),
+                            cx,
+                            move |settings, _| settings.set_model(model.clone()),
+                        );
+                    },
+                    window,
+                    cx,
+                )
+            }),
             edited_since_done: false,
             gutter_dimensions,
             prompt_history,

crates/assistant/src/terminal_inline_assistant.rs 🔗

@@ -19,7 +19,7 @@ use language_model::{
     report_assistant_event, LanguageModelRegistry, LanguageModelRequest,
     LanguageModelRequestMessage, Role,
 };
-use language_model_selector::inline_language_model_selector;
+use language_model_selector::{LanguageModelSelector, LanguageModelSelectorPopoverMenu};
 use prompt_store::PromptBuilder;
 use settings::{update_settings_file, Settings};
 use std::{
@@ -487,9 +487,9 @@ enum PromptEditorEvent {
 
 struct PromptEditor {
     id: TerminalInlineAssistId,
-    fs: Arc<dyn Fs>,
     height_in_lines: u8,
     editor: Entity<Editor>,
+    language_model_selector: Entity<LanguageModelSelector>,
     edited_since_done: bool,
     prompt_history: VecDeque<String>,
     prompt_history_ix: Option<usize>,
@@ -641,16 +641,29 @@ impl Render for PromptEditor {
                     .w_12()
                     .justify_center()
                     .gap_2()
-                    .child(inline_language_model_selector({
-                        let fs = self.fs.clone();
-                        move |model, cx| {
-                            update_settings_file::<AssistantSettings>(
-                                fs.clone(),
+                    .child(LanguageModelSelectorPopoverMenu::new(
+                        self.language_model_selector.clone(),
+                        IconButton::new("change-model", IconName::SettingsAlt)
+                            .shape(IconButtonShape::Square)
+                            .icon_size(IconSize::Small)
+                            .icon_color(Color::Muted),
+                        move |window, cx| {
+                            Tooltip::with_meta(
+                                format!(
+                                    "Using {}",
+                                    LanguageModelRegistry::read_global(cx)
+                                        .active_model()
+                                        .map(|model| model.name().0)
+                                        .unwrap_or_else(|| "No model selected".into()),
+                                ),
+                                None,
+                                "Change Model",
+                                window,
                                 cx,
-                                move |settings, _| settings.set_model(model.clone()),
-                            );
-                        }
-                    }))
+                            )
+                        },
+                        gpui::Corner::TopRight,
+                    ))
                     .children(
                         if let CodegenStatus::Error(error) = &self.codegen.read(cx).status {
                             let error_message = SharedString::from(error.to_string());
@@ -728,9 +741,22 @@ impl PromptEditor {
 
         let mut this = Self {
             id,
-            fs,
             height_in_lines: 1,
             editor: prompt_editor,
+            language_model_selector: cx.new(|cx| {
+                let fs = fs.clone();
+                LanguageModelSelector::new(
+                    move |model, cx| {
+                        update_settings_file::<AssistantSettings>(
+                            fs.clone(),
+                            cx,
+                            move |settings, _| settings.set_model(model.clone()),
+                        );
+                    },
+                    window,
+                    cx,
+                )
+            }),
             edited_since_done: false,
             prompt_history,
             prompt_history_ix: None,

crates/assistant2/src/assistant_model_selector.rs 🔗

@@ -1,28 +1,45 @@
 use assistant_settings::AssistantSettings;
 use fs::Fs;
-use gpui::FocusHandle;
-use language_model_selector::{assistant_language_model_selector, LanguageModelSelector};
+use gpui::{Entity, FocusHandle, SharedString};
+use language_model::LanguageModelRegistry;
+use language_model_selector::{
+    LanguageModelSelector, LanguageModelSelectorPopoverMenu, ToggleModelSelector,
+};
 use settings::update_settings_file;
 use std::sync::Arc;
-use ui::{prelude::*, PopoverMenuHandle};
+use ui::{prelude::*, ButtonLike, PopoverMenuHandle, Tooltip};
 
 pub struct AssistantModelSelector {
+    selector: Entity<LanguageModelSelector>,
     menu_handle: PopoverMenuHandle<LanguageModelSelector>,
     focus_handle: FocusHandle,
-    fs: Arc<dyn Fs>,
 }
 
 impl AssistantModelSelector {
     pub(crate) fn new(
         fs: Arc<dyn Fs>,
+        menu_handle: PopoverMenuHandle<LanguageModelSelector>,
         focus_handle: FocusHandle,
-        _window: &mut Window,
-        _cx: &mut App,
+        window: &mut Window,
+        cx: &mut App,
     ) -> Self {
         Self {
-            fs,
+            selector: cx.new(|cx| {
+                let fs = fs.clone();
+                LanguageModelSelector::new(
+                    move |model, cx| {
+                        update_settings_file::<AssistantSettings>(
+                            fs.clone(),
+                            cx,
+                            move |settings, _cx| settings.set_model(model.clone()),
+                        );
+                    },
+                    window,
+                    cx,
+                )
+            }),
+            menu_handle,
             focus_handle,
-            menu_handle: PopoverMenuHandle::default(),
         }
     }
 
@@ -32,21 +49,43 @@ impl AssistantModelSelector {
 }
 
 impl Render for AssistantModelSelector {
-    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
-        assistant_language_model_selector(
-            self.focus_handle.clone(),
-            Some(self.menu_handle.clone()),
-            cx,
-            {
-                let fs = self.fs.clone();
-                move |model, cx| {
-                    update_settings_file::<AssistantSettings>(
-                        fs.clone(),
-                        cx,
-                        move |settings, _| settings.set_model(model.clone()),
-                    );
-                }
+    fn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
+        let active_model = LanguageModelRegistry::read_global(cx).active_model();
+        let focus_handle = self.focus_handle.clone();
+        let model_name = match active_model {
+            Some(model) => model.name().0,
+            _ => SharedString::from("No model selected"),
+        };
+
+        LanguageModelSelectorPopoverMenu::new(
+            self.selector.clone(),
+            ButtonLike::new("active-model")
+                .style(ButtonStyle::Subtle)
+                .child(
+                    h_flex()
+                        .gap_0p5()
+                        .child(
+                            Label::new(model_name)
+                                .size(LabelSize::Small)
+                                .color(Color::Muted),
+                        )
+                        .child(
+                            Icon::new(IconName::ChevronDown)
+                                .color(Color::Muted)
+                                .size(IconSize::XSmall),
+                        ),
+                ),
+            move |window, cx| {
+                Tooltip::for_action_in(
+                    "Change Model",
+                    &ToggleModelSelector,
+                    &focus_handle,
+                    window,
+                    cx,
+                )
             },
+            gpui::Corner::BottomRight,
         )
+        .with_handle(self.menu_handle.clone())
     }
 }

crates/assistant2/src/inline_prompt_editor.rs 🔗

@@ -857,6 +857,7 @@ impl PromptEditor<BufferCodegen> {
             editor
         });
         let context_picker_menu_handle = PopoverMenuHandle::default();
+        let model_selector_menu_handle = PopoverMenuHandle::default();
 
         let context_strip = cx.new(|cx| {
             ContextStrip::new(
@@ -880,7 +881,13 @@ impl PromptEditor<BufferCodegen> {
             context_strip,
             context_picker_menu_handle,
             model_selector: cx.new(|cx| {
-                AssistantModelSelector::new(fs, prompt_editor.focus_handle(cx), window, cx)
+                AssistantModelSelector::new(
+                    fs,
+                    model_selector_menu_handle,
+                    prompt_editor.focus_handle(cx),
+                    window,
+                    cx,
+                )
             }),
             edited_since_done: false,
             prompt_history,
@@ -1005,6 +1012,7 @@ impl PromptEditor<TerminalCodegen> {
             editor
         });
         let context_picker_menu_handle = PopoverMenuHandle::default();
+        let model_selector_menu_handle = PopoverMenuHandle::default();
 
         let context_strip = cx.new(|cx| {
             ContextStrip::new(
@@ -1028,7 +1036,13 @@ impl PromptEditor<TerminalCodegen> {
             context_strip,
             context_picker_menu_handle,
             model_selector: cx.new(|cx| {
-                AssistantModelSelector::new(fs, prompt_editor.focus_handle(cx), window, cx)
+                AssistantModelSelector::new(
+                    fs,
+                    model_selector_menu_handle.clone(),
+                    prompt_editor.focus_handle(cx),
+                    window,
+                    cx,
+                )
             }),
             edited_since_done: false,
             prompt_history,

crates/assistant2/src/message_editor.rs 🔗

@@ -54,6 +54,7 @@ impl MessageEditor {
         let context_store = cx.new(|_cx| ContextStore::new(workspace.clone()));
         let context_picker_menu_handle = PopoverMenuHandle::default();
         let inline_context_picker_menu_handle = PopoverMenuHandle::default();
+        let model_selector_menu_handle = PopoverMenuHandle::default();
 
         let editor = cx.new(|cx| {
             let mut editor = Editor::auto_height(10, window, cx);
@@ -106,8 +107,15 @@ impl MessageEditor {
             context_picker_menu_handle,
             inline_context_picker,
             inline_context_picker_menu_handle,
-            model_selector: cx
-                .new(|cx| AssistantModelSelector::new(fs, editor.focus_handle(cx), window, cx)),
+            model_selector: cx.new(|cx| {
+                AssistantModelSelector::new(
+                    fs,
+                    model_selector_menu_handle,
+                    editor.focus_handle(cx),
+                    window,
+                    cx,
+                )
+            }),
             use_tools: false,
             _subscriptions: subscriptions,
         }

crates/assistant_context_editor/src/context_editor.rs 🔗

@@ -38,7 +38,7 @@ use language_model::{
     Role,
 };
 use language_model_selector::{
-    assistant_language_model_selector, LanguageModelSelector, ToggleModelSelector,
+    LanguageModelSelector, LanguageModelSelectorPopoverMenu, ToggleModelSelector,
 };
 use multi_buffer::MultiBufferRow;
 use picker::Picker;
@@ -197,7 +197,8 @@ pub struct ContextEditor {
     // the file is opened. In order to keep the worktree alive for the duration of the
     // context editor, we keep a reference here.
     dragged_file_worktrees: Vec<Entity<Worktree>>,
-    language_model_selector: PopoverMenuHandle<LanguageModelSelector>,
+    language_model_selector: Entity<LanguageModelSelector>,
+    language_model_selector_menu_handle: PopoverMenuHandle<LanguageModelSelector>,
 }
 
 pub const DEFAULT_TAB_TITLE: &str = "New Chat";
@@ -263,7 +264,7 @@ impl ContextEditor {
             image_blocks: Default::default(),
             scroll_position: None,
             remote_id: None,
-            fs,
+            fs: fs.clone(),
             workspace,
             project,
             pending_slash_command_creases: HashMap::default(),
@@ -275,7 +276,20 @@ impl ContextEditor {
             show_accept_terms: false,
             slash_menu_handle: Default::default(),
             dragged_file_worktrees: Vec::new(),
-            language_model_selector: PopoverMenuHandle::default(),
+            language_model_selector: cx.new(|cx| {
+                LanguageModelSelector::new(
+                    move |model, cx| {
+                        update_settings_file::<AssistantSettings>(
+                            fs.clone(),
+                            cx,
+                            move |settings, _| settings.set_model(model.clone()),
+                        );
+                    },
+                    window,
+                    cx,
+                )
+            }),
+            language_model_selector_menu_handle: PopoverMenuHandle::default(),
         };
         this.update_message_headers(cx);
         this.update_image_blocks(cx);
@@ -2375,6 +2389,46 @@ impl ContextEditor {
         )
     }
 
+    fn render_language_model_selector(&self, cx: &mut Context<Self>) -> impl IntoElement {
+        let active_model = LanguageModelRegistry::read_global(cx).active_model();
+        let focus_handle = self.editor().focus_handle(cx).clone();
+        let model_name = match active_model {
+            Some(model) => model.name().0,
+            None => SharedString::from("No model selected"),
+        };
+
+        LanguageModelSelectorPopoverMenu::new(
+            self.language_model_selector.clone(),
+            ButtonLike::new("active-model")
+                .style(ButtonStyle::Subtle)
+                .child(
+                    h_flex()
+                        .gap_0p5()
+                        .child(
+                            Label::new(model_name)
+                                .size(LabelSize::Small)
+                                .color(Color::Muted),
+                        )
+                        .child(
+                            Icon::new(IconName::ChevronDown)
+                                .color(Color::Muted)
+                                .size(IconSize::XSmall),
+                        ),
+                ),
+            move |window, cx| {
+                Tooltip::for_action_in(
+                    "Change Model",
+                    &ToggleModelSelector,
+                    &focus_handle,
+                    window,
+                    cx,
+                )
+            },
+            gpui::Corner::BottomLeft,
+        )
+        .with_handle(self.language_model_selector_menu_handle.clone())
+    }
+
     fn render_last_error(&self, cx: &mut Context<Self>) -> Option<AnyElement> {
         let last_error = self.last_error.as_ref()?;
 
@@ -2819,7 +2873,7 @@ impl Render for ContextEditor {
             None
         };
 
-        let language_model_selector = self.language_model_selector.clone();
+        let language_model_selector = self.language_model_selector_menu_handle.clone();
         v_flex()
             .key_context("ContextEditor")
             .capture_action(cx.listener(ContextEditor::cancel))
@@ -2872,23 +2926,11 @@ impl Render for ContextEditor {
                                 .gap_1()
                                 .child(self.render_inject_context_menu(cx))
                                 .child(ui::Divider::vertical())
-                                .child(div().pl_0p5().child(assistant_language_model_selector(
-                                    self.editor().focus_handle(cx),
-                                    Some(self.language_model_selector.clone()),
-                                    cx,
-                                    {
-                                        let fs = self.fs.clone();
-                                        move |model, cx| {
-                                            update_settings_file::<AssistantSettings>(
-                                                fs.clone(),
-                                                cx,
-                                                move |settings, _| {
-                                                    settings.set_model(model.clone())
-                                                },
-                                            );
-                                        }
-                                    },
-                                ))),
+                                .child(
+                                    div()
+                                        .pl_0p5()
+                                        .child(self.render_language_model_selector(cx)),
+                                ),
                         )
                         .child(
                             h_flex()

crates/language_model_selector/src/language_model_selector.rs 🔗

@@ -1,8 +1,8 @@
-use std::{rc::Rc, sync::Arc};
+use std::sync::Arc;
 
 use feature_flags::ZedPro;
 use gpui::{
-    action_with_deprecated_aliases, Action, AnyElement, App, Corner, DismissEvent, Entity,
+    action_with_deprecated_aliases, Action, AnyElement, AnyView, App, Corner, DismissEvent, Entity,
     EventEmitter, FocusHandle, Focusable, Subscription, Task, WeakEntity,
 };
 use language_model::{
@@ -10,10 +10,7 @@ use language_model::{
 };
 use picker::{Picker, PickerDelegate};
 use proto::Plan;
-use ui::{
-    prelude::*, ButtonLike, IconButtonShape, ListItem, ListItemSpacing, PopoverMenu,
-    PopoverMenuHandle, Tooltip,
-};
+use ui::{prelude::*, ListItem, ListItemSpacing, PopoverMenu, PopoverMenuHandle, PopoverTrigger};
 use workspace::ShowConfiguration;
 
 action_with_deprecated_aliases!(
@@ -31,7 +28,6 @@ pub struct LanguageModelSelector {
     /// The task used to update the picker's matches when there is a change to
     /// the language model registry.
     update_matches_task: Option<Task<()>>,
-    popover_menu_handle: PopoverMenuHandle<LanguageModelSelector>,
     _authenticate_all_providers_task: Task<()>,
     _subscriptions: Vec<Subscription>,
 }
@@ -63,7 +59,6 @@ impl LanguageModelSelector {
         LanguageModelSelector {
             picker,
             update_matches_task: None,
-            popover_menu_handle: PopoverMenuHandle::default(),
             _authenticate_all_providers_task: Self::authenticate_all_providers(cx),
             _subscriptions: vec![cx.subscribe_in(
                 &LanguageModelRegistry::global(cx),
@@ -73,15 +68,6 @@ impl LanguageModelSelector {
         }
     }
 
-    pub fn toggle_model_selector(
-        &mut self,
-        _: &ToggleModelSelector,
-        window: &mut Window,
-        cx: &mut Context<Self>,
-    ) {
-        self.popover_menu_handle.toggle(window, cx);
-    }
-
     fn handle_language_model_registry_event(
         &mut self,
         _registry: &Entity<LanguageModelRegistry>,
@@ -201,6 +187,65 @@ impl Render for LanguageModelSelector {
     }
 }
 
+#[derive(IntoElement)]
+pub struct LanguageModelSelectorPopoverMenu<T, TT>
+where
+    T: PopoverTrigger + ButtonCommon,
+    TT: Fn(&mut Window, &mut App) -> AnyView + 'static,
+{
+    language_model_selector: Entity<LanguageModelSelector>,
+    trigger: T,
+    tooltip: TT,
+    handle: Option<PopoverMenuHandle<LanguageModelSelector>>,
+    anchor: Corner,
+}
+
+impl<T, TT> LanguageModelSelectorPopoverMenu<T, TT>
+where
+    T: PopoverTrigger + ButtonCommon,
+    TT: Fn(&mut Window, &mut App) -> AnyView + 'static,
+{
+    pub fn new(
+        language_model_selector: Entity<LanguageModelSelector>,
+        trigger: T,
+        tooltip: TT,
+        anchor: Corner,
+    ) -> Self {
+        Self {
+            language_model_selector,
+            trigger,
+            tooltip,
+            handle: None,
+            anchor,
+        }
+    }
+
+    pub fn with_handle(mut self, handle: PopoverMenuHandle<LanguageModelSelector>) -> Self {
+        self.handle = Some(handle);
+        self
+    }
+}
+
+impl<T, TT> RenderOnce for LanguageModelSelectorPopoverMenu<T, TT>
+where
+    T: PopoverTrigger + ButtonCommon,
+    TT: Fn(&mut Window, &mut App) -> AnyView + 'static,
+{
+    fn render(self, _window: &mut Window, _cx: &mut App) -> impl IntoElement {
+        let language_model_selector = self.language_model_selector.clone();
+
+        PopoverMenu::new("model-switcher")
+            .menu(move |_window, _cx| Some(language_model_selector.clone()))
+            .trigger_with_tooltip(self.trigger, self.tooltip)
+            .anchor(self.anchor)
+            .when_some(self.handle.clone(), |menu, handle| menu.with_handle(handle))
+            .offset(gpui::Point {
+                x: px(0.0),
+                y: px(-2.0),
+            })
+    }
+}
+
 #[derive(Clone)]
 struct ModelInfo {
     model: Arc<dyn LanguageModel>,
@@ -482,114 +527,3 @@ impl PickerDelegate for LanguageModelPickerDelegate {
         )
     }
 }
-
-pub fn inline_language_model_selector(
-    on_model_changed: impl Fn(Arc<dyn LanguageModel>, &App) + 'static,
-) -> PopoverMenu<LanguageModelSelector> {
-    let on_model_changed = Rc::new(on_model_changed);
-    PopoverMenu::new("popover-button")
-        .menu(move |window, cx| {
-            Some(cx.new(|cx| {
-                LanguageModelSelector::new(
-                    {
-                        let on_model_changed = on_model_changed.clone();
-                        move |model, cx| {
-                            on_model_changed(model, cx);
-                        }
-                    },
-                    window,
-                    cx,
-                )
-            }))
-        })
-        .trigger_with_tooltip(
-            IconButton::new("context", IconName::SettingsAlt)
-                .shape(IconButtonShape::Square)
-                .icon_size(IconSize::Small)
-                .icon_color(Color::Muted),
-            move |window, cx| {
-                Tooltip::with_meta(
-                    format!(
-                        "Using {}",
-                        LanguageModelRegistry::read_global(cx)
-                            .active_model()
-                            .map(|model| model.name().0)
-                            .unwrap_or_else(|| "No model selected".into()),
-                    ),
-                    None,
-                    "Change Model",
-                    window,
-                    cx,
-                )
-            },
-        )
-        .anchor(gpui::Corner::TopRight)
-        .offset(gpui::Point {
-            x: px(0.0),
-            y: px(-2.0),
-        })
-}
-
-pub fn assistant_language_model_selector(
-    keybinding_target: FocusHandle,
-    menu_handle: Option<PopoverMenuHandle<LanguageModelSelector>>,
-    cx: &App,
-    on_model_changed: impl Fn(Arc<dyn LanguageModel>, &App) + 'static,
-) -> PopoverMenu<LanguageModelSelector> {
-    let active_model = LanguageModelRegistry::read_global(cx).active_model();
-    let model_name = match active_model {
-        Some(model) => model.name().0,
-        _ => SharedString::from("No model selected"),
-    };
-
-    let on_model_changed = Rc::new(on_model_changed);
-
-    PopoverMenu::new("popover-button")
-        .menu(move |window, cx| {
-            Some(cx.new(|cx| {
-                LanguageModelSelector::new(
-                    {
-                        let on_model_changed = on_model_changed.clone();
-                        move |model, cx| {
-                            on_model_changed(model, cx);
-                        }
-                    },
-                    window,
-                    cx,
-                )
-            }))
-        })
-        .trigger_with_tooltip(
-            ButtonLike::new("active-model")
-                .style(ButtonStyle::Subtle)
-                .child(
-                    h_flex()
-                        .gap_0p5()
-                        .child(
-                            Label::new(model_name)
-                                .size(LabelSize::Small)
-                                .color(Color::Muted),
-                        )
-                        .child(
-                            Icon::new(IconName::ChevronDown)
-                                .color(Color::Muted)
-                                .size(IconSize::XSmall),
-                        ),
-                ),
-            move |window, cx| {
-                Tooltip::for_action_in(
-                    "Change Model",
-                    &ToggleModelSelector,
-                    &keybinding_target,
-                    window,
-                    cx,
-                )
-            },
-        )
-        .anchor(Corner::BottomRight)
-        .when_some(menu_handle, |el, handle| el.with_handle(handle))
-        .offset(gpui::Point {
-            x: px(0.0),
-            y: px(-2.0),
-        })
-}