assistant_model_selector.rs

 1use assistant_settings::AssistantSettings;
 2use fs::Fs;
 3use gpui::{Entity, FocusHandle, SharedString};
 4use language_model::LanguageModelRegistry;
 5use language_model_selector::{
 6    LanguageModelSelector, LanguageModelSelectorPopoverMenu, ToggleModelSelector,
 7};
 8use settings::update_settings_file;
 9use std::sync::Arc;
10use ui::{prelude::*, ButtonLike, PopoverMenuHandle, Tooltip};
11
12pub struct AssistantModelSelector {
13    selector: Entity<LanguageModelSelector>,
14    menu_handle: PopoverMenuHandle<LanguageModelSelector>,
15    focus_handle: FocusHandle,
16}
17
18impl AssistantModelSelector {
19    pub(crate) fn new(
20        fs: Arc<dyn Fs>,
21        menu_handle: PopoverMenuHandle<LanguageModelSelector>,
22        focus_handle: FocusHandle,
23        window: &mut Window,
24        cx: &mut App,
25    ) -> Self {
26        Self {
27            selector: cx.new(|cx| {
28                let fs = fs.clone();
29                LanguageModelSelector::new(
30                    move |model, cx| {
31                        update_settings_file::<AssistantSettings>(
32                            fs.clone(),
33                            cx,
34                            move |settings, _cx| settings.set_model(model.clone()),
35                        );
36                    },
37                    window,
38                    cx,
39                )
40            }),
41            menu_handle,
42            focus_handle,
43        }
44    }
45
46    pub fn toggle(&self, window: &mut Window, cx: &mut Context<Self>) {
47        self.menu_handle.toggle(window, cx);
48    }
49}
50
51impl Render for AssistantModelSelector {
52    fn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
53        let active_model = LanguageModelRegistry::read_global(cx).active_model();
54        let focus_handle = self.focus_handle.clone();
55        let model_name = match active_model {
56            Some(model) => model.name().0,
57            _ => SharedString::from("No model selected"),
58        };
59
60        LanguageModelSelectorPopoverMenu::new(
61            self.selector.clone(),
62            ButtonLike::new("active-model")
63                .style(ButtonStyle::Subtle)
64                .child(
65                    h_flex()
66                        .gap_0p5()
67                        .child(
68                            Label::new(model_name)
69                                .size(LabelSize::Small)
70                                .color(Color::Muted),
71                        )
72                        .child(
73                            Icon::new(IconName::ChevronDown)
74                                .color(Color::Muted)
75                                .size(IconSize::XSmall),
76                        ),
77                ),
78            move |window, cx| {
79                Tooltip::for_action_in(
80                    "Change Model",
81                    &ToggleModelSelector,
82                    &focus_handle,
83                    window,
84                    cx,
85                )
86            },
87            gpui::Corner::BottomRight,
88        )
89        .with_handle(self.menu_handle.clone())
90    }
91}