feat(hooks): Hooks Commands Panel, Enable/Disable, and Migrate (#14225)

This commit is contained in:
Edilmo Palencia
2025-12-03 10:01:57 -08:00
committed by GitHub
parent 08067acc71
commit b8c038f41f
24 changed files with 2568 additions and 16 deletions

View File

@@ -14,8 +14,6 @@ import type {
BugCommandSettings,
TelemetrySettings,
AuthType,
HookDefinition,
HookEventName,
} from '@google/gemini-cli-core';
import {
DEFAULT_TRUNCATE_TOOL_OUTPUT_LINES,
@@ -80,6 +78,11 @@ export interface SettingCollectionDefinition {
* For example, a JSON schema generator can use this to point to a shared definition.
*/
ref?: string;
/**
* Optional merge strategy for dynamically added properties.
* Used when this collection definition is referenced via additionalProperties.
*/
mergeStrategy?: MergeStrategy;
}
export enum MergeStrategy {
@@ -1422,11 +1425,165 @@ const SETTINGS_SCHEMA = {
label: 'Hooks',
category: 'Advanced',
requiresRestart: false,
default: {} as { [K in HookEventName]?: HookDefinition[] },
default: {},
description:
'Hook configurations for intercepting and customizing agent behavior.',
showInDialog: false,
mergeStrategy: MergeStrategy.SHALLOW_MERGE,
properties: {
disabled: {
type: 'array',
label: 'Disabled Hooks',
category: 'Advanced',
requiresRestart: false,
default: [] as string[],
description:
'List of hook names (commands) that should be disabled. Hooks in this list will not execute even if configured.',
showInDialog: false,
items: {
type: 'string',
description: 'Hook command name',
},
mergeStrategy: MergeStrategy.UNION,
},
BeforeTool: {
type: 'array',
label: 'Before Tool Hooks',
category: 'Advanced',
requiresRestart: false,
default: [],
description:
'Hooks that execute before tool execution. Can intercept, validate, or modify tool calls.',
showInDialog: false,
ref: 'HookDefinitionArray',
mergeStrategy: MergeStrategy.CONCAT,
},
AfterTool: {
type: 'array',
label: 'After Tool Hooks',
category: 'Advanced',
requiresRestart: false,
default: [],
description:
'Hooks that execute after tool execution. Can process results, log outputs, or trigger follow-up actions.',
showInDialog: false,
ref: 'HookDefinitionArray',
mergeStrategy: MergeStrategy.CONCAT,
},
BeforeAgent: {
type: 'array',
label: 'Before Agent Hooks',
category: 'Advanced',
requiresRestart: false,
default: [],
description:
'Hooks that execute before agent loop starts. Can set up context or initialize resources.',
showInDialog: false,
ref: 'HookDefinitionArray',
mergeStrategy: MergeStrategy.CONCAT,
},
AfterAgent: {
type: 'array',
label: 'After Agent Hooks',
category: 'Advanced',
requiresRestart: false,
default: [],
description:
'Hooks that execute after agent loop completes. Can perform cleanup or summarize results.',
showInDialog: false,
ref: 'HookDefinitionArray',
mergeStrategy: MergeStrategy.CONCAT,
},
Notification: {
type: 'array',
label: 'Notification Hooks',
category: 'Advanced',
requiresRestart: false,
default: [],
description:
'Hooks that execute on notification events (errors, warnings, info). Can log or alert on specific conditions.',
showInDialog: false,
ref: 'HookDefinitionArray',
mergeStrategy: MergeStrategy.CONCAT,
},
SessionStart: {
type: 'array',
label: 'Session Start Hooks',
category: 'Advanced',
requiresRestart: false,
default: [],
description:
'Hooks that execute when a session starts. Can initialize session-specific resources or state.',
showInDialog: false,
ref: 'HookDefinitionArray',
mergeStrategy: MergeStrategy.CONCAT,
},
SessionEnd: {
type: 'array',
label: 'Session End Hooks',
category: 'Advanced',
requiresRestart: false,
default: [],
description:
'Hooks that execute when a session ends. Can perform cleanup or persist session data.',
showInDialog: false,
ref: 'HookDefinitionArray',
mergeStrategy: MergeStrategy.CONCAT,
},
PreCompress: {
type: 'array',
label: 'Pre-Compress Hooks',
category: 'Advanced',
requiresRestart: false,
default: [],
description:
'Hooks that execute before chat history compression. Can back up or analyze conversation before compression.',
showInDialog: false,
ref: 'HookDefinitionArray',
mergeStrategy: MergeStrategy.CONCAT,
},
BeforeModel: {
type: 'array',
label: 'Before Model Hooks',
category: 'Advanced',
requiresRestart: false,
default: [],
description:
'Hooks that execute before LLM requests. Can modify prompts, inject context, or control model parameters.',
showInDialog: false,
ref: 'HookDefinitionArray',
mergeStrategy: MergeStrategy.CONCAT,
},
AfterModel: {
type: 'array',
label: 'After Model Hooks',
category: 'Advanced',
requiresRestart: false,
default: [],
description:
'Hooks that execute after LLM responses. Can process outputs, extract information, or log interactions.',
showInDialog: false,
ref: 'HookDefinitionArray',
mergeStrategy: MergeStrategy.CONCAT,
},
BeforeToolSelection: {
type: 'array',
label: 'Before Tool Selection Hooks',
category: 'Advanced',
requiresRestart: false,
default: [],
description:
'Hooks that execute before tool selection. Can filter or prioritize available tools dynamically.',
showInDialog: false,
ref: 'HookDefinitionArray',
mergeStrategy: MergeStrategy.CONCAT,
},
},
additionalProperties: {
type: 'array',
description:
'Custom hook event arrays that contain hook definitions for user-defined events',
mergeStrategy: MergeStrategy.CONCAT,
},
},
} as const satisfies SettingsSchema;
@@ -1698,6 +1855,46 @@ export const SETTINGS_SCHEMA_DEFINITIONS: Record<
description: 'Accepts either a boolean flag or a string command name.',
anyOf: [{ type: 'boolean' }, { type: 'string' }],
},
HookDefinitionArray: {
type: 'array',
description: 'Array of hook definition objects for a specific event.',
items: {
type: 'object',
description:
'Hook definition specifying matcher pattern and hook configurations.',
properties: {
matcher: {
type: 'string',
description:
'Pattern to match against the event context (tool name, notification type, etc.). Supports exact match, regex (/pattern/), and wildcards (*).',
},
hooks: {
type: 'array',
description: 'Hooks to execute when the matcher matches.',
items: {
type: 'object',
description: 'Individual hook configuration.',
properties: {
type: {
type: 'string',
description:
'Type of hook (currently only "command" supported).',
},
command: {
type: 'string',
description:
'Shell command to execute. Receives JSON input via stdin and returns JSON output via stdout.',
},
timeout: {
type: 'number',
description: 'Timeout in milliseconds for hook execution.',
},
},
},
},
},
},
},
};
export function getSettingsSchema(): SettingsSchemaType {