Unverified 提交 9ee8a523 authored 作者: Will Chen's avatar Will Chen 提交者: GitHub

Prevent duplicate chat streams when one is already in progress (#2243)

上级 e655e5e4
...@@ -33,6 +33,10 @@ export function getRandomNumberId() { ...@@ -33,6 +33,10 @@ export function getRandomNumberId() {
return Math.floor(Math.random() * 1_000_000_000_000_000); return Math.floor(Math.random() * 1_000_000_000_000_000);
} }
// Module-level set to track chatIds with active/pending streams
// This prevents race conditions when clicking rapidly before state updates
const pendingStreamChatIds = new Set<number>();
export function useStreamChat({ export function useStreamChat({
hasChatId = true, hasChatId = true,
}: { hasChatId?: boolean } = {}) { }: { hasChatId?: boolean } = {}) {
...@@ -86,6 +90,19 @@ export function useStreamChat({ ...@@ -86,6 +90,19 @@ export function useStreamChat({
return; return;
} }
// Prevent duplicate streams - check module-level set to avoid race conditions
if (pendingStreamChatIds.has(chatId)) {
console.warn(
`[CHAT] Ignoring duplicate stream request for chat ${chatId} - stream already in progress`,
);
// Call onSettled to allow callers to clean up their local loading state
onSettled?.();
return;
}
// Mark this chat as having a pending stream
pendingStreamChatIds.add(chatId);
setRecentStreamChatIds((prev) => { setRecentStreamChatIds((prev) => {
const next = new Set(prev); const next = new Set(prev);
next.add(chatId); next.add(chatId);
...@@ -127,6 +144,9 @@ export function useStreamChat({ ...@@ -127,6 +144,9 @@ export function useStreamChat({
}); });
}, },
onEnd: (response: ChatResponseEnd) => { onEnd: (response: ChatResponseEnd) => {
// Remove from pending set now that stream is complete
pendingStreamChatIds.delete(chatId);
if (response.updatedFiles) { if (response.updatedFiles) {
setIsPreviewOpen(true); setIsPreviewOpen(true);
refreshAppIframe(); refreshAppIframe();
...@@ -159,6 +179,9 @@ export function useStreamChat({ ...@@ -159,6 +179,9 @@ export function useStreamChat({
onSettled?.(); onSettled?.();
}, },
onError: (errorMessage: string) => { onError: (errorMessage: string) => {
// Remove from pending set now that stream ended with error
pendingStreamChatIds.delete(chatId);
console.error(`[CHAT] Stream error for ${chatId}:`, errorMessage); console.error(`[CHAT] Stream error for ${chatId}:`, errorMessage);
setErrorById((prev) => { setErrorById((prev) => {
const next = new Map(prev); const next = new Map(prev);
...@@ -180,6 +203,9 @@ export function useStreamChat({ ...@@ -180,6 +203,9 @@ export function useStreamChat({
}, },
}); });
} catch (error) { } catch (error) {
// Remove from pending set on exception
pendingStreamChatIds.delete(chatId);
console.error("[CHAT] Exception during streaming setup:", error); console.error("[CHAT] Exception during streaming setup:", error);
setIsStreamingById((prev) => { setIsStreamingById((prev) => {
const next = new Map(prev); const next = new Map(prev);
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论