From 802bcf4dee9aeacc5673b963a8ee5f71f56eaf92 Mon Sep 17 00:00:00 2001 From: Abhi <43648792+abhipatel12@users.noreply.github.com> Date: Sun, 8 Feb 2026 15:28:37 -0500 Subject: [PATCH 1/2] refactor(cli): switch useToolScheduler to event-driven engine (#18565) --- packages/cli/src/test-utils/mockConfig.ts | 1 - packages/cli/src/ui/hooks/useGeminiStream.ts | 4 +- packages/cli/src/ui/hooks/useToolScheduler.ts | 34 +++------ .../ui/hooks/useToolSchedulerFacade.test.ts | 70 ------------------- 4 files changed, 9 insertions(+), 100 deletions(-) delete mode 100644 packages/cli/src/ui/hooks/useToolSchedulerFacade.test.ts diff --git a/packages/cli/src/test-utils/mockConfig.ts b/packages/cli/src/test-utils/mockConfig.ts index 777db91364..e970fdb726 100644 --- a/packages/cli/src/test-utils/mockConfig.ts +++ b/packages/cli/src/test-utils/mockConfig.ts @@ -45,7 +45,6 @@ export const createMockConfig = (overrides: Partial = {}): Config => setRemoteAdminSettings: vi.fn(), isYoloModeDisabled: vi.fn(() => false), isPlanEnabled: vi.fn(() => false), - isEventDrivenSchedulerEnabled: vi.fn(() => false), getCoreTools: vi.fn(() => []), getAllowedTools: vi.fn(() => []), getApprovalMode: vi.fn(() => 'default'), diff --git a/packages/cli/src/ui/hooks/useGeminiStream.ts b/packages/cli/src/ui/hooks/useGeminiStream.ts index 4fb84308b2..17dcbdb136 100644 --- a/packages/cli/src/ui/hooks/useGeminiStream.ts +++ b/packages/cli/src/ui/hooks/useGeminiStream.ts @@ -389,7 +389,6 @@ export const useGeminiStream = ( toolCalls.length > 0 && toolCalls.every((tc) => pushedToolCallIds.has(tc.request.callId)); - const isEventDriven = config.isEventDrivenSchedulerEnabled(); const anyVisibleInHistory = pushedToolCallIds.size > 0; const anyVisibleInPending = remainingTools.some((tc) => { // AskUser tools are rendered by AskUserDialog, not ToolGroupMessage @@ -400,7 +399,6 @@ export const useGeminiStream = ( if (tc.request.name === ASK_USER_TOOL_NAME && isInProgress) { return false; } - if (!isEventDriven) return true; return ( tc.status !== 'scheduled' && tc.status !== 'validating' && @@ -422,7 +420,7 @@ export const useGeminiStream = ( } return items; - }, [toolCalls, pushedToolCallIds, config]); + }, [toolCalls, pushedToolCallIds]); const activeToolPtyId = useMemo(() => { const executingShellTool = toolCalls.find( diff --git a/packages/cli/src/ui/hooks/useToolScheduler.ts b/packages/cli/src/ui/hooks/useToolScheduler.ts index 3a6d38aff4..b6835565e7 100644 --- a/packages/cli/src/ui/hooks/useToolScheduler.ts +++ b/packages/cli/src/ui/hooks/useToolScheduler.ts @@ -11,8 +11,6 @@ import type { ToolCallRequestInfo, } from '@google/gemini-cli-core'; import { - useReactToolScheduler, - type TrackedToolCall as LegacyTrackedToolCall, type TrackedScheduledToolCall, type TrackedValidatingToolCall, type TrackedWaitingToolCall, @@ -24,12 +22,13 @@ import { } from './useReactToolScheduler.js'; import { useToolExecutionScheduler, - type TrackedToolCall as NewTrackedToolCall, + type TrackedToolCall, } from './useToolExecutionScheduler.js'; // Re-export specific state types from Legacy, as the structures are compatible // and useGeminiStream relies on them for narrowing. export type { + TrackedToolCall, TrackedScheduledToolCall, TrackedValidatingToolCall, TrackedWaitingToolCall, @@ -40,9 +39,6 @@ export type { CancelAllFn, }; -// Unified type that covers both implementations -export type TrackedToolCall = LegacyTrackedToolCall | NewTrackedToolCall; - // Unified Schedule function (Promise | Promise) export type ScheduleFn = ( request: ToolCallRequestInfo | ToolCallRequestInfo[], @@ -59,30 +55,16 @@ export type UseToolSchedulerReturn = [ ]; /** - * Facade hook that switches between the Legacy and Event-Driven schedulers - * based on configuration. - * - * Note: This conditionally calls hooks, which technically violates the standard - * Rules of Hooks linting. However, this is safe here because - * `config.isEventDrivenSchedulerEnabled()` is static for the lifetime of the - * application session (it essentially acts as a compile-time feature flag). + * Hook that uses the Event-Driven scheduler for tool execution. */ export function useToolScheduler( onComplete: (tools: CompletedToolCall[]) => Promise, config: Config, getPreferredEditor: () => EditorType | undefined, ): UseToolSchedulerReturn { - const isEventDriven = config.isEventDrivenSchedulerEnabled(); - - // Note: We return the hooks directly without casting. They return compatible - // tuple structures, but use explicit tuple signatures rather than the - // UseToolSchedulerReturn named type to avoid circular dependencies back to - // this facade. - if (isEventDriven) { - // eslint-disable-next-line react-hooks/rules-of-hooks - return useToolExecutionScheduler(onComplete, config, getPreferredEditor); - } - - // eslint-disable-next-line react-hooks/rules-of-hooks - return useReactToolScheduler(onComplete, config, getPreferredEditor); + return useToolExecutionScheduler( + onComplete, + config, + getPreferredEditor, + ) as UseToolSchedulerReturn; } diff --git a/packages/cli/src/ui/hooks/useToolSchedulerFacade.test.ts b/packages/cli/src/ui/hooks/useToolSchedulerFacade.test.ts deleted file mode 100644 index 112b7f34db..0000000000 --- a/packages/cli/src/ui/hooks/useToolSchedulerFacade.test.ts +++ /dev/null @@ -1,70 +0,0 @@ -/** - * @license - * Copyright 2026 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -import { describe, it, expect, vi, beforeEach } from 'vitest'; -import { renderHook } from '../../test-utils/render.js'; -import { useToolScheduler } from './useToolScheduler.js'; -import { useReactToolScheduler } from './useReactToolScheduler.js'; -import { useToolExecutionScheduler } from './useToolExecutionScheduler.js'; -import type { Config } from '@google/gemini-cli-core'; - -vi.mock('./useReactToolScheduler.js', () => ({ - useReactToolScheduler: vi.fn().mockReturnValue(['legacy']), -})); - -vi.mock('./useToolExecutionScheduler.js', () => ({ - useToolExecutionScheduler: vi.fn().mockReturnValue(['modern']), -})); - -describe('useToolScheduler (Facade)', () => { - let mockConfig: Config; - - beforeEach(() => { - vi.clearAllMocks(); - }); - - it('delegates to useReactToolScheduler when event-driven scheduler is disabled', () => { - mockConfig = { - isEventDrivenSchedulerEnabled: () => false, - } as unknown as Config; - - const onComplete = vi.fn(); - const getPreferredEditor = vi.fn(); - - const { result } = renderHook(() => - useToolScheduler(onComplete, mockConfig, getPreferredEditor), - ); - - expect(result.current).toEqual(['legacy']); - expect(useReactToolScheduler).toHaveBeenCalledWith( - onComplete, - mockConfig, - getPreferredEditor, - ); - expect(useToolExecutionScheduler).not.toHaveBeenCalled(); - }); - - it('delegates to useToolExecutionScheduler when event-driven scheduler is enabled', () => { - mockConfig = { - isEventDrivenSchedulerEnabled: () => true, - } as unknown as Config; - - const onComplete = vi.fn(); - const getPreferredEditor = vi.fn(); - - const { result } = renderHook(() => - useToolScheduler(onComplete, mockConfig, getPreferredEditor), - ); - - expect(result.current).toEqual(['modern']); - expect(useToolExecutionScheduler).toHaveBeenCalledWith( - onComplete, - mockConfig, - getPreferredEditor, - ); - expect(useReactToolScheduler).not.toHaveBeenCalled(); - }); -}); From 92012365caba4aad0752c44a7e6b232e708d870a Mon Sep 17 00:00:00 2001 From: "N. Taylor Mullen" Date: Sun, 8 Feb 2026 13:08:17 -0800 Subject: [PATCH 2/2] fix(core): correct escaped interpolation in system prompt (#18557) --- .../src/core/__snapshots__/prompts.test.ts.snap | 14 +++++++------- packages/core/src/prompts/snippets.ts | 4 ++-- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/packages/core/src/core/__snapshots__/prompts.test.ts.snap b/packages/core/src/core/__snapshots__/prompts.test.ts.snap index 43af6ddc05..36e77a93cb 100644 --- a/packages/core/src/core/__snapshots__/prompts.test.ts.snap +++ b/packages/core/src/core/__snapshots__/prompts.test.ts.snap @@ -491,7 +491,7 @@ Mock Agent Directory Operate using a **Research -> Strategy -> Execution** lifecycle. For the Execution phase, resolve each sub-task through an iterative **Plan -> Act -> Validate** cycle. 1. **Research:** Systematically map the codebase and validate assumptions. Use 'grep_search' and 'glob' search tools extensively (in parallel if independent) to understand file structures, existing code patterns, and conventions. Use 'read_file' to validate all assumptions. **Prioritize empirical reproduction of reported issues to confirm the failure state.** -2. **Strategy:** Formulate a grounded plan based on your research.\${options.interactive ? ' Share a concise summary of your strategy.' : ''} +2. **Strategy:** Formulate a grounded plan based on your research. Share a concise summary of your strategy. 3. **Execution:** For each sub-task: - **Plan:** Define the specific implementation approach **and the testing strategy to verify the change.** - **Act:** Apply targeted, surgical changes strictly related to the sub-task. Use the available tools (e.g., 'replace', 'write_file', 'run_shell_command'). Ensure changes are idiomatically complete and follow all workspace standards, even if it requires multiple tool calls. **Include necessary automated tests; a change is incomplete without verification logic.** Avoid unrelated refactoring or "cleanup" of outside code. Before making manual code changes, check if an ecosystem tool (like 'eslint --fix', 'prettier --write', 'go fmt', 'cargo fmt') is available in the project to perform the task automatically. @@ -610,7 +610,7 @@ Mock Agent Directory Operate using a **Research -> Strategy -> Execution** lifecycle. For the Execution phase, resolve each sub-task through an iterative **Plan -> Act -> Validate** cycle. 1. **Research:** Systematically map the codebase and validate assumptions. Use 'grep_search' and 'glob' search tools extensively (in parallel if independent) to understand file structures, existing code patterns, and conventions. Use 'read_file' to validate all assumptions. **Prioritize empirical reproduction of reported issues to confirm the failure state.** -2. **Strategy:** Formulate a grounded plan based on your research.\${options.interactive ? ' Share a concise summary of your strategy.' : ''} +2. **Strategy:** Formulate a grounded plan based on your research. 3. **Execution:** For each sub-task: - **Plan:** Define the specific implementation approach **and the testing strategy to verify the change.** - **Act:** Apply targeted, surgical changes strictly related to the sub-task. Use the available tools (e.g., 'replace', 'write_file', 'run_shell_command'). Ensure changes are idiomatically complete and follow all workspace standards, even if it requires multiple tool calls. **Include necessary automated tests; a change is incomplete without verification logic.** Avoid unrelated refactoring or "cleanup" of outside code. Before making manual code changes, check if an ecosystem tool (like 'eslint --fix', 'prettier --write', 'go fmt', 'cargo fmt') is available in the project to perform the task automatically. @@ -710,7 +710,7 @@ Mock Agent Directory Operate using a **Research -> Strategy -> Execution** lifecycle. For the Execution phase, resolve each sub-task through an iterative **Plan -> Act -> Validate** cycle. 1. **Research:** Systematically map the codebase and validate assumptions. Utilize specialized sub-agents (e.g., \`codebase_investigator\`) as the primary mechanism for initial discovery when the task involves **complex refactoring, codebase exploration or system-wide analysis**. For **simple, targeted searches** (like finding a specific function name, file path, or variable declaration), use 'grep_search' or 'glob' directly in parallel. Use 'read_file' to validate all assumptions. **Prioritize empirical reproduction of reported issues to confirm the failure state.** -2. **Strategy:** Formulate a grounded plan based on your research.\${options.interactive ? ' Share a concise summary of your strategy.' : ''} +2. **Strategy:** Formulate a grounded plan based on your research. 3. **Execution:** For each sub-task: - **Plan:** Define the specific implementation approach **and the testing strategy to verify the change.** - **Act:** Apply targeted, surgical changes strictly related to the sub-task. Use the available tools (e.g., 'replace', 'write_file', 'run_shell_command'). Ensure changes are idiomatically complete and follow all workspace standards, even if it requires multiple tool calls. **Include necessary automated tests; a change is incomplete without verification logic.** Avoid unrelated refactoring or "cleanup" of outside code. Before making manual code changes, check if an ecosystem tool (like 'eslint --fix', 'prettier --write', 'go fmt', 'cargo fmt') is available in the project to perform the task automatically. @@ -1721,7 +1721,7 @@ Mock Agent Directory Operate using a **Research -> Strategy -> Execution** lifecycle. For the Execution phase, resolve each sub-task through an iterative **Plan -> Act -> Validate** cycle. 1. **Research:** Systematically map the codebase and validate assumptions. Use 'grep_search' and 'glob' search tools extensively (in parallel if independent) to understand file structures, existing code patterns, and conventions. Use 'read_file' to validate all assumptions. **Prioritize empirical reproduction of reported issues to confirm the failure state.** -2. **Strategy:** Formulate a grounded plan based on your research.\${options.interactive ? ' Share a concise summary of your strategy.' : ''} +2. **Strategy:** Formulate a grounded plan based on your research. Share a concise summary of your strategy. 3. **Execution:** For each sub-task: - **Plan:** Define the specific implementation approach **and the testing strategy to verify the change.** - **Act:** Apply targeted, surgical changes strictly related to the sub-task. Use the available tools (e.g., 'replace', 'write_file', 'run_shell_command'). Ensure changes are idiomatically complete and follow all workspace standards, even if it requires multiple tool calls. **Include necessary automated tests; a change is incomplete without verification logic.** Avoid unrelated refactoring or "cleanup" of outside code. Before making manual code changes, check if an ecosystem tool (like 'eslint --fix', 'prettier --write', 'go fmt', 'cargo fmt') is available in the project to perform the task automatically. @@ -1822,7 +1822,7 @@ Mock Agent Directory Operate using a **Research -> Strategy -> Execution** lifecycle. For the Execution phase, resolve each sub-task through an iterative **Plan -> Act -> Validate** cycle. 1. **Research:** Systematically map the codebase and validate assumptions. Use 'grep_search' and 'glob' search tools extensively (in parallel if independent) to understand file structures, existing code patterns, and conventions. Use 'read_file' to validate all assumptions. **Prioritize empirical reproduction of reported issues to confirm the failure state.** -2. **Strategy:** Formulate a grounded plan based on your research.\${options.interactive ? ' Share a concise summary of your strategy.' : ''} +2. **Strategy:** Formulate a grounded plan based on your research. Share a concise summary of your strategy. 3. **Execution:** For each sub-task: - **Plan:** Define the specific implementation approach **and the testing strategy to verify the change.** - **Act:** Apply targeted, surgical changes strictly related to the sub-task. Use the available tools (e.g., 'replace', 'write_file', 'run_shell_command'). Ensure changes are idiomatically complete and follow all workspace standards, even if it requires multiple tool calls. **Include necessary automated tests; a change is incomplete without verification logic.** Avoid unrelated refactoring or "cleanup" of outside code. Before making manual code changes, check if an ecosystem tool (like 'eslint --fix', 'prettier --write', 'go fmt', 'cargo fmt') is available in the project to perform the task automatically. @@ -2021,7 +2021,7 @@ Mock Agent Directory Operate using a **Research -> Strategy -> Execution** lifecycle. For the Execution phase, resolve each sub-task through an iterative **Plan -> Act -> Validate** cycle. 1. **Research:** Systematically map the codebase and validate assumptions. Use 'grep_search' and 'glob' search tools extensively (in parallel if independent) to understand file structures, existing code patterns, and conventions. Use 'read_file' to validate all assumptions. **Prioritize empirical reproduction of reported issues to confirm the failure state.** -2. **Strategy:** Formulate a grounded plan based on your research.\${options.interactive ? ' Share a concise summary of your strategy.' : ''} +2. **Strategy:** Formulate a grounded plan based on your research. Share a concise summary of your strategy. 3. **Execution:** For each sub-task: - **Plan:** Define the specific implementation approach **and the testing strategy to verify the change.** - **Act:** Apply targeted, surgical changes strictly related to the sub-task. Use the available tools (e.g., 'replace', 'write_file', 'run_shell_command'). Ensure changes are idiomatically complete and follow all workspace standards, even if it requires multiple tool calls. **Include necessary automated tests; a change is incomplete without verification logic.** Avoid unrelated refactoring or "cleanup" of outside code. Before making manual code changes, check if an ecosystem tool (like 'eslint --fix', 'prettier --write', 'go fmt', 'cargo fmt') is available in the project to perform the task automatically. @@ -2122,7 +2122,7 @@ Mock Agent Directory Operate using a **Research -> Strategy -> Execution** lifecycle. For the Execution phase, resolve each sub-task through an iterative **Plan -> Act -> Validate** cycle. 1. **Research:** Systematically map the codebase and validate assumptions. Use 'grep_search' and 'glob' search tools extensively (in parallel if independent) to understand file structures, existing code patterns, and conventions. Use 'read_file' to validate all assumptions. **Prioritize empirical reproduction of reported issues to confirm the failure state.** -2. **Strategy:** Formulate a grounded plan based on your research.\${options.interactive ? ' Share a concise summary of your strategy.' : ''} +2. **Strategy:** Formulate a grounded plan based on your research. Share a concise summary of your strategy. 3. **Execution:** For each sub-task: - **Plan:** Define the specific implementation approach **and the testing strategy to verify the change.** - **Act:** Apply targeted, surgical changes strictly related to the sub-task. Use the available tools (e.g., 'replace', 'write_file', 'run_shell_command'). Ensure changes are idiomatically complete and follow all workspace standards, even if it requires multiple tool calls. **Include necessary automated tests; a change is incomplete without verification logic.** Avoid unrelated refactoring or "cleanup" of outside code. Before making manual code changes, check if an ecosystem tool (like 'eslint --fix', 'prettier --write', 'go fmt', 'cargo fmt') is available in the project to perform the task automatically. diff --git a/packages/core/src/prompts/snippets.ts b/packages/core/src/prompts/snippets.ts index 1461f61633..502bf0cca7 100644 --- a/packages/core/src/prompts/snippets.ts +++ b/packages/core/src/prompts/snippets.ts @@ -430,9 +430,9 @@ function workflowStepStrategy(options: PrimaryWorkflowsOptions): string { } if (options.enableWriteTodosTool) { - return `2. **Strategy:** Formulate a grounded plan based on your research. \${options.interactive ? 'Share a concise summary of your strategy.' : ''} For complex tasks, break them down into smaller, manageable subtasks and use the \`${WRITE_TODOS_TOOL_NAME}\` tool to track your progress.`; + return `2. **Strategy:** Formulate a grounded plan based on your research.${options.interactive ? ' Share a concise summary of your strategy.' : ''} For complex tasks, break them down into smaller, manageable subtasks and use the \`${WRITE_TODOS_TOOL_NAME}\` tool to track your progress.`; } - return `2. **Strategy:** Formulate a grounded plan based on your research.\${options.interactive ? ' Share a concise summary of your strategy.' : ''}`; + return `2. **Strategy:** Formulate a grounded plan based on your research.${options.interactive ? ' Share a concise summary of your strategy.' : ''}`; } function workflowVerifyStandardsSuffix(interactive: boolean): string {