diff --git a/lib/features/chat/widgets/assistant_message_widget.dart b/lib/features/chat/widgets/assistant_message_widget.dart index 1a614be..b6bc8d5 100644 --- a/lib/features/chat/widgets/assistant_message_widget.dart +++ b/lib/features/chat/widgets/assistant_message_widget.dart @@ -720,26 +720,14 @@ class _AssistantMessageWidgetState extends ConsumerState return const SizedBox.shrink(); } - // Always hide tool_calls blocks; tiles render them separately. - String cleaned = content.replaceAll( - RegExp( - r']*>[\s\S]*?<\/details>', - multiLine: true, - dotAll: true, - ), - '', - ); - // Also hide reasoning details blocks if any slipped into text - cleaned = cleaned.replaceAll( - RegExp( - r']*>[\s\S]*?<\/details>', - multiLine: true, - dotAll: true, - ), - '', - ); - // Remove raw ... or ... tags in text - cleaned = cleaned + // Note: The markdown parser now handles
tags (including type="reasoning" + // and type="tool_calls") via a custom block syntax, so they won't be rendered as + // plain text during streaming. This prevents character flashing. + + // We still clean raw reasoning tags (, ) as a fallback. + // The server normally converts these to
format, but raw mode or + // direct API responses might still use them. + String cleaned = content .replaceAll( RegExp(r'[\s\S]*?<\/think>', multiLine: true, dotAll: true), '', @@ -753,10 +741,6 @@ class _AssistantMessageWidgetState extends ConsumerState '', ); - // Note: The markdown parser now handles
tags via a custom block syntax, - // so they won't be rendered as plain text during streaming. This prevents the - // character flashing issue. - // Process images in the remaining text final processedContent = _processContentForImages(cleaned); diff --git a/lib/shared/widgets/markdown/markdown_config.dart b/lib/shared/widgets/markdown/markdown_config.dart index 6a974d9..42ec6cd 100644 --- a/lib/shared/widgets/markdown/markdown_config.dart +++ b/lib/shared/widgets/markdown/markdown_config.dart @@ -763,9 +763,11 @@ class _DetailsBuilder extends MarkdownElementBuilder { @override Widget? visitElementAfter(md.Element element, TextStyle? preferredStyle) { - // The details element should not be rendered as markdown during streaming. - // Instead, it's handled by the ReasoningParser in assistant_message_widget. - // Return empty widget to prevent flashing. + // Details elements with type="reasoning" or type="tool_calls" should not be + // rendered as markdown during streaming. They are handled by: + // - ReasoningParser for reasoning blocks (creates thinking tiles) + // - ToolCallsParser for tool_calls blocks (creates tool execution tiles) + // Return empty widget to prevent character flashing during streaming. return const SizedBox.shrink(); } }