From 87632d00ce7026172f999a0ae1c8a985e2388081 Mon Sep 17 00:00:00 2001 From: Luke Marsden Date: Wed, 4 Mar 2026 18:22:28 +0000 Subject: [PATCH] Fix thread entity brain split after container restart After a container restart, the agent panel restores its thread from persistent state (creating Entity #1), then load_thread_from_agent() creates a NEW entity (Entity #2) for the same thread when a WebSocket message arrives. The panel's notify_thread_display() compared session IDs (identical for both entities) and returned early, never rebinding to the live entity. Result: Helix saw live updates but the Zed display was frozen on stale content. Fix: compare Entity references instead of session IDs so the panel detects the entity changed and rebinds via from_existing_thread(). Co-Authored-By: Claude Opus 4.6 --- crates/agent_ui/src/agent_panel.rs | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/crates/agent_ui/src/agent_panel.rs b/crates/agent_ui/src/agent_panel.rs index 431c816e832321..0edb0457c108b0 100644 --- a/crates/agent_ui/src/agent_panel.rs +++ b/crates/agent_ui/src/agent_panel.rs @@ -805,14 +805,20 @@ impl AgentPanel { // focus_panel triggers set_active which creates a default thread // if the view is Uninitialized — we need to set our view first // to prevent that race. - // Check if current view is already for this thread + // Check if current view is already showing this exact thread entity. + // IMPORTANT: Compare Entity references, NOT session IDs. After a + // container restart, load_thread_from_agent() creates a NEW Entity + // for the same thread ID. If we only compare session IDs, the panel + // keeps observing the stale entity from state restoration while the + // new entity receives live updates — causing a "brain split" where + // Helix sees updates but Zed's display is frozen. if let ActiveView::AgentThread { server_view } = &this.active_view { if let Some(active_thread) = server_view.read(cx).active_thread() { - let existing_session_id = active_thread.read(cx).thread.read(cx).session_id().to_string(); - if existing_session_id == incoming_session_id { - eprintln!("🔄 [AGENT_PANEL] Already showing thread {}, skipping", incoming_session_id); + if active_thread.read(cx).thread == notification.thread_entity { + eprintln!("🔄 [AGENT_PANEL] Already showing thread {} with same entity, skipping", incoming_session_id); return; } + eprintln!("🔄 [AGENT_PANEL] Thread {} entity changed (container restart?), rebinding to new entity", incoming_session_id); } }