@@ -12,12 +12,12 @@ use serde::{Deserialize, Serialize};
use crate::NewExternalAgentThread;
use crate::agent_diff::AgentDiffThread;
use crate::message_editor::{MAX_EDITOR_LINES, MIN_EDITOR_LINES};
-use crate::ui::NewThreadButton;
use crate::{
AddContextServer, AgentDiffPane, ContinueThread, ContinueWithBurnMode,
DeleteRecentlyOpenThread, ExpandMessageEditor, Follow, InlineAssistant, NewTextThread,
NewThread, OpenActiveThreadAsMarkdown, OpenAgentDiff, OpenHistory, ResetTrialEndUpsell,
- ResetTrialUpsell, ToggleBurnMode, ToggleContextPicker, ToggleNavigationMenu, ToggleOptionsMenu,
+ ResetTrialUpsell, ToggleBurnMode, ToggleContextPicker, ToggleNavigationMenu,
+ ToggleNewThreadMenu, ToggleOptionsMenu,
acp::AcpThreadView,
active_thread::{self, ActiveThread, ActiveThreadEvent},
agent_configuration::{AgentConfiguration, AssistantConfigurationEvent},
@@ -67,8 +67,8 @@ use theme::ThemeSettings;
use time::UtcOffset;
use ui::utils::WithRemSize;
use ui::{
- Banner, Callout, ContextMenu, ContextMenuEntry, ElevationIndex, KeyBinding, PopoverMenu,
- PopoverMenuHandle, ProgressBar, Tab, Tooltip, prelude::*,
+ Banner, ButtonLike, Callout, ContextMenu, ContextMenuEntry, ElevationIndex, KeyBinding,
+ PopoverMenu, PopoverMenuHandle, ProgressBar, Tab, Tooltip, prelude::*,
};
use util::ResultExt as _;
use workspace::{
@@ -86,6 +86,7 @@ const AGENT_PANEL_KEY: &str = "agent_panel";
#[derive(Serialize, Deserialize)]
struct SerializedAgentPanel {
width: Option<Pixels>,
+ selected_agent: Option<AgentType>,
}
pub fn init(cx: &mut App) {
@@ -179,6 +180,14 @@ pub fn init(cx: &mut App) {
});
}
})
+ .register_action(|workspace, _: &ToggleNewThreadMenu, window, cx| {
+ if let Some(panel) = workspace.panel::<AgentPanel>(cx) {
+ workspace.focus_panel::<AgentPanel>(window, cx);
+ panel.update(cx, |panel, cx| {
+ panel.toggle_new_thread_menu(&ToggleNewThreadMenu, window, cx);
+ });
+ }
+ })
.register_action(|workspace, _: &OpenOnboardingModal, window, cx| {
AgentOnboardingModal::toggle(workspace, window, cx)
})
@@ -223,6 +232,36 @@ enum WhichFontSize {
None,
}
+#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
+pub enum AgentType {
+ #[default]
+ Zed,
+ TextThread,
+ Gemini,
+ ClaudeCode,
+ NativeAgent,
+}
+
+impl AgentType {
+ fn label(self) -> impl Into<SharedString> {
+ match self {
+ Self::Zed | Self::TextThread => "Zed",
+ Self::NativeAgent => "Agent 2",
+ Self::Gemini => "Gemini",
+ Self::ClaudeCode => "Claude Code",
+ }
+ }
+
+ fn icon(self) -> IconName {
+ match self {
+ Self::Zed | Self::TextThread => IconName::AiZed,
+ Self::NativeAgent => IconName::ZedAssistant,
+ Self::Gemini => IconName::AiGemini,
+ Self::ClaudeCode => IconName::AiClaude,
+ }
+ }
+}
+
impl ActiveView {
pub fn which_font_size_used(&self) -> WhichFontSize {
match self {
@@ -453,16 +492,21 @@ pub struct AgentPanel {
zoomed: bool,
pending_serialization: Option<Task<Result<()>>>,
onboarding: Entity<AgentPanelOnboarding>,
+ selected_agent: AgentType,
}
impl AgentPanel {
fn serialize(&mut self, cx: &mut Context<Self>) {
let width = self.width;
+ let selected_agent = self.selected_agent;
self.pending_serialization = Some(cx.background_spawn(async move {
KEY_VALUE_STORE
.write_kvp(
AGENT_PANEL_KEY.into(),
- serde_json::to_string(&SerializedAgentPanel { width })?,
+ serde_json::to_string(&SerializedAgentPanel {
+ width,
+ selected_agent: Some(selected_agent),
+ })?,
)
.await?;
anyhow::Ok(())
@@ -531,6 +575,9 @@ impl AgentPanel {
if let Some(serialized_panel) = serialized_panel {
panel.update(cx, |panel, cx| {
panel.width = serialized_panel.width.map(|w| w.round());
+ if let Some(selected_agent) = serialized_panel.selected_agent {
+ panel.selected_agent = selected_agent;
+ }
cx.notify();
});
}
@@ -732,6 +779,7 @@ impl AgentPanel {
zoomed: false,
pending_serialization: None,
onboarding,
+ selected_agent: AgentType::default(),
}
}
@@ -1174,6 +1222,15 @@ impl AgentPanel {
self.agent_panel_menu_handle.toggle(window, cx);
}
+ pub fn toggle_new_thread_menu(
+ &mut self,
+ _: &ToggleNewThreadMenu,
+ window: &mut Window,
+ cx: &mut Context<Self>,
+ ) {
+ self.new_thread_menu_handle.toggle(window, cx);
+ }
+
pub fn increase_font_size(
&mut self,
action: &IncreaseBufferFontSize,
@@ -1581,6 +1638,17 @@ impl AgentPanel {
menu
}
+
+ pub fn set_selected_agent(&mut self, agent: AgentType, cx: &mut Context<Self>) {
+ if self.selected_agent != agent {
+ self.selected_agent = agent;
+ self.serialize(cx);
+ }
+ }
+
+ pub fn selected_agent(&self) -> AgentType {
+ self.selected_agent
+ }
}
impl Focusable for AgentPanel {
@@ -1811,75 +1879,170 @@ impl AgentPanel {
.into_any()
}
- fn render_toolbar(&self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
+ fn render_panel_options_menu(
+ &self,
+ window: &mut Window,
+ cx: &mut Context<Self>,
+ ) -> impl IntoElement {
let user_store = self.user_store.read(cx);
let usage = user_store.model_request_usage();
-
let account_url = zed_urls::account_url(cx);
let focus_handle = self.focus_handle(cx);
- let go_back_button = div().child(
- IconButton::new("go-back", IconName::ArrowLeft)
- .icon_size(IconSize::Small)
- .on_click(cx.listener(|this, _, window, cx| {
- this.go_back(&workspace::GoBack, window, cx);
- }))
- .tooltip({
+ let full_screen_label = if self.is_zoomed(window, cx) {
+ "Disable Full Screen"
+ } else {
+ "Enable Full Screen"
+ };
+
+ PopoverMenu::new("agent-options-menu")
+ .trigger_with_tooltip(
+ IconButton::new("agent-options-menu", IconName::Ellipsis)
+ .icon_size(IconSize::Small),
+ {
let focus_handle = focus_handle.clone();
move |window, cx| {
Tooltip::for_action_in(
- "Go Back",
- &workspace::GoBack,
+ "Toggle Agent Menu",
+ &ToggleOptionsMenu,
&focus_handle,
window,
cx,
)
}
- }),
- );
+ },
+ )
+ .anchor(Corner::TopRight)
+ .with_handle(self.agent_panel_menu_handle.clone())
+ .menu({
+ let focus_handle = focus_handle.clone();
+ move |window, cx| {
+ Some(ContextMenu::build(window, cx, |mut menu, _window, _| {
+ menu = menu.context(focus_handle.clone());
+ if let Some(usage) = usage {
+ menu = menu
+ .header_with_link("Prompt Usage", "Manage", account_url.clone())
+ .custom_entry(
+ move |_window, cx| {
+ let used_percentage = match usage.limit {
+ UsageLimit::Limited(limit) => {
+ Some((usage.amount as f32 / limit as f32) * 100.)
+ }
+ UsageLimit::Unlimited => None,
+ };
- let recent_entries_menu = div().child(
- PopoverMenu::new("agent-nav-menu")
- .trigger_with_tooltip(
- IconButton::new("agent-nav-menu", IconName::MenuAlt)
- .icon_size(IconSize::Small)
- .style(ui::ButtonStyle::Subtle),
- {
- let focus_handle = focus_handle.clone();
- move |window, cx| {
- Tooltip::for_action_in(
- "Toggle Panel Menu",
- &ToggleNavigationMenu,
- &focus_handle,
- window,
- cx,
- )
+ h_flex()
+ .flex_1()
+ .gap_1p5()
+ .children(used_percentage.map(|percent| {
+ ProgressBar::new("usage", percent, 100., cx)
+ }))
+ .child(
+ Label::new(match usage.limit {
+ UsageLimit::Limited(limit) => {
+ format!("{} / {limit}", usage.amount)
+ }
+ UsageLimit::Unlimited => {
+ format!("{} / ∞", usage.amount)
+ }
+ })
+ .size(LabelSize::Small)
+ .color(Color::Muted),
+ )
+ .into_any_element()
+ },
+ move |_, cx| cx.open_url(&zed_urls::account_url(cx)),
+ )
+ .separator()
}
- },
- )
- .anchor(Corner::TopLeft)
- .with_handle(self.assistant_navigation_menu_handle.clone())
- .menu({
- let menu = self.assistant_navigation_menu.clone();
+
+ menu = menu
+ .header("MCP Servers")
+ .action(
+ "View Server Extensions",
+ Box::new(zed_actions::Extensions {
+ category_filter: Some(
+ zed_actions::ExtensionCategoryFilter::ContextServers,
+ ),
+ id: None,
+ }),
+ )
+ .action("Add Custom Server…", Box::new(AddContextServer))
+ .separator();
+
+ menu = menu
+ .action("Rules…", Box::new(OpenRulesLibrary::default()))
+ .action("Settings", Box::new(OpenSettings))
+ .separator()
+ .action(full_screen_label, Box::new(ToggleZoom));
+ menu
+ }))
+ }
+ })
+ }
+
+ fn render_recent_entries_menu(
+ &self,
+ icon: IconName,
+ cx: &mut Context<Self>,
+ ) -> impl IntoElement {
+ let focus_handle = self.focus_handle(cx);
+
+ PopoverMenu::new("agent-nav-menu")
+ .trigger_with_tooltip(
+ IconButton::new("agent-nav-menu", icon)
+ .icon_size(IconSize::Small)
+ .style(ui::ButtonStyle::Subtle),
+ {
+ let focus_handle = focus_handle.clone();
move |window, cx| {
- if let Some(menu) = menu.as_ref() {
- menu.update(cx, |_, cx| {
- cx.defer_in(window, |menu, window, cx| {
- menu.rebuild(window, cx);
- });
- })
- }
- menu.clone()
+ Tooltip::for_action_in(
+ "Toggle Panel Menu",
+ &ToggleNavigationMenu,
+ &focus_handle,
+ window,
+ cx,
+ )
}
- }),
- );
+ },
+ )
+ .anchor(Corner::TopLeft)
+ .with_handle(self.assistant_navigation_menu_handle.clone())
+ .menu({
+ let menu = self.assistant_navigation_menu.clone();
+ move |window, cx| {
+ if let Some(menu) = menu.as_ref() {
+ menu.update(cx, |_, cx| {
+ cx.defer_in(window, |menu, window, cx| {
+ menu.rebuild(window, cx);
+ });
+ })
+ }
+ menu.clone()
+ }
+ })
+ }
- let full_screen_label = if self.is_zoomed(window, cx) {
- "Disable Full Screen"
- } else {
- "Enable Full Screen"
- };
+ fn render_toolbar_back_button(&self, cx: &mut Context<Self>) -> impl IntoElement {
+ let focus_handle = self.focus_handle(cx);
+
+ IconButton::new("go-back", IconName::ArrowLeft)
+ .icon_size(IconSize::Small)
+ .on_click(cx.listener(|this, _, window, cx| {
+ this.go_back(&workspace::GoBack, window, cx);
+ }))
+ .tooltip({
+ let focus_handle = focus_handle.clone();
+
+ move |window, cx| {
+ Tooltip::for_action_in("Go Back", &workspace::GoBack, &focus_handle, window, cx)
+ }
+ })
+ }
+
+ fn render_toolbar_old(&self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
+ let focus_handle = self.focus_handle(cx);
let active_thread = match &self.active_view {
ActiveView::Thread { thread, .. } => Some(thread.read(cx).thread().clone()),
@@ -1903,9 +2066,6 @@ impl AgentPanel {
Some(ContextMenu::build(window, cx, |mut menu, _window, cx| {
menu = menu
.context(focus_handle.clone())
- .when(cx.has_flag::<feature_flags::AcpFeatureFlag>(), |this| {
- this.header("Zed Agent")
- })
.when_some(active_thread, |this, active_thread| {
let thread = active_thread.read(cx);
@@ -1948,72 +2108,101 @@ impl AgentPanel {
.handler(move |window, cx| {
window.dispatch_action(NewTextThread.boxed_clone(), cx);
}),
- )
- .when(cx.has_flag::<feature_flags::AcpFeatureFlag>(), |this| {
- this.separator()
- .header("External Agents")
- .item(
- ContextMenuEntry::new("New Gemini Thread")
- .icon(IconName::AiGemini)
- .icon_color(Color::Muted)
- .handler(move |window, cx| {
- window.dispatch_action(
- NewExternalAgentThread {
- agent: Some(crate::ExternalAgent::Gemini),
- }
- .boxed_clone(),
- cx,
- );
- }),
- )
- .item(
- ContextMenuEntry::new("New Claude Code Thread")
- .icon(IconName::AiClaude)
- .icon_color(Color::Muted)
- .handler(move |window, cx| {
- window.dispatch_action(
- NewExternalAgentThread {
- agent: Some(
- crate::ExternalAgent::ClaudeCode,
- ),
- }
- .boxed_clone(),
- cx,
- );
- }),
- )
- .item(
- ContextMenuEntry::new("New Native Agent Thread")
- .icon(IconName::ZedAssistant)
- .icon_color(Color::Muted)
- .handler(move |window, cx| {
- window.dispatch_action(
- NewExternalAgentThread {
- agent: Some(
- crate::ExternalAgent::NativeAgent,
- ),
- }
- .boxed_clone(),
- cx,
- );
- }),
- )
- });
+ );
menu
}))
}
});
- let agent_panel_menu = PopoverMenu::new("agent-options-menu")
+ h_flex()
+ .id("assistant-toolbar")
+ .h(Tab::container_height(cx))
+ .max_w_full()
+ .flex_none()
+ .justify_between()
+ .gap_2()
+ .bg(cx.theme().colors().tab_bar_background)
+ .border_b_1()
+ .border_color(cx.theme().colors().border)
+ .child(
+ h_flex()
+ .size_full()
+ .pl_1()
+ .gap_1()
+ .child(match &self.active_view {
+ ActiveView::History | ActiveView::Configuration => {
+ self.render_toolbar_back_button(cx).into_any_element()
+ }
+ _ => self
+ .render_recent_entries_menu(IconName::MenuAlt, cx)
+ .into_any_element(),
+ })
+ .child(self.render_title_view(window, cx)),
+ )
+ .child(
+ h_flex()
+ .h_full()
+ .gap_2()
+ .children(self.render_token_count(cx))
+ .child(
+ h_flex()
+ .h_full()
+ .gap(DynamicSpacing::Base02.rems(cx))
+ .px(DynamicSpacing::Base08.rems(cx))
+ .border_l_1()
+ .border_color(cx.theme().colors().border)
+ .child(new_thread_menu)
+ .child(self.render_panel_options_menu(window, cx)),
+ ),
+ )
+ }
+
+ fn render_toolbar_new(&self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
+ let focus_handle = self.focus_handle(cx);
+
+ let active_thread = match &self.active_view {
+ ActiveView::Thread { thread, .. } => Some(thread.read(cx).thread().clone()),
+ ActiveView::ExternalAgentThread { .. }
+ | ActiveView::TextThread { .. }
+ | ActiveView::History
+ | ActiveView::Configuration => None,
+ };
+
+ let new_thread_menu = PopoverMenu::new("new_thread_menu")
.trigger_with_tooltip(
- IconButton::new("agent-options-menu", IconName::Ellipsis)
- .icon_size(IconSize::Small),
+ ButtonLike::new("new_thread_menu_btn").child(
+ h_flex()
+ .group("agent-selector")
+ .gap_1p5()
+ .child(
+ h_flex()
+ .relative()
+ .size_4()
+ .justify_center()
+ .child(
+ h_flex()
+ .group_hover("agent-selector", |s| s.invisible())
+ .child(
+ Icon::new(self.selected_agent.icon())
+ .color(Color::Muted),
+ ),
+ )
+ .child(
+ h_flex()
+ .absolute()
+ .invisible()
+ .group_hover("agent-selector", |s| s.visible())
+ .child(Icon::new(IconName::Plus)),
+ ),
+ )
+ .child(Label::new(self.selected_agent.label())),
+ ),
{
let focus_handle = focus_handle.clone();
move |window, cx| {
Tooltip::for_action_in(
- "Toggle Agent Menu",
- &ToggleOptionsMenu,
+ "New…",
+ &ToggleNewThreadMenu,
&focus_handle,
window,
cx,
@@ -2021,76 +2210,197 @@ impl AgentPanel {
}
},
)
- .anchor(Corner::TopRight)
- .with_handle(self.agent_panel_menu_handle.clone())
+ .anchor(Corner::TopLeft)
+ .with_handle(self.new_thread_menu_handle.clone())
.menu({
let focus_handle = focus_handle.clone();
+ let workspace = self.workspace.clone();
+
move |window, cx| {
- Some(ContextMenu::build(window, cx, |mut menu, _window, _| {
- menu = menu.context(focus_handle.clone());
- if let Some(usage) = usage {
- menu = menu
- .header_with_link("Prompt Usage", "Manage", account_url.clone())
- .custom_entry(
- move |_window, cx| {
- let used_percentage = match usage.limit {
- UsageLimit::Limited(limit) => {
- Some((usage.amount as f32 / limit as f32) * 100.)
- }
- UsageLimit::Unlimited => None,
- };
+ let active_thread = active_thread.clone();
+ Some(ContextMenu::build(window, cx, |mut menu, _window, cx| {
+ menu = menu
+ .context(focus_handle.clone())
+ .header("Zed Agent")
+ .when_some(active_thread, |this, active_thread| {
+ let thread = active_thread.read(cx);
- h_flex()
- .flex_1()
- .gap_1p5()
- .children(used_percentage.map(|percent| {
- ProgressBar::new("usage", percent, 100., cx)
- }))
- .child(
- Label::new(match usage.limit {
- UsageLimit::Limited(limit) => {
- format!("{} / {limit}", usage.amount)
+ if !thread.is_empty() {
+ let thread_id = thread.id().clone();
+ this.item(
+ ContextMenuEntry::new("New From Summary")
+ .icon(IconName::ThreadFromSummary)
+ .icon_color(Color::Muted)
+ .handler(move |window, cx| {
+ window.dispatch_action(
+ Box::new(NewThread {
+ from_thread_id: Some(thread_id.clone()),
+ }),
+ cx,
+ );
+ }),
+ )
+ } else {
+ this
+ }
+ })
+ .item(
+ ContextMenuEntry::new("New Thread")
+ .icon(IconName::Thread)
+ .icon_color(Color::Muted)
+ .action(NewThread::default().boxed_clone())
+ .handler({
+ let workspace = workspace.clone();
+ move |window, cx| {
+ if let Some(workspace) = workspace.upgrade() {
+ workspace.update(cx, |workspace, cx| {
+ if let Some(panel) =
+ workspace.panel::<AgentPanel>(cx)
+ {
+ panel.update(cx, |panel, cx| {
+ panel.set_selected_agent(
+ AgentType::Zed,
+ cx,
+ );
+ });
}
- UsageLimit::Unlimited => {
- format!("{} / ∞", usage.amount)
+ });
+ }
+ window.dispatch_action(
+ NewThread::default().boxed_clone(),
+ cx,
+ );
+ }
+ }),
+ )
+ .item(
+ ContextMenuEntry::new("New Text Thread")
+ .icon(IconName::TextThread)
+ .icon_color(Color::Muted)
+ .action(NewTextThread.boxed_clone())
+ .handler({
+ let workspace = workspace.clone();
+ move |window, cx| {
+ if let Some(workspace) = workspace.upgrade() {
+ workspace.update(cx, |workspace, cx| {
+ if let Some(panel) =
+ workspace.panel::<AgentPanel>(cx)
+ {
+ panel.update(cx, |panel, cx| {
+ panel.set_selected_agent(
+ AgentType::TextThread,
+ cx,
+ );
+ });
}
- })
- .size(LabelSize::Small)
- .color(Color::Muted),
- )
- .into_any_element()
- },
- move |_, cx| cx.open_url(&zed_urls::account_url(cx)),
- )
- .separator()
- }
-
- menu = menu
- .header("MCP Servers")
- .action(
- "View Server Extensions",
- Box::new(zed_actions::Extensions {
- category_filter: Some(
- zed_actions::ExtensionCategoryFilter::ContextServers,
- ),
- id: None,
- }),
+ });
+ }
+ window.dispatch_action(NewTextThread.boxed_clone(), cx);
+ }
+ }),
+ )
+ .item(
+ ContextMenuEntry::new("New Native Agent Thread")
+ .icon(IconName::ZedAssistant)
+ .icon_color(Color::Muted)
+ .handler({
+ let workspace = workspace.clone();
+ move |window, cx| {
+ if let Some(workspace) = workspace.upgrade() {
+ workspace.update(cx, |workspace, cx| {
+ if let Some(panel) =
+ workspace.panel::<AgentPanel>(cx)
+ {
+ panel.update(cx, |panel, cx| {
+ panel.set_selected_agent(
+ AgentType::NativeAgent,
+ cx,
+ );
+ });
+ }
+ });
+ }
+ window.dispatch_action(
+ NewExternalAgentThread {
+ agent: Some(crate::ExternalAgent::NativeAgent),
+ }
+ .boxed_clone(),
+ cx,
+ );
+ }
+ }),
)
- .action("Add Custom Server…", Box::new(AddContextServer))
- .separator();
-
- menu = menu
- .action("Rules…", Box::new(OpenRulesLibrary::default()))
- .action("Settings", Box::new(OpenSettings))
.separator()
- .action(full_screen_label, Box::new(ToggleZoom));
+ .header("External Agents")
+ .item(
+ ContextMenuEntry::new("New Gemini Thread")
+ .icon(IconName::AiGemini)
+ .icon_color(Color::Muted)
+ .handler({
+ let workspace = workspace.clone();
+ move |window, cx| {
+ if let Some(workspace) = workspace.upgrade() {
+ workspace.update(cx, |workspace, cx| {
+ if let Some(panel) =
+ workspace.panel::<AgentPanel>(cx)
+ {
+ panel.update(cx, |panel, cx| {
+ panel.set_selected_agent(
+ AgentType::Gemini,
+ cx,
+ );
+ });
+ }
+ });
+ }
+ window.dispatch_action(
+ NewExternalAgentThread {
+ agent: Some(crate::ExternalAgent::Gemini),
+ }
+ .boxed_clone(),
+ cx,
+ );
+ }
+ }),
+ )
+ .item(
+ ContextMenuEntry::new("New Claude Code Thread")
+ .icon(IconName::AiClaude)
+ .icon_color(Color::Muted)
+ .handler({
+ let workspace = workspace.clone();
+ move |window, cx| {
+ if let Some(workspace) = workspace.upgrade() {
+ workspace.update(cx, |workspace, cx| {
+ if let Some(panel) =
+ workspace.panel::<AgentPanel>(cx)
+ {
+ panel.update(cx, |panel, cx| {
+ panel.set_selected_agent(
+ AgentType::ClaudeCode,
+ cx,
+ );
+ });
+ }
+ });
+ }
+ window.dispatch_action(
+ NewExternalAgentThread {
+ agent: Some(crate::ExternalAgent::ClaudeCode),
+ }
+ .boxed_clone(),
+ cx,
+ );
+ }
+ }),
+ );
menu
}))
}
});
h_flex()
- .id("assistant-toolbar")
+ .id("agent-panel-toolbar")
.h(Tab::container_height(cx))
.max_w_full()
.flex_none()
@@ -2102,11 +2412,18 @@ impl AgentPanel {
.child(
h_flex()
.size_full()
- .pl_1()
- .gap_1()
+ .gap(DynamicSpacing::Base08.rems(cx))
.child(match &self.active_view {
- ActiveView::History | ActiveView::Configuration => go_back_button,
- _ => recent_entries_menu,
+ ActiveView::History | ActiveView::Configuration => {
+ self.render_toolbar_back_button(cx).into_any_element()
+ }
+ _ => h_flex()
+ .h_full()
+ .px(DynamicSpacing::Base04.rems(cx))
+ .border_r_1()
+ .border_color(cx.theme().colors().border)
+ .child(new_thread_menu)
+ .into_any_element(),
})
.child(self.render_title_view(window, cx)),
)
@@ -2119,15 +2436,24 @@ impl AgentPanel {
h_flex()
.h_full()
.gap(DynamicSpacing::Base02.rems(cx))
- .px(DynamicSpacing::Base08.rems(cx))
+ .pl(DynamicSpacing::Base04.rems(cx))
+ .pr(DynamicSpacing::Base06.rems(cx))
.border_l_1()
.border_color(cx.theme().colors().border)
- .child(new_thread_menu)
- .child(agent_panel_menu),
+ .child(self.render_recent_entries_menu(IconName::HistoryRerun, cx))
+ .child(self.render_panel_options_menu(window, cx)),
),
)
}
+ fn render_toolbar(&self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
+ if cx.has_flag::<feature_flags::AcpFeatureFlag>() {
+ self.render_toolbar_new(window, cx).into_any_element()
+ } else {
+ self.render_toolbar_old(window, cx).into_any_element()
+ }
+ }
+
fn render_token_count(&self, cx: &App) -> Option<AnyElement> {
match &self.active_view {
ActiveView::Thread {
@@ -2576,138 +2902,6 @@ impl AgentPanel {
},
)),
)
- .child(self.render_empty_state_section_header("Start", None, cx))
- .child(
- v_flex()
- .p_1()
- .gap_2()
- .child(
- h_flex()
- .w_full()
- .gap_2()
- .child(
- NewThreadButton::new(
- "new-thread-btn",
- "New Thread",
- IconName::Thread,
- )
- .keybinding(KeyBinding::for_action_in(
- &NewThread::default(),
- &self.focus_handle(cx),
- window,
- cx,
- ))
- .on_click(
- |window, cx| {
- window.dispatch_action(
- NewThread::default().boxed_clone(),
- cx,
- )
- },
- ),
- )
- .child(
- NewThreadButton::new(
- "new-text-thread-btn",
- "New Text Thread",
- IconName::TextThread,
- )
- .keybinding(KeyBinding::for_action_in(
- &NewTextThread,
- &self.focus_handle(cx),
- window,
- cx,
- ))
- .on_click(
- |window, cx| {
- window.dispatch_action(Box::new(NewTextThread), cx)
- },
- ),
- ),
- )
- .when(cx.has_flag::<feature_flags::AcpFeatureFlag>(), |this| {
- this.child(
- h_flex()
- .w_full()
- .gap_2()
- .child(
- NewThreadButton::new(
- "new-gemini-thread-btn",
- "New Gemini Thread",
- IconName::AiGemini,
- )
- // .keybinding(KeyBinding::for_action_in(
- // &OpenHistory,
- // &self.focus_handle(cx),
- // window,
- // cx,
- // ))
- .on_click(
- |window, cx| {
- window.dispatch_action(
- Box::new(NewExternalAgentThread {
- agent: Some(
- crate::ExternalAgent::Gemini,
- ),
- }),
- cx,
- )
- },
- ),
- )
- .child(
- NewThreadButton::new(
- "new-claude-thread-btn",
- "New Claude Code Thread",
- IconName::AiClaude,
- )
- // .keybinding(KeyBinding::for_action_in(
- // &OpenHistory,
- // &self.focus_handle(cx),
- // window,
- // cx,
- // ))
- .on_click(
- |window, cx| {
- window.dispatch_action(
- Box::new(NewExternalAgentThread {
- agent: Some(
- crate::ExternalAgent::ClaudeCode,
- ),
- }),
- cx,
- )
- },
- ),
- )
- .child(
- NewThreadButton::new(
- "new-native-agent-thread-btn",
- "New Native Agent Thread",
- IconName::ZedAssistant,
- )
- // .keybinding(KeyBinding::for_action_in(
- // &OpenHistory,
- // &self.focus_handle(cx),
- // window,
- // cx,
- // ))
- .on_click(
- |window, cx| {
- window.dispatch_action(
- Box::new(NewExternalAgentThread {
- agent: Some(
- crate::ExternalAgent::NativeAgent,
- ),
- }),
- cx,
- )
- },
- ),
- ),
- )
- }),
- )
.when_some(configuration_error.as_ref(), |this, err| {
this.child(self.render_configuration_error(err, &focus_handle, window, cx))
})