fix(desktop): prevent empty blocks rendering in chat UI
- Guard empty thinking events from creating blank ThinkingBlock rows - Skip empty assistant_text from history loading - Hide ToolResultBlock when content is empty (non-error) - Add component-level null returns as safety net Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -8,6 +8,8 @@ type Props = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function AssistantMessage({ content, isStreaming }: Props) {
|
export function AssistantMessage({ content, isStreaming }: Props) {
|
||||||
|
if (!content.trim() && !isStreaming) return null
|
||||||
|
|
||||||
const documentLayout = shouldUseDocumentLayout(content)
|
const documentLayout = shouldUseDocumentLayout(content)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -17,6 +17,8 @@ export function ThinkingBlock({ content, isActive = false }: { content: string;
|
|||||||
const firstLine = lines[0]?.replace(/\s+/g, ' ').trim() || ''
|
const firstLine = lines[0]?.replace(/\s+/g, ' ').trim() || ''
|
||||||
const preview = firstLine.length > 80 ? firstLine.slice(0, 80) + '...' : firstLine
|
const preview = firstLine.length > 80 ? firstLine.slice(0, 80) + '...' : firstLine
|
||||||
|
|
||||||
|
if (!content.trim() && !isActive) return null
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="mb-1">
|
<div className="mb-1">
|
||||||
<style>{thinkingStyles}</style>
|
<style>{thinkingStyles}</style>
|
||||||
|
|||||||
@@ -23,6 +23,8 @@ export function ToolResultBlock({ content, isError, toolName, standalone = true
|
|||||||
if (!standalone) return null
|
if (!standalone) return null
|
||||||
|
|
||||||
const text = extractText(content)
|
const text = extractText(content)
|
||||||
|
if (!text.trim() && !isError) return null
|
||||||
|
|
||||||
const preview = text.slice(0, 200)
|
const preview = text.slice(0, 200)
|
||||||
const hasMore = text.length > 200
|
const hasMore = text.length > 200
|
||||||
|
|
||||||
|
|||||||
@@ -634,6 +634,9 @@ export const useChatStore = create<ChatStore>((set, get) => ({
|
|||||||
updated[updated.length - 1] = { ...last, content: last.content + msg.text }
|
updated[updated.length - 1] = { ...last, content: last.content + msg.text }
|
||||||
return { messages: updated, chatState: 'thinking', activeThinkingId: last.id, streamingText: '' }
|
return { messages: updated, chatState: 'thinking', activeThinkingId: last.id, streamingText: '' }
|
||||||
}
|
}
|
||||||
|
if (!msg.text) {
|
||||||
|
return { chatState: 'thinking', streamingText: '' }
|
||||||
|
}
|
||||||
const id = nextId()
|
const id = nextId()
|
||||||
return {
|
return {
|
||||||
messages: [...base, { id, type: 'thinking', content: msg.text, timestamp: Date.now() }],
|
messages: [...base, { id, type: 'thinking', content: msg.text, timestamp: Date.now() }],
|
||||||
@@ -1037,7 +1040,9 @@ export function mapHistoryMessagesToUiMessages(
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if (msg.type === 'assistant' && typeof msg.content === 'string') {
|
if (msg.type === 'assistant' && typeof msg.content === 'string') {
|
||||||
uiMessages.push({ id: msg.id || nextId(), type: 'assistant_text', content: msg.content, timestamp, model: msg.model })
|
if (msg.content.trim()) {
|
||||||
|
uiMessages.push({ id: msg.id || nextId(), type: 'assistant_text', content: msg.content, timestamp, model: msg.model })
|
||||||
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if ((msg.type === 'assistant' || msg.type === 'tool_use') && Array.isArray(msg.content)) {
|
if ((msg.type === 'assistant' || msg.type === 'tool_use') && Array.isArray(msg.content)) {
|
||||||
|
|||||||
Reference in New Issue
Block a user