You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@rocketmq.apache.org by li...@apache.org on 2026/09/21 13:10:44 UTC
(rocketmq-dashboard) branch rocketmq-studio updated: fix: prevent unread badge from inflating when streaming fails (#4715)
This is an automated email from the ASF dual-hosted git repository.
lizhimins pushed a commit to branch rocketmq-studio
in repository https://gitbox.apache.org/repos/asf/rocketmq-dashboard.git
The following commit(s) were added to refs/heads/rocketmq-studio by this push:
new ef9b98269 fix: prevent unread badge from inflating when streaming fails (#4715)
ef9b98269 is described below
commit ef9b98269ad85ae0cf230c1f687f6ae366c926fc
Author: cyberslack_lee <je...@163.com>
AuthorDate: Mon Sep 21 21:10:39 2026 +0800
fix: prevent unread badge from inflating when streaming fails (#4715)
`ChatThread.tsx` counted unread messages with an effect keyed on `bubbleCount` that incremented on any change, although its own comment says it counts what arrives while the reader is away. `bubbleCount` is `bubbles.length` plus one whenever live blocks exist, so it goes down too: when an SSE read fails, `useAgentRun` finishes the stream and refetches the timeline, and if the run has not written an assistant row yet the refetch clears the live blocks and the count drops. A reader who [...]
The effect now keeps the previous count in a ref and returns early unless the count actually grew, so only arrivals increment the badge. That is the component's only increment site — the other three write points clear it — and a conversation switch already resets `atBottomRef` before this effect runs, so nothing is counted across a switch.
---
web/src/pages/ai/components/ChatThread.tsx | 7 +++++-
.../ai/components/__tests__/ChatThread.test.tsx | 27 ++++++++++++++++++++++
2 files changed, 33 insertions(+), 1 deletion(-)
diff --git a/web/src/pages/ai/components/ChatThread.tsx b/web/src/pages/ai/components/ChatThread.tsx
index b350070b5..e954163e5 100644
--- a/web/src/pages/ai/components/ChatThread.tsx
+++ b/web/src/pages/ai/components/ChatThread.tsx
@@ -100,6 +100,7 @@ const ChatThread = ({
const positionedRef = useRef(false);
const [atBottom, setAtBottom] = useState(true);
const [unread, setUnread] = useState(0);
+ const prevBubbleCountRef = useRef(bubbles.length);
const bubbleCount = bubbles.length + (liveBlocks && liveBlocks.length > 0 ? 1 : 0);
@@ -149,8 +150,12 @@ const ChatThread = ({
}, [bubbles, followToBottom, liveBlocks]);
// Count what arrives while the reader is away: one per message, not one per streamed token.
+ // Only a genuine increase in bubble count is a new message — a streaming failure that removes
+ // the live bubble must not inflate the badge.
useEffect(() => {
- if (atBottomRef.current) return;
+ const previous = prevBubbleCountRef.current;
+ prevBubbleCountRef.current = bubbleCount;
+ if (atBottomRef.current || bubbleCount <= previous) return;
setUnread((count) => count + 1);
}, [bubbleCount]);
diff --git a/web/src/pages/ai/components/__tests__/ChatThread.test.tsx b/web/src/pages/ai/components/__tests__/ChatThread.test.tsx
index 75f909b64..a1d0f7773 100644
--- a/web/src/pages/ai/components/__tests__/ChatThread.test.tsx
+++ b/web/src/pages/ai/components/__tests__/ChatThread.test.tsx
@@ -222,6 +222,33 @@ describe('ChatThread', () => {
expect(screen.queryByTestId('ai-thread-jump-to-latest')).not.toBeInTheDocument();
});
+ it('doesNotInflateUnreadWhenStreamingFailsAndLiveBlocksDisappearTest', () => {
+ const { rerender } = renderThread({ bubbles: [userBubble('检查集群状态')] });
+ placeReader(600);
+ fireEvent.scroll(screen.getByTestId('ai-thread-scroll'));
+
+ // The answer starts streaming: one new message arrives.
+ rerender(
+ <LangProvider>
+ <ChatThread
+ bubbles={[userBubble('检查集群状态')]}
+ liveBlocks={appendText([], '部分')}
+ streaming
+ />
+ </LangProvider>,
+ );
+ expect(screen.getByTestId('ai-thread-unread')).toHaveTextContent('1');
+
+ // Streaming fails / is aborted and the live bubble disappears without being persisted.
+ // The unread count must not increase when a bubble is removed.
+ rerender(
+ <LangProvider>
+ <ChatThread bubbles={[userBubble('检查集群状态')]} />
+ </LangProvider>,
+ );
+ expect(screen.getByTestId('ai-thread-unread')).toHaveTextContent('1');
+ });
+
it('rendersTheEmptySlotWhenThereIsNoTranscriptTest', () => {
render(
<LangProvider>