/**
 * @license
 * Copyright 2025 Google LLC
 * SPDX-License-Identifier: Apache-2.0
 */
import { isSlashCommand } from './ui/utils/commandUtils.js';
import { executeToolCall, shutdownTelemetry, isTelemetrySdkInitialized, GeminiEventType, FatalInputError, promptIdContext, OutputFormat, JsonFormatter, uiTelemetryService, } from '@google/gemini-cli-core';
import { handleSlashCommand } from './nonInteractiveCliCommands.js';
import { ConsolePatcher } from './ui/utils/ConsolePatcher.js';
import { handleAtCommand } from './ui/hooks/atCommandProcessor.js';
import { handleError, handleToolError, handleCancellationError, handleMaxTurnsExceededError, } from './utils/errors.js';
export async function runNonInteractive(config, settings, input, prompt_id) {
    return promptIdContext.run(prompt_id, async () => {
        const consolePatcher = new ConsolePatcher({
            stderr: true,
            debugMode: config.getDebugMode(),
        });
        try {
            consolePatcher.patch();
            // Handle EPIPE errors when the output is piped to a command that closes early.
            process.stdout.on('error', (err) => {
                if (err.code === 'EPIPE') {
                    // Exit gracefully if the pipe is closed.
                    process.exit(0);
                }
            });
            const geminiClient = config.getGeminiClient();
            const abortController = new AbortController();
            let query;
            if (isSlashCommand(input)) {
                const slashCommandResult = await handleSlashCommand(input, abortController, config, settings);
                // If a slash command is found and returns a prompt, use it.
                // Otherwise, slashCommandResult fall through to the default prompt
                // handling.
                if (slashCommandResult) {
                    query = slashCommandResult;
                }
            }
            if (!query) {
                const { processedQuery, shouldProceed } = await handleAtCommand({
                    query: input,
                    config,
                    addItem: (_item, _timestamp) => 0,
                    onDebugMessage: () => { },
                    messageId: Date.now(),
                    signal: abortController.signal,
                });
                if (!shouldProceed || !processedQuery) {
                    // An error occurred during @include processing (e.g., file not found).
                    // The error message is already logged by handleAtCommand.
                    throw new FatalInputError('Exiting due to an error processing the @ command.');
                }
                query = processedQuery;
            }
            let currentMessages = [{ role: 'user', parts: query }];
            let turnCount = 0;
            while (true) {
                turnCount++;
                if (config.getMaxSessionTurns() >= 0 &&
                    turnCount > config.getMaxSessionTurns()) {
                    handleMaxTurnsExceededError(config);
                }
                const toolCallRequests = [];
                const responseStream = geminiClient.sendMessageStream(currentMessages[0]?.parts || [], abortController.signal, prompt_id);
                let responseText = '';
                for await (const event of responseStream) {
                    if (abortController.signal.aborted) {
                        handleCancellationError(config);
                    }
                    if (event.type === GeminiEventType.Content) {
                        if (config.getOutputFormat() === OutputFormat.JSON) {
                            responseText += event.value;
                        }
                        else {
                            process.stdout.write(event.value);
                        }
                    }
                    else if (event.type === GeminiEventType.ToolCallRequest) {
                        toolCallRequests.push(event.value);
                    }
                }
                if (toolCallRequests.length > 0) {
                    const toolResponseParts = [];
                    const completedToolCalls = [];
                    for (const requestInfo of toolCallRequests) {
                        const completedToolCall = await executeToolCall(config, requestInfo, abortController.signal);
                        const toolResponse = completedToolCall.response;
                        completedToolCalls.push(completedToolCall);
                        if (toolResponse.error) {
                            handleToolError(requestInfo.name, toolResponse.error, config, toolResponse.errorType || 'TOOL_EXECUTION_ERROR', typeof toolResponse.resultDisplay === 'string'
                                ? toolResponse.resultDisplay
                                : undefined);
                        }
                        if (toolResponse.responseParts) {
                            toolResponseParts.push(...toolResponse.responseParts);
                        }
                    }
                    // Record tool calls with full metadata before sending responses to Gemini
                    try {
                        const currentModel = geminiClient.getCurrentSequenceModel() ?? config.getModel();
                        geminiClient
                            .getChat()
                            .recordCompletedToolCalls(currentModel, completedToolCalls);
                    }
                    catch (error) {
                        console.error(`Error recording completed tool call information: ${error}`);
                    }
                    currentMessages = [{ role: 'user', parts: toolResponseParts }];
                }
                else {
                    if (config.getOutputFormat() === OutputFormat.JSON) {
                        const formatter = new JsonFormatter();
                        const stats = uiTelemetryService.getMetrics();
                        process.stdout.write(formatter.format(responseText, stats));
                    }
                    else {
                        process.stdout.write('\n'); // Ensure a final newline
                    }
                    return;
                }
            }
        }
        catch (error) {
            handleError(error, config);
        }
        finally {
            consolePatcher.cleanup();
            if (isTelemetrySdkInitialized()) {
                await shutdownTelemetry(config);
            }
        }
    });
}
//# sourceMappingURL=nonInteractiveCli.js.map