refactor(chat): execution graph optimize (#873)

Co-authored-by: Haze <hazeone@users.noreply.github.com>
This commit is contained in:
Haze
2026-04-19 19:36:33 +08:00
committed by GitHub
parent 2f03aa1fad
commit 1b2dccee6e
24 changed files with 1444 additions and 536 deletions

View File

@@ -16,9 +16,17 @@ import { extractText, extractThinking, extractImages, extractToolUse, formatTime
interface ChatMessageProps {
message: RawMessage;
showThinking: boolean;
textOverride?: string;
suppressToolCards?: boolean;
suppressProcessAttachments?: boolean;
/**
* When true, hides the assistant text bubble (and any thinking block that
* would be shown above it). Used when the message's text is being folded
* into an ExecutionGraphCard as a narration step, to prevent the same text
* from appearing both inside the graph and as an orphan bubble in the chat
* stream.
*/
suppressAssistantText?: boolean;
isStreaming?: boolean;
streamingTools?: Array<{
id?: string;
@@ -41,21 +49,27 @@ function imageSrc(img: ExtractedImage): string | null {
export const ChatMessage = memo(function ChatMessage({
message,
showThinking,
textOverride,
suppressToolCards = false,
suppressProcessAttachments = false,
suppressAssistantText = false,
isStreaming = false,
streamingTools = [],
}: ChatMessageProps) {
const isUser = message.role === 'user';
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 text = textOverride ?? extractText(message);
// When text is folded into an ExecutionGraphCard, treat the message as
// having no text for rendering purposes. Keeping this behind a flag (vs
// blanking `text` outright) lets future hover affordances still read the
// original content without surfacing the bubble.
const hideAssistantText = suppressAssistantText && !isUser;
const hasText = !hideAssistantText && text.trim().length > 0;
const visibleThinkingRaw = extractThinking(message);
const visibleThinking = hideAssistantText ? null : visibleThinkingRaw;
const images = extractImages(message);
const tools = extractToolUse(message);
const visibleThinking = showThinking ? thinking : null;
const visibleTools = suppressToolCards ? [] : tools;
const shouldHideProcessAttachments = suppressProcessAttachments
&& (hasText || !!visibleThinking || images.length > 0 || visibleTools.length > 0);