From be623582706fd015d1851019063f71a183ac94a6 Mon Sep 17 00:00:00 2001 From: cogwheel0 <172976095+cogwheel0@users.noreply.github.com> Date: Thu, 23 Oct 2025 22:37:06 +0530 Subject: [PATCH] feat(chat): strip reasoning when copying Remove internal reasoning from copied message text to avoidleaking implementation details or developer-only when a user content from the chat- In chat_pagecopyMessage, cleaning steps to: -
...
think> and ... tags - trim leftover whitespace before writing to the clipboard - In assistant_message_widget._buildSegmentedContent, remove an unused hasMediaAbove calculation and a conditional spacer that added extra top padding before reasoning tiles. This simplifies rendering logic and avoids relying on removed spacing behavior. --- lib/features/chat/views/chat_page.dart | 28 ++++++++++++++++++- .../widgets/assistant_message_widget.dart | 9 ------ 2 files changed, 27 insertions(+), 10 deletions(-) diff --git a/lib/features/chat/views/chat_page.dart b/lib/features/chat/views/chat_page.dart index a157b4f..67c7e16 100644 --- a/lib/features/chat/views/chat_page.dart +++ b/lib/features/chat/views/chat_page.dart @@ -969,7 +969,33 @@ class _ChatPageState extends ConsumerState { } void _copyMessage(String content) { - Clipboard.setData(ClipboardData(text: content)); + // Strip reasoning details from the copied content + String cleanedContent = content; + + // Remove
blocks + cleanedContent = cleanedContent.replaceAll( + RegExp( + r']*>[\s\S]*?<\/details>', + multiLine: true, + dotAll: true, + ), + '', + ); + + // Remove raw reasoning tags + cleanedContent = cleanedContent.replaceAll( + RegExp(r'[\s\S]*?<\/think>', multiLine: true, dotAll: true), + '', + ); + cleanedContent = cleanedContent.replaceAll( + RegExp(r'[\s\S]*?<\/reasoning>', multiLine: true, dotAll: true), + '', + ); + + // Clean up any extra whitespace + cleanedContent = cleanedContent.trim(); + + Clipboard.setData(ClipboardData(text: cleanedContent)); } void _regenerateMessage(dynamic message) async { diff --git a/lib/features/chat/widgets/assistant_message_widget.dart b/lib/features/chat/widgets/assistant_message_widget.dart index 6bd4ea9..0359fba 100644 --- a/lib/features/chat/widgets/assistant_message_widget.dart +++ b/lib/features/chat/widgets/assistant_message_widget.dart @@ -435,10 +435,6 @@ class _AssistantMessageWidgetState extends ConsumerState Widget _buildSegmentedContent() { final children = []; - // Determine if media (attachments or generated images) is rendered above. - final hasMediaAbove = - (widget.message.attachmentIds?.isNotEmpty ?? false) || - (widget.message.files?.isNotEmpty ?? false); bool firstToolSpacerAdded = false; int idx = 0; for (final seg in _segments) { @@ -450,11 +446,6 @@ class _AssistantMessageWidgetState extends ConsumerState } children.add(_buildToolCallTile(seg.toolCall!)); } else if (seg.isReasoning && seg.reasoning != null) { - // If a reasoning tile is the very first content and sits at the top, - // add a small spacer above it for breathing room. - if (children.isEmpty && !hasMediaAbove) { - children.add(const SizedBox(height: Spacing.sm)); - } children.add(_buildReasoningTile(seg.reasoning!, idx)); } else if ((seg.text ?? '').trim().isNotEmpty) { children.add(_buildEnhancedMarkdownContent(seg.text!));