diff --git a/Cargo.lock b/Cargo.lock index cb2e662311..2a5c4d94bb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -458,6 +458,8 @@ dependencies = [ "command_palette_hooks", "feature_flags", "gpui", + "language_model", + "language_model_selector", "proto", "ui", "workspace", diff --git a/crates/assistant2/Cargo.toml b/crates/assistant2/Cargo.toml index 320cd015e2..8e3405c340 100644 --- a/crates/assistant2/Cargo.toml +++ b/crates/assistant2/Cargo.toml @@ -17,6 +17,8 @@ anyhow.workspace = true command_palette_hooks.workspace = true feature_flags.workspace = true gpui.workspace = true +language_model.workspace = true +language_model_selector.workspace = true proto.workspace = true ui.workspace = true workspace.workspace = true diff --git a/crates/assistant2/src/assistant.rs b/crates/assistant2/src/assistant.rs index 31676198ba..da1038f2ca 100644 --- a/crates/assistant2/src/assistant.rs +++ b/crates/assistant2/src/assistant.rs @@ -6,7 +6,7 @@ use gpui::{actions, AppContext}; pub use crate::assistant_panel::AssistantPanel; -actions!(assistant2, [ToggleFocus, NewChat]); +actions!(assistant2, [ToggleFocus, NewChat, ToggleModelSelector]); const NAMESPACE: &str = "assistant2"; diff --git a/crates/assistant2/src/assistant_panel.rs b/crates/assistant2/src/assistant_panel.rs index 7c586dd35e..51bfb8c4ff 100644 --- a/crates/assistant2/src/assistant_panel.rs +++ b/crates/assistant2/src/assistant_panel.rs @@ -3,11 +3,13 @@ use gpui::{ prelude::*, px, Action, AppContext, AsyncWindowContext, EventEmitter, FocusHandle, FocusableView, Pixels, Task, View, ViewContext, WeakView, WindowContext, }; -use ui::prelude::*; +use language_model::LanguageModelRegistry; +use language_model_selector::LanguageModelSelector; +use ui::{prelude::*, ButtonLike, Divider, IconButtonShape, Tab, Tooltip}; use workspace::dock::{DockPosition, Panel, PanelEvent}; use workspace::{Pane, Workspace}; -use crate::{NewChat, ToggleFocus}; +use crate::{NewChat, ToggleFocus, ToggleModelSelector}; pub fn init(cx: &mut AppContext) { cx.observe_new_views( @@ -116,8 +118,123 @@ impl Panel for AssistantPanel { } } -impl Render for AssistantPanel { - fn render(&mut self, _cx: &mut ViewContext) -> impl IntoElement { - div().child(Label::new("Assistant II")) +impl AssistantPanel { + fn render_toolbar(&self, cx: &mut ViewContext) -> impl IntoElement { + let focus_handle = self.focus_handle(cx); + + h_flex() + .id("assistant-toolbar") + .justify_between() + .gap(DynamicSpacing::Base08.rems(cx)) + .h(Tab::container_height(cx)) + .px(DynamicSpacing::Base08.rems(cx)) + .bg(cx.theme().colors().tab_bar_background) + .border_b_1() + .border_color(cx.theme().colors().border_variant) + .child(h_flex().child(Label::new("Chat Title Goes Here"))) + .child( + h_flex() + .gap(DynamicSpacing::Base08.rems(cx)) + .child(self.render_language_model_selector(cx)) + .child(Divider::vertical()) + .child( + IconButton::new("new-chat", IconName::Plus) + .shape(IconButtonShape::Square) + .icon_size(IconSize::Small) + .style(ButtonStyle::Subtle) + .tooltip({ + let focus_handle = focus_handle.clone(); + move |cx| { + Tooltip::for_action_in("New Chat", &NewChat, &focus_handle, cx) + } + }) + .on_click(move |_event, _cx| { + println!("New Chat"); + }), + ) + .child( + IconButton::new("open-history", IconName::HistoryRerun) + .shape(IconButtonShape::Square) + .icon_size(IconSize::Small) + .style(ButtonStyle::Subtle) + .tooltip(move |cx| Tooltip::text("Open History", cx)) + .on_click(move |_event, _cx| { + println!("Open History"); + }), + ) + .child( + IconButton::new("configure-assistant", IconName::Settings) + .shape(IconButtonShape::Square) + .icon_size(IconSize::Small) + .style(ButtonStyle::Subtle) + .tooltip(move |cx| Tooltip::text("Configure Assistant", cx)) + .on_click(move |_event, _cx| { + println!("Configure Assistant"); + }), + ), + ) + } + + fn render_language_model_selector(&self, cx: &mut ViewContext) -> impl IntoElement { + let active_provider = LanguageModelRegistry::read_global(cx).active_provider(); + let active_model = LanguageModelRegistry::read_global(cx).active_model(); + + LanguageModelSelector::new( + |model, _cx| { + println!("Selected {:?}", model.name()); + }, + ButtonLike::new("active-model") + .style(ButtonStyle::Subtle) + .child( + h_flex() + .w_full() + .gap_0p5() + .child( + div() + .overflow_x_hidden() + .flex_grow() + .whitespace_nowrap() + .child(match (active_provider, active_model) { + (Some(provider), Some(model)) => h_flex() + .gap_1() + .child( + Icon::new( + model.icon().unwrap_or_else(|| provider.icon()), + ) + .color(Color::Muted) + .size(IconSize::XSmall), + ) + .child( + Label::new(model.name().0) + .size(LabelSize::Small) + .color(Color::Muted), + ) + .into_any_element(), + _ => Label::new("No model selected") + .size(LabelSize::Small) + .color(Color::Muted) + .into_any_element(), + }), + ) + .child( + Icon::new(IconName::ChevronDown) + .color(Color::Muted) + .size(IconSize::XSmall), + ), + ) + .tooltip(move |cx| Tooltip::for_action("Change Model", &ToggleModelSelector, cx)), + ) + } +} + +impl Render for AssistantPanel { + fn render(&mut self, cx: &mut ViewContext) -> impl IntoElement { + v_flex() + .key_context("AssistantPanel2") + .size_full() + .on_action(cx.listener(|_this, _: &NewChat, _cx| { + println!("Action: New Chat"); + })) + .child(self.render_toolbar(cx)) } }