@@ -151,28 +151,13 @@ const CopilotMessage: FC<CopilotMessageProps> = memo(
151151 } , [ message . content ] )
152152
153153 // Parse special tags from message content (options, plan)
154- // During streaming, also check content blocks since message.content may not be updated yet
154+ // Only parse after streaming is complete to avoid affecting streaming smoothness
155155 const parsedTags = useMemo ( ( ) => {
156- if ( isUser ) return null
157-
158- // Try message.content first
159- if ( message . content ) {
160- const parsed = parseSpecialTags ( message . content )
161- if ( parsed . options ) return parsed
162- }
163-
164- // During streaming, check content blocks for options
165- if ( message . contentBlocks && message . contentBlocks . length > 0 ) {
166- for ( const block of message . contentBlocks ) {
167- if ( block . type === 'text' && block . content ) {
168- const parsed = parseSpecialTags ( block . content )
169- if ( parsed . options ) return parsed
170- }
171- }
172- }
156+ if ( isUser || isStreaming ) return null
173157
158+ // Only parse when not streaming - options should appear after message completes
174159 return message . content ? parseSpecialTags ( message . content ) : null
175- } , [ message . content , message . contentBlocks , isUser ] )
160+ } , [ message . content , isUser , isStreaming ] )
176161
177162 // Get sendMessage from store for continuation actions
178163 const sendMessage = useCopilotStore ( ( s ) => s . sendMessage )
@@ -196,12 +181,14 @@ const CopilotMessage: FC<CopilotMessageProps> = memo(
196181 if ( block . type === 'text' ) {
197182 const isLastTextBlock =
198183 index === message . contentBlocks ! . length - 1 && block . type === 'text'
199- // Clean content for this text block - strip special tags and excessive newlines
200- const parsed = parseSpecialTags ( block . content )
201- const cleanBlockContent = parsed . cleanContent . replace ( / \n { 3 , } / g, '\n\n' )
184+ // During streaming, use raw content for smooth performance
185+ // Only strip special tags after streaming completes
186+ const cleanBlockContent = isStreaming
187+ ? block . content . replace ( / \n { 3 , } / g, '\n\n' )
188+ : parseSpecialTags ( block . content ) . cleanContent . replace ( / \n { 3 , } / g, '\n\n' )
202189
203- // Skip if no content after stripping tags
204- if ( ! cleanBlockContent . trim ( ) ) return null
190+ // Skip if no content after stripping tags (only when not streaming)
191+ if ( ! isStreaming && ! cleanBlockContent . trim ( ) ) return null
205192
206193 // Use smooth streaming for the last text block if we're streaming
207194 const shouldUseSmoothing = isStreaming && isLastTextBlock
@@ -508,14 +495,14 @@ const CopilotMessage: FC<CopilotMessageProps> = memo(
508495 </ div >
509496 ) }
510497
511- { /* Options selector when agent presents choices - streams in but disabled until complete */ }
512- { parsedTags ?. options && Object . keys ( parsedTags . options ) . length > 0 && (
498+ { /* Options selector when agent presents choices - only shown after streaming completes */ }
499+ { ! isStreaming && parsedTags ?. options && Object . keys ( parsedTags . options ) . length > 0 && (
513500 < OptionsSelector
514501 options = { parsedTags . options }
515502 onSelect = { handleOptionSelect }
516503 disabled = { isSendingMessage }
517- enableKeyboardNav = { isLastMessage && parsedTags . optionsComplete === true }
518- streaming = { ! parsedTags . optionsComplete }
504+ enableKeyboardNav = { isLastMessage }
505+ streaming = { false }
519506 />
520507 ) }
521508 </ div >
0 commit comments