diff --git a/packages/cli/src/ui/AppContainer.tsx b/packages/cli/src/ui/AppContainer.tsx index 241e0f3030..259913f161 100644 --- a/packages/cli/src/ui/AppContainer.tsx +++ b/packages/cli/src/ui/AppContainer.tsx @@ -85,7 +85,6 @@ import { buildUserSteeringHintPrompt, logBillingEvent, ApiKeyUpdatedEvent, - type InjectionSource, } from '@google/gemini-cli-core'; import { validateAuthMethod } from '../config/auth.js'; import process from 'node:process'; @@ -1078,8 +1077,6 @@ Logging in with Google... Restarting Gemini CLI to continue. const pendingHintsRef = useRef([]); const [pendingHintCount, setPendingHintCount] = useState(0); - const pendingBackgroundCompletionsRef = useRef([]); - const [pendingBgCompletionCount, setPendingBgCompletionCount] = useState(0); const consumePendingHints = useCallback(() => { if (pendingHintsRef.current.length === 0) { @@ -1091,29 +1088,14 @@ Logging in with Google... Restarting Gemini CLI to continue. return hint; }, []); - const consumePendingBackgroundCompletions = useCallback(() => { - if (pendingBackgroundCompletionsRef.current.length === 0) { - return null; - } - const output = pendingBackgroundCompletionsRef.current.join('\n'); - pendingBackgroundCompletionsRef.current = []; - setPendingBgCompletionCount(0); - return output; - }, []); - useEffect(() => { - const injectionListener = (text: string, source: InjectionSource) => { - if (source === 'user_steering') { - pendingHintsRef.current.push(text); - setPendingHintCount((prev) => prev + 1); - } else if (source === 'background_completion') { - pendingBackgroundCompletionsRef.current.push(text); - setPendingBgCompletionCount((prev) => prev + 1); - } + const hintListener = (hint: string) => { + pendingHintsRef.current.push(hint); + setPendingHintCount((prev) => prev + 1); }; - config.injectionService.onInjection(injectionListener); + config.injectionService.onUserHint(hintListener); return () => { - config.injectionService.offInjection(injectionListener); + config.injectionService.offUserHint(hintListener); }; }, [config]); @@ -2148,38 +2130,6 @@ Logging in with Google... Restarting Gemini CLI to continue. pendingHintCount, ]); - // Reinject completed background execution output into the model conversation. - // Unlike user steering hints, this is NOT gated on model steering being enabled. - useEffect(() => { - if ( - !isConfigInitialized || - streamingState !== StreamingState.Idle || - !isMcpReady || - isToolAwaitingConfirmation(pendingHistoryItems) - ) { - return; - } - - const bgOutput = consumePendingBackgroundCompletions(); - if (!bgOutput) { - return; - } - - void submitQuery([ - { - text: `Background execution update:\n${bgOutput}\n\nThe above background execution has completed. Review the output and continue your work accordingly.`, - }, - ]); - }, [ - isConfigInitialized, - isMcpReady, - streamingState, - submitQuery, - consumePendingBackgroundCompletions, - pendingHistoryItems, - pendingBgCompletionCount, - ]); - const allToolCalls = useMemo( () => pendingHistoryItems diff --git a/packages/core/src/agents/local-executor.ts b/packages/core/src/agents/local-executor.ts index c761641b55..29c0593184 100644 --- a/packages/core/src/agents/local-executor.ts +++ b/packages/core/src/agents/local-executor.ts @@ -65,6 +65,7 @@ import { getToolCallContext } from '../utils/toolCallContext.js'; import { scheduleAgentTools } from './agent-scheduler.js'; import { DeadlineTimer } from '../utils/deadlineTimer.js'; import { formatUserHintsForModel } from '../utils/fastAckHelper.js'; +import type { InjectionSource } from '../config/injectionService.js'; /** A callback function to report on agent activity. */ export type ActivityCallback = (activity: SubagentActivityEvent) => void; @@ -526,14 +527,19 @@ export class LocalAgentExecutor { : DEFAULT_QUERY_STRING; const pendingHintsQueue: string[] = []; - const hintListener = (hint: string) => { - pendingHintsQueue.push(hint); + const pendingBgCompletionsQueue: string[] = []; + const injectionListener = (text: string, source: InjectionSource) => { + if (source === 'user_steering') { + pendingHintsQueue.push(text); + } else if (source === 'background_completion') { + pendingBgCompletionsQueue.push(text); + } }; // Capture the index of the last hint before starting to avoid re-injecting old hints. // NOTE: Hints added AFTER this point will be broadcast to all currently running // local agents via the listener below. const startIndex = this.config.injectionService.getLatestHintIndex(); - this.config.injectionService.onUserHint(hintListener); + this.config.injectionService.onInjection(injectionListener); try { const initialHints = @@ -585,20 +591,29 @@ export class LocalAgentExecutor { // If status is 'continue', update message for the next loop currentMessage = turnResult.nextMessage; - // Check for new user steering hints collected via subscription + // Inject background completion output into the next turn. + if (pendingBgCompletionsQueue.length > 0) { + const bgText = pendingBgCompletionsQueue.join('\n'); + pendingBgCompletionsQueue.length = 0; + currentMessage.parts ??= []; + currentMessage.parts.unshift({ + text: `Background execution update:\n${bgText}\n\nThe above background execution has completed. Review the output and continue your work accordingly.`, + }); + } + + // Check for new user steering hints collected via subscription. if (pendingHintsQueue.length > 0) { const hintsToProcess = [...pendingHintsQueue]; pendingHintsQueue.length = 0; const formattedHints = formatUserHintsForModel(hintsToProcess); if (formattedHints) { - // Append hints to the current message (next turn) currentMessage.parts ??= []; currentMessage.parts.unshift({ text: formattedHints }); } } } } finally { - this.config.injectionService.offUserHint(hintListener); + this.config.injectionService.offInjection(injectionListener); } // === UNIFIED RECOVERY BLOCK ===