Detailed changes
@@ -36,6 +36,26 @@ use util::path_list::PathList;
use util::{ResultExt, get_default_system_shell_preferring_bash, paths::PathStyle};
use uuid::Uuid;
+/// A unique identifier for a conversation thread, allocated by Zed.
+///
+/// This is the internal identity type used throughout the application for
+/// bookkeeping. It is distinct from `acp::SessionId`, which is allocated
+/// by the agent and used for the wire protocol.
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
+pub struct ThreadId(pub Uuid);
+
+impl ThreadId {
+ pub fn new() -> Self {
+ Self(Uuid::new_v4())
+ }
+}
+
+impl std::fmt::Display for ThreadId {
+ fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
+ write!(f, "{}", self.0)
+ }
+}
+
/// Key used in ACP ToolCall meta to store the tool's programmatic name.
/// This is a workaround since ACP's ToolCall doesn't have a dedicated name field.
pub const TOOL_NAME_META_KEY: &str = "tool_name";
@@ -1017,9 +1037,10 @@ struct RunningTurn {
}
pub struct AcpThread {
+ thread_id: ThreadId,
session_id: acp::SessionId,
work_dirs: Option<PathList>,
- parent_session_id: Option<acp::SessionId>,
+ parent_thread_id: Option<ThreadId>,
title: Option<SharedString>,
provisional_title: Option<SharedString>,
entries: Vec<AgentThreadEntry>,
@@ -1184,12 +1205,13 @@ impl Error for LoadError {}
impl AcpThread {
pub fn new(
- parent_session_id: Option<acp::SessionId>,
+ parent_thread_id: Option<ThreadId>,
title: Option<SharedString>,
work_dirs: Option<PathList>,
connection: Rc<dyn AgentConnection>,
project: Entity<Project>,
action_log: Entity<ActionLog>,
+ thread_id: ThreadId,
session_id: acp::SessionId,
mut prompt_capabilities_rx: watch::Receiver<acp::PromptCapabilities>,
cx: &mut Context<Self>,
@@ -1206,7 +1228,8 @@ impl AcpThread {
});
Self {
- parent_session_id,
+ thread_id,
+ parent_thread_id,
work_dirs,
action_log,
shared_buffers: Default::default(),
@@ -1233,8 +1256,12 @@ impl AcpThread {
}
}
- pub fn parent_session_id(&self) -> Option<&acp::SessionId> {
- self.parent_session_id.as_ref()
+ pub fn thread_id(&self) -> ThreadId {
+ self.thread_id
+ }
+
+ pub fn parent_thread_id(&self) -> Option<ThreadId> {
+ self.parent_thread_id
}
pub fn prompt_capabilities(&self) -> acp::PromptCapabilities {
@@ -1845,7 +1872,7 @@ impl AcpThread {
let agent_telemetry_id = self.connection().telemetry_id();
let session = self.session_id();
- let parent_session_id = self.parent_session_id();
+ let parent_thread_id = self.parent_thread_id();
if let ToolCallStatus::Completed | ToolCallStatus::Failed = status {
let status = if matches!(status, ToolCallStatus::Completed) {
"completed"
@@ -1856,7 +1883,7 @@ impl AcpThread {
"Agent Tool Call Completed",
agent_telemetry_id,
session,
- parent_session_id,
+ parent_thread_id,
status
);
}
@@ -1960,7 +1987,7 @@ impl AcpThread {
pub fn resolve_locations(&mut self, id: acp::ToolCallId, cx: &mut Context<Self>) {
let project = self.project.clone();
- let should_update_agent_location = self.parent_session_id.is_none();
+ let should_update_agent_location = self.parent_thread_id.is_none();
let Some((_, tool_call)) = self.tool_call_mut(&id) else {
return;
};
@@ -2236,7 +2263,7 @@ impl AcpThread {
.await?;
this.update(cx, |this, cx| {
- if this.parent_session_id.is_none() {
+ if this.parent_thread_id.is_none() {
this.project
.update(cx, |project, cx| project.set_agent_location(None, cx));
}
@@ -2538,7 +2565,7 @@ impl AcpThread {
let limit = limit.unwrap_or(u32::MAX);
let project = self.project.clone();
let action_log = self.action_log.clone();
- let should_update_agent_location = self.parent_session_id.is_none();
+ let should_update_agent_location = self.parent_thread_id.is_none();
cx.spawn(async move |this, cx| {
let load = project.update(cx, |project, cx| {
let path = project
@@ -2613,7 +2640,7 @@ impl AcpThread {
) -> Task<Result<()>> {
let project = self.project.clone();
let action_log = self.action_log.clone();
- let should_update_agent_location = self.parent_session_id.is_none();
+ let should_update_agent_location = self.parent_thread_id.is_none();
cx.spawn(async move |this, cx| {
let load = project.update(cx, |project, cx| {
let path = project
@@ -734,6 +734,7 @@ mod test_support {
cx: &mut gpui::App,
) -> Entity<AcpThread> {
let action_log = cx.new(|_| ActionLog::new(project.clone()));
+ let thread_id = ThreadId::new();
let thread = cx.new(|cx| {
AcpThread::new(
None,
@@ -742,6 +743,7 @@ mod test_support {
self.clone(),
project,
action_log,
+ thread_id,
session_id.clone(),
watch::Receiver::constant(
acp::PromptCapabilities::new()
@@ -26,7 +26,7 @@ pub use tools::*;
use acp_thread::{
AcpThread, AgentModelSelector, AgentSessionInfo, AgentSessionList, AgentSessionListRequest,
- AgentSessionListResponse, TokenUsageRatio, UserMessageId,
+ AgentSessionListResponse, ThreadId, TokenUsageRatio, UserMessageId,
};
use agent_client_protocol as acp;
use anyhow::{Context as _, Result, anyhow};
@@ -328,8 +328,9 @@ impl NativeAgent {
let connection = Rc::new(NativeAgentConnection(cx.entity()));
let thread = thread_handle.read(cx);
- let session_id = thread.id().clone();
- let parent_session_id = thread.parent_thread_id();
+ let thread_id = thread.id();
+ let session_id = thread.session_id().clone();
+ let parent_thread_id = thread.parent_thread_id();
let title = thread.title();
let draft_prompt = thread.draft_prompt().map(Vec::from);
let scroll_position = thread.ui_scroll_position();
@@ -339,12 +340,13 @@ impl NativeAgent {
let prompt_capabilities_rx = thread.prompt_capabilities_rx.clone();
let acp_thread = cx.new(|cx| {
let mut acp_thread = acp_thread::AcpThread::new(
- parent_session_id,
+ parent_thread_id,
title,
None,
connection,
project.clone(),
action_log.clone(),
+ thread_id,
session_id.clone(),
prompt_capabilities_rx,
cx,
@@ -658,7 +660,7 @@ impl NativeAgent {
_: &TitleUpdated,
cx: &mut Context<Self>,
) {
- let session_id = thread.read(cx).id();
+ let session_id = thread.read(cx).session_id();
let Some(session) = self.sessions.get(session_id) else {
return;
};
@@ -683,7 +685,7 @@ impl NativeAgent {
usage: &TokenUsageUpdated,
cx: &mut Context<Self>,
) {
- let Some(session) = self.sessions.get(thread.read(cx).id()) else {
+ let Some(session) = self.sessions.get(thread.read(cx).session_id()) else {
return;
};
session.acp_thread.update(cx, |acp_thread, cx| {
@@ -905,6 +907,7 @@ impl NativeAgent {
Ok(cx.new(|cx| {
let mut thread = Thread::from_db(
+ ThreadId::new(),
id.clone(),
db_thread,
project_state.project.clone(),
@@ -958,16 +961,11 @@ impl NativeAgent {
let thread = self.open_thread(id.clone(), project, cx);
cx.spawn(async move |this, cx| {
let acp_thread = thread.await?;
- let result = this
- .update(cx, |this, cx| {
- this.sessions
- .get(&id)
- .unwrap()
- .thread
- .update(cx, |thread, cx| thread.summary(cx))
- })?
- .await
- .context("Failed to generate summary")?;
+ let summary_task = this.update(cx, |this, cx| {
+ let session = this.sessions.get(&id).context("session not found")?;
+ anyhow::Ok(session.thread.update(cx, |thread, cx| thread.summary(cx)))
+ })??;
+ let result = summary_task.await.context("Failed to generate summary")?;
drop(acp_thread);
Ok(result)
})
@@ -978,8 +976,8 @@ impl NativeAgent {
return;
}
- let id = thread.read(cx).id().clone();
- let Some(session) = self.sessions.get_mut(&id) else {
+ let session_id = thread.read(cx).session_id().clone();
+ let Some(session) = self.sessions.get_mut(&session_id) else {
return;
};
@@ -1010,7 +1008,7 @@ impl NativeAgent {
};
let db_thread = db_thread.await;
database
- .save_thread(id, db_thread, folder_paths)
+ .save_thread(session_id, db_thread, folder_paths)
.await
.log_err();
thread_store.update(cx, |store, cx| store.reload(cx));
@@ -1155,7 +1153,7 @@ impl NativeAgentConnection {
let Some((thread, acp_thread)) = self.0.update(cx, |agent, _cx| {
agent
.sessions
- .get_mut(&session_id)
+ .get(&session_id)
.map(|s| (s.thread.clone(), s.acp_thread.clone()))
}) else {
return Task::ready(Err(anyhow!("Session not found")));
@@ -1788,7 +1786,7 @@ impl NativeThreadEnvironment {
};
let parent_thread = parent_thread_entity.read(cx);
let current_depth = parent_thread.depth();
- let parent_session_id = parent_thread.id().clone();
+ let parent_session_id = parent_thread.session_id().clone();
if current_depth >= MAX_SUBAGENT_DEPTH {
return Err(anyhow!(
@@ -1803,7 +1801,7 @@ impl NativeThreadEnvironment {
thread
});
- let session_id = subagent_thread.read(cx).id().clone();
+ let subagent_thread_id = subagent_thread.read(cx).id();
let acp_thread = self
.agent
@@ -1821,12 +1819,12 @@ impl NativeThreadEnvironment {
telemetry::event!(
"Subagent Started",
session = parent_thread_entity.read(cx).id().to_string(),
- subagent_session = session_id.to_string(),
+ subagent_session = subagent_thread_id.to_string(),
depth,
is_resumed = false,
);
- self.prompt_subagent(session_id, subagent_thread, acp_thread)
+ self.prompt_subagent(subagent_thread_id, subagent_thread, acp_thread)
}
pub(crate) fn resume_subagent_thread(
@@ -1834,12 +1832,17 @@ impl NativeThreadEnvironment {
session_id: acp::SessionId,
cx: &mut App,
) -> Result<Rc<dyn SubagentHandle>> {
- let (subagent_thread, acp_thread) = self.agent.update(cx, |agent, _cx| {
+ let (subagent_thread, acp_thread, thread_id) = self.agent.update(cx, |agent, _cx| {
let session = agent
.sessions
.get(&session_id)
.ok_or_else(|| anyhow!("No subagent session found with id {session_id}"))?;
- anyhow::Ok((session.thread.clone(), session.acp_thread.clone()))
+ let thread_id = session.thread.read(_cx).id();
+ anyhow::Ok((
+ session.thread.clone(),
+ session.acp_thread.clone(),
+ thread_id,
+ ))
})??;
let depth = subagent_thread.read(cx).depth();
@@ -1854,12 +1857,12 @@ impl NativeThreadEnvironment {
);
}
- self.prompt_subagent(session_id, subagent_thread, acp_thread)
+ self.prompt_subagent(thread_id, subagent_thread, acp_thread)
}
fn prompt_subagent(
&self,
- session_id: acp::SessionId,
+ thread_id: ThreadId,
subagent_thread: Entity<Thread>,
acp_thread: Entity<acp_thread::AcpThread>,
) -> Result<Rc<dyn SubagentHandle>> {
@@ -1867,7 +1870,7 @@ impl NativeThreadEnvironment {
anyhow::bail!("Parent thread no longer exists".to_string());
};
Ok(Rc::new(NativeSubagentHandle::new(
- session_id,
+ thread_id,
subagent_thread,
acp_thread,
parent_thread_entity,
@@ -1931,7 +1934,7 @@ enum SubagentPromptResult {
}
pub struct NativeSubagentHandle {
- session_id: acp::SessionId,
+ thread_id: ThreadId,
parent_thread: WeakEntity<Thread>,
subagent_thread: Entity<Thread>,
acp_thread: Entity<acp_thread::AcpThread>,
@@ -1939,13 +1942,13 @@ pub struct NativeSubagentHandle {
impl NativeSubagentHandle {
fn new(
- session_id: acp::SessionId,
+ thread_id: ThreadId,
subagent_thread: Entity<Thread>,
acp_thread: Entity<acp_thread::AcpThread>,
parent_thread_entity: Entity<Thread>,
) -> Self {
NativeSubagentHandle {
- session_id,
+ thread_id,
subagent_thread,
parent_thread: parent_thread_entity.downgrade(),
acp_thread,
@@ -1954,8 +1957,12 @@ impl NativeSubagentHandle {
}
impl SubagentHandle for NativeSubagentHandle {
- fn id(&self) -> acp::SessionId {
- self.session_id.clone()
+ fn id(&self) -> ThreadId {
+ self.thread_id
+ }
+
+ fn session_id(&self, cx: &App) -> acp::SessionId {
+ self.subagent_thread.read(cx).session_id().clone()
}
fn num_entries(&self, cx: &App) -> usize {
@@ -1965,7 +1972,7 @@ impl SubagentHandle for NativeSubagentHandle {
fn send(&self, message: String, cx: &AsyncApp) -> Task<Result<String>> {
let thread = self.subagent_thread.clone();
let acp_thread = self.acp_thread.clone();
- let subagent_session_id = self.session_id.clone();
+ let subagent_thread_id = self.thread_id;
let parent_thread = self.parent_thread.clone();
cx.spawn(async move |cx| {
@@ -2065,7 +2072,7 @@ impl SubagentHandle for NativeSubagentHandle {
parent_thread
.update(cx, |parent_thread, cx| {
- parent_thread.unregister_running_subagent(&subagent_session_id, cx)
+ parent_thread.unregister_running_subagent(subagent_thread_id, cx)
})
.ok();
@@ -457,10 +457,10 @@ impl ThreadsDatabase {
let title = thread.title.to_string();
let updated_at = thread.updated_at.to_rfc3339();
- let parent_id = thread
+ let parent_id: Option<Arc<str>> = thread
.subagent_context
.as_ref()
- .map(|ctx| ctx.parent_thread_id.0.clone());
+ .map(|ctx| Arc::from(ctx.parent_thread_id.0.to_string()));
let serialized_folder_paths = folder_paths.serialize();
let (folder_paths_str, folder_paths_order_str): (Option<String>, Option<String>) =
if folder_paths.is_empty() {
@@ -157,12 +157,17 @@ impl crate::TerminalHandle for FakeTerminalHandle {
}
struct FakeSubagentHandle {
+ thread_id: acp_thread::ThreadId,
session_id: acp::SessionId,
send_task: Shared<Task<String>>,
}
impl SubagentHandle for FakeSubagentHandle {
- fn id(&self) -> acp::SessionId {
+ fn id(&self) -> acp_thread::ThreadId {
+ self.thread_id
+ }
+
+ fn session_id(&self, _cx: &App) -> acp::SessionId {
self.session_id.clone()
}
@@ -6,7 +6,7 @@ use crate::{
SystemPromptTemplate, Template, Templates, TerminalTool, ToolPermissionDecision,
UpdatePlanTool, WebSearchTool, decide_permission_from_settings,
};
-use acp_thread::{MentionUri, UserMessageId};
+use acp_thread::{MentionUri, ThreadId, UserMessageId};
use action_log::ActionLog;
use feature_flags::{
FeatureFlagAppExt as _, StreamingEditFileToolFeatureFlag, UpdatePlanToolFeatureFlag,
@@ -68,7 +68,7 @@ pub const MAX_SUBAGENT_DEPTH: u8 = 1;
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct SubagentContext {
/// ID of the parent thread
- pub parent_thread_id: acp::SessionId,
+ pub parent_thread_id: ThreadId,
/// Current depth level (0 = root agent, 1 = first-level subagent, etc.)
pub depth: u8,
@@ -620,8 +620,10 @@ pub trait TerminalHandle {
}
pub trait SubagentHandle {
- /// The session ID of this subagent thread
- fn id(&self) -> acp::SessionId;
+ /// The internal thread ID of this subagent thread, allocated by Zed.
+ fn id(&self) -> ThreadId;
+ /// The ACP session ID for this subagent, allocated by the agent.
+ fn session_id(&self, cx: &App) -> acp::SessionId;
/// The current number of entries in the thread.
/// Useful for knowing where the next turn will begin
fn num_entries(&self, cx: &App) -> usize;
@@ -922,7 +924,8 @@ enum CompletionError {
}
pub struct Thread {
- id: acp::SessionId,
+ id: ThreadId,
+ session_id: acp::SessionId,
prompt_id: PromptId,
updated_at: DateTime<Utc>,
title: Option<SharedString>,
@@ -996,7 +999,7 @@ impl Thread {
cx,
);
thread.subagent_context = Some(SubagentContext {
- parent_thread_id: parent_thread.read(cx).id().clone(),
+ parent_thread_id: parent_thread.read(cx).id(),
depth: parent_thread.read(cx).depth() + 1,
});
thread.inherit_parent_settings(parent_thread, cx);
@@ -1048,7 +1051,8 @@ impl Thread {
let (prompt_capabilities_tx, prompt_capabilities_rx) =
watch::channel(Self::prompt_capabilities(model.as_deref()));
Self {
- id: acp::SessionId::new(uuid::Uuid::new_v4().to_string()),
+ id: ThreadId::new(),
+ session_id: acp::SessionId::new(uuid::Uuid::new_v4().to_string()),
prompt_id: PromptId::new(),
updated_at: Utc::now(),
title: None,
@@ -1103,8 +1107,12 @@ impl Thread {
self.profile_id = parent.profile_id.clone();
}
- pub fn id(&self) -> &acp::SessionId {
- &self.id
+ pub fn id(&self) -> ThreadId {
+ self.id
+ }
+
+ pub fn session_id(&self) -> &acp::SessionId {
+ &self.session_id
}
/// Returns true if this thread was imported from a shared thread.
@@ -1236,7 +1244,8 @@ impl Thread {
}
pub fn from_db(
- id: acp::SessionId,
+ id: ThreadId,
+ session_id: acp::SessionId,
db_thread: DbThread,
project: Entity<Project>,
project_context: Entity<ProjectContext>,
@@ -1279,6 +1288,7 @@ impl Thread {
Self {
id,
+ session_id,
prompt_id: PromptId::new(),
title: if db_thread.title.is_empty() {
None
@@ -2908,22 +2918,18 @@ impl Thread {
self.running_subagents.push(subagent);
}
- pub(crate) fn unregister_running_subagent(
- &mut self,
- subagent_session_id: &acp::SessionId,
- cx: &App,
- ) {
+ pub(crate) fn unregister_running_subagent(&mut self, subagent_thread_id: ThreadId, cx: &App) {
self.running_subagents.retain(|s| {
s.upgrade()
- .map_or(false, |s| s.read(cx).id() != subagent_session_id)
+ .map_or(false, |s| s.read(cx).id() != subagent_thread_id)
});
}
#[cfg(any(test, feature = "test-support"))]
- pub fn running_subagent_ids(&self, cx: &App) -> Vec<acp::SessionId> {
+ pub fn running_subagent_ids(&self, cx: &App) -> Vec<ThreadId> {
self.running_subagents
.iter()
- .filter_map(|s| s.upgrade().map(|s| s.read(cx).id().clone()))
+ .filter_map(|s| s.upgrade().map(|s| s.read(cx).id()))
.collect()
}
@@ -2931,10 +2937,8 @@ impl Thread {
self.subagent_context.is_some()
}
- pub fn parent_thread_id(&self) -> Option<acp::SessionId> {
- self.subagent_context
- .as_ref()
- .map(|c| c.parent_thread_id.clone())
+ pub fn parent_thread_id(&self) -> Option<ThreadId> {
+ self.subagent_context.as_ref().map(|c| c.parent_thread_id)
}
pub fn depth(&self) -> u8 {
@@ -153,12 +153,12 @@ impl AgentTool for SpawnAgentTool {
session_info: None,
})?;
let session_info = SubagentSessionInfo {
- session_id: subagent.id(),
+ session_id: subagent.session_id(cx),
message_start_index: subagent.num_entries(cx),
message_end_index: None,
};
- event_stream.subagent_spawned(subagent.id());
+ event_stream.subagent_spawned(subagent.session_id(cx));
event_stream.update_fields_with_meta(
acp::ToolCallUpdateFields::new(),
Some(acp::Meta::from_iter([(
@@ -685,6 +685,7 @@ impl AgentConnection for AcpConnection {
self.clone(),
project,
action_log,
+ acp_thread::ThreadId::new(),
response.session_id.clone(),
// ACP doesn't currently support per-session prompt capabilities or changing capabilities dynamically.
watch::Receiver::constant(self.agent_capabilities.prompt_capabilities.clone()),
@@ -746,6 +747,7 @@ impl AgentConnection for AcpConnection {
self.clone(),
project,
action_log,
+ acp_thread::ThreadId::new(),
session_id.clone(),
watch::Receiver::constant(self.agent_capabilities.prompt_capabilities.clone()),
cx,
@@ -828,6 +830,7 @@ impl AgentConnection for AcpConnection {
self.clone(),
project,
action_log,
+ acp_thread::ThreadId::new(),
session_id.clone(),
watch::Receiver::constant(self.agent_capabilities.prompt_capabilities.clone()),
cx,
@@ -3955,7 +3955,7 @@ impl AgentPanel {
let thread = active_thread.read(cx);
if !thread.is_empty() {
- let session_id = thread.id().clone();
+ let session_id = thread.session_id().clone();
this.item(
ContextMenuEntry::new("New From Summary")
.icon(IconName::ThreadFromSummary)
@@ -219,7 +219,7 @@ impl Conversation {
cx: &'a App,
) -> Option<(acp::SessionId, acp::ToolCallId, &'a PermissionOptions)> {
let thread = self.threads.get(session_id)?;
- let is_subagent = thread.read(cx).parent_session_id().is_some();
+ let is_subagent = thread.read(cx).parent_thread_id().is_some();
let (thread, tool_id) = if is_subagent {
let id = self.permission_requests.get(session_id)?.iter().next()?;
(thread, id)
@@ -246,7 +246,7 @@ impl Conversation {
.iter()
.filter_map(|(session_id, tool_call_ids)| {
let thread = self.threads.get(session_id)?;
- if thread.read(cx).parent_session_id().is_some() && !tool_call_ids.is_empty() {
+ if thread.read(cx).parent_thread_id().is_some() && !tool_call_ids.is_empty() {
Some((session_id.clone(), tool_call_ids.len()))
} else {
None
@@ -1250,7 +1250,7 @@ impl ConversationView {
cx: &mut Context<Self>,
) {
let thread_id = thread.read(cx).session_id().clone();
- let is_subagent = thread.read(cx).parent_session_id().is_some();
+ let is_subagent = thread.read(cx).parent_thread_id().is_some();
match event {
AcpThreadEvent::NewEntry => {
let len = thread.read(cx).entries().len();
@@ -56,7 +56,7 @@ impl ThreadFeedbackState {
}
}
let session_id = thread.read(cx).session_id().clone();
- let parent_session_id = thread.read(cx).parent_session_id().cloned();
+ let parent_session_id = thread.read(cx).parent_thread_id();
let agent_telemetry_id = thread.read(cx).connection().telemetry_id();
let task = telemetry.thread_data(&session_id, cx);
let rating = match feedback {
@@ -1050,7 +1050,7 @@ impl ThreadView {
cx: &mut Context<Self>,
) {
let session_id = self.thread.read(cx).session_id().clone();
- let parent_session_id = self.thread.read(cx).parent_session_id().cloned();
+ let parent_session_id = self.thread.read(cx).parent_thread_id();
let agent_telemetry_id = self.thread.read(cx).connection().telemetry_id();
let is_first_message = self.thread.read(cx).entries().is_empty();
let thread = self.thread.downgrade();
@@ -1270,7 +1270,7 @@ impl ThreadView {
let parent_session_id = self
.thread
.read(cx)
- .parent_session_id()
+ .parent_thread_id()
.map(|id| id.to_string());
telemetry::event!(
@@ -2235,7 +2235,7 @@ impl ThreadView {
this.child(Divider::horizontal().color(DividerColor::Border))
})
.when(
- !changed_buffers.is_empty() && thread.parent_session_id().is_none(),
+ !changed_buffers.is_empty() && thread.parent_thread_id().is_none(),
|this| {
this.child(self.render_edits_summary(
&changed_buffers,
@@ -73,7 +73,7 @@ impl EntryViewState {
match thread_entry {
AgentThreadEntry::UserMessage(message) => {
let has_id = message.id.is_some();
- let is_subagent = thread.read(cx).parent_session_id().is_some();
+ let is_subagent = thread.read(cx).parent_thread_id().is_some();
let chunks = message.chunks.clone();
if let Some(Entry::UserMessage(editor)) = self.entries.get_mut(index) {
if !editor.focus_handle(cx).is_focused(window) {
@@ -879,7 +879,7 @@ impl ThreadMetadataStore {
cx.observe_new::<acp_thread::AcpThread>(move |thread, _window, cx| {
// Don't track subagent threads in the sidebar.
- if thread.parent_session_id().is_some() {
+ if thread.parent_thread_id().is_some() {
return;
}
@@ -965,7 +965,7 @@ impl ThreadMetadataStore {
cx: &mut Context<Self>,
) {
// Don't track subagent threads in the sidebar.
- if thread.read(cx).parent_session_id().is_some() {
+ if thread.read(cx).parent_thread_id().is_some() {
return;
}
@@ -0,0 +1,10 @@
+# Seeds for failure cases proptest has generated in the past. It is
+# automatically read and these particular cases re-run before any
+# novel cases are generated.
+#
+# It is recommended to check this file in to source control so that
+# everyone who runs the test benefits from these saved cases.
+cc 7ab586bbc9abb1188a649c7c1cacc1a0976a22747ebe6c88111354df7e5b51af # shrinks to TestSidebarInvariantsArgs = TestSidebarInvariantsArgs { __seed: 8174137932693891958, raw_operations: [87] }
+cc c26d806fa636aa90647d990385d05d45d071406308696f6664405885b3cf493c # shrinks to TestSidebarInvariantsArgs = TestSidebarInvariantsArgs { __seed: 17908799813400136853, raw_operations: [7] }
+cc 32e0926d11da3d33495bf2ace4768e3a2e112d00b90a6289e601a4d94414feec # shrinks to TestSidebarInvariantsArgs = TestSidebarInvariantsArgs { __seed: 15152078651144901147, raw_operations: [36] }
+cc bb64a25f4eda0896e496ee89650be38906276aa5695cc3197450da62a2e90196 # shrinks to TestSidebarInvariantsArgs = TestSidebarInvariantsArgs { __seed: 18226949068654728636, raw_operations: [84] }