@@ -125,9 +125,6 @@ export interface UseDevMode {
125125 */
126126export default function useDevMode ( options : UseDevModeOptions ) : UseDevMode {
127127 const { directory } = options ;
128-
129- // Approval handling state (declared early so it can be used in callbacks)
130- const [ approvalHandled , setApprovalHandled ] = useState < string | undefined > ( ) ;
131128 const [ autoApprove , setAutoApprove ] = useState ( false ) ;
132129
133130 // Mode state
@@ -141,8 +138,6 @@ export default function useDevMode(options: UseDevModeOptions): UseDevMode {
141138 ( newMode : DevMode ) => {
142139 setModeState ( newMode ) ;
143140 options . onModeChange ?.( newMode ) ;
144- // Clear approval state when switching modes
145- setApprovalHandled ( undefined ) ;
146141 } ,
147142 [ options . onModeChange ]
148143 ) ;
@@ -504,11 +499,6 @@ export default function useDevMode(options: UseDevModeOptions): UseDevMode {
504499 if ( ! lastMessage ) {
505500 return ;
506501 }
507- // Don't show approval prompt if we've already handled this message
508- if ( approvalHandled === lastMessage . id ) {
509- return ;
510- }
511-
512502 const parts = lastMessage . parts . filter ( isToolOrDynamicToolUIPart ) ;
513503 if ( parts . length === 0 ) {
514504 return ;
@@ -521,8 +511,9 @@ export default function useDevMode(options: UseDevModeOptions): UseDevMode {
521511 return lastMessage as UIMessage ;
522512 }
523513 return undefined ;
524- } , [ chat . messages , approvalHandled ] ) ;
514+ } , [ chat . messages ] ) ;
525515
516+ const approvalHandledRef = useRef < string | undefined > ( undefined ) ;
526517 const handleApproval = useCallback (
527518 async ( approved : boolean , enableAutoApprove ?: boolean ) => {
528519 if ( ! needsApproval ) return ;
@@ -532,9 +523,6 @@ export default function useDevMode(options: UseDevModeOptions): UseDevMode {
532523 setAutoApprove ( true ) ;
533524 }
534525
535- // Mark this message as handled immediately
536- setApprovalHandled ( needsApproval . id ) ;
537-
538526 const messages = chat . messages ;
539527 if ( messages . length === 0 ) {
540528 return ;
@@ -549,6 +537,12 @@ export default function useDevMode(options: UseDevModeOptions): UseDevMode {
549537 if ( ! Array . isArray ( lastMsg . parts ) ) {
550538 return ;
551539 }
540+ if ( approvalHandledRef . current === lastMsg . id ) {
541+ return ;
542+ }
543+ // CRITICAL: all code before this point must be synchronous.
544+ // Otherwise, the approval may be handled multiple times.
545+ approvalHandledRef . current = lastMsg . id ;
552546 // Update all pending approval outputs
553547 const updatedParts = lastMsg . parts . map ( ( part : any ) => {
554548 if (
@@ -589,14 +583,10 @@ export default function useDevMode(options: UseDevModeOptions): UseDevMode {
589583 const id = crypto . randomUUID ( ) ;
590584 setChatId ( id ) ;
591585 setChatIds ( ( prev ) => [ ...prev , id ] ) ;
592- // Clear approval state when switching chats
593- setApprovalHandled ( undefined ) ;
594586 } , [ ] ) ;
595587
596588 const switchChat = useCallback ( ( id : ID ) => {
597589 setChatId ( id ) ;
598- // Clear approval state when switching chats
599- setApprovalHandled ( undefined ) ;
600590 } , [ ] ) ;
601591
602592 // Build approval object if needed
0 commit comments