Structured JSON Output (#8119)

This commit is contained in:
Jerop Kipruto
2025-09-11 05:19:47 +09:00
committed by GitHub
parent db99fc70b6
commit 514767c88b
20 changed files with 1526 additions and 23 deletions

View File

@@ -1972,6 +1972,55 @@ describe('loadCliConfig fileFiltering', () => {
);
});
describe('Output Format Configuration', () => {
const originalArgv = process.argv;
afterEach(() => {
process.argv = originalArgv;
vi.restoreAllMocks();
});
it('should default to text format when no setting or flag is provided', async () => {
process.argv = ['node', 'script.js'];
const argv = await parseArguments({} as Settings);
const config = await loadCliConfig(
{} as Settings,
[],
'test-session',
argv,
);
expect(config.getOutputFormat()).toBe(ServerConfig.OutputFormat.TEXT);
});
it('should use the format from settings when no flag is provided', async () => {
process.argv = ['node', 'script.js'];
const settings: Settings = { output: { format: 'json' } };
const argv = await parseArguments(settings);
const config = await loadCliConfig(settings, [], 'test-session', argv);
expect(config.getOutputFormat()).toBe(ServerConfig.OutputFormat.JSON);
});
it('should use the format from the flag when provided', async () => {
process.argv = ['node', 'script.js', '--output-format', 'json'];
const argv = await parseArguments({} as Settings);
const config = await loadCliConfig(
{} as Settings,
[],
'test-session',
argv,
);
expect(config.getOutputFormat()).toBe(ServerConfig.OutputFormat.JSON);
});
it('should prioritize the flag over the setting', async () => {
process.argv = ['node', 'script.js', '--output-format', 'text'];
const settings: Settings = { output: { format: 'json' } };
const argv = await parseArguments(settings);
const config = await loadCliConfig(settings, [], 'test-session', argv);
expect(config.getOutputFormat()).toBe(ServerConfig.OutputFormat.TEXT);
});
});
describe('parseArguments with positional prompt', () => {
const originalArgv = process.argv;

View File

@@ -15,6 +15,7 @@ import type {
TelemetryTarget,
FileFilteringOptions,
MCPServerConfig,
OutputFormat,
} from '@google/gemini-cli-core';
import { extensionsCommand } from '../commands/extensions.js';
import {
@@ -81,6 +82,7 @@ export interface CliArgs {
useSmartEdit: boolean | undefined;
sessionSummary: string | undefined;
promptWords: string[] | undefined;
outputFormat: string | undefined;
}
export async function parseArguments(settings: Settings): Promise<CliArgs> {
@@ -234,6 +236,11 @@ export async function parseArguments(settings: Settings): Promise<CliArgs> {
type: 'string',
description: 'File to write session summary to.',
})
.option('output-format', {
type: 'string',
description: 'The format of the CLI output.',
choices: ['text', 'json'],
})
.deprecateOption(
'telemetry',
'Use the "telemetry.enabled" setting in settings.json instead. This flag will be removed in a future version.',
@@ -627,6 +634,9 @@ export async function loadCliConfig(
enableToolOutputTruncation: settings.tools?.enableToolOutputTruncation,
eventEmitter: appEvents,
useSmartEdit: argv.useSmartEdit ?? settings.useSmartEdit,
output: {
format: (argv.outputFormat ?? settings.output?.format) as OutputFormat,
},
});
}

View File

@@ -1078,6 +1078,30 @@ describe('Settings Loading and Merging', () => {
});
});
it('should merge output format settings, with workspace taking precedence', () => {
(mockFsExistsSync as Mock).mockReturnValue(true);
const userSettingsContent = {
output: { format: 'text' },
};
const workspaceSettingsContent = {
output: { format: 'json' },
};
(fs.readFileSync as Mock).mockImplementation(
(p: fs.PathOrFileDescriptor) => {
if (p === USER_SETTINGS_PATH)
return JSON.stringify(userSettingsContent);
if (p === MOCK_WORKSPACE_SETTINGS_PATH)
return JSON.stringify(workspaceSettingsContent);
return '{}';
},
);
const settings = loadSettings(MOCK_WORKSPACE_DIR);
expect(settings.merged.output?.format).toBe('json');
});
it('should handle chatCompression when only in user settings', () => {
(mockFsExistsSync as Mock).mockImplementation(
(p: fs.PathLike) => p === USER_SETTINGS_PATH,

View File

@@ -187,6 +187,30 @@ const SETTINGS_SCHEMA = {
},
},
},
output: {
type: 'object',
label: 'Output',
category: 'General',
requiresRestart: false,
default: {},
description: 'Settings for the CLI output.',
showInDialog: false,
properties: {
format: {
type: 'enum',
label: 'Output Format',
category: 'General',
requiresRestart: false,
default: 'text',
description: 'The format of the CLI output.',
showInDialog: true,
options: [
{ value: 'text', label: 'Text' },
{ value: 'json', label: 'JSON' },
],
},
},
},
ui: {
type: 'object',