temp states with session-learnings hook

This commit is contained in:
Aishanee Shah
2026-02-11 19:56:26 +00:00
parent 0569a3dba5
commit d6eca7f663
8 changed files with 12 additions and 177 deletions
-2
View File
@@ -796,8 +796,6 @@ export async function loadCliConfig(
toolOutputMasking: settings.experimental?.toolOutputMasking,
noBrowser: !!process.env['NO_BROWSER'],
summarizeToolOutput: settings.model?.summarizeToolOutput,
sessionLearnings: settings.general?.sessionLearnings?.enabled,
sessionLearningsOutputPath: settings.general?.sessionLearnings?.outputPath,
ideMode,
disableLoopDetection: settings.model?.disableLoopDetection,
compressionThreshold: settings.model?.compressionThreshold,
-31
View File
@@ -322,37 +322,6 @@ const SETTINGS_SCHEMA = {
},
description: 'Settings for automatic session cleanup.',
},
sessionLearnings: {
type: 'object',
label: 'Session Learnings',
category: 'General',
requiresRestart: false,
default: {},
description: 'Settings for session learning summaries.',
showInDialog: false,
properties: {
enabled: {
type: 'boolean',
label: 'Enable Session Learnings',
category: 'General',
requiresRestart: false,
default: false,
description:
'Automatically generate a session-learnings.md file when the session ends.',
showInDialog: true,
},
outputPath: {
type: 'string',
label: 'Output Path',
category: 'General',
requiresRestart: false,
default: undefined as string | undefined,
description:
'Directory where session-learnings files should be saved. Defaults to project root.',
showInDialog: true,
},
},
},
},
},
output: {
-14
View File
@@ -477,8 +477,6 @@ export interface ConfigParameters {
experimentalJitContext?: boolean;
toolOutputMasking?: Partial<ToolOutputMaskingConfig>;
disableLLMCorrection?: boolean;
sessionLearnings?: boolean;
sessionLearningsOutputPath?: string;
plan?: boolean;
onModelChange?: (model: string) => void;
mcpEnabled?: boolean;
@@ -664,8 +662,6 @@ export class Config {
private readonly experimentalJitContext: boolean;
private readonly disableLLMCorrection: boolean;
private readonly sessionLearnings: boolean;
private readonly sessionLearningsOutputPath: string | undefined;
private readonly planEnabled: boolean;
private contextManager?: ContextManager;
private terminalBackground: string | undefined = undefined;
@@ -754,8 +750,6 @@ export class Config {
this.enableAgents = params.enableAgents ?? false;
this.agents = params.agents ?? {};
this.disableLLMCorrection = params.disableLLMCorrection ?? true;
this.sessionLearnings = params.sessionLearnings ?? false;
this.sessionLearningsOutputPath = params.sessionLearningsOutputPath;
this.planEnabled = params.plan ?? false;
this.enableEventDrivenScheduler = params.enableEventDrivenScheduler ?? true;
this.skillsSupport = params.skillsSupport ?? true;
@@ -1955,14 +1949,6 @@ export class Config {
return this.disableLLMCorrection;
}
isSessionLearningsEnabled(): boolean {
return this.sessionLearnings;
}
getSessionLearningsOutputPath(): string | undefined {
return this.sessionLearningsOutputPath;
}
isPlanEnabled(): boolean {
return this.planEnabled;
}
@@ -74,7 +74,6 @@ describe('HookRegistry', () => {
getDisabledHooks: vi.fn().mockReturnValue([]),
isTrustedFolder: vi.fn().mockReturnValue(true),
getProjectRoot: vi.fn().mockReturnValue('/project'),
isSessionLearningsEnabled: vi.fn().mockReturnValue(false),
} as unknown as Config;
hookRegistry = new HookRegistry(mockConfig);
@@ -280,21 +279,6 @@ describe('HookRegistry', () => {
hookRegistry.getHooksForEvent(HookEventName.BeforeTool),
).toHaveLength(0);
});
it('should register builtin session-learnings hook when enabled', async () => {
vi.mocked(mockConfig.isSessionLearningsEnabled).mockReturnValue(true);
await hookRegistry.initialize();
const hooks = hookRegistry.getHooksForEvent(HookEventName.SessionEnd);
expect(hooks).toHaveLength(1);
expect(hooks[0].config.type).toBe(HookType.Builtin);
expect((hooks[0].config as BuiltinHookConfig).builtin_id).toBe(
'session-learnings',
);
expect(hooks[0].source).toBe(ConfigSource.System);
});
});
describe('getHooksForEvent', () => {
+1 -29
View File
@@ -6,12 +6,7 @@
import type { Config } from '../config/config.js';
import type { HookDefinition, HookConfig } from './types.js';
import {
HookEventName,
ConfigSource,
HOOKS_CONFIG_FIELDS,
HookType,
} from './types.js';
import { HookEventName, ConfigSource, HOOKS_CONFIG_FIELDS } from './types.js';
import { debugLogger } from '../utils/debugLogger.js';
import { TrustedHooksManager } from './trustedHooks.js';
import { coreEvents } from '../utils/events.js';
@@ -142,8 +137,6 @@ please review the project settings (.gemini/settings.json) and remove them.`;
this.checkProjectHooksTrust();
}
this.registerBuiltinHooks();
// Get hooks from the main config (this comes from the merged settings)
const configHooks = this.config.getHooks();
if (configHooks) {
@@ -168,27 +161,6 @@ please review the project settings (.gemini/settings.json) and remove them.`;
}
}
/**
* Register system-level builtin hooks
*/
private registerBuiltinHooks(): void {
if (this.config.isSessionLearningsEnabled()) {
debugLogger.debug('Registering builtin session-learnings hook');
this.entries.push({
config: {
type: HookType.Builtin,
builtin_id: 'session-learnings',
name: 'session-learnings',
description: 'Automatically generate session learning summaries',
source: ConfigSource.System,
},
source: ConfigSource.System,
eventName: HookEventName.SessionEnd,
enabled: true,
});
}
}
/**
* Process hooks configuration and add entries
*/
+7 -71
View File
@@ -6,7 +6,7 @@
import { spawn } from 'node:child_process';
import type { HookConfig } from './types.js';
import { HookEventName, ConfigSource, HookType } from './types.js';
import { HookEventName, ConfigSource } from './types.js';
import type { Config } from '../config/config.js';
import type {
HookInput,
@@ -16,9 +16,7 @@ import type {
BeforeModelInput,
BeforeModelOutput,
BeforeToolInput,
SessionEndInput,
} from './types.js';
import { SessionEndReason } from './types.js';
import type { LLMRequest } from './hookTranslator.js';
import { debugLogger } from '../utils/debugLogger.js';
import { sanitizeEnvironment } from '../services/environmentSanitization.js';
@@ -27,7 +25,6 @@ import {
getShellConfiguration,
type ShellType,
} from '../utils/shell-utils.js';
import { SessionLearningsService } from '../services/sessionLearningsService.js';
/**
* Default timeout for hook execution (60 seconds)
@@ -46,11 +43,9 @@ const EXIT_CODE_NON_BLOCKING_ERROR = 1;
*/
export class HookRunner {
private readonly config: Config;
private readonly sessionLearningsService: SessionLearningsService;
constructor(config: Config) {
this.config = config;
this.sessionLearningsService = new SessionLearningsService(config);
}
/**
@@ -81,25 +76,12 @@ export class HookRunner {
}
try {
if (hookConfig.type === HookType.Command) {
return await this.executeCommandHook(
hookConfig,
eventName,
input,
startTime,
);
} else if (hookConfig.type === HookType.Builtin) {
return await this.executeBuiltinHook(
hookConfig,
eventName,
input,
startTime,
);
} else {
throw new Error(
`Unsupported hook type: ${(hookConfig as HookConfig).type}`,
);
}
return await this.executeCommandHook(
hookConfig,
eventName,
input,
startTime,
);
} catch (error) {
const duration = Date.now() - startTime;
const hookId = hookConfig.name || hookConfig.command || 'unknown';
@@ -249,52 +231,6 @@ export class HookRunner {
return modifiedInput;
}
/**
* Execute a builtin hook
*/
private async executeBuiltinHook(
hookConfig: HookConfig,
eventName: HookEventName,
input: HookInput,
startTime: number,
): Promise<HookExecutionResult> {
if (hookConfig.type !== HookType.Builtin) {
throw new Error('Expected builtin hook configuration');
}
try {
if (hookConfig.builtin_id === 'session-learnings') {
if (eventName === HookEventName.SessionEnd) {
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
const sessionEndInput = input as SessionEndInput;
if (
sessionEndInput.reason === SessionEndReason.Exit ||
sessionEndInput.reason === SessionEndReason.Logout
) {
await this.sessionLearningsService.generateAndSaveLearnings();
}
}
}
return {
hookConfig,
eventName,
success: true,
duration: Date.now() - startTime,
exitCode: EXIT_CODE_SUCCESS,
output: {},
};
} catch (error) {
return {
hookConfig,
eventName,
success: false,
error: error instanceof Error ? error : new Error(String(error)),
duration: Date.now() - startTime,
};
}
}
/**
* Execute a command hook
*/
+3 -14
View File
@@ -62,16 +62,7 @@ export interface CommandHookConfig {
env?: Record<string, string>;
}
export interface BuiltinHookConfig {
type: HookType.Builtin;
builtin_id: string;
name?: string;
description?: string;
timeout?: number;
source?: ConfigSource;
}
export type HookConfig = CommandHookConfig | BuiltinHookConfig;
export type HookConfig = CommandHookConfig;
/**
* Hook definition with matcher
@@ -87,7 +78,6 @@ export interface HookDefinition {
*/
export enum HookType {
Command = 'command',
Builtin = 'builtin',
}
/**
@@ -95,9 +85,8 @@ export enum HookType {
*/
export function getHookKey(hook: HookConfig): string {
const name = hook.name || '';
const identifier =
hook.type === HookType.Command ? hook.command : hook.builtin_id;
return `${name}:${identifier}`;
const command = hook.command || '';
return `${name}:${command}`;
}
/**