assistant2: Add ability to configure tools for profiles in the UI (#27562)
This PR adds the ability to configure tools for a profile in the UI: https://github.com/user-attachments/assets/16642f14-8faa-4a91-bb9e-1d480692f1f2 Note: Doesn't yet work for customizing tools for the default profiles. Release Notes: - N/A
This commit is contained in:
parent
47b94e5ef0
commit
231e9c2000
10 changed files with 427 additions and 106 deletions
|
@ -1,17 +1,33 @@
|
|||
use gpui::{prelude::*, DismissEvent, Entity, EventEmitter, FocusHandle, Focusable, WeakEntity};
|
||||
use ui::prelude::*;
|
||||
use std::sync::Arc;
|
||||
|
||||
use assistant_settings::AssistantSettings;
|
||||
use assistant_tool::ToolWorkingSet;
|
||||
use fs::Fs;
|
||||
use gpui::{prelude::*, DismissEvent, Entity, EventEmitter, FocusHandle, Focusable};
|
||||
use settings::Settings as _;
|
||||
use ui::{prelude::*, ListItem, ListItemSpacing, Navigable, NavigableEntry};
|
||||
use workspace::{ModalView, Workspace};
|
||||
|
||||
use crate::assistant_configuration::profile_picker::{ProfilePicker, ProfilePickerDelegate};
|
||||
use crate::ManageProfiles;
|
||||
use crate::assistant_configuration::tool_picker::{ToolPicker, ToolPickerDelegate};
|
||||
use crate::{AssistantPanel, ManageProfiles};
|
||||
|
||||
enum Mode {
|
||||
ChooseProfile(Entity<ProfilePicker>),
|
||||
ViewProfile(ViewProfileMode),
|
||||
ConfigureTools(Entity<ToolPicker>),
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ViewProfileMode {
|
||||
profile_id: Arc<str>,
|
||||
configure_tools: NavigableEntry,
|
||||
}
|
||||
|
||||
pub struct ManageProfilesModal {
|
||||
#[allow(dead_code)]
|
||||
workspace: WeakEntity<Workspace>,
|
||||
fs: Arc<dyn Fs>,
|
||||
tools: Arc<ToolWorkingSet>,
|
||||
focus_handle: FocusHandle,
|
||||
mode: Mode,
|
||||
}
|
||||
|
||||
|
@ -22,27 +38,79 @@ impl ManageProfilesModal {
|
|||
_cx: &mut Context<Workspace>,
|
||||
) {
|
||||
workspace.register_action(|workspace, _: &ManageProfiles, window, cx| {
|
||||
let workspace_handle = cx.entity().downgrade();
|
||||
workspace.toggle_modal(window, cx, |window, cx| {
|
||||
Self::new(workspace_handle, window, cx)
|
||||
})
|
||||
if let Some(panel) = workspace.panel::<AssistantPanel>(cx) {
|
||||
let fs = workspace.app_state().fs.clone();
|
||||
let thread_store = panel.read(cx).thread_store().read(cx);
|
||||
let tools = thread_store.tools();
|
||||
workspace.toggle_modal(window, cx, |window, cx| Self::new(fs, tools, window, cx))
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
pub fn new(
|
||||
workspace: WeakEntity<Workspace>,
|
||||
fs: Arc<dyn Fs>,
|
||||
tools: Arc<ToolWorkingSet>,
|
||||
window: &mut Window,
|
||||
cx: &mut Context<Self>,
|
||||
) -> Self {
|
||||
let focus_handle = cx.focus_handle();
|
||||
let handle = cx.entity();
|
||||
|
||||
Self {
|
||||
workspace,
|
||||
fs,
|
||||
tools,
|
||||
focus_handle,
|
||||
mode: Mode::ChooseProfile(cx.new(|cx| {
|
||||
let delegate = ProfilePickerDelegate::new(cx);
|
||||
let delegate = ProfilePickerDelegate::new(
|
||||
move |profile_id, window, cx| {
|
||||
handle.update(cx, |this, cx| {
|
||||
this.view_profile(profile_id.clone(), window, cx);
|
||||
})
|
||||
},
|
||||
cx,
|
||||
);
|
||||
ProfilePicker::new(delegate, window, cx)
|
||||
})),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn view_profile(
|
||||
&mut self,
|
||||
profile_id: Arc<str>,
|
||||
window: &mut Window,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
self.mode = Mode::ViewProfile(ViewProfileMode {
|
||||
profile_id,
|
||||
configure_tools: NavigableEntry::focusable(cx),
|
||||
});
|
||||
self.focus_handle(cx).focus(window);
|
||||
}
|
||||
|
||||
fn configure_tools(
|
||||
&mut self,
|
||||
profile_id: Arc<str>,
|
||||
window: &mut Window,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
let settings = AssistantSettings::get_global(cx);
|
||||
let Some(profile) = settings.profiles.get(&profile_id).cloned() else {
|
||||
return;
|
||||
};
|
||||
|
||||
self.mode = Mode::ConfigureTools(cx.new(|cx| {
|
||||
let delegate = ToolPickerDelegate::new(
|
||||
self.fs.clone(),
|
||||
self.tools.clone(),
|
||||
profile_id,
|
||||
profile,
|
||||
cx,
|
||||
);
|
||||
ToolPicker::new(delegate, window, cx)
|
||||
}));
|
||||
self.focus_handle(cx).focus(window);
|
||||
}
|
||||
|
||||
fn confirm(&mut self, _window: &mut Window, _cx: &mut Context<Self>) {}
|
||||
|
||||
fn cancel(&mut self, _window: &mut Window, _cx: &mut Context<Self>) {}
|
||||
|
@ -53,15 +121,65 @@ impl ModalView for ManageProfilesModal {}
|
|||
impl Focusable for ManageProfilesModal {
|
||||
fn focus_handle(&self, cx: &App) -> FocusHandle {
|
||||
match &self.mode {
|
||||
Mode::ChooseProfile(profile_picker) => profile_picker.read(cx).focus_handle(cx),
|
||||
Mode::ChooseProfile(profile_picker) => profile_picker.focus_handle(cx),
|
||||
Mode::ConfigureTools(tool_picker) => tool_picker.focus_handle(cx),
|
||||
Mode::ViewProfile(_) => self.focus_handle.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl EventEmitter<DismissEvent> for ManageProfilesModal {}
|
||||
|
||||
impl ManageProfilesModal {
|
||||
fn render_view_profile(
|
||||
&mut self,
|
||||
mode: ViewProfileMode,
|
||||
window: &mut Window,
|
||||
cx: &mut Context<Self>,
|
||||
) -> impl IntoElement {
|
||||
Navigable::new(
|
||||
div()
|
||||
.track_focus(&self.focus_handle(cx))
|
||||
.size_full()
|
||||
.child(
|
||||
v_flex().child(
|
||||
div()
|
||||
.id("configure-tools")
|
||||
.track_focus(&mode.configure_tools.focus_handle)
|
||||
.on_action({
|
||||
let profile_id = mode.profile_id.clone();
|
||||
cx.listener(move |this, _: &menu::Confirm, window, cx| {
|
||||
this.configure_tools(profile_id.clone(), window, cx);
|
||||
})
|
||||
})
|
||||
.child(
|
||||
ListItem::new("configure-tools")
|
||||
.toggle_state(
|
||||
mode.configure_tools
|
||||
.focus_handle
|
||||
.contains_focused(window, cx),
|
||||
)
|
||||
.inset(true)
|
||||
.spacing(ListItemSpacing::Sparse)
|
||||
.start_slot(Icon::new(IconName::Cog))
|
||||
.child(Label::new("Configure Tools"))
|
||||
.on_click({
|
||||
let profile_id = mode.profile_id.clone();
|
||||
cx.listener(move |this, _, window, cx| {
|
||||
this.configure_tools(profile_id.clone(), window, cx);
|
||||
})
|
||||
}),
|
||||
),
|
||||
),
|
||||
)
|
||||
.into_any_element(),
|
||||
)
|
||||
.entry(mode.configure_tools)
|
||||
}
|
||||
}
|
||||
|
||||
impl Render for ManageProfilesModal {
|
||||
fn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
|
||||
fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
|
||||
div()
|
||||
.elevation_3(cx)
|
||||
.w(rems(34.))
|
||||
|
@ -74,6 +192,10 @@ impl Render for ManageProfilesModal {
|
|||
.on_mouse_down_out(cx.listener(|_this, _, _, cx| cx.emit(DismissEvent)))
|
||||
.child(match &self.mode {
|
||||
Mode::ChooseProfile(profile_picker) => profile_picker.clone().into_any_element(),
|
||||
Mode::ViewProfile(mode) => self
|
||||
.render_view_profile(mode.clone(), window, cx)
|
||||
.into_any_element(),
|
||||
Mode::ConfigureTools(tool_picker) => tool_picker.clone().into_any_element(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue