From 6880859fdb3674152055609be3235463e2abd8a5 Mon Sep 17 00:00:00 2001 From: Adam Weidman Date: Mon, 16 Mar 2026 15:55:46 -0400 Subject: [PATCH] feat(cli): auto-restart agent on background task completion When the agent is idle and a backgrounded execution completes, the completion output is now automatically submitted as a new turn instead of being silently dropped. Uses the same InjectionService listener pattern as user steering hints. --- packages/cli/src/ui/AppContainer.tsx | 42 +++++++++++++++++++++++----- 1 file changed, 35 insertions(+), 7 deletions(-) diff --git a/packages/cli/src/ui/AppContainer.tsx b/packages/cli/src/ui/AppContainer.tsx index b0a936a81b..e26bfffa0f 100644 --- a/packages/cli/src/ui/AppContainer.tsx +++ b/packages/cli/src/ui/AppContainer.tsx @@ -83,6 +83,7 @@ import { ProjectIdRequiredError, CoreToolCallStatus, buildUserSteeringHintPrompt, + formatBackgroundCompletionForModel, logBillingEvent, ApiKeyUpdatedEvent, type InjectionSource, @@ -1078,6 +1079,8 @@ Logging in with Google... Restarting Gemini CLI to continue. const pendingHintsRef = useRef([]); const [pendingHintCount, setPendingHintCount] = useState(0); + const pendingBgCompletionsRef = useRef([]); + const [pendingBgCompletionCount, setPendingBgCompletionCount] = useState(0); const consumePendingHints = useCallback(() => { if (pendingHintsRef.current.length === 0) { @@ -1090,16 +1093,18 @@ Logging in with Google... Restarting Gemini CLI to continue. }, []); useEffect(() => { - const hintListener = (text: string, source: InjectionSource) => { - if (source !== 'user_steering') { - return; + const injectionListener = (text: string, source: InjectionSource) => { + if (source === 'user_steering') { + pendingHintsRef.current.push(text); + setPendingHintCount((prev) => prev + 1); + } else if (source === 'background_completion') { + pendingBgCompletionsRef.current.push(text); + setPendingBgCompletionCount((prev) => prev + 1); } - pendingHintsRef.current.push(text); - setPendingHintCount((prev) => prev + 1); }; - config.injectionService.onInjection(hintListener); + config.injectionService.onInjection(injectionListener); return () => { - config.injectionService.offInjection(hintListener); + config.injectionService.offInjection(injectionListener); }; }, [config]); @@ -2135,6 +2140,29 @@ Logging in with Google... Restarting Gemini CLI to continue. pendingHintCount, ]); + useEffect(() => { + if ( + !isConfigInitialized || + streamingState !== StreamingState.Idle || + !isMcpReady || + pendingBgCompletionsRef.current.length === 0 + ) { + return; + } + + const bgText = pendingBgCompletionsRef.current.join('\n'); + pendingBgCompletionsRef.current = []; + setPendingBgCompletionCount(0); + + void submitQuery([{ text: formatBackgroundCompletionForModel(bgText) }]); + }, [ + isConfigInitialized, + isMcpReady, + streamingState, + submitQuery, + pendingBgCompletionCount, + ]); + const allToolCalls = useMemo( () => pendingHistoryItems