agent_model_selector.rs

  1use agent_settings::AgentSettings;
  2use fs::Fs;
  3use gpui::{Entity, FocusHandle, SharedString};
  4use picker::popover_menu::PickerPopoverMenu;
  5
  6use crate::ModelUsageContext;
  7use assistant_context_editor::language_model_selector::{
  8    LanguageModelSelector, ToggleModelSelector, language_model_selector,
  9};
 10use language_model::{ConfiguredModel, LanguageModelRegistry};
 11use settings::update_settings_file;
 12use std::sync::Arc;
 13use ui::{PopoverMenuHandle, Tooltip, prelude::*};
 14
 15pub struct AgentModelSelector {
 16    selector: Entity<LanguageModelSelector>,
 17    menu_handle: PopoverMenuHandle<LanguageModelSelector>,
 18    focus_handle: FocusHandle,
 19}
 20
 21impl AgentModelSelector {
 22    pub(crate) fn new(
 23        fs: Arc<dyn Fs>,
 24        menu_handle: PopoverMenuHandle<LanguageModelSelector>,
 25        focus_handle: FocusHandle,
 26        model_usage_context: ModelUsageContext,
 27        window: &mut Window,
 28        cx: &mut Context<Self>,
 29    ) -> Self {
 30        Self {
 31            selector: cx.new(move |cx| {
 32                let fs = fs.clone();
 33                language_model_selector(
 34                    {
 35                        let model_context = model_usage_context.clone();
 36                        move |cx| model_context.configured_model(cx)
 37                    },
 38                    move |model, cx| {
 39                        let provider = model.provider_id().0.to_string();
 40                        let model_id = model.id().0.to_string();
 41                        match &model_usage_context {
 42                            ModelUsageContext::Thread(thread) => {
 43                                thread.update(cx, |thread, cx| {
 44                                    let registry = LanguageModelRegistry::read_global(cx);
 45                                    if let Some(provider) = registry.provider(&model.provider_id())
 46                                    {
 47                                        thread.set_configured_model(
 48                                            Some(ConfiguredModel {
 49                                                provider,
 50                                                model: model.clone(),
 51                                            }),
 52                                            cx,
 53                                        );
 54                                    }
 55                                });
 56                                update_settings_file::<AgentSettings>(
 57                                    fs.clone(),
 58                                    cx,
 59                                    move |settings, _cx| {
 60                                        settings.set_model(model.clone());
 61                                    },
 62                                );
 63                            }
 64                            ModelUsageContext::InlineAssistant => {
 65                                update_settings_file::<AgentSettings>(
 66                                    fs.clone(),
 67                                    cx,
 68                                    move |settings, _cx| {
 69                                        settings.set_inline_assistant_model(
 70                                            provider.clone(),
 71                                            model_id.clone(),
 72                                        );
 73                                    },
 74                                );
 75                            }
 76                        }
 77                    },
 78                    window,
 79                    cx,
 80                )
 81            }),
 82            menu_handle,
 83            focus_handle,
 84        }
 85    }
 86
 87    pub fn toggle(&self, window: &mut Window, cx: &mut Context<Self>) {
 88        self.menu_handle.toggle(window, cx);
 89    }
 90}
 91
 92impl Render for AgentModelSelector {
 93    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
 94        let model = self.selector.read(cx).delegate.active_model(cx);
 95        let model_name = model
 96            .map(|model| model.model.name().0)
 97            .unwrap_or_else(|| SharedString::from("No model selected"));
 98
 99        let focus_handle = self.focus_handle.clone();
100
101        PickerPopoverMenu::new(
102            self.selector.clone(),
103            Button::new("active-model", model_name)
104                .label_size(LabelSize::Small)
105                .color(Color::Muted)
106                .icon(IconName::ChevronDown)
107                .icon_size(IconSize::XSmall)
108                .icon_position(IconPosition::End)
109                .icon_color(Color::Muted),
110            move |window, cx| {
111                Tooltip::for_action_in(
112                    "Change Model",
113                    &ToggleModelSelector,
114                    &focus_handle,
115                    window,
116                    cx,
117                )
118            },
119            gpui::Corner::BottomRight,
120            cx,
121        )
122        .with_handle(self.menu_handle.clone())
123        .render(window, cx)
124    }
125}