Add support for output-format stream-jsonflag for headless mode (#10883)

This commit is contained in:
anj-s
2025-10-15 13:55:37 -07:00
committed by GitHub
parent 7bed302f21
commit 47f693173a
12 changed files with 957 additions and 20 deletions
+66 -4
View File
@@ -8,6 +8,9 @@ import type { Config } from '@google/gemini-cli-core';
import {
OutputFormat,
JsonFormatter,
StreamJsonFormatter,
JsonStreamEventType,
uiTelemetryService,
parseAndFormatApiError,
FatalTurnLimitedError,
FatalCancellationError,
@@ -58,6 +61,7 @@ function getNumericExitCode(errorCode: string | number): number {
/**
* Handles errors consistently for both JSON and text output formats.
* In JSON mode, outputs formatted JSON error and exits.
* In streaming JSON mode, emits a result event with error status.
* In text mode, outputs error message and re-throws.
*/
export function handleError(
@@ -70,7 +74,24 @@ export function handleError(
config.getContentGeneratorConfig()?.authType,
);
if (config.getOutputFormat() === OutputFormat.JSON) {
if (config.getOutputFormat() === OutputFormat.STREAM_JSON) {
const streamFormatter = new StreamJsonFormatter();
const errorCode = customErrorCode ?? extractErrorCode(error);
const metrics = uiTelemetryService.getMetrics();
streamFormatter.emitEvent({
type: JsonStreamEventType.RESULT,
timestamp: new Date().toISOString(),
status: 'error',
error: {
type: error instanceof Error ? error.constructor.name : 'Error',
message: errorMessage,
},
stats: streamFormatter.convertToStreamStats(metrics, 0),
});
process.exit(getNumericExitCode(errorCode));
} else if (config.getOutputFormat() === OutputFormat.JSON) {
const formatter = new JsonFormatter();
const errorCode = customErrorCode ?? extractErrorCode(error);
@@ -110,7 +131,20 @@ export function handleToolError(
if (isFatal) {
const toolExecutionError = new FatalToolExecutionError(errorMessage);
if (config.getOutputFormat() === OutputFormat.JSON) {
if (config.getOutputFormat() === OutputFormat.STREAM_JSON) {
const streamFormatter = new StreamJsonFormatter();
const metrics = uiTelemetryService.getMetrics();
streamFormatter.emitEvent({
type: JsonStreamEventType.RESULT,
timestamp: new Date().toISOString(),
status: 'error',
error: {
type: errorType ?? 'FatalToolExecutionError',
message: toolExecutionError.message,
},
stats: streamFormatter.convertToStreamStats(metrics, 0),
});
} else if (config.getOutputFormat() === OutputFormat.JSON) {
const formatter = new JsonFormatter();
const formattedError = formatter.formatError(
toolExecutionError,
@@ -133,7 +167,21 @@ export function handleToolError(
export function handleCancellationError(config: Config): never {
const cancellationError = new FatalCancellationError('Operation cancelled.');
if (config.getOutputFormat() === OutputFormat.JSON) {
if (config.getOutputFormat() === OutputFormat.STREAM_JSON) {
const streamFormatter = new StreamJsonFormatter();
const metrics = uiTelemetryService.getMetrics();
streamFormatter.emitEvent({
type: JsonStreamEventType.RESULT,
timestamp: new Date().toISOString(),
status: 'error',
error: {
type: 'FatalCancellationError',
message: cancellationError.message,
},
stats: streamFormatter.convertToStreamStats(metrics, 0),
});
process.exit(cancellationError.exitCode);
} else if (config.getOutputFormat() === OutputFormat.JSON) {
const formatter = new JsonFormatter();
const formattedError = formatter.formatError(
cancellationError,
@@ -156,7 +204,21 @@ export function handleMaxTurnsExceededError(config: Config): never {
'Reached max session turns for this session. Increase the number of turns by specifying maxSessionTurns in settings.json.',
);
if (config.getOutputFormat() === OutputFormat.JSON) {
if (config.getOutputFormat() === OutputFormat.STREAM_JSON) {
const streamFormatter = new StreamJsonFormatter();
const metrics = uiTelemetryService.getMetrics();
streamFormatter.emitEvent({
type: JsonStreamEventType.RESULT,
timestamp: new Date().toISOString(),
status: 'error',
error: {
type: 'FatalTurnLimitedError',
message: maxTurnsError.message,
},
stats: streamFormatter.convertToStreamStats(metrics, 0),
});
process.exit(maxTurnsError.exitCode);
} else if (config.getOutputFormat() === OutputFormat.JSON) {
const formatter = new JsonFormatter();
const formattedError = formatter.formatError(
maxTurnsError,