From 3bdbdaa80c97c8ab225e245902c9fa672b8eaec2 Mon Sep 17 00:00:00 2001 From: Testing Date: Thu, 14 May 2026 00:16:01 +0000 Subject: [PATCH] fix: push agent state to all WS connections and sync sidebar in background tabs - agent.py: add finally block to _process_chain that calls mark_dirty_all() so non-active tabs see running:false without manual refresh - message-queue-store.js: deduplicate allItems by id to prevent Alpine 'Duplicate key' errors during server-poll vs pending-item race - chats-list.html: add data-chat-id attribute for DOM-based targeting - index.js: move chatsStore/tasksStore updates before context-equality check so background state changes always reach the sidebar --- agent.py | 5 +++++ .../chat/message-queue/message-queue-store.js | 9 ++++++++- webui/components/sidebar/chats/chats-list.html | 2 +- webui/index.js | 15 +++++++-------- 4 files changed, 21 insertions(+), 10 deletions(-) diff --git a/agent.py b/agent.py index 267a90807..e875c1269 100644 --- a/agent.py +++ b/agent.py @@ -300,6 +300,11 @@ class AgentContext: return response except Exception as e: await self.handle_exception("process_chain", e) + finally: + # Push updated running state to ALL connections when agent finishes. + # Without this, non-active tabs don't see running:false until they click. + from helpers.state_monitor_integration import mark_dirty_all + mark_dirty_all(reason="agent.AgentContext._process_chain completed") @extension.extensible async def handle_exception(self, location: str, exception: Exception): diff --git a/webui/components/chat/message-queue/message-queue-store.js b/webui/components/chat/message-queue/message-queue-store.js index 9c83a50ba..ac556278b 100644 --- a/webui/components/chat/message-queue/message-queue-store.js +++ b/webui/components/chat/message-queue/message-queue-store.js @@ -47,8 +47,15 @@ const model = { }, // Combined items for display: confirmed first, then pending at the end + // Deduplicate by id to prevent Alpine "Duplicate key" errors during + // the race between server poll updates and pending item cleanup. get allItems() { - return [...this.items, ...this.pendingItems]; + const seen = new Set(); + return [...this.items, ...this.pendingItems].filter((item) => { + if (seen.has(item.id)) return false; + seen.add(item.id); + return true; + }); }, async addToQueue(text, attachments = []) { diff --git a/webui/components/sidebar/chats/chats-list.html b/webui/components/sidebar/chats/chats-list.html index 2c13755fc..e11317c84 100644 --- a/webui/components/sidebar/chats/chats-list.html +++ b/webui/components/sidebar/chats/chats-list.html @@ -24,7 +24,7 @@