From f0dfdb27e7e3a277fe72b8052296a6619ab67669 Mon Sep 17 00:00:00 2001 From: "Joseph T. Lyons" Date: Wed, 28 Jan 2026 14:03:52 -0500 Subject: [PATCH] Improve Zed agent thread history to update across all open windows (#47803) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously, each Agent panel created its own `ThreadStore` instance, so thread history updates wouldn't sync between open windows. Users had to close and reopen windows to see threads created in other windows. Now `ThreadStore` is initialized once as a global and shared across all windows. When any window saves a thread, ThreadStore::reload() calls cx.notify(), which notifies all NativeAgentSessionList observers, causing all windows' history views to refresh. Note: This only works for the native Zed agent. It also is only improving the history view (thread titles)—this PR does not sync edits between multiple windows when the same thread is open in each. Release Notes: - Improved Zed agent thread history to update across all open windows --- crates/agent/src/thread_store.rs | 15 ++++++++++++++- crates/agent_ui/src/agent_panel.rs | 2 +- crates/agent_ui/src/agent_ui.rs | 1 + crates/agent_ui_v2/src/agents_panel.rs | 2 +- 4 files changed, 17 insertions(+), 3 deletions(-) diff --git a/crates/agent/src/thread_store.rs b/crates/agent/src/thread_store.rs index 3a8dd6690f..cd7c03de54 100644 --- a/crates/agent/src/thread_store.rs +++ b/crates/agent/src/thread_store.rs @@ -1,10 +1,14 @@ use crate::{DbThread, DbThreadMetadata, ThreadsDatabase}; use agent_client_protocol as acp; use anyhow::{Result, anyhow}; -use gpui::{App, Context, Entity, Task, prelude::*}; +use gpui::{App, Context, Entity, Global, Task, prelude::*}; use project::Project; use std::rc::Rc; +struct GlobalThreadStore(Entity); + +impl Global for GlobalThreadStore {} + // TODO: Remove once ACP thread loading is fully handled elsewhere. pub fn load_agent_thread( session_id: acp::SessionId, @@ -37,6 +41,15 @@ pub struct ThreadStore { } impl ThreadStore { + pub fn init_global(cx: &mut App) { + let thread_store = cx.new(|cx| Self::new(cx)); + cx.set_global(GlobalThreadStore(thread_store)); + } + + pub fn global(cx: &App) -> Entity { + cx.global::().0.clone() + } + pub fn new(cx: &mut Context) -> Self { let this = Self { threads: Vec::new(), diff --git a/crates/agent_ui/src/agent_panel.rs b/crates/agent_ui/src/agent_panel.rs index 766744907b..aca4386a14 100644 --- a/crates/agent_ui/src/agent_panel.rs +++ b/crates/agent_ui/src/agent_panel.rs @@ -507,7 +507,7 @@ impl AgentPanel { let context_server_registry = cx.new(|cx| ContextServerRegistry::new(project.read(cx).context_server_store(), cx)); - let thread_store = cx.new(|cx| ThreadStore::new(cx)); + let thread_store = ThreadStore::global(cx); let acp_history = cx.new(|cx| AcpThreadHistory::new(None, window, cx)); let text_thread_history = cx.new(|cx| TextThreadHistory::new(text_thread_store.clone(), window, cx)); diff --git a/crates/agent_ui/src/agent_ui.rs b/crates/agent_ui/src/agent_ui.rs index bb39ce96c3..62d22c9a22 100644 --- a/crates/agent_ui/src/agent_ui.rs +++ b/crates/agent_ui/src/agent_ui.rs @@ -256,6 +256,7 @@ pub fn init( is_eval: bool, cx: &mut App, ) { + agent::ThreadStore::init_global(cx); assistant_text_thread::init(client, cx); rules_library::init(cx); if !is_eval { diff --git a/crates/agent_ui_v2/src/agents_panel.rs b/crates/agent_ui_v2/src/agents_panel.rs index f8e223ffbf..3f56704850 100644 --- a/crates/agent_ui_v2/src/agents_panel.rs +++ b/crates/agent_ui_v2/src/agents_panel.rs @@ -124,7 +124,7 @@ impl AgentsPanel { ) -> Self { let focus_handle = cx.focus_handle(); - let thread_store = cx.new(|cx| ThreadStore::new(cx)); + let thread_store = ThreadStore::global(cx); let history = cx.new(|cx| AcpThreadHistory::new(None, window, cx)); let history_handle = history.clone();