@@ -21,6 +21,11 @@ struct MessageListView: View {
2121 @Environment ( ChatBridge . self) private var chatBridge
2222 @Environment ( WindowState . self) private var windowState
2323 @State private var settledItems : [ ChatMessage ] = [ ]
24+ /// Pre-grouped rows for `settledItems`. Streaming deltas re-evaluate this
25+ /// view frequently, so rebuilding every historical row from `settledItems`
26+ /// in `body` makes long threads do work proportional to their full history
27+ /// for every delta.
28+ @State private var settledTranscriptItems : [ ChatTranscriptListItem ] = [ ]
2429 /// Owns the debounced content-growth scroll.
2530 @State private var scrollTask : Task < Void , Never > ?
2631 /// Owns the multi-frame "settle at the bottom" sweep used on session open
@@ -293,7 +298,7 @@ struct MessageListView: View {
293298 var items : [ ChatTranscriptListItem ] = [
294299 . accessory( . init( id: " desktop-top-padding " , kind: . topPadding) ) ,
295300 ]
296- items += ChatTranscriptListItem . items ( for : settledItems )
301+ items += settledTranscriptItems
297302
298303 if !windowState. focusMode {
299304 let activeMessages = activeResponseMessages ( from: chatBridge. messages)
@@ -343,9 +348,18 @@ struct MessageListView: View {
343348 private func rebuildSettledItems( ) {
344349 PerformanceDiagnostics . increment ( " chat.settled_rebuild.total " )
345350 let messages = settledOnlyMessages ( from: chatBridge. messages)
351+ guard messages != settledItems else {
352+ PerformanceDiagnostics . increment ( " chat.settled_rebuild.skipped_unchanged " )
353+ return
354+ }
355+ let transcriptItems = ChatTranscriptListItem . items ( for: messages)
346356 var t = Transaction ( )
347357 t. animation = nil
348- withTransaction ( t) { settledItems = messages }
358+ withTransaction ( t) {
359+ settledItems = messages
360+ settledTranscriptItems = transcriptItems
361+ }
362+ PerformanceDiagnostics . increment ( " chat.settled_rebuild.applied " )
349363 }
350364
351365 private func handleLastMessageChange( ) {
0 commit comments