Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 0 additions & 15 deletions docs/get-started/configuration-v1.md
Original file line number Diff line number Diff line change
Expand Up @@ -473,21 +473,6 @@ a few things you can try in order of recommendation:
"loadMemoryFromIncludeDirectories": true
```

- **`chatCompression`** (object):
- **Description:** Controls the settings for chat history compression, both
automatic and when manually invoked through the /compress command.
- **Properties:**
- **`contextPercentageThreshold`** (number): A value between 0 and 1 that
specifies the token threshold for compression as a percentage of the
model's total token limit. For example, a value of `0.6` will trigger
compression when the chat history exceeds 60% of the token limit.
- **Example:**
```json
"chatCompression": {
"contextPercentageThreshold": 0.6
}
```

- **`showLineNumbers`** (boolean):
- **Description:** Controls whether line numbers are displayed in code blocks
in the CLI output.
Expand Down
6 changes: 3 additions & 3 deletions docs/get-started/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -244,13 +244,13 @@ their corresponding top-level category object in your `settings.json` file.
example `{"run_shell_command": {"tokenBudget": 2000}}`
- **Default:** `undefined`

- **`model.chatCompression.contextPercentageThreshold`** (number):
- **`model.compressionThreshold`** (number):
- **Description:** Sets the threshold for chat history compression as a
percentage of the model's total token limit. This is a value between 0 and 1
fraction of the model's total token limit. This is a value between 0 and 1
that applies to both automatic compression and the manual `/compress`
command. For example, a value of `0.6` will trigger compression when the
chat history exceeds 60% of the token limit.
- **Default:** `0.7`
- **Default:** `0.2`

- **`model.skipNextSpeakerCheck`** (boolean):
- **Description:** Skip the next speaker check.
Expand Down
22 changes: 17 additions & 5 deletions packages/cli/src/config/config.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1572,9 +1572,13 @@ describe('loadCliConfig with includeDirectories', () => {
});
});

<<<<<<< HEAD
describe('loadCliConfig chatCompression', () => {
const originalArgv = process.argv;

=======
describe('loadCliConfig compressionThreshold', () => {
>>>>>>> 3332703f (Make compression threshold editable in the UI. (#12317))
beforeEach(() => {
vi.resetAllMocks();
vi.mocked(os.homedir).mockReturnValue('/mock/home/user');
Expand All @@ -1587,28 +1591,36 @@ describe('loadCliConfig chatCompression', () => {
vi.restoreAllMocks();
});

it('should pass chatCompression settings to the core config', async () => {
it('should pass settings to the core config', async () => {
process.argv = ['node', 'script.js'];
const argv = await parseArguments({} as Settings);
const settings: Settings = {
model: {
chatCompression: {
contextPercentageThreshold: 0.5,
},
compressionThreshold: 0.5,
},
};
<<<<<<< HEAD
const config = await loadCliConfig(settings, [], 'test-session', argv);
expect(config.getChatCompression()).toEqual({
contextPercentageThreshold: 0.5,
});
=======
const config = await loadCliConfig(settings, 'test-session', argv);
expect(config.getCompressionThreshold()).toBe(0.5);
>>>>>>> 3332703f (Make compression threshold editable in the UI. (#12317))
});

it('should have undefined chatCompression if not in settings', async () => {
it('should have undefined compressionThreshold if not in settings', async () => {
process.argv = ['node', 'script.js'];
const argv = await parseArguments({} as Settings);
const settings: Settings = {};
<<<<<<< HEAD
const config = await loadCliConfig(settings, [], 'test-session', argv);
expect(config.getChatCompression()).toBeUndefined();
=======
const config = await loadCliConfig(settings, 'test-session', argv);
expect(config.getCompressionThreshold()).toBeUndefined();
>>>>>>> 3332703f (Make compression threshold editable in the UI. (#12317))
});
});

Expand Down
2 changes: 1 addition & 1 deletion packages/cli/src/config/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -610,7 +610,7 @@ export async function loadCliConfig(
noBrowser: !!process.env['NO_BROWSER'],
summarizeToolOutput: settings.model?.summarizeToolOutput,
ideMode,
chatCompression: settings.model?.chatCompression,
compressionThreshold: settings.model?.compressionThreshold,
folderTrust,
interactive,
trustedFolder,
Expand Down
74 changes: 15 additions & 59 deletions packages/cli/src/config/settings.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1051,15 +1051,15 @@ describe('Settings Loading and Merging', () => {
});
});

it('should merge chatCompression settings, with workspace taking precedence', () => {
it('should merge compressionThreshold settings, with workspace taking precedence', () => {
(mockFsExistsSync as Mock).mockReturnValue(true);
const userSettingsContent = {
general: {},
model: { chatCompression: { contextPercentageThreshold: 0.5 } },
model: { compressionThreshold: 0.5 },
};
const workspaceSettingsContent = {
general: {},
model: { chatCompression: { contextPercentageThreshold: 0.8 } },
model: { compressionThreshold: 0.8 },
};

(fs.readFileSync as Mock).mockImplementation(
Expand All @@ -1074,15 +1074,11 @@ describe('Settings Loading and Merging', () => {

const settings = loadSettings(MOCK_WORKSPACE_DIR);

expect(settings.user.settings.model?.chatCompression).toEqual({
contextPercentageThreshold: 0.5,
});
expect(settings.workspace.settings.model?.chatCompression).toEqual({
contextPercentageThreshold: 0.8,
});
expect(settings.merged.model?.chatCompression).toEqual({
contextPercentageThreshold: 0.8,
});
expect(settings.user.settings.model?.compressionThreshold).toEqual(0.5);
expect(settings.workspace.settings.model?.compressionThreshold).toEqual(
0.8,
);
expect(settings.merged.model?.compressionThreshold).toEqual(0.8);
});

it('should merge output format settings, with workspace taking precedence', () => {
Expand All @@ -1109,13 +1105,13 @@ describe('Settings Loading and Merging', () => {
expect(settings.merged.output?.format).toBe('json');
});

it('should handle chatCompression when only in user settings', () => {
it('should handle compressionThreshold when only in user settings', () => {
(mockFsExistsSync as Mock).mockImplementation(
(p: fs.PathLike) => p === USER_SETTINGS_PATH,
);
const userSettingsContent = {
general: {},
model: { chatCompression: { contextPercentageThreshold: 0.5 } },
model: { compressionThreshold: 0.5 },
};
(fs.readFileSync as Mock).mockImplementation(
(p: fs.PathOrFileDescriptor) => {
Expand All @@ -1126,9 +1122,7 @@ describe('Settings Loading and Merging', () => {
);

const settings = loadSettings(MOCK_WORKSPACE_DIR);
expect(settings.merged.model?.chatCompression).toEqual({
contextPercentageThreshold: 0.5,
});
expect(settings.merged.model?.compressionThreshold).toEqual(0.5);
});

it('should have model as undefined if not in any settings file', () => {
Expand All @@ -1138,39 +1132,15 @@ describe('Settings Loading and Merging', () => {
expect(settings.merged.model).toBeUndefined();
});

it('should ignore chatCompression if contextPercentageThreshold is invalid', () => {
const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {});
(mockFsExistsSync as Mock).mockImplementation(
(p: fs.PathLike) => p === USER_SETTINGS_PATH,
);
const userSettingsContent = {
general: {},
model: { chatCompression: { contextPercentageThreshold: 1.5 } },
};
(fs.readFileSync as Mock).mockImplementation(
(p: fs.PathOrFileDescriptor) => {
if (p === USER_SETTINGS_PATH)
return JSON.stringify(userSettingsContent);
return '{}';
},
);

const settings = loadSettings(MOCK_WORKSPACE_DIR);
expect(settings.merged.model?.chatCompression).toEqual({
contextPercentageThreshold: 1.5,
});
warnSpy.mockRestore();
});

it('should deep merge chatCompression settings', () => {
it('should use user compressionThreshold if workspace does not define it', () => {
(mockFsExistsSync as Mock).mockReturnValue(true);
const userSettingsContent = {
general: {},
model: { chatCompression: { contextPercentageThreshold: 0.5 } },
model: { compressionThreshold: 0.5 },
};
const workspaceSettingsContent = {
general: {},
model: { chatCompression: {} },
model: {},
};

(fs.readFileSync as Mock).mockImplementation(
Expand All @@ -1185,9 +1155,7 @@ describe('Settings Loading and Merging', () => {

const settings = loadSettings(MOCK_WORKSPACE_DIR);

expect(settings.merged.model?.chatCompression).toEqual({
contextPercentageThreshold: 0.5,
});
expect(settings.merged.model?.compressionThreshold).toEqual(0.5);
});

it('should merge includeDirectories from all scopes', () => {
Expand Down Expand Up @@ -1972,9 +1940,6 @@ describe('Settings Loading and Merging', () => {
},
model: {
name: 'gemini-pro',
chatCompression: {
contextPercentageThreshold: 0.5,
},
},
mcpServers: {
'server-1': {
Expand All @@ -1993,9 +1958,6 @@ describe('Settings Loading and Merging', () => {
myTheme: {},
},
model: 'gemini-pro',
chatCompression: {
contextPercentageThreshold: 0.5,
},
mcpServers: {
'server-1': {
command: 'node server.js',
Expand Down Expand Up @@ -2035,9 +1997,6 @@ describe('Settings Loading and Merging', () => {
},
model: {
name: 'gemini-pro',
chatCompression: {
contextPercentageThreshold: 0.8,
},
},
context: {
fileName: 'CONTEXT.md',
Expand Down Expand Up @@ -2077,9 +2036,6 @@ describe('Settings Loading and Merging', () => {
theme: 'dark',
usageStatisticsEnabled: false,
model: 'gemini-pro',
chatCompression: {
contextPercentageThreshold: 0.8,
},
contextFileName: 'CONTEXT.md',
includeDirectories: ['/src'],
sandbox: true,
Expand Down
2 changes: 1 addition & 1 deletion packages/cli/src/config/settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ const MIGRATION_MAP: Record<string, string> = {
autoAccept: 'tools.autoAccept',
autoConfigureMaxOldSpaceSize: 'advanced.autoConfigureMemory',
bugCommand: 'advanced.bugCommand',
chatCompression: 'model.chatCompression',
chatCompression: 'model.compressionThreshold',
checkpointing: 'general.checkpointing',
coreTools: 'tools.core',
contextFileName: 'context.fileName',
Expand Down
14 changes: 7 additions & 7 deletions packages/cli/src/config/settingsSchema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import type {
BugCommandSettings,
TelemetrySettings,
AuthType,
ChatCompressionSettings,
} from '@google/gemini-cli-core';
import {
DEFAULT_TRUNCATE_TOOL_OUTPUT_LINES,
Expand Down Expand Up @@ -578,14 +577,15 @@ const SETTINGS_SCHEMA = {
description: 'Settings for summarizing tool output.',
showInDialog: false,
},
chatCompression: {
type: 'object',
label: 'Chat Compression',
compressionThreshold: {
type: 'number',
label: 'Compression Threshold',
category: 'Model',
requiresRestart: false,
default: undefined as ChatCompressionSettings | undefined,
description: 'Chat compression settings.',
showInDialog: false,
default: 0.2 as number,
description:
'The fraction of context usage at which to trigger context compression (e.g. 0.2, 0.3).',
showInDialog: true,
},
skipNextSpeakerCheck: {
type: 'boolean',
Expand Down
14 changes: 5 additions & 9 deletions packages/core/src/config/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,10 +96,6 @@ export interface BugCommandSettings {
urlTemplate: string;
}

export interface ChatCompressionSettings {
contextPercentageThreshold?: number;
}

export interface SummarizeToolOutputSettings {
tokenBudget?: number;
}
Expand Down Expand Up @@ -261,7 +257,7 @@ export interface ConfigParameters {
folderTrust?: boolean;
ideMode?: boolean;
loadMemoryFromIncludeDirectories?: boolean;
chatCompression?: ChatCompressionSettings;
compressionThreshold?: number;
interactive?: boolean;
trustedFolder?: boolean;
useRipgrep?: boolean;
Expand Down Expand Up @@ -354,7 +350,7 @@ export class Config {
| undefined;
private readonly experimentalZedIntegration: boolean = false;
private readonly loadMemoryFromIncludeDirectories: boolean = false;
private readonly chatCompression: ChatCompressionSettings | undefined;
private readonly compressionThreshold: number | undefined;
private readonly interactive: boolean;
private readonly ptyInfo: string;
private readonly trustedFolder: boolean | undefined;
Expand Down Expand Up @@ -453,7 +449,7 @@ export class Config {
this.ideMode = params.ideMode ?? false;
this.loadMemoryFromIncludeDirectories =
params.loadMemoryFromIncludeDirectories ?? false;
this.chatCompression = params.chatCompression;
this.compressionThreshold = params.compressionThreshold;
this.interactive = params.interactive ?? false;
this.ptyInfo = params.ptyInfo ?? 'child_process';
this.trustedFolder = params.trustedFolder;
Expand Down Expand Up @@ -977,8 +973,8 @@ export class Config {
this.fileSystemService = fileSystemService;
}

getChatCompression(): ChatCompressionSettings | undefined {
return this.chatCompression;
getCompressionThreshold(): number | undefined {
return this.compressionThreshold;
}

isInteractiveShellEnabled(): boolean {
Expand Down
Loading
Loading