Detailed changes
@@ -952,6 +952,8 @@ struct RunningTurn {
}
pub struct AcpThread {
+ session_id: acp::SessionId,
+ cwd: Option<PathBuf>,
parent_session_id: Option<acp::SessionId>,
title: SharedString,
provisional_title: Option<SharedString>,
@@ -963,7 +965,6 @@ pub struct AcpThread {
turn_id: u32,
running_turn: Option<RunningTurn>,
connection: Rc<dyn AgentConnection>,
- session_id: acp::SessionId,
token_usage: Option<TokenUsage>,
prompt_capabilities: acp::PromptCapabilities,
_observe_prompt_capabilities: Task<anyhow::Result<()>>,
@@ -1048,87 +1049,6 @@ pub enum TerminalProviderCommand {
},
}
-impl AcpThread {
- pub fn on_terminal_provider_event(
- &mut self,
- event: TerminalProviderEvent,
- cx: &mut Context<Self>,
- ) {
- 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<acp::SessionId>,
title: impl Into<SharedString>,
+ cwd: Option<PathBuf>,
connection: Rc<dyn AgentConnection>,
project: Entity<Project>,
action_log: Entity<ActionLog>,
@@ -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<Self>,
+ ) {
+ 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<Self>,
project: Entity<Project>,
- _cwd: &Path,
+ cwd: &Path,
cx: &mut App,
) -> Task<gpui::Result<Entity<AcpThread>>> {
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,
@@ -45,9 +45,10 @@ pub trait AgentConnection {
/// Load an existing session by ID.
fn load_session(
self: Rc<Self>,
- _session: AgentSessionInfo,
+ _session_id: acp::SessionId,
_project: Entity<Project>,
_cwd: &Path,
+ _title: Option<SharedString>,
_cx: &mut App,
) -> Task<Result<Entity<AcpThread>>> {
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<Self>,
- _session: AgentSessionInfo,
+ _session_id: acp::SessionId,
_project: Entity<Project>,
_cwd: &Path,
+ _title: Option<SharedString>,
_cx: &mut App,
) -> Task<Result<Entity<AcpThread>>> {
Task::ready(Err(anyhow::Error::msg(
@@ -619,7 +621,7 @@ mod test_support {
fn new_session(
self: Rc<Self>,
project: Entity<Project>,
- _cwd: &Path,
+ cwd: &Path,
cx: &mut gpui::App,
) -> Task<gpui::Result<Entity<AcpThread>>> {
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,
@@ -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<Self>,
- session: AgentSessionInfo,
+ session_id: acp::SessionId,
_project: Entity<Project>,
_cwd: &Path,
+ _title: Option<SharedString>,
cx: &mut App,
) -> Task<Result<Entity<acp_thread::AcpThread>>> {
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 {
@@ -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<Self>,
- session: AgentSessionInfo,
+ session_id: acp::SessionId,
project: Entity<Project>,
cwd: &Path,
+ title: Option<SharedString>,
cx: &mut App,
) -> Task<Result<Entity<AcpThread>>> {
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<AcpThread> = 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<Self>,
- session: AgentSessionInfo,
+ session_id: acp::SessionId,
project: Entity<Project>,
cwd: &Path,
+ title: Option<SharedString>,
cx: &mut App,
) -> Task<Result<Entity<AcpThread>>> {
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<AcpThread> = 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);
@@ -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::<AgentPanel>(cx) {
workspace.focus_panel::<AgentPanel>(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<PathBuf>,
+ title: Option<SharedString>,
window: &mut Window,
cx: &mut Context<Self>,
) {
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<crate::ExternalAgent>,
- resume_thread: Option<AgentSessionInfo>,
+ resume_session_id: Option<acp::SessionId>,
+ cwd: Option<PathBuf>,
+ title: Option<SharedString>,
initial_content: Option<AgentInitialContent>,
window: &mut Window,
cx: &mut Context<Self>,
@@ -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>,
) {
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<PathBuf>,
+ title: Option<SharedString>,
window: &mut Window,
cx: &mut Context<Self>,
) {
- 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<dyn AgentServer>,
- resume_thread: Option<AgentSessionInfo>,
+ resume_session_id: Option<acp::SessionId>,
+ cwd: Option<PathBuf>,
+ title: Option<SharedString>,
initial_content: Option<AgentInitialContent>,
workspace: WeakEntity<Workspace>,
project: Entity<Project>,
@@ -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::<AgentPanel>(window, cx);
if let Some(panel) = workspace.panel::<AgentPanel>(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.
@@ -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<SharedString>,
+ },
ContentBlock {
blocks: Vec<agent_client_protocol::ContentBlock>,
auto_submit: bool,
@@ -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<StringMatch>,
entry: PromptContextEntry,
}
-fn session_title(session: &AgentSessionInfo) -> SharedString {
- session
- .title
- .clone()
+fn session_title(title: Option<SharedString>) -> SharedString {
+ title
.filter(|title| !title.is_empty())
.unwrap_or_else(|| SharedString::new_static("New Thread"))
}
@@ -266,7 +271,8 @@ impl<T: PromptCompletionProviderDelegate> PromptCompletionProvider<T> {
}
fn completion_for_thread(
- thread_entry: AgentSessionInfo,
+ session_id: acp::SessionId,
+ title: Option<SharedString>,
source_range: Range<Anchor>,
recent: bool,
source: Arc<T>,
@@ -275,9 +281,9 @@ impl<T: PromptCompletionProviderDelegate> PromptCompletionProvider<T> {
workspace: Entity<Workspace>,
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<T: PromptCompletionProviderDelegate> PromptCompletionProvider<T> {
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::<Vec<_>>();
let search_task =
filter_sessions_by_query(query, cancellation_flag, sessions, cx);
cx.spawn(async move |_cx| {
@@ -1018,15 +1032,18 @@ impl<T: PromptCompletionProviderDelegate> PromptCompletionProvider<T> {
.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<T: PromptCompletionProviderDelegate> 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<T: PromptCompletionProviderDelegate> 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<AtomicBool>,
- sessions: Vec<AgentSessionInfo>,
+ sessions: Vec<SessionMatch>,
cx: &mut App,
-) -> Task<Vec<AgentSessionInfo>> {
+) -> Task<Vec<SessionMatch>> {
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<AtomicBool>,
- sessions: Vec<AgentSessionInfo>,
+ sessions: Vec<SessionMatch>,
executor: BackgroundExecutor,
-) -> Vec<AgentSessionInfo> {
- let titles = sessions.iter().map(session_title).collect::<Vec<_>>();
+) -> Vec<SessionMatch> {
+ let titles = sessions
+ .iter()
+ .map(|session| session.title.clone())
+ .collect::<Vec<_>>();
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];
@@ -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<dyn AgentServer>,
- resume_thread: Option<AgentSessionInfo>,
+ resume_session_id: Option<acp::SessionId>,
+ cwd: Option<PathBuf>,
+ title: Option<SharedString>,
initial_content: Option<AgentInitialContent>,
workspace: WeakEntity<Workspace>,
project: Entity<Project>,
@@ -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<Self>) {
- 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<dyn AgentServer>,
- resume_thread: Option<AgentSessionInfo>,
+ resume_session_id: Option<acp::SessionId>,
+ cwd: Option<PathBuf>,
+ title: Option<SharedString>,
project: Entity<Project>,
initial_content: Option<AgentInitialContent>,
window: &mut Window,
cx: &mut Context<Self>,
) -> ServerState {
- let session_id = resume_thread
- .as_ref()
- .map(|thread| thread.session_id.clone());
if project.read(cx).is_via_collab()
&& agent.clone().downcast::<NativeAgentServer>().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::<Vec<_>>();
@@ -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<AcpThread>,
conversation: Entity<Conversation>,
resumed_without_history: bool,
- resume_thread: Option<AgentSessionInfo>,
initial_content: Option<AgentInitialContent>,
window: &mut Window,
cx: &mut Context<Self>,
@@ -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<Self>) {
- 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<Self>) {
+ 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<Self>,
- session: AgentSessionInfo,
+ session_id: acp::SessionId,
project: Entity<Project>,
_cwd: &Path,
+ _title: Option<SharedString>,
cx: &mut App,
) -> Task<gpui::Result<Entity<AcpThread>>> {
- 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<Self>,
project: Entity<Project>,
- _cwd: &Path,
+ cwd: &Path,
cx: &mut gpui::App,
) -> Task<gpui::Result<Entity<AcpThread>>> {
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<Self>,
project: Entity<Project>,
- _cwd: &Path,
+ cwd: &Path,
cx: &mut gpui::App,
) -> Task<gpui::Result<Entity<AcpThread>>> {
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<Self>,
project: Entity<Project>,
- _cwd: &Path,
+ cwd: &Path,
cx: &mut gpui::App,
) -> Task<gpui::Result<Entity<AcpThread>>> {
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<Self>,
- session: AgentSessionInfo,
+ session_id: acp::SessionId,
project: Entity<Project>,
cwd: &Path,
+ _title: Option<SharedString>,
cx: &mut App,
) -> Task<gpui::Result<Entity<AcpThread>>> {
*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,
@@ -247,7 +247,6 @@ pub struct ThreadView {
pub is_loading_contents: bool,
pub new_server_version_available: Option<SharedString>,
pub resumed_without_history: bool,
- pub resume_thread_metadata: Option<AgentSessionInfo>,
pub _cancel_task: Option<Task<()>>,
_save_task: Option<Task<()>>,
_draft_resolve_task: Option<Task<()>>,
@@ -307,7 +306,6 @@ impl ThreadView {
prompt_capabilities: Rc<RefCell<PromptCapabilities>>,
available_commands: Rc<RefCell<Vec<agent_client_protocol::AvailableCommand>>>,
resumed_without_history: bool,
- resume_thread_metadata: Option<AgentSessionInfo>,
project: WeakEntity<Project>,
thread_store: Option<Entity<ThreadStore>>,
history: Entity<ThreadHistory>,
@@ -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::<AgentPanel>(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)
});
}
}
@@ -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<SharedString>,
window: &mut Window,
cx: &mut Context<Self>,
) {
@@ -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<usize> {
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
})
});
@@ -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::<AgentPanel>(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,
+ );
});
}
}
@@ -269,24 +269,13 @@ fn open_thread(
cx: &mut Context<Workspace>,
) {
use crate::AgentPanel;
- use acp_thread::AgentSessionInfo;
let Some(panel) = workspace.panel::<AgentPanel>(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)
});
}
@@ -1013,7 +1013,13 @@ impl Sidebar {
if let Some(agent_panel) = workspace.read(cx).panel::<AgentPanel>(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,
+ );
});
}
}
@@ -979,21 +979,19 @@ fn handle_open_request(request: OpenRequest, app_state: Arc<AppState>, 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::<AgentPanel>(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);
}