1use std::rc::Rc;
2use std::sync::Arc;
3
4use acp_thread::{AgentModelInfo, AgentModelSelector};
5use agent_servers::AgentServer;
6use fs::Fs;
7use gpui::{Entity, FocusHandle};
8use picker::popover_menu::PickerPopoverMenu;
9use ui::{
10 ButtonLike, Context, IntoElement, PopoverMenuHandle, SharedString, TintColor, Tooltip, Window,
11 prelude::*,
12};
13use zed_actions::agent::ToggleModelSelector;
14
15use crate::acp::{AcpModelSelector, model_selector::acp_model_selector};
16
17pub struct AcpModelSelectorPopover {
18 selector: Entity<AcpModelSelector>,
19 menu_handle: PopoverMenuHandle<AcpModelSelector>,
20 focus_handle: FocusHandle,
21}
22
23impl AcpModelSelectorPopover {
24 pub(crate) fn new(
25 selector: Rc<dyn AgentModelSelector>,
26 agent_server: Rc<dyn AgentServer>,
27 fs: Arc<dyn Fs>,
28 menu_handle: PopoverMenuHandle<AcpModelSelector>,
29 focus_handle: FocusHandle,
30 window: &mut Window,
31 cx: &mut Context<Self>,
32 ) -> Self {
33 Self {
34 selector: cx.new(move |cx| acp_model_selector(selector, agent_server, fs, window, cx)),
35 menu_handle,
36 focus_handle,
37 }
38 }
39
40 pub fn toggle(&self, window: &mut Window, cx: &mut Context<Self>) {
41 self.menu_handle.toggle(window, cx);
42 }
43
44 pub fn active_model<'a>(&self, cx: &'a App) -> Option<&'a AgentModelInfo> {
45 self.selector.read(cx).delegate.active_model()
46 }
47}
48
49impl Render for AcpModelSelectorPopover {
50 fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
51 let model = self.selector.read(cx).delegate.active_model();
52 let model_name = model
53 .as_ref()
54 .map(|model| model.name.clone())
55 .unwrap_or_else(|| SharedString::from("Select a Model"));
56
57 let model_icon = model.as_ref().and_then(|model| model.icon);
58
59 let focus_handle = self.focus_handle.clone();
60
61 let (color, icon) = if self.menu_handle.is_deployed() {
62 (Color::Accent, IconName::ChevronUp)
63 } else {
64 (Color::Muted, IconName::ChevronDown)
65 };
66
67 PickerPopoverMenu::new(
68 self.selector.clone(),
69 ButtonLike::new("active-model")
70 .selected_style(ButtonStyle::Tinted(TintColor::Accent))
71 .when_some(model_icon, |this, icon| {
72 this.child(Icon::new(icon).color(color).size(IconSize::XSmall))
73 })
74 .child(
75 Label::new(model_name)
76 .color(color)
77 .size(LabelSize::Small)
78 .ml_0p5(),
79 )
80 .child(Icon::new(icon).color(Color::Muted).size(IconSize::XSmall)),
81 move |_window, cx| {
82 Tooltip::for_action_in("Change Model", &ToggleModelSelector, &focus_handle, cx)
83 },
84 gpui::Corner::BottomRight,
85 cx,
86 )
87 .with_handle(self.menu_handle.clone())
88 .render(window, cx)
89 }
90}