fix(chat): prevent duplicate renderer requests and thinking messages (#870)

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Haze <hazeone@users.noreply.github.com>
This commit is contained in:
Haze
2026-04-18 15:23:16 +08:00
committed by GitHub
parent 6d67a77633
commit 24b43335f8
12 changed files with 789 additions and 119 deletions

View File

@@ -491,6 +491,7 @@ export function ChatInput({ onSend, onStop, disabled = false, sending = false, i
onPaste={handlePaste}
placeholder={disabled ? t('composer.gatewayDisconnectedPlaceholder') : ''}
disabled={disabled}
data-testid="chat-composer-input"
className="min-h-[40px] max-h-[200px] resize-none border-0 focus-visible:ring-0 focus-visible:ring-offset-0 shadow-none bg-transparent py-2.5 px-2 text-[15px] placeholder:text-muted-foreground/60 leading-relaxed"
rows={1}
/>
@@ -501,6 +502,7 @@ export function ChatInput({ onSend, onStop, disabled = false, sending = false, i
onClick={sending ? handleStop : handleSend}
disabled={sending ? !canStop : !canSend}
size="icon"
data-testid="chat-composer-send"
className={`shrink-0 h-10 w-10 rounded-full transition-colors ${
(sending || canSend)
? 'bg-black/5 dark:bg-white/10 text-foreground hover:bg-black/10 dark:hover:bg-white/20'

View File

@@ -25,6 +25,44 @@ function cleanUserText(text: string): string {
.trim();
}
function normalizeProgressiveText(text: string | undefined): string {
return typeof text === 'string' ? text.replace(/\r\n/g, '\n').trim() : '';
}
function compactProgressiveParts(parts: string[]): string[] {
const compacted: string[] = [];
for (const part of parts) {
const current = normalizeProgressiveText(part);
if (!current) continue;
const previous = compacted.at(-1);
if (!previous) {
compacted.push(part);
continue;
}
const normalizedPrevious = normalizeProgressiveText(previous);
if (!normalizedPrevious) {
compacted[compacted.length - 1] = part;
continue;
}
if (current === normalizedPrevious || normalizedPrevious.startsWith(current)) {
continue;
}
if (current.startsWith(normalizedPrevious)) {
compacted[compacted.length - 1] = part;
continue;
}
compacted.push(part);
}
return compacted;
}
/**
* Extract displayable text from a message's content field.
* Handles both string content and array-of-blocks content.
@@ -49,7 +87,7 @@ export function extractText(message: RawMessage | unknown): string {
}
}
}
const combined = parts.join('\n\n');
const combined = compactProgressiveParts(parts).join('\n\n');
result = combined.trim().length > 0 ? combined : '';
} else if (typeof msg.text === 'string') {
// Fallback: try .text field
@@ -85,7 +123,7 @@ export function extractThinking(message: RawMessage | unknown): string | null {
}
}
const combined = parts.join('\n\n').trim();
const combined = compactProgressiveParts(parts).join('\n\n').trim();
return combined.length > 0 ? combined : null;
}