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}