@@ -471,7 +471,6 @@ private struct ConversationMessageList: View {
471471 }
472472 . frame ( maxWidth: . infinity, minHeight: viewport. size. height, alignment: . top)
473473 }
474- . defaultScrollAnchor ( . bottom)
475474 . onAppear {
476475 syncTranscriptTurns ( )
477476 syncRichRenderedTurns ( reset: true )
@@ -533,13 +532,19 @@ private struct ConversationMessageList: View {
533532 syncRichRenderedTurns ( )
534533 }
535534 }
536- . onChange ( of: items. count) {
537- scheduleScrollToBottom ( proxy)
538- }
539535 . onChange ( of: collapseTurns) {
540536 syncTranscriptTurns ( resetExpansion: true )
541537 syncRichRenderedTurns ( reset: true )
542538 }
539+ . onChange ( of: followScrollToken) {
540+ guard isStreaming else { return }
541+ scheduleScrollToBottom (
542+ proxy,
543+ delay: 0.01 ,
544+ replacePending: true ,
545+ animation: nil
546+ )
547+ }
543548 . onChange ( of: threadStatus) {
544549 syncTranscriptTurns ( )
545550 syncRichRenderedTurns ( )
@@ -551,8 +556,14 @@ private struct ConversationMessageList: View {
551556 animation: . linear( duration: 0.12 )
552557 )
553558 } else {
559+ let shouldFinalizeAtBottom = autoFollowStreaming || isNearBottom
554560 userIsDraggingScroll = false
555- scheduleScrollToBottom ( proxy, delay: 0.1 , force: true )
561+ scheduleScrollToBottom (
562+ proxy,
563+ delay: 0.08 ,
564+ force: shouldFinalizeAtBottom,
565+ animation: nil
566+ )
556567 }
557568 }
558569 . onChange ( of: streamingRenderTick) {
@@ -564,15 +575,6 @@ private struct ConversationMessageList: View {
564575 animation: nil
565576 )
566577 }
567- . onChange ( of: transcriptLayoutTick) {
568- guard !isStreaming else { return }
569- scheduleScrollToBottom (
570- proxy,
571- delay: 0.01 ,
572- replacePending: true ,
573- animation: nil
574- )
575- }
576578 . onDisappear {
577579 pendingScrollWorkItem? . cancel ( )
578580 pendingScrollWorkItem = nil
0 commit comments