Break ground on assistant2
(#21109)
This PR breaks ground on a new `assistant2` crate. In order to see this new version of the assistant, both of the following must be true: 1. The `assistant2` feature flag is enabled for your user - It is **not** currently enabled for all staff. 2. You are running a development build of Zed The intent here is to enable the folks working on `assistant2` to incrementally land work onto `main` without breaking use of the current Assistant for anyone. <img width="1136" alt="Screenshot 2024-11-23 at 10 46 08 AM" src="https://github.com/user-attachments/assets/5723a13f-5be1-4486-9460-ead7329ba78e"> Release Notes: - N/A
This commit is contained in:
parent
f30de4852a
commit
9adc3b4e82
10 changed files with 243 additions and 5 deletions
14
Cargo.lock
generated
14
Cargo.lock
generated
|
@ -449,6 +449,19 @@ dependencies = [
|
||||||
"zed_actions",
|
"zed_actions",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "assistant2"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"anyhow",
|
||||||
|
"command_palette_hooks",
|
||||||
|
"feature_flags",
|
||||||
|
"gpui",
|
||||||
|
"proto",
|
||||||
|
"ui",
|
||||||
|
"workspace",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "assistant_slash_command"
|
name = "assistant_slash_command"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
@ -15549,6 +15562,7 @@ dependencies = [
|
||||||
"ashpd",
|
"ashpd",
|
||||||
"assets",
|
"assets",
|
||||||
"assistant",
|
"assistant",
|
||||||
|
"assistant2",
|
||||||
"async-watch",
|
"async-watch",
|
||||||
"audio",
|
"audio",
|
||||||
"auto_update",
|
"auto_update",
|
||||||
|
|
|
@ -5,6 +5,7 @@ members = [
|
||||||
"crates/anthropic",
|
"crates/anthropic",
|
||||||
"crates/assets",
|
"crates/assets",
|
||||||
"crates/assistant",
|
"crates/assistant",
|
||||||
|
"crates/assistant2",
|
||||||
"crates/assistant_slash_command",
|
"crates/assistant_slash_command",
|
||||||
"crates/assistant_tool",
|
"crates/assistant_tool",
|
||||||
"crates/audio",
|
"crates/audio",
|
||||||
|
@ -186,6 +187,7 @@ ai = { path = "crates/ai" }
|
||||||
anthropic = { path = "crates/anthropic" }
|
anthropic = { path = "crates/anthropic" }
|
||||||
assets = { path = "crates/assets" }
|
assets = { path = "crates/assets" }
|
||||||
assistant = { path = "crates/assistant" }
|
assistant = { path = "crates/assistant" }
|
||||||
|
assistant2 = { path = "crates/assistant2" }
|
||||||
assistant_slash_command = { path = "crates/assistant_slash_command" }
|
assistant_slash_command = { path = "crates/assistant_slash_command" }
|
||||||
assistant_tool = { path = "crates/assistant_tool" }
|
assistant_tool = { path = "crates/assistant_tool" }
|
||||||
audio = { path = "crates/audio" }
|
audio = { path = "crates/audio" }
|
||||||
|
|
22
crates/assistant2/Cargo.toml
Normal file
22
crates/assistant2/Cargo.toml
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
[package]
|
||||||
|
name = "assistant2"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
publish = false
|
||||||
|
license = "GPL-3.0-or-later"
|
||||||
|
|
||||||
|
[lints]
|
||||||
|
workspace = true
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
path = "src/assistant.rs"
|
||||||
|
doctest = false
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
anyhow.workspace = true
|
||||||
|
command_palette_hooks.workspace = true
|
||||||
|
feature_flags.workspace = true
|
||||||
|
gpui.workspace = true
|
||||||
|
proto.workspace = true
|
||||||
|
ui.workspace = true
|
||||||
|
workspace.workspace = true
|
1
crates/assistant2/LICENSE-GPL
Symbolic link
1
crates/assistant2/LICENSE-GPL
Symbolic link
|
@ -0,0 +1 @@
|
||||||
|
../../LICENSE-GPL
|
40
crates/assistant2/src/assistant.rs
Normal file
40
crates/assistant2/src/assistant.rs
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
mod assistant_panel;
|
||||||
|
|
||||||
|
use command_palette_hooks::CommandPaletteFilter;
|
||||||
|
use feature_flags::{Assistant2FeatureFlag, FeatureFlagAppExt};
|
||||||
|
use gpui::{actions, AppContext};
|
||||||
|
|
||||||
|
pub use crate::assistant_panel::AssistantPanel;
|
||||||
|
|
||||||
|
actions!(assistant2, [ToggleFocus, NewChat]);
|
||||||
|
|
||||||
|
const NAMESPACE: &str = "assistant2";
|
||||||
|
|
||||||
|
/// Initializes the `assistant2` crate.
|
||||||
|
pub fn init(cx: &mut AppContext) {
|
||||||
|
assistant_panel::init(cx);
|
||||||
|
feature_gate_assistant2_actions(cx);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn feature_gate_assistant2_actions(cx: &mut AppContext) {
|
||||||
|
const ASSISTANT1_NAMESPACE: &str = "assistant";
|
||||||
|
|
||||||
|
CommandPaletteFilter::update_global(cx, |filter, _cx| {
|
||||||
|
filter.hide_namespace(NAMESPACE);
|
||||||
|
});
|
||||||
|
|
||||||
|
cx.observe_flag::<Assistant2FeatureFlag, _>(move |is_enabled, cx| {
|
||||||
|
if is_enabled {
|
||||||
|
CommandPaletteFilter::update_global(cx, |filter, _cx| {
|
||||||
|
filter.show_namespace(NAMESPACE);
|
||||||
|
filter.hide_namespace(ASSISTANT1_NAMESPACE);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
CommandPaletteFilter::update_global(cx, |filter, _cx| {
|
||||||
|
filter.hide_namespace(NAMESPACE);
|
||||||
|
filter.show_namespace(ASSISTANT1_NAMESPACE);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.detach();
|
||||||
|
}
|
123
crates/assistant2/src/assistant_panel.rs
Normal file
123
crates/assistant2/src/assistant_panel.rs
Normal file
|
@ -0,0 +1,123 @@
|
||||||
|
use anyhow::Result;
|
||||||
|
use gpui::{
|
||||||
|
prelude::*, px, Action, AppContext, AsyncWindowContext, EventEmitter, FocusHandle,
|
||||||
|
FocusableView, Pixels, Task, View, ViewContext, WeakView, WindowContext,
|
||||||
|
};
|
||||||
|
use ui::prelude::*;
|
||||||
|
use workspace::dock::{DockPosition, Panel, PanelEvent};
|
||||||
|
use workspace::{Pane, Workspace};
|
||||||
|
|
||||||
|
use crate::{NewChat, ToggleFocus};
|
||||||
|
|
||||||
|
pub fn init(cx: &mut AppContext) {
|
||||||
|
cx.observe_new_views(
|
||||||
|
|workspace: &mut Workspace, _cx: &mut ViewContext<Workspace>| {
|
||||||
|
workspace.register_action(|workspace, _: &ToggleFocus, cx| {
|
||||||
|
workspace.toggle_panel_focus::<AssistantPanel>(cx);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.detach();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct AssistantPanel {
|
||||||
|
pane: View<Pane>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AssistantPanel {
|
||||||
|
pub fn load(
|
||||||
|
workspace: WeakView<Workspace>,
|
||||||
|
cx: AsyncWindowContext,
|
||||||
|
) -> Task<Result<View<Self>>> {
|
||||||
|
cx.spawn(|mut cx| async move {
|
||||||
|
workspace.update(&mut cx, |workspace, cx| {
|
||||||
|
cx.new_view(|cx| Self::new(workspace, cx))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn new(workspace: &Workspace, cx: &mut ViewContext<Self>) -> Self {
|
||||||
|
let pane = cx.new_view(|cx| {
|
||||||
|
let mut pane = Pane::new(
|
||||||
|
workspace.weak_handle(),
|
||||||
|
workspace.project().clone(),
|
||||||
|
Default::default(),
|
||||||
|
None,
|
||||||
|
NewChat.boxed_clone(),
|
||||||
|
cx,
|
||||||
|
);
|
||||||
|
pane.set_can_split(false, cx);
|
||||||
|
pane.set_can_navigate(true, cx);
|
||||||
|
|
||||||
|
pane
|
||||||
|
});
|
||||||
|
|
||||||
|
Self { pane }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FocusableView for AssistantPanel {
|
||||||
|
fn focus_handle(&self, cx: &AppContext) -> FocusHandle {
|
||||||
|
self.pane.focus_handle(cx)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl EventEmitter<PanelEvent> for AssistantPanel {}
|
||||||
|
|
||||||
|
impl Panel for AssistantPanel {
|
||||||
|
fn persistent_name() -> &'static str {
|
||||||
|
"AssistantPanel2"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn position(&self, _cx: &WindowContext) -> DockPosition {
|
||||||
|
DockPosition::Right
|
||||||
|
}
|
||||||
|
|
||||||
|
fn position_is_valid(&self, _: DockPosition) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_position(&mut self, _position: DockPosition, _cx: &mut ViewContext<Self>) {}
|
||||||
|
|
||||||
|
fn size(&self, _cx: &WindowContext) -> Pixels {
|
||||||
|
px(640.)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_size(&mut self, _size: Option<Pixels>, _cx: &mut ViewContext<Self>) {}
|
||||||
|
|
||||||
|
fn is_zoomed(&self, cx: &WindowContext) -> bool {
|
||||||
|
self.pane.read(cx).is_zoomed()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_zoomed(&mut self, zoomed: bool, cx: &mut ViewContext<Self>) {
|
||||||
|
self.pane.update(cx, |pane, cx| pane.set_zoomed(zoomed, cx));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_active(&mut self, _active: bool, _cx: &mut ViewContext<Self>) {}
|
||||||
|
|
||||||
|
fn pane(&self) -> Option<View<Pane>> {
|
||||||
|
Some(self.pane.clone())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn remote_id() -> Option<proto::PanelId> {
|
||||||
|
Some(proto::PanelId::AssistantPanel)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn icon(&self, _cx: &WindowContext) -> Option<IconName> {
|
||||||
|
Some(IconName::ZedAssistant)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn icon_tooltip(&self, _cx: &WindowContext) -> Option<&'static str> {
|
||||||
|
Some("Assistant Panel")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn toggle_action(&self) -> Box<dyn Action> {
|
||||||
|
Box::new(ToggleFocus)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Render for AssistantPanel {
|
||||||
|
fn render(&mut self, _cx: &mut ViewContext<Self>) -> impl IntoElement {
|
||||||
|
div().child(Label::new("Assistant II"))
|
||||||
|
}
|
||||||
|
}
|
|
@ -39,6 +39,16 @@ pub trait FeatureFlag {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct Assistant2FeatureFlag;
|
||||||
|
|
||||||
|
impl FeatureFlag for Assistant2FeatureFlag {
|
||||||
|
const NAME: &'static str = "assistant2";
|
||||||
|
|
||||||
|
fn enabled_for_staff() -> bool {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct Remoting {}
|
pub struct Remoting {}
|
||||||
impl FeatureFlag for Remoting {
|
impl FeatureFlag for Remoting {
|
||||||
const NAME: &'static str = "remoting";
|
const NAME: &'static str = "remoting";
|
||||||
|
|
|
@ -19,6 +19,7 @@ activity_indicator.workspace = true
|
||||||
anyhow.workspace = true
|
anyhow.workspace = true
|
||||||
assets.workspace = true
|
assets.workspace = true
|
||||||
assistant.workspace = true
|
assistant.workspace = true
|
||||||
|
assistant2.workspace = true
|
||||||
async-watch.workspace = true
|
async-watch.workspace = true
|
||||||
audio.workspace = true
|
audio.workspace = true
|
||||||
auto_update.workspace = true
|
auto_update.workspace = true
|
||||||
|
|
|
@ -406,6 +406,7 @@ fn main() {
|
||||||
stdout_is_a_pty(),
|
stdout_is_a_pty(),
|
||||||
cx,
|
cx,
|
||||||
);
|
);
|
||||||
|
assistant2::init(cx);
|
||||||
assistant_hints::init(cx);
|
assistant_hints::init(cx);
|
||||||
repl::init(
|
repl::init(
|
||||||
app_state.fs.clone(),
|
app_state.fs.clone(),
|
||||||
|
|
|
@ -236,10 +236,29 @@ pub fn initialize_workspace(
|
||||||
.unwrap_or(true)
|
.unwrap_or(true)
|
||||||
});
|
});
|
||||||
|
|
||||||
|
let release_channel = ReleaseChannel::global(cx);
|
||||||
|
let assistant2_feature_flag = cx.wait_for_flag::<feature_flags::Assistant2FeatureFlag>();
|
||||||
|
|
||||||
let prompt_builder = prompt_builder.clone();
|
let prompt_builder = prompt_builder.clone();
|
||||||
cx.spawn(|workspace_handle, mut cx| async move {
|
cx.spawn(|workspace_handle, mut cx| async move {
|
||||||
let assistant_panel =
|
let is_assistant2_enabled = if cfg!(test) {
|
||||||
assistant::AssistantPanel::load(workspace_handle.clone(), prompt_builder, cx.clone());
|
false
|
||||||
|
} else {
|
||||||
|
let is_assistant2_feature_flag_enabled = assistant2_feature_flag.await;
|
||||||
|
release_channel == ReleaseChannel::Dev && is_assistant2_feature_flag_enabled
|
||||||
|
};
|
||||||
|
|
||||||
|
let (assistant_panel, assistant2_panel) = if is_assistant2_enabled {
|
||||||
|
let assistant2_panel =
|
||||||
|
assistant2::AssistantPanel::load(workspace_handle.clone(), cx.clone()).await?;
|
||||||
|
|
||||||
|
(None, Some(assistant2_panel))
|
||||||
|
} else {
|
||||||
|
let assistant_panel =
|
||||||
|
assistant::AssistantPanel::load(workspace_handle.clone(), prompt_builder, cx.clone()).await?;
|
||||||
|
|
||||||
|
(Some(assistant_panel), None)
|
||||||
|
};
|
||||||
|
|
||||||
let project_panel = ProjectPanel::load(workspace_handle.clone(), cx.clone());
|
let project_panel = ProjectPanel::load(workspace_handle.clone(), cx.clone());
|
||||||
let outline_panel = OutlinePanel::load(workspace_handle.clone(), cx.clone());
|
let outline_panel = OutlinePanel::load(workspace_handle.clone(), cx.clone());
|
||||||
|
@ -257,7 +276,6 @@ pub fn initialize_workspace(
|
||||||
project_panel,
|
project_panel,
|
||||||
outline_panel,
|
outline_panel,
|
||||||
terminal_panel,
|
terminal_panel,
|
||||||
assistant_panel,
|
|
||||||
channels_panel,
|
channels_panel,
|
||||||
chat_panel,
|
chat_panel,
|
||||||
notification_panel,
|
notification_panel,
|
||||||
|
@ -265,14 +283,20 @@ pub fn initialize_workspace(
|
||||||
project_panel,
|
project_panel,
|
||||||
outline_panel,
|
outline_panel,
|
||||||
terminal_panel,
|
terminal_panel,
|
||||||
assistant_panel,
|
|
||||||
channels_panel,
|
channels_panel,
|
||||||
chat_panel,
|
chat_panel,
|
||||||
notification_panel,
|
notification_panel,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
workspace_handle.update(&mut cx, |workspace, cx| {
|
workspace_handle.update(&mut cx, |workspace, cx| {
|
||||||
workspace.add_panel(assistant_panel, cx);
|
if let Some(assistant_panel) = assistant_panel {
|
||||||
|
workspace.add_panel(assistant_panel, cx);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(assistant2_panel) = assistant2_panel {
|
||||||
|
workspace.add_panel(assistant2_panel, cx);
|
||||||
|
}
|
||||||
|
|
||||||
workspace.add_panel(project_panel, cx);
|
workspace.add_panel(project_panel, cx);
|
||||||
workspace.add_panel(outline_panel, cx);
|
workspace.add_panel(outline_panel, cx);
|
||||||
workspace.add_panel(terminal_panel, cx);
|
workspace.add_panel(terminal_panel, cx);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue