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: - <details type="ing">...</details blocks - <think>think> and <ing>...</reason> 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.
This commit is contained in:
@@ -969,7 +969,33 @@ class _ChatPageState extends ConsumerState<ChatPage> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void _copyMessage(String content) {
|
void _copyMessage(String content) {
|
||||||
Clipboard.setData(ClipboardData(text: content));
|
// Strip reasoning details from the copied content
|
||||||
|
String cleanedContent = content;
|
||||||
|
|
||||||
|
// Remove <details type="reasoning"> blocks
|
||||||
|
cleanedContent = cleanedContent.replaceAll(
|
||||||
|
RegExp(
|
||||||
|
r'<details\s+type="reasoning"[^>]*>[\s\S]*?<\/details>',
|
||||||
|
multiLine: true,
|
||||||
|
dotAll: true,
|
||||||
|
),
|
||||||
|
'',
|
||||||
|
);
|
||||||
|
|
||||||
|
// Remove raw reasoning tags
|
||||||
|
cleanedContent = cleanedContent.replaceAll(
|
||||||
|
RegExp(r'<think>[\s\S]*?<\/think>', multiLine: true, dotAll: true),
|
||||||
|
'',
|
||||||
|
);
|
||||||
|
cleanedContent = cleanedContent.replaceAll(
|
||||||
|
RegExp(r'<reasoning>[\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 {
|
void _regenerateMessage(dynamic message) async {
|
||||||
|
|||||||
@@ -435,10 +435,6 @@ class _AssistantMessageWidgetState extends ConsumerState<AssistantMessageWidget>
|
|||||||
|
|
||||||
Widget _buildSegmentedContent() {
|
Widget _buildSegmentedContent() {
|
||||||
final children = <Widget>[];
|
final children = <Widget>[];
|
||||||
// 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;
|
bool firstToolSpacerAdded = false;
|
||||||
int idx = 0;
|
int idx = 0;
|
||||||
for (final seg in _segments) {
|
for (final seg in _segments) {
|
||||||
@@ -450,11 +446,6 @@ class _AssistantMessageWidgetState extends ConsumerState<AssistantMessageWidget>
|
|||||||
}
|
}
|
||||||
children.add(_buildToolCallTile(seg.toolCall!));
|
children.add(_buildToolCallTile(seg.toolCall!));
|
||||||
} else if (seg.isReasoning && seg.reasoning != null) {
|
} 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));
|
children.add(_buildReasoningTile(seg.reasoning!, idx));
|
||||||
} else if ((seg.text ?? '').trim().isNotEmpty) {
|
} else if ((seg.text ?? '').trim().isNotEmpty) {
|
||||||
children.add(_buildEnhancedMarkdownContent(seg.text!));
|
children.add(_buildEnhancedMarkdownContent(seg.text!));
|
||||||
|
|||||||
Reference in New Issue
Block a user