Skip to content

Conversation

cevheri
Copy link
Collaborator

@cevheri cevheri commented Jun 15, 2025

… link: #140

This addresses a critical bug that caused two distinct errors in the chat interface, primarily when rendering streaming markdown content with complex elements like code blocks.

  1. The !debugNeedsLayout Error
    Problem: When receiving a streaming response from the LLM, especially one containing markdown with code blocks, the application would frequently crash with a !debugNeedsLayout assertion error. This indicated that a widget was being painted or processed while its layout was still being calculated, a common issue with frequent and inefficient state updates on complex widgets.
    Root Cause: The Markit widget, which renders markdown, was a StatelessWidget that rebuilt the entire MarkdownBlock on every single data chunk received from the stream. This caused significant performance bottlenecks and race conditions in Flutter's rendering pipeline.
  2. The Markit widget had been converted to a StatefulWidget, but its state initialization logic in initState improperly accessed Theme.of(context). According to Flutter's widget lifecycle, context-dependent objects like themes cannot be accessed in initState because the widget has not yet been fully mounted in the tree.
    Solution Implemented:
    A two-part solution was implemented to resolve both issues and improve overall performance and stability.
  3. Optimized Widget Reconciliation and State Management:
    Unique Keys: Added unique ValueKeys to MessageBubble widgets within ChatMessageContent. This ensures Flutter's reconciliation algorithm can correctly identify and update widgets during rebuilds, preventing unnecessary tree mutations.
    Lifecycle-Aware Caching in Markit Widget:
    The _MarkitState was refactored to remove all context-dependent logic from initState.
    The markdown rendering logic now resides entirely within the build method.
    The rendered MarkdownBlock widget is cached in a state variable (_cachedMarkdown).
    This cache is only invalidated and rebuilt if:
    The input data string changes.
    The Theme.of(context).brightness changes (to support dark/light mode switching).
    This approach ensures that expensive markdown parsing and rendering only occur when absolutely necessary, respecting the widget lifecycle and eliminating both the layout and dependency errors.
    These changes have made the chat interface more robust, performant, and free of rendering-related crashes, especially during real-time message streaming.

Updated versions for the following packages:
- checked_yaml: 2.0.3 -> 2.0.4
- coverage: 1.14.0 -> 1.14.1
- file_picker: 10.1.9 -> 10.2.0
- flutter_launcher_icons: 0.14.3 -> 0.14.4
- flutter_popup: 3.3.7 -> 3.3.9
- sqflite_common_ffi: 2.3.5 -> 2.3.6
- vector_graphics: 1.1.18 -> 1.1.19
- watcher: 1.1.1 -> 1.1.2
- win32: 5.13.0 -> 5.14.0
@daodao97
Copy link
Owner

This is a great improvement, thanks for your contribution

@daodao97 daodao97 merged commit cf5bf43 into daodao97:main Jun 15, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants