1use crate::{
2 ModelUsageContext,
3 language_model_selector::{LanguageModelSelector, language_model_selector},
4};
5use fs::Fs;
6use gpui::{Entity, FocusHandle, SharedString};
7use picker::popover_menu::PickerPopoverMenu;
8use settings::update_settings_file;
9use std::sync::Arc;
10use ui::{ButtonLike, PopoverMenuHandle, Tooltip, prelude::*};
11use zed_actions::agent::ToggleModelSelector;
12
13pub struct AgentModelSelector {
14 selector: Entity<LanguageModelSelector>,
15 menu_handle: PopoverMenuHandle<LanguageModelSelector>,
16 focus_handle: FocusHandle,
17}
18
19impl AgentModelSelector {
20 pub(crate) fn new(
21 fs: Arc<dyn Fs>,
22 menu_handle: PopoverMenuHandle<LanguageModelSelector>,
23 focus_handle: FocusHandle,
24 model_usage_context: ModelUsageContext,
25 window: &mut Window,
26 cx: &mut Context<Self>,
27 ) -> Self {
28 Self {
29 selector: cx.new(move |cx| {
30 let fs = fs.clone();
31 language_model_selector(
32 {
33 let model_context = model_usage_context.clone();
34 move |cx| model_context.configured_model(cx)
35 },
36 move |model, cx| {
37 let provider = model.provider_id().0.to_string();
38 let model_id = model.id().0.to_string();
39 match &model_usage_context {
40 ModelUsageContext::InlineAssistant => {
41 update_settings_file(fs.clone(), cx, move |settings, _cx| {
42 settings
43 .agent
44 .get_or_insert_default()
45 .set_inline_assistant_model(provider.clone(), model_id);
46 });
47 }
48 }
49 },
50 window,
51 cx,
52 )
53 }),
54 menu_handle,
55 focus_handle,
56 }
57 }
58
59 pub fn toggle(&self, window: &mut Window, cx: &mut Context<Self>) {
60 self.menu_handle.toggle(window, cx);
61 }
62}
63
64impl Render for AgentModelSelector {
65 fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
66 let model = self.selector.read(cx).delegate.active_model(cx);
67 let model_name = model
68 .as_ref()
69 .map(|model| model.model.name().0)
70 .unwrap_or_else(|| SharedString::from("Select a Model"));
71
72 let provider_icon = model.as_ref().map(|model| model.provider.icon());
73
74 let focus_handle = self.focus_handle.clone();
75
76 PickerPopoverMenu::new(
77 self.selector.clone(),
78 ButtonLike::new("active-model")
79 .when_some(provider_icon, |this, icon| {
80 this.child(Icon::new(icon).color(Color::Muted).size(IconSize::XSmall))
81 })
82 .child(
83 Label::new(model_name)
84 .color(Color::Muted)
85 .size(LabelSize::Small)
86 .ml_0p5(),
87 )
88 .child(
89 Icon::new(IconName::ChevronDown)
90 .color(Color::Muted)
91 .size(IconSize::XSmall),
92 ),
93 move |window, cx| {
94 Tooltip::for_action_in(
95 "Change Model",
96 &ToggleModelSelector,
97 &focus_handle,
98 window,
99 cx,
100 )
101 },
102 gpui::Corner::BottomRight,
103 cx,
104 )
105 .with_handle(self.menu_handle.clone())
106 .render(window, cx)
107 }
108}