♻️ Refactor the thought insight to support new API

This commit is contained in:
2025-11-15 16:59:22 +08:00
parent ea8e7ead2d
commit 645a6dca93
8 changed files with 1397 additions and 124 deletions

View File

@@ -15,29 +15,62 @@ class ThoughtContent extends StatelessWidget {
final String streamingText;
final SnThinkingThought? thought;
bool get _isErrorMessage {
if (thought == null) return false;
// Check if this is an error thought by ID or content
if (thought!.id.startsWith('error-')) return true;
final textParts = thought!.parts
.where((p) => p.type == ThinkingMessagePartType.text)
.map((p) => p.text ?? '')
.join('');
return textParts.startsWith('Error:');
}
@override
Widget build(BuildContext context) {
if (isStreaming) {
// Streaming text with spinner
if (streamingText.isNotEmpty) {
final isStreamingError = streamingText.startsWith('Error:');
return Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(
child: MarkdownTextContent(
isSelectable: true,
content: streamingText,
extraBlockSyntaxList: [ProposalBlockSyntax()],
textStyle: Theme.of(context).textTheme.bodyMedium,
extraGenerators: [
ProposalGenerator(
backgroundColor:
Theme.of(context).colorScheme.secondaryContainer,
foregroundColor:
Theme.of(context).colorScheme.onSecondaryContainer,
borderColor: Theme.of(context).colorScheme.outline,
child: Container(
padding:
isStreamingError
? const EdgeInsets.all(8)
: EdgeInsets.zero,
decoration:
isStreamingError
? BoxDecoration(
border: Border.all(
color: Theme.of(context).colorScheme.error,
width: 1,
),
borderRadius: BorderRadius.circular(8),
)
: null,
child: MarkdownTextContent(
isSelectable: true,
content: streamingText,
extraBlockSyntaxList: [ProposalBlockSyntax()],
textStyle: Theme.of(context).textTheme.bodyMedium!.copyWith(
color:
isStreamingError
? Theme.of(context).colorScheme.error
: null,
),
],
extraGenerators: [
ProposalGenerator(
backgroundColor:
Theme.of(context).colorScheme.secondaryContainer,
foregroundColor:
Theme.of(context).colorScheme.onSecondaryContainer,
borderColor: Theme.of(context).colorScheme.outline,
),
],
),
),
),
const SizedBox(width: 8),
@@ -56,22 +89,53 @@ class ThoughtContent extends StatelessWidget {
}
return const SizedBox.shrink();
} else {
// Regular thought content
if (thought!.content != null && thought!.content!.isNotEmpty) {
return MarkdownTextContent(
isSelectable: true,
content: thought!.content!,
extraBlockSyntaxList: [ProposalBlockSyntax()],
textStyle: Theme.of(context).textTheme.bodyMedium,
extraGenerators: [
ProposalGenerator(
backgroundColor: Theme.of(context).colorScheme.secondaryContainer,
foregroundColor:
Theme.of(context).colorScheme.onSecondaryContainer,
borderColor: Theme.of(context).colorScheme.outline,
// Regular thought content - render parts
if (thought!.parts.isNotEmpty) {
final textParts = thought!.parts
.where((p) => p.type == ThinkingMessagePartType.text)
.map((p) => p.text ?? '')
.join('');
if (textParts.isNotEmpty) {
return Container(
padding:
_isErrorMessage
? const EdgeInsets.symmetric(horizontal: 12, vertical: 4)
: EdgeInsets.zero,
decoration:
_isErrorMessage
? BoxDecoration(
color: Theme.of(
context,
).colorScheme.error.withOpacity(0.1),
border: Border.all(
color: Theme.of(context).colorScheme.error,
width: 1,
),
borderRadius: BorderRadius.circular(8),
)
: null,
child: MarkdownTextContent(
isSelectable: true,
content: textParts,
extraBlockSyntaxList: [ProposalBlockSyntax()],
textStyle: Theme.of(context).textTheme.bodyMedium!.copyWith(
color:
_isErrorMessage
? Theme.of(context).colorScheme.error
: null,
),
extraGenerators: [
ProposalGenerator(
backgroundColor:
Theme.of(context).colorScheme.secondaryContainer,
foregroundColor:
Theme.of(context).colorScheme.onSecondaryContainer,
borderColor: Theme.of(context).colorScheme.outline,
),
],
),
],
);
);
}
}
return const SizedBox.shrink();
}