refactor(cli): switch useToolScheduler to event-driven engine (#18565)

This commit is contained in:
Abhi
2026-02-08 15:28:37 -05:00
committed by GitHub
parent 4a48d7cf93
commit 802bcf4dee
4 changed files with 9 additions and 100 deletions

View File

@@ -45,7 +45,6 @@ export const createMockConfig = (overrides: Partial<Config> = {}): 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'),

View File

@@ -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(

View File

@@ -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<void> | Promise<CompletedToolCall[]>)
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<void>,
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;
}

View File

@@ -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();
});
});