@@ -14,7 +14,6 @@ use settings::{LanguageModelProviderSetting, LanguageModelSelection};
use zed_actions::agent::{OpenClaudeAgentOnboardingModal, ReauthenticateAgent};
-use crate::ManageProfiles;
use crate::ui::{AcpOnboardingModal, ClaudeCodeOnboardingModal};
use crate::{
AddContextServer, AgentDiffPane, CopyThreadToClipboard, Follow, InlineAssistant,
@@ -36,6 +35,7 @@ use crate::{
ExternalAgent, ExternalAgentInitialContent, NewExternalAgentThread,
NewNativeAgentThreadFromSummary,
};
+use crate::{ManageProfiles, acp::thread_view::AcpThreadView};
use agent_settings::AgentSettings;
use ai_onboarding::AgentPanelOnboarding;
use anyhow::{Result, anyhow};
@@ -289,7 +289,7 @@ enum HistoryKind {
enum ActiveView {
Uninitialized,
AgentThread {
- thread_view: Entity<AcpServerView>,
+ server_view: Entity<AcpServerView>,
},
TextThread {
text_thread_editor: Entity<TextThreadEditor>,
@@ -855,7 +855,7 @@ impl AgentPanel {
pub(crate) fn active_thread_view(&self) -> Option<&Entity<AcpServerView>> {
match &self.active_view {
- ActiveView::AgentThread { thread_view, .. } => Some(thread_view),
+ ActiveView::AgentThread { server_view, .. } => Some(server_view),
ActiveView::Uninitialized
| ActiveView::TextThread { .. }
| ActiveView::History { .. }
@@ -1529,9 +1529,21 @@ impl AgentPanel {
}
}
+ pub fn as_active_server_view(&self) -> Option<&Entity<AcpServerView>> {
+ match &self.active_view {
+ ActiveView::AgentThread { server_view } => Some(server_view),
+ _ => None,
+ }
+ }
+
+ pub fn as_active_thread_view(&self, cx: &App) -> Option<Entity<AcpThreadView>> {
+ let server_view = self.as_active_server_view()?;
+ server_view.read(cx).active_thread().cloned()
+ }
+
pub fn active_agent_thread(&self, cx: &App) -> Option<Entity<AcpThread>> {
match &self.active_view {
- ActiveView::AgentThread { thread_view, .. } => thread_view
+ ActiveView::AgentThread { server_view, .. } => server_view
.read(cx)
.active_thread()
.map(|r| r.read(cx).thread.clone()),
@@ -1541,8 +1553,8 @@ impl AgentPanel {
pub(crate) fn active_native_agent_thread(&self, cx: &App) -> Option<Entity<agent::Thread>> {
match &self.active_view {
- ActiveView::AgentThread { thread_view, .. } => {
- thread_view.read(cx).as_native_thread(cx)
+ ActiveView::AgentThread { server_view, .. } => {
+ server_view.read(cx).as_native_thread(cx)
}
_ => None,
}
@@ -1592,8 +1604,8 @@ impl AgentPanel {
}
self._active_view_observation = match &self.active_view {
- ActiveView::AgentThread { thread_view } => {
- Some(cx.observe(thread_view, |this, _, cx| {
+ ActiveView::AgentThread { server_view } => {
+ Some(cx.observe(server_view, |this, _, cx| {
cx.emit(AgentPanelEvent::ActiveViewChanged);
this.serialize(cx);
cx.notify();
@@ -1844,7 +1856,7 @@ impl AgentPanel {
.is_some()
.then(|| self.thread_store.clone());
- let thread_view = cx.new(|cx| {
+ let server_view = cx.new(|cx| {
crate::acp::AcpServerView::new(
server,
resume_thread,
@@ -1859,7 +1871,7 @@ impl AgentPanel {
)
});
- self.set_active_view(ActiveView::AgentThread { thread_view }, true, window, cx);
+ self.set_active_view(ActiveView::AgentThread { server_view }, true, window, cx);
}
}
@@ -1867,7 +1879,7 @@ impl Focusable for AgentPanel {
fn focus_handle(&self, cx: &App) -> FocusHandle {
match &self.active_view {
ActiveView::Uninitialized => self.focus_handle.clone(),
- ActiveView::AgentThread { thread_view, .. } => thread_view.focus_handle(cx),
+ ActiveView::AgentThread { server_view, .. } => server_view.focus_handle(cx),
ActiveView::History { kind } => match kind {
HistoryKind::AgentThreads => self.acp_history.focus_handle(cx),
HistoryKind::TextThreads => self.text_thread_history.focus_handle(cx),
@@ -1988,13 +2000,13 @@ impl AgentPanel {
const LOADING_SUMMARY_PLACEHOLDER: &str = "Loading Summary…";
let content = match &self.active_view {
- ActiveView::AgentThread { thread_view } => {
- let is_generating_title = thread_view
+ ActiveView::AgentThread { server_view } => {
+ let is_generating_title = server_view
.read(cx)
.as_native_thread(cx)
.map_or(false, |t| t.read(cx).is_generating_title());
- if let Some(title_editor) = thread_view
+ if let Some(title_editor) = server_view
.read(cx)
.parent_thread(cx)
.map(|r| r.read(cx).title_editor.clone())
@@ -2002,7 +2014,7 @@ impl AgentPanel {
let container = div()
.w_full()
.on_action({
- let thread_view = thread_view.downgrade();
+ let thread_view = server_view.downgrade();
move |_: &menu::Confirm, window, cx| {
if let Some(thread_view) = thread_view.upgrade() {
thread_view.focus_handle(cx).focus(window, cx);
@@ -2010,7 +2022,7 @@ impl AgentPanel {
}
})
.on_action({
- let thread_view = thread_view.downgrade();
+ let thread_view = server_view.downgrade();
move |_: &editor::actions::Cancel, window, cx| {
if let Some(thread_view) = thread_view.upgrade() {
thread_view.focus_handle(cx).focus(window, cx);
@@ -2033,7 +2045,7 @@ impl AgentPanel {
container.into_any_element()
}
} else {
- Label::new(thread_view.read(cx).title(cx))
+ Label::new(server_view.read(cx).title(cx))
.color(Color::Muted)
.truncate()
.into_any_element()
@@ -2171,12 +2183,12 @@ impl AgentPanel {
};
let thread_view = match &self.active_view {
- ActiveView::AgentThread { thread_view } => Some(thread_view.clone()),
+ ActiveView::AgentThread { server_view } => Some(server_view.clone()),
_ => None,
};
let thread_with_messages = match &self.active_view {
- ActiveView::AgentThread { thread_view } => {
- thread_view.read(cx).has_user_submitted_prompt(cx)
+ ActiveView::AgentThread { server_view } => {
+ server_view.read(cx).has_user_submitted_prompt(cx)
}
_ => false,
};
@@ -2339,7 +2351,7 @@ impl AgentPanel {
};
let active_thread = match &self.active_view {
- ActiveView::AgentThread { thread_view } => thread_view.read(cx).as_native_thread(cx),
+ ActiveView::AgentThread { server_view } => server_view.read(cx).as_native_thread(cx),
ActiveView::Uninitialized
| ActiveView::TextThread { .. }
| ActiveView::History { .. }
@@ -2773,8 +2785,8 @@ impl AgentPanel {
ActiveView::Uninitialized | ActiveView::History { .. } | ActiveView::Configuration => {
false
}
- ActiveView::AgentThread { thread_view, .. }
- if thread_view.read(cx).as_native_thread(cx).is_none() =>
+ ActiveView::AgentThread { server_view, .. }
+ if server_view.read(cx).as_native_thread(cx).is_none() =>
{
false
}
@@ -3046,8 +3058,8 @@ impl AgentPanel {
cx: &mut Context<Self>,
) {
match &self.active_view {
- ActiveView::AgentThread { thread_view } => {
- thread_view.update(cx, |thread_view, cx| {
+ ActiveView::AgentThread { server_view } => {
+ server_view.update(cx, |thread_view, cx| {
thread_view.insert_dragged_files(paths, added_worktrees, window, cx);
});
}
@@ -3165,8 +3177,8 @@ impl Render for AgentPanel {
match &self.active_view {
ActiveView::Uninitialized => parent,
- ActiveView::AgentThread { thread_view, .. } => parent
- .child(thread_view.clone())
+ ActiveView::AgentThread { server_view, .. } => parent
+ .child(server_view.clone())
.child(self.render_drag_target(cx)),
ActiveView::History { kind } => match kind {
HistoryKind::AgentThreads => parent.child(self.acp_history.clone()),
@@ -37,6 +37,7 @@ pub enum AgentThreadStatus {
struct AgentThreadInfo {
title: SharedString,
status: AgentThreadStatus,
+ icon: IconName,
}
const LAST_THREAD_TITLES_KEY: &str = "sidebar-last-thread-titles";
@@ -99,6 +100,7 @@ impl WorkspaceThreadEntry {
Some(AgentThreadInfo {
title: SharedString::from(title.clone()),
status: AgentThreadStatus::Completed,
+ icon: IconName::ZedAgent,
})
});
@@ -112,14 +114,23 @@ impl WorkspaceThreadEntry {
fn thread_info(workspace: &Entity<Workspace>, cx: &App) -> Option<AgentThreadInfo> {
let agent_panel = workspace.read(cx).panel::<AgentPanel>(cx)?;
- let thread = agent_panel.read(cx).active_agent_thread(cx)?;
- let thread_ref = thread.read(cx);
- let title = thread_ref.title();
- let status = match thread_ref.status() {
+ let agent_panel_ref = agent_panel.read(cx);
+
+ let thread_view = agent_panel_ref.as_active_thread_view(cx)?.read(cx);
+ let thread = thread_view.thread.read(cx);
+
+ let icon = thread_view.agent_icon;
+ let title = thread.title();
+
+ let status = match thread.status() {
ThreadStatus::Generating => AgentThreadStatus::Running,
ThreadStatus::Idle => AgentThreadStatus::Completed,
};
- Some(AgentThreadInfo { title, status })
+ Some(AgentThreadInfo {
+ title,
+ status,
+ icon,
+ })
}
}
@@ -594,7 +605,6 @@ impl PickerDelegate for WorkspacePickerDelegate {
let workspace_index = thread_entry.index;
let multi_workspace = self.multi_workspace.clone();
let workspace_count = self.multi_workspace.read(cx).workspaces().len();
- let is_active = self.active_workspace_index == workspace_index;
let is_hovered = self.hovered_thread_item == Some(workspace_index);
let remove_btn = IconButton::new(
@@ -628,11 +638,11 @@ impl PickerDelegate for WorkspacePickerDelegate {
("workspace-item", thread_entry.index),
thread_subtitle.unwrap_or("New Thread".into()),
)
- .icon(if is_active {
- IconName::FolderOpen
- } else {
- IconName::Folder
- })
+ .icon(
+ thread_info
+ .as_ref()
+ .map_or(IconName::ZedAgent, |info| info.icon),
+ )
.running(running)
.generation_done(has_notification)
.selected(selected)
@@ -859,8 +869,14 @@ impl Sidebar {
title: SharedString,
status: AgentThreadStatus,
) {
- self.test_thread_infos
- .insert(index, AgentThreadInfo { title, status });
+ self.test_thread_infos.insert(
+ index,
+ AgentThreadInfo {
+ title,
+ status,
+ icon: IconName::ZedAgent,
+ },
+ );
}
#[cfg(any(test, feature = "test-support"))]