From 5db8d6d1bc88ccd8ae7f4fb254b26a12f9d67cc3 Mon Sep 17 00:00:00 2001 From: Ben Brandt Date: Fri, 6 Mar 2026 14:13:23 +0100 Subject: [PATCH] agent: Only use AgentSessionInfo in history (#50933) Previously we required AgentSessionInfo all over the place, which meant there were lots of unnecessary fake ones created all over the place. Made the methods and functions only take the data they need so we only use these in history contexts now, as intended. Release Notes: - N/A --- crates/acp_thread/src/acp_thread.rs | 172 ++++++++--------- crates/acp_thread/src/connection.rs | 9 +- crates/agent/src/agent.rs | 6 +- crates/agent_servers/src/acp.rs | 42 ++--- crates/agent_ui/src/agent_panel.rs | 117 +++++++----- crates/agent_ui/src/agent_ui.rs | 6 +- crates/agent_ui/src/completion_provider.rs | 74 +++++--- crates/agent_ui/src/connection_view.rs | 174 ++++++++++-------- .../src/connection_view/thread_view.rs | 32 +--- crates/agent_ui/src/message_editor.rs | 46 ++--- crates/agent_ui/src/thread_history.rs | 12 +- crates/agent_ui/src/ui/mention_crease.rs | 13 +- crates/sidebar/src/sidebar.rs | 8 +- crates/zed/src/main.rs | 16 +- 14 files changed, 391 insertions(+), 336 deletions(-) diff --git a/crates/acp_thread/src/acp_thread.rs b/crates/acp_thread/src/acp_thread.rs index bffddde099c05438bb81c8bbbe99e3c77a5113e6..58252eaddca553eb1da4c960a829a88afb9eb497 100644 --- a/crates/acp_thread/src/acp_thread.rs +++ b/crates/acp_thread/src/acp_thread.rs @@ -952,6 +952,8 @@ struct RunningTurn { } pub struct AcpThread { + session_id: acp::SessionId, + cwd: Option, parent_session_id: Option, title: SharedString, provisional_title: Option, @@ -963,7 +965,6 @@ pub struct AcpThread { turn_id: u32, running_turn: Option, connection: Rc, - session_id: acp::SessionId, token_usage: Option, prompt_capabilities: acp::PromptCapabilities, _observe_prompt_capabilities: Task>, @@ -1048,87 +1049,6 @@ pub enum TerminalProviderCommand { }, } -impl AcpThread { - pub fn on_terminal_provider_event( - &mut self, - event: TerminalProviderEvent, - cx: &mut Context, - ) { - match event { - TerminalProviderEvent::Created { - terminal_id, - label, - cwd, - output_byte_limit, - terminal, - } => { - let entity = self.register_terminal_created( - terminal_id.clone(), - label, - cwd, - output_byte_limit, - terminal, - cx, - ); - - if let Some(mut chunks) = self.pending_terminal_output.remove(&terminal_id) { - for data in chunks.drain(..) { - entity.update(cx, |term, cx| { - term.inner().update(cx, |inner, cx| { - inner.write_output(&data, cx); - }) - }); - } - } - - if let Some(_status) = self.pending_terminal_exit.remove(&terminal_id) { - entity.update(cx, |_term, cx| { - cx.notify(); - }); - } - - cx.notify(); - } - TerminalProviderEvent::Output { terminal_id, data } => { - if let Some(entity) = self.terminals.get(&terminal_id) { - entity.update(cx, |term, cx| { - term.inner().update(cx, |inner, cx| { - inner.write_output(&data, cx); - }) - }); - } else { - self.pending_terminal_output - .entry(terminal_id) - .or_default() - .push(data); - } - } - TerminalProviderEvent::TitleChanged { terminal_id, title } => { - if let Some(entity) = self.terminals.get(&terminal_id) { - entity.update(cx, |term, cx| { - term.inner().update(cx, |inner, cx| { - inner.breadcrumb_text = title; - cx.emit(::terminal::Event::BreadcrumbsChanged); - }) - }); - } - } - TerminalProviderEvent::Exit { - terminal_id, - status, - } => { - if let Some(entity) = self.terminals.get(&terminal_id) { - entity.update(cx, |_term, cx| { - cx.notify(); - }); - } else { - self.pending_terminal_exit.insert(terminal_id, status); - } - } - } - } -} - #[derive(PartialEq, Eq, Debug)] pub enum ThreadStatus { Idle, @@ -1175,6 +1095,7 @@ impl AcpThread { pub fn new( parent_session_id: Option, title: impl Into, + cwd: Option, connection: Rc, project: Entity, action_log: Entity, @@ -1195,6 +1116,7 @@ impl AcpThread { Self { parent_session_id, + cwd, action_log, shared_buffers: Default::default(), entries: Default::default(), @@ -1268,6 +1190,10 @@ impl AcpThread { &self.session_id } + pub fn cwd(&self) -> Option<&PathBuf> { + self.cwd.as_ref() + } + pub fn status(&self) -> ThreadStatus { if self.running_turn.is_some() { ThreadStatus::Generating @@ -2624,6 +2550,85 @@ impl AcpThread { } } } + + pub fn on_terminal_provider_event( + &mut self, + event: TerminalProviderEvent, + cx: &mut Context, + ) { + match event { + TerminalProviderEvent::Created { + terminal_id, + label, + cwd, + output_byte_limit, + terminal, + } => { + let entity = self.register_terminal_created( + terminal_id.clone(), + label, + cwd, + output_byte_limit, + terminal, + cx, + ); + + if let Some(mut chunks) = self.pending_terminal_output.remove(&terminal_id) { + for data in chunks.drain(..) { + entity.update(cx, |term, cx| { + term.inner().update(cx, |inner, cx| { + inner.write_output(&data, cx); + }) + }); + } + } + + if let Some(_status) = self.pending_terminal_exit.remove(&terminal_id) { + entity.update(cx, |_term, cx| { + cx.notify(); + }); + } + + cx.notify(); + } + TerminalProviderEvent::Output { terminal_id, data } => { + if let Some(entity) = self.terminals.get(&terminal_id) { + entity.update(cx, |term, cx| { + term.inner().update(cx, |inner, cx| { + inner.write_output(&data, cx); + }) + }); + } else { + self.pending_terminal_output + .entry(terminal_id) + .or_default() + .push(data); + } + } + TerminalProviderEvent::TitleChanged { terminal_id, title } => { + if let Some(entity) = self.terminals.get(&terminal_id) { + entity.update(cx, |term, cx| { + term.inner().update(cx, |inner, cx| { + inner.breadcrumb_text = title; + cx.emit(::terminal::Event::BreadcrumbsChanged); + }) + }); + } + } + TerminalProviderEvent::Exit { + terminal_id, + status, + } => { + if let Some(entity) = self.terminals.get(&terminal_id) { + entity.update(cx, |_term, cx| { + cx.notify(); + }); + } else { + self.pending_terminal_exit.insert(terminal_id, status); + } + } + } + } } fn markdown_for_raw_output( @@ -3988,7 +3993,7 @@ mod tests { fn new_session( self: Rc, project: Entity, - _cwd: &Path, + cwd: &Path, cx: &mut App, ) -> Task>> { let session_id = acp::SessionId::new( @@ -4003,6 +4008,7 @@ mod tests { AcpThread::new( None, "Test", + Some(cwd.to_path_buf()), self.clone(), project, action_log, diff --git a/crates/acp_thread/src/connection.rs b/crates/acp_thread/src/connection.rs index 773508f1c898c39d713d5779c82384caf8f190ec..644986bc15eccbe7d2be32ea5ad6e422db930541 100644 --- a/crates/acp_thread/src/connection.rs +++ b/crates/acp_thread/src/connection.rs @@ -45,9 +45,10 @@ pub trait AgentConnection { /// Load an existing session by ID. fn load_session( self: Rc, - _session: AgentSessionInfo, + _session_id: acp::SessionId, _project: Entity, _cwd: &Path, + _title: Option, _cx: &mut App, ) -> Task>> { Task::ready(Err(anyhow::Error::msg("Loading sessions is not supported"))) @@ -71,9 +72,10 @@ pub trait AgentConnection { /// Resume an existing session by ID without replaying previous messages. fn resume_session( self: Rc, - _session: AgentSessionInfo, + _session_id: acp::SessionId, _project: Entity, _cwd: &Path, + _title: Option, _cx: &mut App, ) -> Task>> { Task::ready(Err(anyhow::Error::msg( @@ -619,7 +621,7 @@ mod test_support { fn new_session( self: Rc, project: Entity, - _cwd: &Path, + cwd: &Path, cx: &mut gpui::App, ) -> Task>> { static NEXT_SESSION_ID: AtomicUsize = AtomicUsize::new(0); @@ -630,6 +632,7 @@ mod test_support { AcpThread::new( None, "Test", + Some(cwd.to_path_buf()), self.clone(), project, action_log, diff --git a/crates/agent/src/agent.rs b/crates/agent/src/agent.rs index a93c2d2062b7472f8ed94a6ea0947a685edd204f..d9ad55c7127983516dbb5fe0392ef135186b79f7 100644 --- a/crates/agent/src/agent.rs +++ b/crates/agent/src/agent.rs @@ -361,6 +361,7 @@ impl NativeAgent { let mut acp_thread = acp_thread::AcpThread::new( parent_session_id, title, + None, connection, project.clone(), action_log.clone(), @@ -1277,13 +1278,14 @@ impl acp_thread::AgentConnection for NativeAgentConnection { fn load_session( self: Rc, - session: AgentSessionInfo, + session_id: acp::SessionId, _project: Entity, _cwd: &Path, + _title: Option, cx: &mut App, ) -> Task>> { self.0 - .update(cx, |agent, cx| agent.open_thread(session.session_id, cx)) + .update(cx, |agent, cx| agent.open_thread(session_id, cx)) } fn supports_close_session(&self) -> bool { diff --git a/crates/agent_servers/src/acp.rs b/crates/agent_servers/src/acp.rs index c63e4fab2201671fa6448e9d58f6c925c2c91cd8..ceceb5b8ae02a0674b27e0fa18244a94f2b409de 100644 --- a/crates/agent_servers/src/acp.rs +++ b/crates/agent_servers/src/acp.rs @@ -385,7 +385,7 @@ impl AgentConnection for AcpConnection { cx.spawn(async move |cx| { let response = self.connection - .new_session(acp::NewSessionRequest::new(cwd).mcp_servers(mcp_servers)) + .new_session(acp::NewSessionRequest::new(cwd.clone()).mcp_servers(mcp_servers)) .await .map_err(map_acp_error)?; @@ -560,6 +560,7 @@ impl AgentConnection for AcpConnection { AcpThread::new( None, self.display_name.clone(), + Some(cwd), self.clone(), project, action_log, @@ -598,9 +599,10 @@ impl AgentConnection for AcpConnection { fn load_session( self: Rc, - session: AgentSessionInfo, + session_id: acp::SessionId, project: Entity, cwd: &Path, + title: Option, cx: &mut App, ) -> Task>> { if !self.agent_capabilities.load_session { @@ -612,25 +614,23 @@ impl AgentConnection for AcpConnection { let cwd = cwd.to_path_buf(); let mcp_servers = mcp_servers_for_project(&project, cx); let action_log = cx.new(|_| ActionLog::new(project.clone())); - let title = session - .title - .clone() - .unwrap_or_else(|| self.display_name.clone()); + let title = title.unwrap_or_else(|| self.display_name.clone()); let thread: Entity = cx.new(|cx| { AcpThread::new( None, title, + Some(cwd.clone()), self.clone(), project, action_log, - session.session_id.clone(), + session_id.clone(), watch::Receiver::constant(self.agent_capabilities.prompt_capabilities.clone()), cx, ) }); self.sessions.borrow_mut().insert( - session.session_id.clone(), + session_id.clone(), AcpSession { thread: thread.downgrade(), suppress_abort_err: false, @@ -644,21 +644,20 @@ impl AgentConnection for AcpConnection { let response = match self .connection .load_session( - acp::LoadSessionRequest::new(session.session_id.clone(), cwd) - .mcp_servers(mcp_servers), + acp::LoadSessionRequest::new(session_id.clone(), cwd).mcp_servers(mcp_servers), ) .await { Ok(response) => response, Err(err) => { - self.sessions.borrow_mut().remove(&session.session_id); + self.sessions.borrow_mut().remove(&session_id); return Err(map_acp_error(err)); } }; let (modes, models, config_options) = config_state(response.modes, response.models, response.config_options); - if let Some(session) = self.sessions.borrow_mut().get_mut(&session.session_id) { + if let Some(session) = self.sessions.borrow_mut().get_mut(&session_id) { session.session_modes = modes; session.models = models; session.config_options = config_options.map(ConfigOptions::new); @@ -670,9 +669,10 @@ impl AgentConnection for AcpConnection { fn resume_session( self: Rc, - session: AgentSessionInfo, + session_id: acp::SessionId, project: Entity, cwd: &Path, + title: Option, cx: &mut App, ) -> Task>> { if self @@ -689,25 +689,23 @@ impl AgentConnection for AcpConnection { let cwd = cwd.to_path_buf(); let mcp_servers = mcp_servers_for_project(&project, cx); let action_log = cx.new(|_| ActionLog::new(project.clone())); - let title = session - .title - .clone() - .unwrap_or_else(|| self.display_name.clone()); + let title = title.unwrap_or_else(|| self.display_name.clone()); let thread: Entity = cx.new(|cx| { AcpThread::new( None, title, + Some(cwd.clone()), self.clone(), project, action_log, - session.session_id.clone(), + session_id.clone(), watch::Receiver::constant(self.agent_capabilities.prompt_capabilities.clone()), cx, ) }); self.sessions.borrow_mut().insert( - session.session_id.clone(), + session_id.clone(), AcpSession { thread: thread.downgrade(), suppress_abort_err: false, @@ -721,21 +719,21 @@ impl AgentConnection for AcpConnection { let response = match self .connection .resume_session( - acp::ResumeSessionRequest::new(session.session_id.clone(), cwd) + acp::ResumeSessionRequest::new(session_id.clone(), cwd) .mcp_servers(mcp_servers), ) .await { Ok(response) => response, Err(err) => { - self.sessions.borrow_mut().remove(&session.session_id); + self.sessions.borrow_mut().remove(&session_id); return Err(map_acp_error(err)); } }; let (modes, models, config_options) = config_state(response.modes, response.models, response.config_options); - if let Some(session) = self.sessions.borrow_mut().get_mut(&session.session_id) { + if let Some(session) = self.sessions.borrow_mut().get_mut(&session_id) { session.session_modes = modes; session.models = models; session.config_options = config_options.map(ConfigOptions::new); diff --git a/crates/agent_ui/src/agent_panel.rs b/crates/agent_ui/src/agent_panel.rs index 45c22856c721fdfe165389e1775617afa7ffadb7..b53cb003969f8519f584aef1269554f4277e31f6 100644 --- a/crates/agent_ui/src/agent_panel.rs +++ b/crates/agent_ui/src/agent_panel.rs @@ -9,7 +9,7 @@ use std::{ time::Duration, }; -use acp_thread::{AcpThread, AgentSessionInfo, MentionUri, ThreadStatus}; +use acp_thread::{AcpThread, MentionUri, ThreadStatus}; use agent::{ContextServerRegistry, SharedThread, ThreadStore}; use agent_client_protocol as acp; use agent_servers::AgentServer; @@ -191,7 +191,15 @@ pub fn init(cx: &mut App) { if let Some(panel) = workspace.panel::(cx) { workspace.focus_panel::(window, cx); panel.update(cx, |panel, cx| { - panel.external_thread(action.agent.clone(), None, None, window, cx) + panel.external_thread( + action.agent.clone(), + None, + None, + None, + None, + window, + cx, + ) }); } }) @@ -322,6 +330,8 @@ pub fn init(cx: &mut App) { panel.update(cx, |panel, cx| { panel.external_thread( + None, + None, None, None, Some(AgentInitialContent::ContentBlock { @@ -715,16 +725,9 @@ impl AgentPanel { if let Some(thread_info) = last_active_thread { let agent_type = thread_info.agent_type.clone(); - let session_info = AgentSessionInfo { - session_id: acp::SessionId::new(thread_info.session_id), - cwd: thread_info.cwd, - title: thread_info.title.map(SharedString::from), - updated_at: None, - meta: None, - }; panel.update(cx, |panel, cx| { panel.selected_agent = agent_type; - panel.load_agent_thread(session_info, window, cx); + panel.load_agent_thread(thread_info.session_id.into(), thread_info.cwd, thread_info.title.map(SharedString::from), window, cx); }); } panel @@ -761,7 +764,13 @@ impl AgentPanel { window, |this, _, event, window, cx| match event { ThreadHistoryEvent::Open(thread) => { - this.load_agent_thread(thread.clone(), window, cx); + this.load_agent_thread( + thread.session_id.clone(), + thread.cwd.clone(), + thread.title.clone(), + window, + cx, + ); } }, ) @@ -950,13 +959,17 @@ impl AgentPanel { pub fn open_thread( &mut self, - thread: AgentSessionInfo, + session_id: acp::SessionId, + cwd: Option, + title: Option, window: &mut Window, cx: &mut Context, ) { self.external_thread( Some(crate::ExternalAgent::NativeAgent), - Some(thread), + Some(session_id), + cwd, + title, None, window, cx, @@ -1015,7 +1028,12 @@ impl AgentPanel { self.external_thread( Some(ExternalAgent::NativeAgent), None, - Some(AgentInitialContent::ThreadSummary(thread)), + None, + None, + Some(AgentInitialContent::ThreadSummary { + session_id: thread.session_id, + title: thread.title, + }), window, cx, ); @@ -1067,7 +1085,9 @@ impl AgentPanel { fn external_thread( &mut self, agent_choice: Option, - resume_thread: Option, + resume_session_id: Option, + cwd: Option, + title: Option, initial_content: Option, window: &mut Window, cx: &mut Context, @@ -1129,7 +1149,9 @@ impl AgentPanel { this.update_in(cx, |agent_panel, window, cx| { agent_panel.create_external_thread( server, - resume_thread, + resume_session_id, + cwd, + title, initial_content, workspace, project, @@ -1548,16 +1570,8 @@ impl AgentPanel { }) .await?; - let thread_metadata = acp_thread::AgentSessionInfo { - session_id, - cwd: None, - title: Some(title), - updated_at: Some(chrono::Utc::now()), - meta: None, - }; - this.update_in(cx, |this, window, cx| { - this.open_thread(thread_metadata, window, cx); + this.open_thread(session_id, None, Some(title), window, cx); })?; this.update_in(cx, |_, _window, cx| { @@ -1839,7 +1853,13 @@ impl AgentPanel { let entry = entry.clone(); panel .update(cx, move |this, cx| { - this.load_agent_thread(entry.clone(), window, cx); + this.load_agent_thread( + entry.session_id.clone(), + entry.cwd.clone(), + entry.title.clone(), + window, + cx, + ); }) .ok(); } @@ -1981,6 +2001,8 @@ impl AgentPanel { cx: &mut Context, ) { self.external_thread( + None, + None, None, None, initial_text.map(|text| AgentInitialContent::ContentBlock { @@ -2006,6 +2028,8 @@ impl AgentPanel { Some(crate::ExternalAgent::NativeAgent), None, None, + None, + None, window, cx, ), @@ -2013,6 +2037,8 @@ impl AgentPanel { Some(crate::ExternalAgent::Custom { name }), None, None, + None, + None, window, cx, ), @@ -2021,11 +2047,12 @@ impl AgentPanel { pub fn load_agent_thread( &mut self, - thread: AgentSessionInfo, + session_id: acp::SessionId, + cwd: Option, + title: Option, window: &mut Window, cx: &mut Context, ) { - let session_id = thread.session_id.clone(); if let Some(server_view) = self.background_threads.remove(&session_id) { self.set_active_view(ActiveView::AgentThread { server_view }, true, window, cx); return; @@ -2059,13 +2086,15 @@ impl AgentPanel { let Some(agent) = self.selected_external_agent() else { return; }; - self.external_thread(Some(agent), Some(thread), None, window, cx); + self.external_thread(Some(agent), Some(session_id), cwd, title, None, window, cx); } pub(crate) fn create_external_thread( &mut self, server: Rc, - resume_thread: Option, + resume_session_id: Option, + cwd: Option, + title: Option, initial_content: Option, workspace: WeakEntity, project: Entity, @@ -2087,7 +2116,9 @@ impl AgentPanel { let server_view = cx.new(|cx| { crate::ConnectionView::new( server, - resume_thread, + resume_session_id, + cwd, + title, initial_content, workspace.clone(), project, @@ -2598,7 +2629,15 @@ impl AgentPanel { workspace.focus_panel::(window, cx); if let Some(panel) = workspace.panel::(cx) { panel.update(cx, |panel, cx| { - panel.external_thread(None, None, Some(initial_content), window, cx); + panel.external_thread( + None, + None, + None, + None, + Some(initial_content), + window, + cx, + ); }); } }); @@ -4466,7 +4505,7 @@ impl AgentPanel { }; self.create_external_thread( - server, None, None, workspace, project, ext_agent, window, cx, + server, None, None, None, None, workspace, project, ext_agent, window, cx, ); } @@ -4877,17 +4916,7 @@ mod tests { // Load thread A back via load_agent_thread โ€” should promote from background. panel.update_in(&mut cx, |panel, window, cx| { - panel.load_agent_thread( - AgentSessionInfo { - session_id: session_id_a.clone(), - cwd: None, - title: None, - updated_at: None, - meta: None, - }, - window, - cx, - ); + panel.load_agent_thread(session_id_a.clone(), None, None, window, cx); }); // Thread A should now be the active view, promoted from background. diff --git a/crates/agent_ui/src/agent_ui.rs b/crates/agent_ui/src/agent_ui.rs index caecce3d0282e33daf8164fb17f48bd53be60b9f..eee7a61576e4f4dbdb56c98b497b50cc59c0053d 100644 --- a/crates/agent_ui/src/agent_ui.rs +++ b/crates/agent_ui/src/agent_ui.rs @@ -35,6 +35,7 @@ mod ui; use std::rc::Rc; use std::sync::Arc; +use agent_client_protocol as acp; use agent_settings::{AgentProfileId, AgentSettings}; use assistant_slash_command::SlashCommandRegistry; use client::Client; @@ -241,7 +242,10 @@ pub enum StartThreadIn { /// Content to initialize new external agent with. pub enum AgentInitialContent { - ThreadSummary(acp_thread::AgentSessionInfo), + ThreadSummary { + session_id: acp::SessionId, + title: Option, + }, ContentBlock { blocks: Vec, auto_submit: bool, diff --git a/crates/agent_ui/src/completion_provider.rs b/crates/agent_ui/src/completion_provider.rs index 30778909b2c9a91dab0b20417e973b7e83ea6a17..40ad7bc729269d5dae3364ecf3e0de6e5ee5b0ec 100644 --- a/crates/agent_ui/src/completion_provider.rs +++ b/crates/agent_ui/src/completion_provider.rs @@ -5,7 +5,8 @@ use std::sync::Arc; use std::sync::atomic::AtomicBool; use crate::ThreadHistory; -use acp_thread::{AgentSessionInfo, MentionUri}; +use acp_thread::MentionUri; +use agent_client_protocol as acp; use anyhow::Result; use editor::{ CompletionProvider, Editor, ExcerptId, code_context_menus::COMPLETION_MENU_MAX_WIDTH, @@ -144,8 +145,8 @@ impl PromptContextType { pub(crate) enum Match { File(FileMatch), Symbol(SymbolMatch), - Thread(AgentSessionInfo), - RecentThread(AgentSessionInfo), + Thread(SessionMatch), + RecentThread(SessionMatch), Fetch(SharedString), Rules(RulesContextEntry), Entry(EntryMatch), @@ -165,15 +166,19 @@ impl Match { } } +#[derive(Debug, Clone)] +pub struct SessionMatch { + session_id: acp::SessionId, + title: SharedString, +} + pub struct EntryMatch { mat: Option, entry: PromptContextEntry, } -fn session_title(session: &AgentSessionInfo) -> SharedString { - session - .title - .clone() +fn session_title(title: Option) -> SharedString { + title .filter(|title| !title.is_empty()) .unwrap_or_else(|| SharedString::new_static("New Thread")) } @@ -266,7 +271,8 @@ impl PromptCompletionProvider { } fn completion_for_thread( - thread_entry: AgentSessionInfo, + session_id: acp::SessionId, + title: Option, source_range: Range, recent: bool, source: Arc, @@ -275,9 +281,9 @@ impl PromptCompletionProvider { workspace: Entity, cx: &mut App, ) -> Completion { - let title = session_title(&thread_entry); + let title = session_title(title); let uri = MentionUri::Thread { - id: thread_entry.session_id, + id: session_id, name: title.to_string(), }; @@ -841,7 +847,15 @@ impl PromptCompletionProvider { Some(PromptContextType::Thread) => { if let Some(history) = self.history.upgrade() { - let sessions = history.read(cx).sessions().to_vec(); + let sessions = history + .read(cx) + .sessions() + .iter() + .map(|session| SessionMatch { + session_id: session.session_id.clone(), + title: session_title(session.title.clone()), + }) + .collect::>(); let search_task = filter_sessions_by_query(query, cancellation_flag, sessions, cx); cx.spawn(async move |_cx| { @@ -1018,15 +1032,18 @@ impl PromptCompletionProvider { .read(cx) .sessions() .into_iter() + .map(|session| SessionMatch { + session_id: session.session_id.clone(), + title: session_title(session.title.clone()), + }) .filter(|session| { let uri = MentionUri::Thread { id: session.session_id.clone(), - name: session_title(session).to_string(), + name: session.title.to_string(), }; !mentions.contains(&uri) }) .take(RECENT_COUNT) - .cloned() .map(Match::RecentThread), ); return Task::ready(recent); @@ -1298,7 +1315,8 @@ impl CompletionProvider for PromptCompletio ) } Match::Thread(thread) => Some(Self::completion_for_thread( - thread, + thread.session_id, + Some(thread.title), source_range.clone(), false, source.clone(), @@ -1308,7 +1326,8 @@ impl CompletionProvider for PromptCompletio cx, )), Match::RecentThread(thread) => Some(Self::completion_for_thread( - thread, + thread.session_id, + Some(thread.title), source_range.clone(), true, source.clone(), @@ -1878,9 +1897,9 @@ pub(crate) fn search_symbols( fn filter_sessions_by_query( query: String, cancellation_flag: Arc, - sessions: Vec, + sessions: Vec, cx: &mut App, -) -> Task> { +) -> Task> { if query.is_empty() { return Task::ready(sessions); } @@ -1893,10 +1912,13 @@ fn filter_sessions_by_query( async fn filter_sessions( query: String, cancellation_flag: Arc, - sessions: Vec, + sessions: Vec, executor: BackgroundExecutor, -) -> Vec { - let titles = sessions.iter().map(session_title).collect::>(); +) -> Vec { + let titles = sessions + .iter() + .map(|session| session.title.clone()) + .collect::>(); let candidates = titles .iter() .enumerate() @@ -2338,10 +2360,14 @@ mod tests { #[gpui::test] async fn test_filter_sessions_by_query(cx: &mut TestAppContext) { - let mut alpha = AgentSessionInfo::new("session-alpha"); - alpha.title = Some("Alpha Session".into()); - let mut beta = AgentSessionInfo::new("session-beta"); - beta.title = Some("Beta Session".into()); + let alpha = SessionMatch { + session_id: acp::SessionId::new("session-alpha"), + title: "Alpha Session".into(), + }; + let beta = SessionMatch { + session_id: acp::SessionId::new("session-beta"), + title: "Beta Session".into(), + }; let sessions = vec![alpha.clone(), beta]; diff --git a/crates/agent_ui/src/connection_view.rs b/crates/agent_ui/src/connection_view.rs index 84aa9e9c2b1959ba5c068e3cfa117506ac459ff0..48aa88a95ba3c1fd440c59768f9328719f02aa70 100644 --- a/crates/agent_ui/src/connection_view.rs +++ b/crates/agent_ui/src/connection_view.rs @@ -39,7 +39,7 @@ use prompt_store::{PromptId, PromptStore}; use rope::Point; use settings::{NotifyWhenAgentWaiting, Settings as _, SettingsStore}; use std::cell::RefCell; -use std::path::Path; +use std::path::{Path, PathBuf}; use std::sync::Arc; use std::time::Instant; use std::{collections::BTreeMap, rc::Rc, time::Duration}; @@ -470,7 +470,9 @@ impl ConnectedServerState { impl ConnectionView { pub fn new( agent: Rc, - resume_thread: Option, + resume_session_id: Option, + cwd: Option, + title: Option, initial_content: Option, workspace: WeakEntity, project: Entity, @@ -514,7 +516,9 @@ impl ConnectionView { prompt_store, server_state: Self::initial_state( agent.clone(), - resume_thread, + resume_session_id, + cwd, + title, project, initial_content, window, @@ -540,13 +544,23 @@ impl ConnectionView { } fn reset(&mut self, window: &mut Window, cx: &mut Context) { - let resume_thread_metadata = self + let (resume_session_id, cwd, title) = self .active_thread() - .and_then(|thread| thread.read(cx).resume_thread_metadata.clone()); + .map(|thread_view| { + let thread = thread_view.read(cx).thread.read(cx); + ( + Some(thread.session_id().clone()), + thread.cwd().cloned(), + Some(thread.title()), + ) + }) + .unwrap_or((None, None, None)); let state = Self::initial_state( self.agent.clone(), - resume_thread_metadata, + resume_session_id, + cwd, + title, self.project.clone(), None, window, @@ -570,15 +584,14 @@ impl ConnectionView { fn initial_state( agent: Rc, - resume_thread: Option, + resume_session_id: Option, + cwd: Option, + title: Option, project: Entity, initial_content: Option, window: &mut Window, cx: &mut Context, ) -> ServerState { - let session_id = resume_thread - .as_ref() - .map(|thread| thread.session_id.clone()); if project.read(cx).is_via_collab() && agent.clone().downcast::().is_none() { @@ -586,7 +599,7 @@ impl ConnectionView { error: LoadError::Other( "External agents are not yet supported in shared projects.".into(), ), - session_id, + session_id: resume_session_id.clone(), }; } let mut worktrees = project.read(cx).visible_worktrees(cx).collect::>(); @@ -608,28 +621,22 @@ impl ConnectionView { } }) .collect(); - let session_cwd = resume_thread - .as_ref() - .and_then(|resume| { - resume - .cwd - .as_ref() - .filter(|cwd| { - // Validate with the normalized path (rejects `..` traversals), - // but return the original cwd to preserve its path separators. - // On Windows, `normalize_lexically` rebuilds the path with - // backslashes via `PathBuf::push`, which would corrupt - // forward-slash Linux paths used by WSL agents. - util::paths::normalize_lexically(cwd) - .ok() - .is_some_and(|normalized| { - worktree_roots - .iter() - .any(|root| normalized.starts_with(root.as_ref())) - }) + let session_cwd = cwd + .filter(|cwd| { + // Validate with the normalized path (rejects `..` traversals), + // but return the original cwd to preserve its path separators. + // On Windows, `normalize_lexically` rebuilds the path with + // backslashes via `PathBuf::push`, which would corrupt + // forward-slash Linux paths used by WSL agents. + util::paths::normalize_lexically(cwd) + .ok() + .is_some_and(|normalized| { + worktree_roots + .iter() + .any(|root| normalized.starts_with(root.as_ref())) }) - .map(|path| Arc::from(path.as_path())) }) + .map(|path| path.into()) .or_else(|| worktree_roots.first().cloned()) .unwrap_or_else(|| paths::home_dir().as_path().into()); @@ -643,7 +650,7 @@ impl ConnectionView { ); let connect_task = agent.connect(delegate, cx); - let load_session_id = session_id.clone(); + let load_session_id = resume_session_id.clone(); let load_task = cx.spawn_in(window, async move |this, cx| { let connection = match connect_task.await { Ok(connection) => connection, @@ -666,17 +673,25 @@ impl ConnectionView { telemetry::event!("Agent Thread Started", agent = connection.telemetry_id()); let mut resumed_without_history = false; - let result = if let Some(resume) = resume_thread.clone() { + let result = if let Some(session_id) = load_session_id.clone() { cx.update(|_, cx| { if connection.supports_load_session() { - connection - .clone() - .load_session(resume, project.clone(), &session_cwd, cx) + connection.clone().load_session( + session_id, + project.clone(), + &session_cwd, + title, + cx, + ) } else if connection.supports_resume_session() { resumed_without_history = true; - connection - .clone() - .resume_session(resume, project.clone(), &session_cwd, cx) + connection.clone().resume_session( + session_id, + project.clone(), + &session_cwd, + title, + cx, + ) } else { Task::ready(Err(anyhow!(LoadError::Other( "Loading or resuming sessions is not supported by this agent.".into() @@ -732,7 +747,6 @@ impl ConnectionView { thread, conversation.clone(), resumed_without_history, - resume_thread, initial_content, window, cx, @@ -803,7 +817,7 @@ impl ConnectionView { }); LoadingView { - session_id, + session_id: resume_session_id, title: "Loadingโ€ฆ".into(), _load_task: load_task, _update_title_task: update_title_task, @@ -819,7 +833,6 @@ impl ConnectionView { thread: Entity, conversation: Entity, resumed_without_history: bool, - resume_thread: Option, initial_content: Option, window: &mut Window, cx: &mut Context, @@ -1002,7 +1015,6 @@ impl ConnectionView { prompt_capabilities, available_commands, resumed_without_history, - resume_thread, self.project.downgrade(), self.thread_store.clone(), self.history.clone(), @@ -1680,9 +1692,10 @@ impl ConnectionView { let cwd = root_dir.unwrap_or_else(|| paths::home_dir().as_path().into()); let subagent_thread_task = connected.connection.clone().load_session( - AgentSessionInfo::new(subagent_id.clone()), + subagent_id.clone(), self.project.clone(), &cwd, + None, cx, ); @@ -1704,7 +1717,6 @@ impl ConnectionView { conversation, false, None, - None, window, cx, ); @@ -2606,10 +2618,10 @@ impl ConnectionView { }) } - pub fn delete_history_entry(&mut self, entry: AgentSessionInfo, cx: &mut Context) { - let task = self.history.update(cx, |history, cx| { - history.delete_session(&entry.session_id, cx) - }); + pub fn delete_history_entry(&mut self, session_id: &acp::SessionId, cx: &mut Context) { + let task = self + .history + .update(cx, |history, cx| history.delete_session(&session_id, cx)); task.detach_and_log_err(cx); } } @@ -2856,6 +2868,8 @@ pub(crate) mod tests { Rc::new(StubAgentServer::default_response()), None, None, + None, + None, workspace.downgrade(), project, Some(thread_store), @@ -2939,7 +2953,6 @@ pub(crate) mod tests { async fn test_resume_without_history_adds_notice(cx: &mut TestAppContext) { init_test(cx); - let session = AgentSessionInfo::new(SessionId::new("resume-session")); let fs = FakeFs::new(cx.executor()); let project = Project::test(fs, [], cx).await; let (multi_workspace, cx) = @@ -2953,7 +2966,9 @@ pub(crate) mod tests { cx.new(|cx| { ConnectionView::new( Rc::new(StubAgentServer::new(ResumeOnlyAgentConnection)), - Some(session), + Some(SessionId::new("resume-session")), + None, + None, None, workspace.downgrade(), project, @@ -2997,9 +3012,6 @@ pub(crate) mod tests { let connection = CwdCapturingConnection::new(); let captured_cwd = connection.captured_cwd.clone(); - let mut session = AgentSessionInfo::new(SessionId::new("session-1")); - session.cwd = Some(PathBuf::from("/project/subdir")); - let thread_store = cx.update(|_window, cx| cx.new(|cx| ThreadStore::new(cx))); let history = cx.update(|window, cx| cx.new(|cx| ThreadHistory::new(None, window, cx))); @@ -3007,7 +3019,9 @@ pub(crate) mod tests { cx.new(|cx| { ConnectionView::new( Rc::new(StubAgentServer::new(connection)), - Some(session), + Some(SessionId::new("session-1")), + Some(PathBuf::from("/project/subdir")), + None, None, workspace.downgrade(), project, @@ -3049,9 +3063,6 @@ pub(crate) mod tests { let connection = CwdCapturingConnection::new(); let captured_cwd = connection.captured_cwd.clone(); - let mut session = AgentSessionInfo::new(SessionId::new("session-1")); - session.cwd = Some(PathBuf::from("/some/other/path")); - let thread_store = cx.update(|_window, cx| cx.new(|cx| ThreadStore::new(cx))); let history = cx.update(|window, cx| cx.new(|cx| ThreadHistory::new(None, window, cx))); @@ -3059,7 +3070,9 @@ pub(crate) mod tests { cx.new(|cx| { ConnectionView::new( Rc::new(StubAgentServer::new(connection)), - Some(session), + Some(SessionId::new("session-1")), + Some(PathBuf::from("/some/other/path")), + None, None, workspace.downgrade(), project, @@ -3101,9 +3114,6 @@ pub(crate) mod tests { let connection = CwdCapturingConnection::new(); let captured_cwd = connection.captured_cwd.clone(); - let mut session = AgentSessionInfo::new(SessionId::new("session-1")); - session.cwd = Some(PathBuf::from("/project/../outside")); - let thread_store = cx.update(|_window, cx| cx.new(|cx| ThreadStore::new(cx))); let history = cx.update(|window, cx| cx.new(|cx| ThreadHistory::new(None, window, cx))); @@ -3111,7 +3121,9 @@ pub(crate) mod tests { cx.new(|cx| { ConnectionView::new( Rc::new(StubAgentServer::new(connection)), - Some(session), + Some(SessionId::new("session-1")), + Some(PathBuf::from("/project/../outside")), + None, None, workspace.downgrade(), project, @@ -3424,6 +3436,8 @@ pub(crate) mod tests { Rc::new(agent), None, None, + None, + None, workspace1.downgrade(), project1.clone(), Some(thread_store), @@ -3612,6 +3626,8 @@ pub(crate) mod tests { Rc::new(agent), None, None, + None, + None, workspace.downgrade(), project, Some(thread_store), @@ -3792,6 +3808,7 @@ pub(crate) mod tests { AcpThread::new( None, name, + None, connection, project, action_log, @@ -3894,18 +3911,14 @@ pub(crate) mod tests { fn resume_session( self: Rc, - session: AgentSessionInfo, + session_id: acp::SessionId, project: Entity, _cwd: &Path, + _title: Option, cx: &mut App, ) -> Task>> { - let thread = build_test_thread( - self, - project, - "ResumeOnlyAgentConnection", - session.session_id, - cx, - ); + let thread = + build_test_thread(self, project, "ResumeOnlyAgentConnection", session_id, cx); Task::ready(Ok(thread)) } @@ -3965,7 +3978,7 @@ pub(crate) mod tests { fn new_session( self: Rc, project: Entity, - _cwd: &Path, + cwd: &Path, cx: &mut gpui::App, ) -> Task>> { if !*self.authenticated.lock() { @@ -3980,6 +3993,7 @@ pub(crate) mod tests { AcpThread::new( None, "AuthGatedAgent", + Some(cwd.to_path_buf()), self, project, action_log, @@ -4041,7 +4055,7 @@ pub(crate) mod tests { fn new_session( self: Rc, project: Entity, - _cwd: &Path, + cwd: &Path, cx: &mut gpui::App, ) -> Task>> { Task::ready(Ok(cx.new(|cx| { @@ -4049,6 +4063,7 @@ pub(crate) mod tests { AcpThread::new( None, "SaboteurAgentConnection", + Some(cwd.to_path_buf()), self, project, action_log, @@ -4106,7 +4121,7 @@ pub(crate) mod tests { fn new_session( self: Rc, project: Entity, - _cwd: &Path, + cwd: &Path, cx: &mut gpui::App, ) -> Task>> { Task::ready(Ok(cx.new(|cx| { @@ -4114,6 +4129,7 @@ pub(crate) mod tests { AcpThread::new( None, "RefusalAgentConnection", + Some(cwd.to_path_buf()), self, project, action_log, @@ -4189,6 +4205,7 @@ pub(crate) mod tests { AcpThread::new( None, "CwdCapturingConnection", + Some(cwd.to_path_buf()), self.clone(), project, action_log, @@ -4211,9 +4228,10 @@ pub(crate) mod tests { fn load_session( self: Rc, - session: AgentSessionInfo, + session_id: acp::SessionId, project: Entity, cwd: &Path, + _title: Option, cx: &mut App, ) -> Task>> { *self.captured_cwd.lock() = Some(cwd.to_path_buf()); @@ -4222,10 +4240,11 @@ pub(crate) mod tests { AcpThread::new( None, "CwdCapturingConnection", + Some(cwd.to_path_buf()), self.clone(), project, action_log, - session.session_id, + session_id, watch::Receiver::constant( acp::PromptCapabilities::new() .image(true) @@ -4327,6 +4346,8 @@ pub(crate) mod tests { Rc::new(StubAgentServer::new(connection.as_ref().clone())), None, None, + None, + None, workspace.downgrade(), project.clone(), Some(thread_store.clone()), @@ -6036,6 +6057,7 @@ pub(crate) mod tests { AcpThread::new( parent_session_id, "Test Thread", + None, connection, project, action_log, diff --git a/crates/agent_ui/src/connection_view/thread_view.rs b/crates/agent_ui/src/connection_view/thread_view.rs index 3397c619b7fc6544177ba52e9e71c887c74180cc..1c3b8ba244d895ba3ab2e6473f6cbe33ddae550b 100644 --- a/crates/agent_ui/src/connection_view/thread_view.rs +++ b/crates/agent_ui/src/connection_view/thread_view.rs @@ -247,7 +247,6 @@ pub struct ThreadView { pub is_loading_contents: bool, pub new_server_version_available: Option, pub resumed_without_history: bool, - pub resume_thread_metadata: Option, pub _cancel_task: Option>, _save_task: Option>, _draft_resolve_task: Option>, @@ -307,7 +306,6 @@ impl ThreadView { prompt_capabilities: Rc>, available_commands: Rc>>, resumed_without_history: bool, - resume_thread_metadata: Option, project: WeakEntity, thread_store: Option>, history: Entity, @@ -347,8 +345,8 @@ impl ThreadView { ); if let Some(content) = initial_content { match content { - AgentInitialContent::ThreadSummary(entry) => { - editor.insert_thread_summary(entry, window, cx); + AgentInitialContent::ThreadSummary { session_id, title } => { + editor.insert_thread_summary(session_id, title, window, cx); } AgentInitialContent::ContentBlock { blocks, @@ -439,7 +437,6 @@ impl ThreadView { prompt_capabilities, available_commands, resumed_without_history, - resume_thread_metadata, _subscriptions: subscriptions, permission_dropdown_handle: PopoverMenuHandle::default(), thread_retry_status: None, @@ -1772,18 +1769,7 @@ impl ThreadView { }) .await?; - let thread_metadata = AgentSessionInfo { - session_id, - cwd: None, - title: Some(format!("๐Ÿ”— {}", response.title).into()), - updated_at: Some(chrono::Utc::now()), - meta: None, - }; - - this.update_in(cx, |this, window, cx| { - this.resume_thread_metadata = Some(thread_metadata); - server_view.update(cx, |server_view, cx| server_view.reset(window, cx)); - })?; + server_view.update_in(cx, |server_view, window, cx| server_view.reset(window, cx))?; this.update_in(cx, |this, _window, cx| { if let Some(workspace) = this.workspace.upgrade() { @@ -7906,17 +7892,7 @@ pub(crate) fn open_link( MentionUri::Thread { id, name } => { if let Some(panel) = workspace.panel::(cx) { panel.update(cx, |panel, cx| { - panel.open_thread( - AgentSessionInfo { - session_id: id, - cwd: None, - title: Some(name.into()), - updated_at: None, - meta: None, - }, - window, - cx, - ) + panel.open_thread(id, None, Some(name.into()), window, cx) }); } } diff --git a/crates/agent_ui/src/message_editor.rs b/crates/agent_ui/src/message_editor.rs index 6ce0b7e356dc75f1c3d4db0f318d1978a37d00cc..cee6725cd15c15f4f39ad5e53be5578f5f5cc3d8 100644 --- a/crates/agent_ui/src/message_editor.rs +++ b/crates/agent_ui/src/message_editor.rs @@ -10,7 +10,7 @@ use crate::{ Mention, MentionImage, MentionSet, insert_crease_for_mention, paste_images_as_context, }, }; -use acp_thread::{AgentSessionInfo, MentionUri}; +use acp_thread::MentionUri; use agent::ThreadStore; use agent_client_protocol as acp; use anyhow::{Result, anyhow}; @@ -301,7 +301,8 @@ impl MessageEditor { pub fn insert_thread_summary( &mut self, - thread: AgentSessionInfo, + session_id: acp::SessionId, + title: Option, window: &mut Window, cx: &mut Context, ) { @@ -311,13 +312,11 @@ impl MessageEditor { let Some(workspace) = self.workspace.upgrade() else { return; }; - let thread_title = thread - .title - .clone() + let thread_title = title .filter(|title| !title.is_empty()) .unwrap_or_else(|| SharedString::new_static("New Thread")); let uri = MentionUri::Thread { - id: thread.session_id, + id: session_id, name: thread_title.to_string(), }; let content = format!("{}\n", uri.as_link()); @@ -1571,7 +1570,7 @@ fn find_matching_bracket(text: &str, open: char, close: char) -> Option { mod tests { use std::{cell::RefCell, ops::Range, path::Path, rc::Rc, sync::Arc}; - use acp_thread::{AgentSessionInfo, MentionUri}; + use acp_thread::MentionUri; use agent::{ThreadStore, outline}; use agent_client_protocol as acp; use editor::{ @@ -2811,14 +2810,8 @@ mod tests { let history = cx.update(|window, cx| cx.new(|cx| crate::ThreadHistory::new(None, window, cx))); - // Create a thread metadata to insert as summary - let thread_metadata = AgentSessionInfo { - session_id: acp::SessionId::new("thread-123"), - cwd: None, - title: Some("Previous Conversation".into()), - updated_at: Some(chrono::Utc::now()), - meta: None, - }; + let session_id = acp::SessionId::new("thread-123"); + let title = Some("Previous Conversation".into()); let message_editor = cx.update(|window, cx| { cx.new(|cx| { @@ -2839,17 +2832,17 @@ mod tests { window, cx, ); - editor.insert_thread_summary(thread_metadata.clone(), window, cx); + editor.insert_thread_summary(session_id.clone(), title.clone(), window, cx); editor }) }); // Construct expected values for verification let expected_uri = MentionUri::Thread { - id: thread_metadata.session_id.clone(), - name: thread_metadata.title.as_ref().unwrap().to_string(), + id: session_id.clone(), + name: title.as_ref().unwrap().to_string(), }; - let expected_title = thread_metadata.title.as_ref().unwrap(); + let expected_title = title.as_ref().unwrap(); let expected_link = format!("[@{}]({})", expected_title, expected_uri.to_uri()); message_editor.read_with(cx, |editor, cx| { @@ -2893,14 +2886,6 @@ mod tests { let history = cx.update(|window, cx| cx.new(|cx| crate::ThreadHistory::new(None, window, cx))); - let thread_metadata = AgentSessionInfo { - session_id: acp::SessionId::new("thread-123"), - cwd: None, - title: Some("Previous Conversation".into()), - updated_at: Some(chrono::Utc::now()), - meta: None, - }; - let message_editor = cx.update(|window, cx| { cx.new(|cx| { let mut editor = MessageEditor::new( @@ -2920,7 +2905,12 @@ mod tests { window, cx, ); - editor.insert_thread_summary(thread_metadata, window, cx); + editor.insert_thread_summary( + acp::SessionId::new("thread-123"), + Some("Previous Conversation".into()), + window, + cx, + ); editor }) }); diff --git a/crates/agent_ui/src/thread_history.rs b/crates/agent_ui/src/thread_history.rs index 8f8488cb94f94e036b37ef31c9c588740cd6cf02..6601616e9f2ef447beb448f2753460fa7c380fa6 100644 --- a/crates/agent_ui/src/thread_history.rs +++ b/crates/agent_ui/src/thread_history.rs @@ -948,12 +948,12 @@ impl RenderOnce for HistoryEntryElement { }) .on_click({ let thread_view = self.thread_view.clone(); - let entry = self.entry.clone(); + let session_id = self.entry.session_id.clone(); move |_event, _window, cx| { if let Some(thread_view) = thread_view.upgrade() { thread_view.update(cx, |thread_view, cx| { - thread_view.delete_history_entry(entry.clone(), cx); + thread_view.delete_history_entry(&session_id, cx); }); } } @@ -973,7 +973,13 @@ impl RenderOnce for HistoryEntryElement { { if let Some(panel) = workspace.read(cx).panel::(cx) { panel.update(cx, |panel, cx| { - panel.load_agent_thread(entry.clone(), window, cx); + panel.load_agent_thread( + entry.session_id.clone(), + entry.cwd.clone(), + entry.title.clone(), + window, + cx, + ); }); } } diff --git a/crates/agent_ui/src/ui/mention_crease.rs b/crates/agent_ui/src/ui/mention_crease.rs index 0a61b8e4ef2ec69714f158a72f83cc0528cc8a8f..8b813ef7e40c2afe91b98600b9d1146d4751d48b 100644 --- a/crates/agent_ui/src/ui/mention_crease.rs +++ b/crates/agent_ui/src/ui/mention_crease.rs @@ -269,24 +269,13 @@ fn open_thread( cx: &mut Context, ) { use crate::AgentPanel; - use acp_thread::AgentSessionInfo; let Some(panel) = workspace.panel::(cx) else { return; }; panel.update(cx, |panel, cx| { - panel.load_agent_thread( - AgentSessionInfo { - session_id: id, - cwd: None, - title: Some(name.into()), - updated_at: None, - meta: None, - }, - window, - cx, - ) + panel.load_agent_thread(id, None, Some(name.into()), window, cx) }); } diff --git a/crates/sidebar/src/sidebar.rs b/crates/sidebar/src/sidebar.rs index 7f1512ee549ce7acc7094ee86ccc233443cd6eac..3bb3ea9ea44efe2cf57a4d021b0a1755ac3b3681 100644 --- a/crates/sidebar/src/sidebar.rs +++ b/crates/sidebar/src/sidebar.rs @@ -1013,7 +1013,13 @@ impl Sidebar { if let Some(agent_panel) = workspace.read(cx).panel::(cx) { agent_panel.update(cx, |panel, cx| { - panel.load_agent_thread(session_info, window, cx); + panel.load_agent_thread( + session_info.session_id, + session_info.cwd, + session_info.title, + window, + cx, + ); }); } } diff --git a/crates/zed/src/main.rs b/crates/zed/src/main.rs index 4c188042482443ea0df59096884194f0740fcda1..062d0bd1f956b959f8ff3cabc6d4a44fbd5a3a7a 100644 --- a/crates/zed/src/main.rs +++ b/crates/zed/src/main.rs @@ -979,21 +979,19 @@ fn handle_open_request(request: OpenRequest, app_state: Arc, cx: &mut }) .await?; - let thread_metadata = acp_thread::AgentSessionInfo { - session_id, - cwd: None, - title: Some(format!("๐Ÿ”— {}", response.title).into()), - updated_at: Some(chrono::Utc::now()), - meta: None, - }; - let sharer_username = response.sharer_username.clone(); multi_workspace.update(cx, |_, window, cx| { workspace.update(cx, |workspace, cx| { if let Some(panel) = workspace.panel::(cx) { panel.update(cx, |panel, cx| { - panel.open_thread(thread_metadata, window, cx); + panel.open_thread( + session_id, + None, + Some(format!("๐Ÿ”— {}", response.title).into()), + window, + cx, + ); }); panel.focus_handle(cx).focus(window, cx); }