@@ -169,6 +169,8 @@ const ChatViewComponent: React.ForwardRefRenderFunction<ChatViewRef, ChatViewPro
169169 } ) ,
170170 )
171171 const autoApproveTimeoutRef = useRef < NodeJS . Timeout | null > ( null )
172+ const userRespondedRef = useRef < boolean > ( false )
173+ const [ currentFollowUpTs , setCurrentFollowUpTs ] = useState < number | null > ( null )
172174
173175 const clineAskRef = useRef ( clineAsk )
174176 useEffect ( ( ) => {
@@ -415,6 +417,15 @@ const ChatViewComponent: React.ForwardRefRenderFunction<ChatViewRef, ChatViewPro
415417 useEffect ( ( ) => {
416418 setExpandedRows ( { } )
417419 everVisibleMessagesTsRef . current . clear ( ) // Clear for new task
420+ setCurrentFollowUpTs ( null ) // Clear follow-up answered state for new task
421+
422+ // Clear any pending auto-approval timeout from previous task
423+ if ( autoApproveTimeoutRef . current ) {
424+ clearTimeout ( autoApproveTimeoutRef . current )
425+ autoApproveTimeoutRef . current = null
426+ }
427+ // Reset user response flag for new task
428+ userRespondedRef . current = false
418429 } , [ task ?. ts ] )
419430
420431 useEffect ( ( ) => {
@@ -486,7 +497,22 @@ const ChatViewComponent: React.ForwardRefRenderFunction<ChatViewRef, ChatViewPro
486497 return false
487498 } , [ modifiedMessages , clineAsk , enableButtons , primaryButtonText ] )
488499
500+ const markFollowUpAsAnswered = useCallback ( ( ) => {
501+ const lastFollowUpMessage = messagesRef . current . findLast ( ( msg ) => msg . ask === "followup" )
502+ if ( lastFollowUpMessage ) {
503+ setCurrentFollowUpTs ( lastFollowUpMessage . ts )
504+ }
505+ } , [ ] )
506+
489507 const handleChatReset = useCallback ( ( ) => {
508+ // Clear any pending auto-approval timeout
509+ if ( autoApproveTimeoutRef . current ) {
510+ clearTimeout ( autoApproveTimeoutRef . current )
511+ autoApproveTimeoutRef . current = null
512+ }
513+ // Reset user response flag for new message
514+ userRespondedRef . current = false
515+
490516 // Only reset message-specific state, preserving mode.
491517 setInputValue ( "" )
492518 setSendingDisabled ( true )
@@ -504,9 +530,16 @@ const ChatViewComponent: React.ForwardRefRenderFunction<ChatViewRef, ChatViewPro
504530 text = text . trim ( )
505531
506532 if ( text || images . length > 0 ) {
533+ // Mark that user has responded - this prevents any pending auto-approvals
534+ userRespondedRef . current = true
535+
507536 if ( messagesRef . current . length === 0 ) {
508537 vscode . postMessage ( { type : "newTask" , text, images } )
509538 } else if ( clineAskRef . current ) {
539+ if ( clineAskRef . current === "followup" ) {
540+ markFollowUpAsAnswered ( )
541+ }
542+
510543 // Use clineAskRef.current
511544 switch (
512545 clineAskRef . current // Use clineAskRef.current
@@ -530,7 +563,7 @@ const ChatViewComponent: React.ForwardRefRenderFunction<ChatViewRef, ChatViewPro
530563 handleChatReset ( )
531564 }
532565 } ,
533- [ handleChatReset ] , // messagesRef and clineAskRef are stable
566+ [ handleChatReset , markFollowUpAsAnswered ] , // messagesRef and clineAskRef are stable
534567 )
535568
536569 const handleSetChatBoxMessage = useCallback (
@@ -555,6 +588,9 @@ const ChatViewComponent: React.ForwardRefRenderFunction<ChatViewRef, ChatViewPro
555588 // extension.
556589 const handlePrimaryButtonClick = useCallback (
557590 ( text ?: string , images ?: string [ ] ) => {
591+ // Mark that user has responded
592+ userRespondedRef . current = true
593+
558594 const trimmedInput = text ?. trim ( )
559595
560596 switch ( clineAsk ) {
@@ -599,6 +635,9 @@ const ChatViewComponent: React.ForwardRefRenderFunction<ChatViewRef, ChatViewPro
599635
600636 const handleSecondaryButtonClick = useCallback (
601637 ( text ?: string , images ?: string [ ] ) => {
638+ // Mark that user has responded
639+ userRespondedRef . current = true
640+
602641 const trimmedInput = text ?. trim ( )
603642
604643 if ( isStreaming ) {
@@ -1219,6 +1258,16 @@ const ChatViewComponent: React.ForwardRefRenderFunction<ChatViewRef, ChatViewPro
12191258
12201259 const handleSuggestionClickInRow = useCallback (
12211260 ( suggestion : SuggestionItem , event ?: React . MouseEvent ) => {
1261+ // Mark that user has responded if this is a manual click (not auto-approval)
1262+ if ( event ) {
1263+ userRespondedRef . current = true
1264+ }
1265+
1266+ // Mark the current follow-up question as answered when a suggestion is clicked
1267+ if ( clineAsk === "followup" && ! event ?. shiftKey ) {
1268+ markFollowUpAsAnswered ( )
1269+ }
1270+
12221271 // Check if we need to switch modes
12231272 if ( suggestion . mode ) {
12241273 // Only switch modes if it's a manual click (event exists) or auto-approval is allowed
@@ -1238,7 +1287,7 @@ const ChatViewComponent: React.ForwardRefRenderFunction<ChatViewRef, ChatViewPro
12381287 handleSendMessage ( suggestion . answer , [ ] )
12391288 }
12401289 } ,
1241- [ handleSendMessage , setInputValue , switchToMode , alwaysAllowModeSwitch ] ,
1290+ [ handleSendMessage , setInputValue , switchToMode , alwaysAllowModeSwitch , clineAsk , markFollowUpAsAnswered ] ,
12421291 )
12431292
12441293 const handleBatchFileResponse = useCallback ( ( response : { [ key : string ] : boolean } ) => {
@@ -1248,11 +1297,8 @@ const ChatViewComponent: React.ForwardRefRenderFunction<ChatViewRef, ChatViewPro
12481297
12491298 // Handler for when FollowUpSuggest component unmounts
12501299 const handleFollowUpUnmount = useCallback ( ( ) => {
1251- // Clear the auto-approve timeout to prevent race conditions
1252- if ( autoApproveTimeoutRef . current ) {
1253- clearTimeout ( autoApproveTimeoutRef . current )
1254- autoApproveTimeoutRef . current = null
1255- }
1300+ // Mark that user has responded
1301+ userRespondedRef . current = true
12561302 } , [ ] )
12571303
12581304 const itemContent = useCallback (
@@ -1291,6 +1337,7 @@ const ChatViewComponent: React.ForwardRefRenderFunction<ChatViewRef, ChatViewPro
12911337 onSuggestionClick = { handleSuggestionClickInRow } // This was already stabilized
12921338 onBatchFileResponse = { handleBatchFileResponse }
12931339 onFollowUpUnmount = { handleFollowUpUnmount }
1340+ isFollowUpAnswered = { messageOrGroup . ts === currentFollowUpTs }
12941341 editable = {
12951342 messageOrGroup . type === "ask" &&
12961343 messageOrGroup . ask === "tool" &&
@@ -1322,6 +1369,7 @@ const ChatViewComponent: React.ForwardRefRenderFunction<ChatViewRef, ChatViewPro
13221369 handleSuggestionClickInRow ,
13231370 handleBatchFileResponse ,
13241371 handleFollowUpUnmount ,
1372+ currentFollowUpTs ,
13251373 alwaysAllowUpdateTodoList ,
13261374 enableButtons ,
13271375 primaryButtonText ,
@@ -1338,6 +1386,11 @@ const ChatViewComponent: React.ForwardRefRenderFunction<ChatViewRef, ChatViewPro
13381386 return
13391387 }
13401388
1389+ // Exit early if user has already responded
1390+ if ( userRespondedRef . current ) {
1391+ return
1392+ }
1393+
13411394 const autoApprove = async ( ) => {
13421395 if ( lastMessage ?. ask && isAutoApproved ( lastMessage ) ) {
13431396 // Special handling for follow-up questions
@@ -1354,9 +1407,17 @@ const ChatViewComponent: React.ForwardRefRenderFunction<ChatViewRef, ChatViewPro
13541407 if ( followUpData && followUpData . suggest && followUpData . suggest . length > 0 ) {
13551408 // Wait for the configured timeout before auto-selecting the first suggestion
13561409 await new Promise < void > ( ( resolve ) => {
1357- autoApproveTimeoutRef . current = setTimeout ( resolve , followupAutoApproveTimeoutMs )
1410+ autoApproveTimeoutRef . current = setTimeout ( ( ) => {
1411+ autoApproveTimeoutRef . current = null
1412+ resolve ( )
1413+ } , followupAutoApproveTimeoutMs )
13581414 } )
13591415
1416+ // Check if user responded manually
1417+ if ( userRespondedRef . current ) {
1418+ return
1419+ }
1420+
13601421 // Get the first suggestion
13611422 const firstSuggestion = followUpData . suggest [ 0 ]
13621423
@@ -1366,7 +1427,10 @@ const ChatViewComponent: React.ForwardRefRenderFunction<ChatViewRef, ChatViewPro
13661427 }
13671428 } else if ( lastMessage . ask === "tool" && isWriteToolAction ( lastMessage ) ) {
13681429 await new Promise < void > ( ( resolve ) => {
1369- autoApproveTimeoutRef . current = setTimeout ( resolve , writeDelayMs )
1430+ autoApproveTimeoutRef . current = setTimeout ( ( ) => {
1431+ autoApproveTimeoutRef . current = null
1432+ resolve ( )
1433+ } , writeDelayMs )
13701434 } )
13711435 }
13721436
0 commit comments