Skip to content

Commit 862456d

Browse files
authored
fix: flaky auto-approve (#62)
1 parent 25c21cb commit 862456d

File tree

1 file changed

+8
-18
lines changed

1 file changed

+8
-18
lines changed

packages/blink/src/react/use-dev-mode.ts

Lines changed: 8 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -125,9 +125,6 @@ export interface UseDevMode {
125125
*/
126126
export 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

Comments
 (0)