From 734da8b9d24ab7e2cfcfe80e43f061734b7ae6ba Mon Sep 17 00:00:00 2001 From: Sandy Tao Date: Mon, 14 Jul 2025 20:25:16 -0700 Subject: Introduce loop detection service that breaks simple loop (#3919) Co-authored-by: Scott Densmore Co-authored-by: N. Taylor Mullen --- packages/cli/src/ui/hooks/useGeminiStream.ts | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) (limited to 'packages/cli/src') diff --git a/packages/cli/src/ui/hooks/useGeminiStream.ts b/packages/cli/src/ui/hooks/useGeminiStream.ts index 21d57b3b..9fa23c52 100644 --- a/packages/cli/src/ui/hooks/useGeminiStream.ts +++ b/packages/cli/src/ui/hooks/useGeminiStream.ts @@ -141,6 +141,8 @@ export const useGeminiStream = ( [toolCalls], ); + const loopDetectedRef = useRef(false); + const onExec = useCallback(async (done: Promise) => { setIsResponding(true); await done; @@ -450,6 +452,16 @@ export const useGeminiStream = ( [addItem, config], ); + const handleLoopDetectedEvent = useCallback(() => { + addItem( + { + type: 'info', + text: `A potential loop was detected. This can happen due to repetitive tool calls or other model behavior. The request has been halted.`, + }, + Date.now(), + ); + }, [addItem]); + const processGeminiStreamEvents = useCallback( async ( stream: AsyncIterable, @@ -489,6 +501,11 @@ export const useGeminiStream = ( case ServerGeminiEventType.MaxSessionTurns: handleMaxSessionTurnsEvent(); break; + case ServerGeminiEventType.LoopDetected: + // handle later because we want to move pending history to history + // before we add loop detected message to history + loopDetectedRef.current = true; + break; default: { // enforces exhaustive switch-case const unreachable: never = event; @@ -579,6 +596,10 @@ export const useGeminiStream = ( addItem(pendingHistoryItemRef.current, userMessageTimestamp); setPendingHistoryItem(null); } + if (loopDetectedRef.current) { + loopDetectedRef.current = false; + handleLoopDetectedEvent(); + } } catch (error: unknown) { if (error instanceof UnauthorizedError) { onAuthError(); @@ -616,6 +637,7 @@ export const useGeminiStream = ( config, startNewPrompt, getPromptCount, + handleLoopDetectedEvent, ], ); -- cgit v1.2.3