/// Utility class for parsing and extracting reasoning/thinking content from messages class ReasoningParser { /// Parses a message and extracts reasoning content static ReasoningContent? parseReasoningContent(String content) { if (content.isEmpty) return null; // Check if content contains reasoning if (!content.contains('
tag with type="reasoning" final reasoningRegex = RegExp( r']*>\s*([^<]*)\s*(.*?)\s*
', multiLine: true, dotAll: true, ); final match = reasoningRegex.firstMatch(content); if (match == null) { return null; } final isDone = match.group(1) == 'true'; final duration = int.tryParse(match.group(2) ?? '0') ?? 0; final summary = match.group(3)?.trim() ?? ''; final reasoning = match.group(4)?.trim() ?? ''; // Remove the reasoning section from the main content final mainContent = content.replaceAll(reasoningRegex, '').trim(); return ReasoningContent( reasoning: reasoning, summary: summary, duration: duration, isDone: isDone, mainContent: mainContent, originalContent: content, ); } /// Checks if a message contains reasoning content static bool hasReasoningContent(String content) { return content.contains('
identical(this, other) || other is ReasoningContent && runtimeType == other.runtimeType && reasoning == other.reasoning && summary == other.summary && duration == other.duration && isDone == other.isDone && mainContent == other.mainContent && originalContent == other.originalContent; @override int get hashCode => reasoning.hashCode ^ summary.hashCode ^ duration.hashCode ^ isDone.hashCode ^ mainContent.hashCode ^ originalContent.hashCode; String get formattedDuration => ReasoningParser.formatDuration(duration); /// Gets the cleaned reasoning text (removes leading '>') String get cleanedReasoning { // Split by lines and clean each line return reasoning .split('\n') .map((line) => line.startsWith('>') ? line.substring(1).trim() : line) .join('\n') .trim(); } }