diff --git a/src/pages/Chat/ChatMessage.tsx b/src/pages/Chat/ChatMessage.tsx index d84c09cf4..2fb2b43d9 100644 --- a/src/pages/Chat/ChatMessage.tsx +++ b/src/pages/Chat/ChatMessage.tsx @@ -16,25 +16,38 @@ interface ChatMessageProps { message: RawMessage; showThinking: boolean; isStreaming?: boolean; + streamingTools?: Array<{ + id?: string; + toolCallId?: string; + name: string; + status: 'running' | 'completed' | 'error'; + durationMs?: number; + summary?: string; + }>; } export const ChatMessage = memo(function ChatMessage({ message, showThinking, isStreaming = false, + streamingTools = [], }: ChatMessageProps) { const isUser = message.role === 'user'; - const isToolResult = message.role === 'toolresult'; + const role = typeof message.role === 'string' ? message.role.toLowerCase() : ''; + const isToolResult = role === 'toolresult' || role === 'tool_result'; const text = extractText(message); + const hasText = text.trim().length > 0; const thinking = extractThinking(message); const images = extractImages(message); const tools = extractToolUse(message); + const visibleThinking = showThinking ? thinking : null; + const visibleTools = showThinking ? tools : []; - // Don't render empty tool results when thinking is hidden - if (isToolResult && !showThinking) return null; + // Never render tool result messages in chat UI + if (isToolResult) return null; // Don't render empty messages - if (!text && !thinking && images.length === 0 && tools.length === 0) return null; + if (!hasText && !visibleThinking && images.length === 0 && visibleTools.length === 0) return null; return (
{/* Content */} -
+
+ {showThinking && isStreaming && !isUser && streamingTools.length > 0 && ( + + )} + {/* Thinking section */} - {showThinking && thinking && ( - + {visibleThinking && ( + )} {/* Tool use cards */} - {showThinking && tools.length > 0 && ( + {visibleTools.length > 0 && (
- {tools.map((tool, i) => ( + {visibleTools.map((tool, i) => ( ))}
)} {/* Main text bubble */} - {text && ( + {hasText && ( ; +}) { + return ( +
+
+ {tools.map((tool) => { + const duration = formatDuration(tool.durationMs); + const statusLabel = tool.status === 'running' ? 'running' : (tool.status === 'error' ? 'error' : 'done'); + return ( +
+ + {tool.name} + {statusLabel} + + {duration && {duration}} + {tool.summary && ( + {tool.summary} + )} +
+ ); + })} +
+
+ ); +} + // ── Message Bubble ────────────────────────────────────────────── function MessageBubble({ @@ -124,6 +191,7 @@ function MessageBubble({
+