mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-03-10 22:21:22 -07:00
Log all user settings to enable measurement of experiment impacts (#11354)
This commit is contained in:
@@ -37,7 +37,6 @@ import { AgentTerminateMode } from '../../agents/types.js';
|
||||
import { GIT_COMMIT_INFO, CLI_VERSION } from '../../generated/git-commit.js';
|
||||
import { UserAccountManager } from '../../utils/userAccountManager.js';
|
||||
import { InstallationManager } from '../../utils/installationManager.js';
|
||||
import { safeJsonStringify } from '../../utils/safeJsonStringify.js';
|
||||
|
||||
interface CustomMatchers<R = unknown> {
|
||||
toHaveMetadataValue: ([key, value]: [EventMetadataKey, string]) => R;
|
||||
@@ -260,15 +259,13 @@ describe('ClearcutLogger', () => {
|
||||
const cli_version = CLI_VERSION;
|
||||
const git_commit_hash = GIT_COMMIT_INFO;
|
||||
const prompt_id = 'my-prompt-123';
|
||||
const user_settings = safeJsonStringify([
|
||||
{ smart_edit_enabled: true, model_router_enabled: false },
|
||||
]);
|
||||
|
||||
// Setup logger with expected values
|
||||
const { logger, loggerConfig } = setup({
|
||||
lifetimeGoogleAccounts: google_accounts,
|
||||
config: { sessionId: session_id },
|
||||
});
|
||||
|
||||
vi.spyOn(loggerConfig, 'getContentGeneratorConfig').mockReturnValue({
|
||||
authType: auth_type,
|
||||
} as ContentGeneratorConfig);
|
||||
@@ -315,7 +312,7 @@ describe('ClearcutLogger', () => {
|
||||
},
|
||||
{
|
||||
gemini_cli_key: EventMetadataKey.GEMINI_CLI_USER_SETTINGS,
|
||||
value: user_settings,
|
||||
value: logger?.getConfigJson(),
|
||||
},
|
||||
]),
|
||||
);
|
||||
@@ -346,11 +343,7 @@ describe('ClearcutLogger', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('logs the value of config.useSmartEdit and config.useModelRouter', () => {
|
||||
const user_settings = safeJsonStringify([
|
||||
{ smart_edit_enabled: true, model_router_enabled: true },
|
||||
]);
|
||||
|
||||
it('logs all user settings', () => {
|
||||
const { logger } = setup({
|
||||
config: { useSmartEdit: true, useModelRouter: true },
|
||||
});
|
||||
@@ -362,7 +355,7 @@ describe('ClearcutLogger', () => {
|
||||
|
||||
expect(event?.event_metadata[0]).toContainEqual({
|
||||
gemini_cli_key: EventMetadataKey.GEMINI_CLI_USER_SETTINGS,
|
||||
value: user_settings,
|
||||
value: logger?.getConfigJson(),
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -42,7 +42,10 @@ import { EventMetadataKey } from './event-metadata-key.js';
|
||||
import type { Config } from '../../config/config.js';
|
||||
import { InstallationManager } from '../../utils/installationManager.js';
|
||||
import { UserAccountManager } from '../../utils/userAccountManager.js';
|
||||
import { safeJsonStringify } from '../../utils/safeJsonStringify.js';
|
||||
import {
|
||||
safeJsonStringify,
|
||||
safeJsonStringifyBooleanValuesOnly,
|
||||
} from '../../utils/safeJsonStringify.js';
|
||||
import { FixedDeque } from 'mnemonist';
|
||||
import { GIT_COMMIT_INFO, CLI_VERSION } from '../../generated/git-commit.js';
|
||||
import {
|
||||
@@ -1217,12 +1220,7 @@ export class ClearcutLogger {
|
||||
},
|
||||
{
|
||||
gemini_cli_key: EventMetadataKey.GEMINI_CLI_USER_SETTINGS,
|
||||
value: safeJsonStringify([
|
||||
{
|
||||
smart_edit_enabled: this.config?.getUseSmartEdit() ?? false,
|
||||
model_router_enabled: this.config?.getUseModelRouter() ?? false,
|
||||
},
|
||||
]),
|
||||
value: this.getConfigJson(),
|
||||
},
|
||||
];
|
||||
return [...data, ...defaultLogMetadata];
|
||||
@@ -1240,6 +1238,12 @@ export class ClearcutLogger {
|
||||
}
|
||||
}
|
||||
|
||||
getConfigJson() {
|
||||
const configJson = safeJsonStringifyBooleanValuesOnly(this.config);
|
||||
console.debug(configJson);
|
||||
return safeJsonStringifyBooleanValuesOnly(this.config);
|
||||
}
|
||||
|
||||
shutdown() {
|
||||
this.logEndSessionEvent();
|
||||
}
|
||||
|
||||
@@ -11,6 +11,8 @@
|
||||
* @param space - Optional space parameter for formatting (defaults to no formatting)
|
||||
* @returns JSON string with circular references replaced by [Circular]
|
||||
*/
|
||||
import type { Config } from '../config/config.js';
|
||||
|
||||
export function safeJsonStringify(
|
||||
obj: unknown,
|
||||
space?: string | number,
|
||||
@@ -30,3 +32,37 @@ export function safeJsonStringify(
|
||||
space,
|
||||
);
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
function removeEmptyObjects(data: any): object {
|
||||
const cleanedObject: { [key: string]: unknown } = {};
|
||||
for (const k in data) {
|
||||
const v = data[k];
|
||||
if (v !== null && v !== undefined && typeof v === 'boolean') {
|
||||
cleanedObject[k] = v;
|
||||
}
|
||||
}
|
||||
|
||||
return cleanedObject;
|
||||
}
|
||||
|
||||
/**
|
||||
* Safely stringifies an object to JSON, retaining only non-null, Boolean-valued members.
|
||||
*
|
||||
* @param obj - The object to stringify
|
||||
* @returns JSON string with circular references skipped and only non-null, Boolean member values retained.
|
||||
*/
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
export function safeJsonStringifyBooleanValuesOnly(obj: any): string {
|
||||
let configSeen = false;
|
||||
return JSON.stringify(removeEmptyObjects(obj), (key, value) => {
|
||||
if ((value as Config) !== null && !configSeen) {
|
||||
configSeen = true;
|
||||
return value;
|
||||
}
|
||||
if (typeof value === 'boolean') {
|
||||
return value;
|
||||
}
|
||||
return '';
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user