mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-05-14 22:02:59 -07:00
switch to sidecar profile
This commit is contained in:
File diff suppressed because one or more lines are too long
@@ -54,36 +54,6 @@ describe('ContextManager Golden Tests', () => {
|
||||
protectLatestTurn: false,
|
||||
protectionThresholdTokens: 100,
|
||||
}),
|
||||
getContextManagementConfig: vi.fn().mockReturnValue({
|
||||
strategies: {
|
||||
historySquashing: { maxTokensPerNode: 3000 },
|
||||
toolMasking: { stringLengthThresholdTokens: 10000 },
|
||||
semanticCompression: {
|
||||
nodeThresholdTokens: 5000,
|
||||
compressionModel: 'chat-compression-2.5-flash-lite',
|
||||
},
|
||||
},
|
||||
budget: {
|
||||
maxTokens: 1000,
|
||||
retainedTokens: 500,
|
||||
protectedEpisodes: 1,
|
||||
protectSystemEpisode: true,
|
||||
},
|
||||
historyWindow: { maxTokens: 1000, retainedTokens: 500 },
|
||||
messageLimits: {
|
||||
normalMaxTokens: 100,
|
||||
retainedMaxTokens: 50,
|
||||
normalizationHeadRatio: 0.1,
|
||||
},
|
||||
tools: {
|
||||
outputMasking: {
|
||||
enabled: true,
|
||||
protectLatestTurn: false,
|
||||
protectionThresholdTokens: 100,
|
||||
minPrunableThresholdTokens: 50,
|
||||
},
|
||||
},
|
||||
}),
|
||||
storage: { getProjectTempDir: vi.fn().mockReturnValue('/tmp') },
|
||||
getUsageStatisticsEnabled: vi.fn().mockReturnValue(false),
|
||||
getBaseLlmClient: vi.fn().mockReturnValue({
|
||||
@@ -145,56 +115,12 @@ describe('ContextManager Golden Tests', () => {
|
||||
});
|
||||
|
||||
it('should not modify history when under budget', async () => {
|
||||
mockConfig.getContextManagementConfig.mockReturnValue({
|
||||
strategies: {
|
||||
historySquashing: { maxTokensPerNode: 3000 },
|
||||
toolMasking: { stringLengthThresholdTokens: 10000 },
|
||||
semanticCompression: {
|
||||
nodeThresholdTokens: 5000,
|
||||
compressionModel: 'chat-compression-2.5-flash-lite',
|
||||
},
|
||||
},
|
||||
budget: {
|
||||
maxTokens: 15000000,
|
||||
retainedTokens: 50000,
|
||||
protectedEpisodes: 1,
|
||||
protectSystemEpisode: true,
|
||||
},
|
||||
historyWindow: { maxTokens: 100000, retainedTokens: 50000 },
|
||||
messageLimits: {
|
||||
normalMaxTokens: 100,
|
||||
retainedMaxTokens: 50,
|
||||
normalizationHeadRatio: 0.1,
|
||||
},
|
||||
tools: {
|
||||
outputMasking: {
|
||||
enabled: true,
|
||||
protectLatestTurn: false,
|
||||
protectionThresholdTokens: 100,
|
||||
minPrunableThresholdTokens: 50,
|
||||
},
|
||||
},
|
||||
});
|
||||
const history = createLargeHistory();
|
||||
(contextManager as any).pristineEpisodes = (
|
||||
await import('./ir/mapper.js')
|
||||
).IrMapper.toIr(history);
|
||||
// In Golden Tests, we just want to ensure the logic doesn't throw or alter unprotected history in weird ways.
|
||||
// Since we're skipping processors due to being under budget, it should equal history.
|
||||
mockConfig.getContextManagementConfig.mockReturnValue({
|
||||
strategies: {
|
||||
historySquashing: { maxTokensPerNode: 3000 },
|
||||
toolMasking: { stringLengthThresholdTokens: 10000 },
|
||||
semanticCompression: {
|
||||
nodeThresholdTokens: 5000,
|
||||
},
|
||||
},
|
||||
budget: {
|
||||
maxTokens: 15000000,
|
||||
retainedTokens: 50000,
|
||||
},
|
||||
gcBackstop: { target: 'incremental', strategy: 'truncate' },
|
||||
});
|
||||
const tracer2 = new ContextTracer('/tmp', 'test2');
|
||||
contextManager = new ContextManager({ pipelines: { eagerBackground: [], normalProcessingGraph: [], retainedProcessingGraph: [] } } as any, {} as any, tracer2);
|
||||
|
||||
|
||||
@@ -4,56 +4,32 @@
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import * as fs from 'node:fs';
|
||||
import type { Config } from '../../config/config.js';
|
||||
import type { SidecarConfig } from './types.js';
|
||||
import { defaultSidecarProfile } from './profiles.js';
|
||||
|
||||
export class SidecarLoader {
|
||||
/**
|
||||
* Generates a default Sidecar JSON graph from the user's legacy UI profile settings.
|
||||
* Generates a Sidecar JSON graph from the experimental config file path or defaults.
|
||||
*/
|
||||
static fromLegacyConfig(config: Config): SidecarConfig {
|
||||
const mngConfig = config.getContextManagementConfig ? config.getContextManagementConfig() : undefined;
|
||||
const strat: any = mngConfig?.strategies ?? {};
|
||||
const budget = mngConfig?.budget ?? { retainedTokens: 65000, maxTokens: 150000, maxPressureStrategy: 'truncate', gcTarget: 'incremental', freeTokensTarget: 10000 };
|
||||
|
||||
return {
|
||||
budget: {
|
||||
retainedTokens: budget.retainedTokens,
|
||||
maxTokens: budget.maxTokens,
|
||||
},
|
||||
gcBackstop: {
|
||||
strategy: budget.maxPressureStrategy,
|
||||
target: budget.gcTarget,
|
||||
freeTokensTarget: budget.freeTokensTarget,
|
||||
},
|
||||
pipelines: {
|
||||
eagerBackground: [
|
||||
{
|
||||
processorId: 'StateSnapshotWorker',
|
||||
options: {},
|
||||
}
|
||||
],
|
||||
retainedProcessingGraph: [
|
||||
{
|
||||
processorId: 'HistorySquashingProcessor',
|
||||
options: { maxTokensPerNode: strat.historySquashing?.maxTokensPerNode ?? 3000 }
|
||||
}
|
||||
],
|
||||
normalProcessingGraph: [
|
||||
{
|
||||
processorId: 'ToolMaskingProcessor',
|
||||
options: { stringLengthThresholdTokens: strat.toolMasking?.stringLengthThresholdTokens ?? 8000 }
|
||||
},
|
||||
{
|
||||
processorId: 'BlobDegradationProcessor',
|
||||
options: {}
|
||||
},
|
||||
{
|
||||
processorId: 'SemanticCompressionProcessor',
|
||||
options: { nodeThresholdTokens: strat.semanticCompression?.nodeThresholdTokens ?? 3000 }
|
||||
}
|
||||
]
|
||||
static fromConfig(config: Config): SidecarConfig {
|
||||
const sidecarPath = typeof (config as any).getExperimentalContextSidecarConfig === 'function' ? (config as any).getExperimentalContextSidecarConfig() : undefined;
|
||||
|
||||
if (sidecarPath && fs.existsSync(sidecarPath)) {
|
||||
try {
|
||||
const fileContent = fs.readFileSync(sidecarPath, 'utf8');
|
||||
return JSON.parse(fileContent) as SidecarConfig;
|
||||
} catch (error) {
|
||||
console.error(`Failed to parse Sidecar configuration file at ${sidecarPath}:`, error);
|
||||
// Fallback to default
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
return defaultSidecarProfile;
|
||||
}
|
||||
|
||||
static fromLegacyConfig(config: Config): SidecarConfig {
|
||||
return SidecarLoader.fromConfig(config);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2026 Google LLC
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import type { SidecarConfig } from './types.js';
|
||||
|
||||
/**
|
||||
* The standard default context management profile.
|
||||
* Optimized for safety, precision, and reliable summarization.
|
||||
*/
|
||||
export const defaultSidecarProfile: SidecarConfig = {
|
||||
budget: {
|
||||
retainedTokens: 65000,
|
||||
maxTokens: 150000,
|
||||
},
|
||||
gcBackstop: {
|
||||
strategy: 'truncate',
|
||||
target: 'incremental',
|
||||
freeTokensTarget: 10000,
|
||||
},
|
||||
pipelines: {
|
||||
eagerBackground: [
|
||||
{
|
||||
processorId: 'StateSnapshotWorker',
|
||||
options: { pollingIntervalMs: 5000 }
|
||||
}
|
||||
],
|
||||
retainedProcessingGraph: [
|
||||
{
|
||||
processorId: 'HistorySquashingProcessor',
|
||||
options: { maxTokensPerNode: 3000 }
|
||||
}
|
||||
],
|
||||
normalProcessingGraph: [
|
||||
{
|
||||
processorId: 'ToolMaskingProcessor',
|
||||
options: { stringLengthThresholdTokens: 8000 }
|
||||
},
|
||||
{
|
||||
processorId: 'BlobDegradationProcessor',
|
||||
options: {}
|
||||
},
|
||||
{
|
||||
processorId: 'SemanticCompressionProcessor',
|
||||
options: { nodeThresholdTokens: 5000, contextWindowPercentage: 0.2 }
|
||||
}
|
||||
]
|
||||
}
|
||||
};
|
||||
@@ -69,26 +69,6 @@ export function createMockContextConfig(
|
||||
storage: {
|
||||
getProjectTempDir: vi.fn().mockReturnValue('/tmp/gemini-test'),
|
||||
},
|
||||
getContextManagementConfig: vi.fn().mockReturnValue({
|
||||
enabled: true,
|
||||
charsPerToken: 1,
|
||||
strategies: {
|
||||
historySquashing: { maxTokensPerNode: 3000 },
|
||||
toolMasking: { stringLengthThresholdTokens: 10000 },
|
||||
semanticCompression: { nodeThresholdTokens: 5000 },
|
||||
},
|
||||
budget: { retainedTokens: 500, maxTokens: 150000, maxPressureStrategy: 'truncate', gcTarget: 'incremental', freeTokensTarget: 1000 },
|
||||
gcBackstop: { strategy: 'truncate', target: 'freeNTokens', freeTokensTarget: 100 },
|
||||
pipelines: {
|
||||
eagerBackground: [{ processorId: 'StateSnapshotWorker', options: {} }],
|
||||
retainedProcessingGraph: [{ processorId: 'HistorySquashingProcessor', options: { maxTokensPerNode: 3000 } }],
|
||||
normalProcessingGraph: [
|
||||
{ processorId: 'ToolMaskingProcessor', options: { stringLengthThresholdTokens: 10000 } },
|
||||
{ processorId: 'BlobDegradationProcessor', options: {} },
|
||||
{ processorId: 'SemanticCompressionProcessor', options: { nodeThresholdTokens: 5000 } }
|
||||
]
|
||||
}
|
||||
}),
|
||||
getBaseLlmClient: vi.fn().mockReturnValue(
|
||||
llmClientOverride || {
|
||||
generateContent: vi.fn().mockResolvedValue({
|
||||
|
||||
@@ -62,11 +62,7 @@ describe('ToolOutputMaskingService', () => {
|
||||
}
|
||||
});
|
||||
|
||||
it('should respect remote configuration overrides', async () => {
|
||||
mockConfig.getContextManagementConfig = () =>
|
||||
({
|
||||
strategies: { toolMasking: { stringLengthThresholdTokens: 100 } },
|
||||
}) as any; // eslint-disable-line @typescript-eslint/no-explicit-any
|
||||
it.skip('should respect remote configuration overrides (Feature Moved to Sidecar)', async () => {
|
||||
|
||||
const history: Content[] = [
|
||||
{
|
||||
|
||||
@@ -75,8 +75,7 @@ export class ToolOutputMaskingService {
|
||||
return { newHistory: history, maskedCount: 0, tokensSaved: 0 };
|
||||
}
|
||||
|
||||
const maskingConfig = config.getContextManagementConfig?.()?.strategies
|
||||
?.toolMasking || { stringLengthThresholdTokens: 10000 };
|
||||
const maskingConfig = { stringLengthThresholdTokens: 10000 };
|
||||
let cumulativeToolTokens = 0;
|
||||
let protectionBoundaryReached = false;
|
||||
let totalPrunableTokens = 0;
|
||||
|
||||
@@ -258,7 +258,7 @@ describe('Gemini Client (client.ts)', () => {
|
||||
getProjectRoot: vi.fn().mockReturnValue('/test/project/root'),
|
||||
getIncludeDirectoryTree: vi.fn().mockReturnValue(true),
|
||||
storage: {
|
||||
getProjectTempDir: vi.fn().mockReturnValue('/test/temp'),
|
||||
getProjectTempDir: vi.fn().mockReturnValue('/tmp/gemini-test'),
|
||||
},
|
||||
getContentGenerator: vi.fn().mockReturnValue(mockContentGenerator),
|
||||
getBaseLlmClient: vi.fn().mockReturnValue({
|
||||
|
||||
Reference in New Issue
Block a user