diff --git a/crates/assistant/src/assistant_panel.rs b/crates/assistant/src/assistant_panel.rs index 064279bb4b9892cfe55caf76b1bc950cb67b86af..06acbe626c4cc91472d21a6e3c78470cb1ba79de 100644 --- a/crates/assistant/src/assistant_panel.rs +++ b/crates/assistant/src/assistant_panel.rs @@ -46,7 +46,7 @@ use multi_buffer::MultiBufferRow; use picker::{Picker, PickerDelegate}; use project::{Project, ProjectLspAdapterDelegate}; use search::{buffer_search::DivRegistrar, BufferSearchBar}; -use settings::Settings; +use settings::{update_settings_file, Settings}; use std::{ borrow::Cow, cmp::{self, Ordering}, @@ -139,6 +139,7 @@ pub struct AssistantPanel { model_selector_menu_handle: PopoverMenuHandle, model_summary_editor: View, authenticate_provider_task: Option<(LanguageModelProviderId, Task<()>)>, + configuration_subscription: Option, } #[derive(Clone)] @@ -423,6 +424,7 @@ impl AssistantPanel { model_selector_menu_handle, model_summary_editor, authenticate_provider_task: None, + configuration_subscription: None, }; if LanguageModelRegistry::read_global(cx) @@ -478,6 +480,17 @@ impl AssistantPanel { true } + pane::Event::RemoveItem { idx } => { + if self + .pane + .read(cx) + .item_for_index(*idx) + .map_or(false, |item| item.downcast::().is_some()) + { + self.configuration_subscription = None; + } + false + } pane::Event::RemovedItem { .. } => { cx.emit(AssistantPanelEvent::ContextEdited); true @@ -546,12 +559,7 @@ impl AssistantPanel { log::error!("no context found with ID: {}", context_id.to_proto()); return; }; - let Some(workspace) = self.workspace.upgrade() else { - return; - }; - let lsp_adapter_delegate = workspace.update(cx, |workspace, cx| { - make_lsp_adapter_delegate(workspace.project(), cx).log_err() - }); + let lsp_adapter_delegate = make_lsp_adapter_delegate(&self.project, cx).log_err(); let assistant_panel = cx.view().downgrade(); let editor = cx.new_view(|cx| { @@ -943,6 +951,27 @@ impl AssistantPanel { } view }); + self.configuration_subscription = Some(cx.subscribe( + &configuration, + |this, _, event: &ConfigurationViewEvent, cx| match event { + ConfigurationViewEvent::NewProviderContextEditor(provider) => { + if LanguageModelRegistry::read_global(cx) + .active_provider() + .map_or(true, |p| p.id() != provider.id()) + { + if let Some(model) = provider.provided_models(cx).first().cloned() { + update_settings_file::( + this.fs.clone(), + cx, + move |settings, _| settings.set_model(model), + ); + } + } + + this.new_context(cx); + } + }, + )); self.pane.update(cx, |pane, cx| { pane.add_item(Box::new(configuration), true, true, None, cx); }); @@ -1024,12 +1053,7 @@ impl AssistantPanel { let project = self.project.clone(); let workspace = self.workspace.clone(); - let lsp_adapter_delegate = workspace - .update(cx, |workspace, cx| { - make_lsp_adapter_delegate(workspace.project(), cx).log_err() - }) - .log_err() - .flatten(); + let lsp_adapter_delegate = make_lsp_adapter_delegate(&project, cx).log_err(); cx.spawn(|this, mut cx| async move { let context = context.await?; @@ -1076,13 +1100,7 @@ impl AssistantPanel { .update(cx, |store, cx| store.open_remote_context(id, cx)); let fs = self.fs.clone(); let workspace = self.workspace.clone(); - - let lsp_adapter_delegate = workspace - .update(cx, |workspace, cx| { - make_lsp_adapter_delegate(workspace.project(), cx).log_err() - }) - .log_err() - .flatten(); + let lsp_adapter_delegate = make_lsp_adapter_delegate(&self.project, cx).log_err(); cx.spawn(|this, mut cx| async move { let context = context.await?; @@ -3100,6 +3118,9 @@ impl ConfigurationView { return None; }; + let provider = active_tab.provider.clone(); + let provider_name = provider.name().0.clone(); + let show_spinner = active_tab.is_loading_credentials(); let content = if show_spinner { @@ -3123,13 +3144,41 @@ impl ConfigurationView { }; Some( - div() - .p(Spacing::Large.rems(cx)) - .bg(cx.theme().colors().title_bar_background) - .border_1() - .border_color(cx.theme().colors().border_variant) - .rounded_md() - .child(content), + v_flex() + .gap_4() + .child( + div() + .p(Spacing::Large.rems(cx)) + .bg(cx.theme().colors().title_bar_background) + .border_1() + .border_color(cx.theme().colors().border_variant) + .rounded_md() + .child(content), + ) + .when( + !show_spinner && provider.is_authenticated(cx), + move |this| { + this.child( + h_flex().justify_end().child( + Button::new( + "new-context", + format!("Open new context using {}", provider_name), + ) + .icon_position(IconPosition::Start) + .icon(IconName::Plus) + .style(ButtonStyle::Filled) + .layer(ElevationIndex::ModalSurface) + .on_click(cx.listener( + move |_, _, cx| { + cx.emit(ConfigurationViewEvent::NewProviderContextEditor( + provider.clone(), + )) + }, + )), + ), + ) + }, + ), ) } @@ -3218,7 +3267,11 @@ impl Render for ConfigurationView { } } -impl EventEmitter<()> for ConfigurationView {} +pub enum ConfigurationViewEvent { + NewProviderContextEditor(Arc), +} + +impl EventEmitter for ConfigurationView {} impl FocusableView for ConfigurationView { fn focus_handle(&self, _: &AppContext) -> FocusHandle { @@ -3230,7 +3283,7 @@ impl FocusableView for ConfigurationView { } impl Item for ConfigurationView { - type Event = (); + type Event = ConfigurationViewEvent; fn tab_content_text(&self, _cx: &WindowContext) -> Option { Some("Configuration".into())