mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-04-23 19:44:30 -07:00
feat(plan): hide plan write and edit operations on plans in Plan Mode (#19012)
This commit is contained in:
@@ -5,11 +5,7 @@
|
||||
*/
|
||||
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
||||
import {
|
||||
AskUserTool,
|
||||
shouldHideAskUserTool,
|
||||
isCompletedAskUserTool,
|
||||
} from './ask-user.js';
|
||||
import { AskUserTool, isCompletedAskUserTool } from './ask-user.js';
|
||||
import { QuestionType, type Question } from '../confirmation-bus/types.js';
|
||||
import type { MessageBus } from '../confirmation-bus/message-bus.js';
|
||||
import { ToolConfirmationOutcome } from './tools.js';
|
||||
@@ -17,54 +13,6 @@ import { ToolErrorType } from './tool-error.js';
|
||||
import { ASK_USER_DISPLAY_NAME } from './tool-names.js';
|
||||
|
||||
describe('AskUserTool Helpers', () => {
|
||||
describe('shouldHideAskUserTool', () => {
|
||||
it('returns false for non-AskUser tools', () => {
|
||||
expect(shouldHideAskUserTool('other-tool', 'Success', true)).toBe(false);
|
||||
});
|
||||
|
||||
it('hides Pending AskUser tool', () => {
|
||||
expect(
|
||||
shouldHideAskUserTool(ASK_USER_DISPLAY_NAME, 'Pending', false),
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
it('hides Executing AskUser tool', () => {
|
||||
expect(
|
||||
shouldHideAskUserTool(ASK_USER_DISPLAY_NAME, 'Executing', false),
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
it('hides Confirming AskUser tool', () => {
|
||||
expect(
|
||||
shouldHideAskUserTool(ASK_USER_DISPLAY_NAME, 'Confirming', false),
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
it('shows Success AskUser tool', () => {
|
||||
expect(
|
||||
shouldHideAskUserTool(ASK_USER_DISPLAY_NAME, 'Success', true),
|
||||
).toBe(false);
|
||||
});
|
||||
|
||||
it('shows Canceled AskUser tool', () => {
|
||||
expect(
|
||||
shouldHideAskUserTool(ASK_USER_DISPLAY_NAME, 'Canceled', true),
|
||||
).toBe(false);
|
||||
});
|
||||
|
||||
it('hides Error AskUser tool without result display', () => {
|
||||
expect(shouldHideAskUserTool(ASK_USER_DISPLAY_NAME, 'Error', false)).toBe(
|
||||
true,
|
||||
);
|
||||
});
|
||||
|
||||
it('shows Error AskUser tool with result display', () => {
|
||||
expect(shouldHideAskUserTool(ASK_USER_DISPLAY_NAME, 'Error', true)).toBe(
|
||||
false,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('isCompletedAskUserTool', () => {
|
||||
it('returns false for non-AskUser tools', () => {
|
||||
expect(isCompletedAskUserTool('other-tool', 'Success')).toBe(false);
|
||||
|
||||
@@ -259,38 +259,6 @@ export class AskUserInvocation extends BaseToolInvocation<
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if an 'Ask User' tool call should be hidden from the standard tool history UI.
|
||||
*
|
||||
* We hide Ask User tools in two cases:
|
||||
* 1. They are in progress because they are displayed using a specialized UI (AskUserDialog).
|
||||
* 2. They have errored without a result display (e.g. validation errors), in which case
|
||||
* the agent self-corrects and we don't want to clutter the UI.
|
||||
*
|
||||
* NOTE: The 'status' parameter values are intended to match the CLI's ToolCallStatus enum.
|
||||
*/
|
||||
export function shouldHideAskUserTool(
|
||||
name: string,
|
||||
status: string,
|
||||
hasResultDisplay: boolean,
|
||||
): boolean {
|
||||
if (name !== ASK_USER_DISPLAY_NAME) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Case 1: In-progress tools (Pending, Executing, Confirming)
|
||||
if (['Pending', 'Executing', 'Confirming'].includes(status)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Case 2: Error without result display
|
||||
if (status === 'Error' && !hasResultDisplay) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the tool name and status correspond to a completed 'Ask User' tool call.
|
||||
*/
|
||||
|
||||
@@ -43,7 +43,11 @@ import { EditCorrectionEvent } from '../telemetry/types.js';
|
||||
import { logEditCorrectionEvent } from '../telemetry/loggers.js';
|
||||
|
||||
import { correctPath } from '../utils/pathCorrector.js';
|
||||
import { EDIT_TOOL_NAME, READ_FILE_TOOL_NAME } from './tool-names.js';
|
||||
import {
|
||||
EDIT_TOOL_NAME,
|
||||
READ_FILE_TOOL_NAME,
|
||||
EDIT_DISPLAY_NAME,
|
||||
} from './tool-names.js';
|
||||
import { debugLogger } from '../utils/debugLogger.js';
|
||||
import { EDIT_DEFINITION } from './definitions/coreTools.js';
|
||||
import { resolveToolDeclaration } from './definitions/resolver.js';
|
||||
@@ -908,7 +912,7 @@ export class EditTool
|
||||
) {
|
||||
super(
|
||||
EditTool.Name,
|
||||
'Edit',
|
||||
EDIT_DISPLAY_NAME,
|
||||
EDIT_DEFINITION.base.description!,
|
||||
Kind.Edit,
|
||||
EDIT_DEFINITION.base.parametersJsonSchema,
|
||||
|
||||
@@ -14,7 +14,7 @@ import { shortenPath, makeRelative } from '../utils/paths.js';
|
||||
import { type Config } from '../config/config.js';
|
||||
import { DEFAULT_FILE_FILTERING_OPTIONS } from '../config/constants.js';
|
||||
import { ToolErrorType } from './tool-error.js';
|
||||
import { GLOB_TOOL_NAME } from './tool-names.js';
|
||||
import { GLOB_TOOL_NAME, GLOB_DISPLAY_NAME } from './tool-names.js';
|
||||
import { getErrorMessage } from '../utils/errors.js';
|
||||
import { debugLogger } from '../utils/debugLogger.js';
|
||||
import { GLOB_DEFINITION } from './definitions/coreTools.js';
|
||||
@@ -271,7 +271,7 @@ export class GlobTool extends BaseDeclarativeTool<GlobToolParams, ToolResult> {
|
||||
) {
|
||||
super(
|
||||
GlobTool.Name,
|
||||
'FindFiles',
|
||||
GLOB_DISPLAY_NAME,
|
||||
GLOB_DEFINITION.base.description!,
|
||||
Kind.Search,
|
||||
GLOB_DEFINITION.base.parametersJsonSchema,
|
||||
|
||||
@@ -21,7 +21,7 @@ import { FileOperation } from '../telemetry/metrics.js';
|
||||
import { getProgrammingLanguage } from '../telemetry/telemetry-utils.js';
|
||||
import { logFileOperation } from '../telemetry/loggers.js';
|
||||
import { FileOperationEvent } from '../telemetry/types.js';
|
||||
import { READ_FILE_TOOL_NAME } from './tool-names.js';
|
||||
import { READ_FILE_TOOL_NAME, READ_FILE_DISPLAY_NAME } from './tool-names.js';
|
||||
import { FileDiscoveryService } from '../services/fileDiscoveryService.js';
|
||||
import { READ_FILE_DEFINITION } from './definitions/coreTools.js';
|
||||
import { resolveToolDeclaration } from './definitions/resolver.js';
|
||||
@@ -173,7 +173,7 @@ export class ReadFileTool extends BaseDeclarativeTool<
|
||||
) {
|
||||
super(
|
||||
ReadFileTool.Name,
|
||||
'ReadFile',
|
||||
READ_FILE_DISPLAY_NAME,
|
||||
READ_FILE_DEFINITION.base.description!,
|
||||
Kind.Read,
|
||||
READ_FILE_DEFINITION.base.parametersJsonSchema,
|
||||
|
||||
@@ -40,10 +40,16 @@ export const GET_INTERNAL_DOCS_TOOL_NAME = 'get_internal_docs';
|
||||
export const ACTIVATE_SKILL_TOOL_NAME = 'activate_skill';
|
||||
export const EDIT_TOOL_NAMES = new Set([EDIT_TOOL_NAME, WRITE_FILE_TOOL_NAME]);
|
||||
export const ASK_USER_TOOL_NAME = 'ask_user';
|
||||
export const ASK_USER_DISPLAY_NAME = 'Ask User';
|
||||
export const EXIT_PLAN_MODE_TOOL_NAME = 'exit_plan_mode';
|
||||
export const ENTER_PLAN_MODE_TOOL_NAME = 'enter_plan_mode';
|
||||
|
||||
// Tool Display Names
|
||||
export const WRITE_FILE_DISPLAY_NAME = 'WriteFile';
|
||||
export const EDIT_DISPLAY_NAME = 'Edit';
|
||||
export const ASK_USER_DISPLAY_NAME = 'Ask User';
|
||||
export const READ_FILE_DISPLAY_NAME = 'ReadFile';
|
||||
export const GLOB_DISPLAY_NAME = 'FindFiles';
|
||||
|
||||
/**
|
||||
* Mapping of legacy tool names to their current names.
|
||||
* This ensures backward compatibility for user-defined policies, skills, and hooks.
|
||||
|
||||
@@ -9,7 +9,7 @@ import fsPromises from 'node:fs/promises';
|
||||
import path from 'node:path';
|
||||
import os from 'node:os';
|
||||
import * as Diff from 'diff';
|
||||
import { WRITE_FILE_TOOL_NAME } from './tool-names.js';
|
||||
import { WRITE_FILE_TOOL_NAME, WRITE_FILE_DISPLAY_NAME } from './tool-names.js';
|
||||
import type { Config } from '../config/config.js';
|
||||
import { ApprovalMode } from '../policy/types.js';
|
||||
|
||||
@@ -446,7 +446,7 @@ export class WriteFileTool
|
||||
) {
|
||||
super(
|
||||
WriteFileTool.Name,
|
||||
'WriteFile',
|
||||
WRITE_FILE_DISPLAY_NAME,
|
||||
WRITE_FILE_DEFINITION.base.description!,
|
||||
Kind.Edit,
|
||||
WRITE_FILE_DEFINITION.base.parametersJsonSchema,
|
||||
|
||||
Reference in New Issue
Block a user