/**
 * @license
 * Copyright 2025 Vybestack LLC
 * SPDX-License-Identifier: Apache-2.0
 */
// @plan:PLAN-20251023-STATELESS-HARDENING.P08 @requirement:REQ-SP4-002
// createHash import removed - no longer needed without client caching
import { DebugLogger } from '../../debug/index.js';
import { Config } from '../../config/config.js';
import { AuthType } from '../../core/contentGenerator.js';
import { getCoreSystemPromptAsync } from '../../core/prompts.js';
import { Type, } from '@google/genai';
import { BaseProvider, } from '../BaseProvider.js';
import { resolveUserMemory } from '../utils/userMemory.js';
import { buildToolResponsePayload } from '../utils/toolResponsePayload.js';
import { ensureActiveLoopHasThoughtSignatures, stripThoughtsFromHistory, } from './thoughtSignatures.js';
import { shouldDumpSDKContext, dumpSDKContext, } from '../utils/dumpSDKContext.js';
import { retryWithBackoff, getErrorStatus, isNetworkTransientError, } from '../../utils/retry.js';
import { ApiError } from '@google/genai';
export class GeminiProvider extends BaseProvider {
    /**
     * @plan:PLAN-20251023-STATELESS-HARDENING.P08
     * @requirement:REQ-SP4-002
     * @pseudocode lines 10-14
     *
     * Removed cached state variables to ensure stateless behavior.
     * Provider now resolves model, auth, and parameters per call.
     * No instance state: authMode, model overrides, modelExplicitlySet, currentModel removed.
     * @requirement:REQ-SP4-003: Auth/model/params come from NormalizedGenerateChatOptions
     */
    geminiOAuthManager;
    /**
     * @plan:PLAN-20251023-STATELESS-HARDENING.P08
     * @requirement:REQ-SP4-002, REQ-SP4-003
     * @pseudocode lines 10-14
     *
     * Simplified constructor that only stores readonly OAuth manager.
     * All other state is now resolved per call from NormalizedGenerateChatOptions.
     * No loggers cached - created on demand like AnthropicProvider.
     */
    constructor(apiKey, baseURL, config, oauthManager) {
        const baseConfig = {
            name: 'gemini',
            apiKey,
            baseURL,
            envKeyNames: ['GEMINI_API_KEY', 'GOOGLE_API_KEY'],
            isOAuthEnabled: !!oauthManager,
            oauthProvider: oauthManager ? 'gemini' : undefined,
            oauthManager,
        };
        super(baseConfig, config);
        this.geminiOAuthManager = oauthManager;
    }
    /**
     * @description Cleans a JSON Schema object to ensure it strictly conforms to the Gemini API's supported Schema definition.
     * This function acts as a whitelist, removing any properties not explicitly defined in the OpenAPI 3.03 Schema Object
     * as understood by the Gemini API. This is crucial for compatibility, as external SDKs might generate schemas
     * with unsupported keywords (e.g., `exclusiveMinimum`, `exclusiveMaximum`) which cause API errors.
     *
     * This approach aligns with how `gemini-cli` handles schema compatibility by relying on the `@google/genai` library's
     * internal cleaning mechanisms.
     *
     * @see https://ai.google.dev/api/caching#Schema
     * @param schema The JSON Schema object to clean.
     * @returns A new Schema object containing only supported properties.
     */
    cleanGeminiSchema(schema) {
        if (typeof schema !== 'object' || schema === null) {
            return schema;
        }
        const cleanedSchema = {};
        const typedSchema = schema;
        const supportedSchemaProperties = [
            'type',
            'format',
            'title',
            'description',
            'nullable',
            'enum',
            'maxItems',
            'minItems',
            'properties',
            'required',
            'minProperties',
            'maxProperties',
            'minLength',
            'maxLength',
            'pattern',
            'example',
            'anyOf',
            'propertyOrdering',
            'default',
            'items',
            'minimum',
            'maximum',
        ];
        for (const key of supportedSchemaProperties) {
            if (Object.prototype.hasOwnProperty.call(schema, key)) {
                if (key === 'properties' &&
                    typeof typedSchema[key] === 'object' &&
                    typedSchema[key] !== null) {
                    // Recursively clean properties within 'properties'
                    const cleanedProperties = {};
                    const propertiesObject = typedSchema[key];
                    for (const propKey in propertiesObject) {
                        cleanedProperties[propKey] = this.cleanGeminiSchema(propertiesObject[propKey]);
                    }
                    cleanedSchema[key] = cleanedProperties;
                }
                else if (key === 'items' && typeof typedSchema[key] === 'object') {
                    // Recursively clean schema within 'items' for array types
                    cleanedSchema[key] = this.cleanGeminiSchema(typedSchema[key]);
                }
                else if (key === 'anyOf' && Array.isArray(typedSchema[key])) {
                    // Recursively clean schemas within 'anyOf'
                    cleanedSchema[key] = typedSchema[key].map((item) => this.cleanGeminiSchema(item));
                }
                else {
                    cleanedSchema[key] = schema[key];
                }
            }
        }
        return cleanedSchema;
    }
    /**
     * @plan:PLAN-20251023-STATELESS-HARDENING.P08
     * @requirement:REQ-SP4-002
     * Create loggers on-demand to avoid instance state, like AnthropicProvider
     */
    getLogger() {
        return new DebugLogger('llxprt:gemini:provider');
    }
    getToolsLogger() {
        return new DebugLogger('llxprt:gemini:tools');
    }
    /**
     * @plan PLAN-20251215-issue813
     * @requirement REQ-RETRY-001: GeminiProvider must use retryWithBackoff for all SDK calls
     *
     * Determines if an error should trigger a retry.
     * - 429 (rate limit) errors are retried
     * - 5xx server errors are retried
     * - 400 (bad request) errors are NOT retried
     * - Network transient errors are retried
     */
    shouldRetryOnError(error) {
        // Priority check for ApiError
        if (error instanceof ApiError) {
            // Explicitly do not retry 400 (Bad Request)
            if (error.status === 400)
                return false;
            // Retry on rate limit and server errors
            return (error.status === 429 || (error.status >= 500 && error.status < 600));
        }
        // Check for status using helper (handles other error shapes)
        const status = getErrorStatus(error);
        if (status !== undefined) {
            if (status === 400)
                return false;
            return status === 429 || (status >= 500 && status < 600);
        }
        // Check for network transient errors
        if (isNetworkTransientError(error)) {
            return true;
        }
        return false;
    }
    /**
     * @plan PLAN-20251018-STATELESSPROVIDER2.P12
     * @requirement REQ-SP2-001
     * @pseudocode anthropic-gemini-stateless.md lines 1-2
     */
    /**
     * @plan:PLAN-20251023-STATELESS-HARDENING.P08
     * @requirement:REQ-SP4-003
     * Determine streaming preference from config settings per call
     */
    getStreamingPreference(_options) {
        const streamingSetting = this.providerConfig?.getEphemeralSettings?.()?.['streaming'];
        return streamingSetting !== 'disabled';
    }
    async createOAuthContentGenerator(httpOptions, config, baseURL) {
        const { createCodeAssistContentGenerator } = await import('../../code_assist/codeAssist.js');
        return createCodeAssistContentGenerator(httpOptions, AuthType.LOGIN_WITH_GOOGLE, config, baseURL);
    }
    /**
     * @plan:PLAN-20251023-STATELESS-HARDENING.P08
     * @requirement:REQ-SP4-002
     * No operation - stateless provider has no cache to clear
     */
    clearClientCache(_runtimeKey) {
        this.getLogger().debug(() => 'Cache clear called on stateless provider - no operation');
    }
    /**
     * Updates OAuth configuration based on current OAuth manager state
     */
    updateOAuthState() {
        if (this.geminiOAuthManager) {
            const manager = this.geminiOAuthManager;
            if (manager.isOAuthEnabled &&
                typeof manager.isOAuthEnabled === 'function') {
                const isEnabled = manager.isOAuthEnabled('gemini');
                // Update the OAuth configuration
                this.updateOAuthConfig(isEnabled, 'gemini', this.geminiOAuthManager);
            }
        }
    }
    /**
     * @plan:PLAN-20251023-STATELESS-HARDENING.P08
     * @requirement:REQ-SP4-002, REQ-SP4-003
     * Determines the best available authentication method per call without storing state.
     * Returns both authMode and token - caller must handle both values.
     */
    async determineBestAuth() {
        this.updateOAuthState();
        // 1. CHECK STANDARD AUTH FIRST (via AuthResolver)
        //    This checks in order:
        //    - SettingsService auth-key
        //    - SettingsService auth-keyfile
        //    - Constructor apiKey
        //    - Environment variables (GEMINI_API_KEY, GOOGLE_API_KEY)
        const standardAuth = await this.authResolver.resolveAuthentication({
            settingsService: this.resolveSettingsService(),
            includeOAuth: false, // Just checking, not triggering OAuth
        });
        if (standardAuth) {
            return { authMode: 'gemini-api-key', token: standardAuth };
        }
        // 2. CHECK PROVIDER-SPECIFIC AUTH (Vertex AI)
        if (this.hasVertexAICredentials()) {
            this.setupVertexAIAuth();
            return { authMode: 'vertex-ai', token: 'USE_VERTEX_AI' };
        }
        // 3. CHECK IF OAUTH IS ENABLED (for compatibility with downstream code)
        //    Use the EXACT pattern from current GeminiProvider.ts lines 305-320:
        const manager = this.geminiOAuthManager;
        const isOAuthEnabled = manager?.isOAuthEnabled &&
            typeof manager.isOAuthEnabled === 'function' &&
            manager.isOAuthEnabled('gemini');
        if (isOAuthEnabled) {
            return { authMode: 'oauth', token: 'USE_LOGIN_WITH_GOOGLE' };
        }
        // 4. NO AUTH AVAILABLE - throw error (don't return 'none')
        throw new Error('No Gemini authentication configured. ' +
            'Set GEMINI_API_KEY environment variable, use --keyfile, or configure Vertex AI credentials.');
    }
    /**
     * Implementation of BaseProvider abstract method
     * Determines if this provider supports OAuth authentication
     */
    supportsOAuth() {
        // Check if OAuth is actually enabled for Gemini in the OAuth manager
        const manager = this.geminiOAuthManager;
        if (manager?.isOAuthEnabled &&
            typeof manager.isOAuthEnabled === 'function') {
            return manager.isOAuthEnabled('gemini');
        }
        // Default to false if OAuth manager is not available
        // This ensures we don't fall back to LOGIN_WITH_GOOGLE when OAuth is disabled
        return false;
    }
    /**
     * Checks if Vertex AI credentials are available
     */
    hasVertexAICredentials() {
        const hasProjectAndLocation = !!process.env.GOOGLE_CLOUD_PROJECT && !!process.env.GOOGLE_CLOUD_LOCATION;
        // eslint-disable-next-line no-restricted-syntax -- Legacy existence check, to be refactored to use authResolver
        const hasGoogleApiKey = !!process.env.GOOGLE_API_KEY;
        const hasApplicationCredentials = 
        // eslint-disable-next-line no-restricted-syntax -- Legacy existence check, to be refactored to use authResolver
        !!process.env.GOOGLE_APPLICATION_CREDENTIALS;
        return (hasProjectAndLocation || hasGoogleApiKey || hasApplicationCredentials);
    }
    /**
     * Sets up environment variables for Vertex AI authentication
     */
    setupVertexAIAuth() {
        process.env.GOOGLE_GENAI_USE_VERTEXAI = 'true';
        // Other Vertex AI env vars are already set, no need to duplicate
    }
    createHttpOptions() {
        const customHeaders = this.getCustomHeaders();
        return {
            headers: {
                'User-Agent': `LLxprt-Code/${process.env.CLI_VERSION || process.version} (${process.platform}; ${process.arch})`,
                ...(customHeaders ?? {}),
            },
        };
    }
    /**
     * Sets the config instance for reading OAuth credentials
     */
    setConfig(config) {
        // Call base provider implementation
        super.setConfig?.(config);
        this.refreshCachedSettings();
        // Sync with config model if user hasn't explicitly set a model
        // This ensures consistency between config and provider state
        // @plan:PLAN-20251023-STATELESS-HARDENING.P08 @requirement:REQ-SP4-002
        // Removed model caching in stateless implementation
        // const configModel = config.getModel();
        // if (!this.modelExplicitlySet && configModel) {
        //   this.currentModel = configModel;
        // }
        // Update OAuth configuration based on OAuth manager state, not config authType
        // This ensures that if OAuth is disabled via /auth gemini disable, it stays disabled
        this.updateOAuthState();
        // Clear auth cache when config changes to allow re-determination
    }
    /**
     * @plan:PLAN-20251023-STATELESS-HARDENING.P08
     * @requirement:REQ-SP4-002
     * Determine auth mode per call instead of using cached state
     */
    async getModels() {
        // Determine auth mode for this call
        const { authMode } = await this.determineBestAuth();
        // For OAuth mode, return fixed list of models
        if (authMode === 'oauth') {
            return [
                {
                    id: 'gemini-2.5-pro',
                    name: 'Gemini 2.5 Pro',
                    provider: this.name,
                    supportedToolFormats: [],
                },
                {
                    id: 'gemini-2.5-flash',
                    name: 'Gemini 2.5 Flash',
                    provider: this.name,
                    supportedToolFormats: [],
                },
                {
                    id: 'gemini-2.5-flash-lite',
                    name: 'Gemini 2.5 Flash Lite',
                    provider: this.name,
                    supportedToolFormats: [],
                },
                {
                    id: 'gemini-3-pro-preview',
                    name: 'Gemini 3 Pro Preview',
                    provider: this.name,
                    supportedToolFormats: [],
                },
            ];
        }
        // For API key modes (gemini-api-key or vertex-ai), try to fetch real models
        if (authMode === 'gemini-api-key' || authMode === 'vertex-ai') {
            // eslint-disable-next-line no-restricted-syntax -- Legacy fallback, to be refactored to use authResolver
            const apiKey = (await this.getAuthToken()) || process.env.GEMINI_API_KEY;
            if (apiKey) {
                try {
                    const baseURL = this.getBaseURL();
                    const url = baseURL
                        ? `${baseURL.replace(/\/$/, '')}/v1beta/models?key=${apiKey}`
                        : `https://generativelanguage.googleapis.com/v1beta/models?key=${apiKey}`;
                    const response = await fetch(url, {
                        method: 'GET',
                        headers: {
                            'Content-Type': 'application/json',
                        },
                    });
                    if (response.ok) {
                        const data = (await response.json());
                        if (data.models && data.models.length > 0) {
                            return data.models.map((model) => ({
                                id: model.name.replace('models/', ''), // Remove 'models/' prefix
                                name: model.displayName || model.name,
                                provider: this.name,
                                supportedToolFormats: [],
                            }));
                        }
                    }
                }
                catch (_error) {
                    // Fall through to default models
                }
            }
        }
        // Return default models as fallback
        return [
            {
                id: 'gemini-2.5-pro',
                name: 'Gemini 2.5 Pro',
                provider: this.name,
                supportedToolFormats: [],
            },
            {
                id: 'gemini-2.5-flash',
                name: 'Gemini 2.5 Flash',
                provider: this.name,
                supportedToolFormats: [],
            },
            {
                id: 'gemini-2.5-flash-exp',
                name: 'Gemini 2.5 Flash Experimental',
                provider: this.name,
                supportedToolFormats: [],
            },
        ];
    }
    /**
     * @plan:PLAN-20251023-STATELESS-HARDENING.P08
     * @requirement:REQ-SP4-002
     * Gets the current authentication mode per call without caching
     */
    async getAuthMode() {
        const { authMode } = await this.determineBestAuth();
        return authMode;
    }
    /**
     * @plan:PLAN-20251023-STATELESS-HARDENING.P08
     * @requirement:REQ-SP4-002
     * Gets the appropriate AuthType for the core library per call
     */
    async getCoreAuthType() {
        const { authMode } = await this.determineBestAuth();
        switch (authMode) {
            case 'oauth':
                return AuthType.LOGIN_WITH_GOOGLE;
            case 'gemini-api-key':
                return AuthType.USE_GEMINI;
            case 'vertex-ai':
                return AuthType.USE_VERTEX_AI;
            default:
                return AuthType.LOGIN_WITH_GOOGLE; // Default to OAuth
        }
    }
    /**
     * @plan:PLAN-20251023-STATELESS-HARDENING.P08
     * @requirement:REQ-SP4-002
     * No caching - this method is now a no-op. Settings read on demand.
     */
    refreshCachedSettings() {
        // No operation - stateless provider doesn't cache settings
    }
    /**
     * @plan:PLAN-20251023-STATELESS-HARDENING.P08
     * @requirement:REQ-SP4-003
     * Gets the current model ID from SettingsService per call
     */
    getCurrentModel() {
        // Try to get from SettingsService first (source of truth)
        try {
            const settingsService = this.resolveSettingsService();
            const providerSettings = settingsService.getProviderSettings(this.name);
            if (providerSettings.model) {
                return providerSettings.model;
            }
        }
        catch (error) {
            this.getLogger().debug(() => `Failed to get model from SettingsService: ${error}`);
        }
        // In stateless mode, always return default since model should come from options
        return this.getDefaultModel();
    }
    /**
     * Gets the default model for Gemini
     */
    getDefaultModel() {
        return 'gemini-2.5-pro';
    }
    /**
     * @plan:PLAN-20251023-STATELESS-HARDENING.P08
     * @requirement:REQ-SP4-003
     * Gets model parameters from SettingsService per call
     */
    getModelParams() {
        try {
            const settingsService = this.resolveSettingsService();
            const providerSettings = settingsService.getProviderSettings(this.name);
            const reservedKeys = new Set([
                'enabled',
                'apiKey',
                'api-key',
                'apiKeyfile',
                'api-keyfile',
                'baseUrl',
                'base-url',
                'model',
                'toolFormat',
                'tool-format',
                'toolFormatOverride',
                'tool-format-override',
                'defaultModel',
            ]);
            const params = {};
            if (providerSettings) {
                for (const [key, value] of Object.entries(providerSettings)) {
                    if (reservedKeys.has(key) || value === undefined || value === null) {
                        continue;
                    }
                    params[key] = value;
                }
            }
            return Object.keys(params).length > 0 ? params : undefined;
        }
        catch (error) {
            this.getLogger().debug(() => `Failed to get Gemini provider settings from SettingsService: ${error}`);
            return undefined;
        }
    }
    /**
     * @plan:PLAN-20251023-STATELESS-HARDENING.P08
     * @requirement:REQ-SP4-002
     * Checks if using paid mode synchronously via env vars (stateless check)
     */
    isPaidMode() {
        // Synchronous check based on environment variables only
        // Note: This doesn't check SettingsService to maintain synchronous behavior
        // eslint-disable-next-line no-restricted-syntax -- Legacy existence check, to be refactored to use authResolver
        return !!process.env.GEMINI_API_KEY || this.hasVertexAICredentials();
    }
    /**
     * @plan:PLAN-20251023-STATELESS-HARDENING.P08
     * @requirement:REQ-SP4-002
     * No state to clear in stateless implementation
     */
    clearState() {
        // No operation - stateless provider has no state to clear
        this.clearAuthCache();
    }
    /**
     * Clear all authentication including environment variable
     */
    clearAuth() {
        // Call base implementation to clear SettingsService
        super.clearAuth?.();
        // CRITICAL: Also clear the environment variable that setApiKey sets
        // eslint-disable-next-line no-restricted-syntax -- Legacy cleanup, required for setApiKey compatibility
        delete process.env.GEMINI_API_KEY;
    }
    /**
     * Forces re-determination of auth method
     */
    clearAuthCache() {
        // Call the base implementation to clear the cached token
        super.clearAuthCache();
        this.clearClientCache();
        // Don't clear the auth mode itself, just allow re-determination next time
    }
    /**
     * Get the list of server tools supported by this provider
     */
    getServerTools() {
        return ['web_search', 'web_fetch'];
    }
    /**
     * @plan:PLAN-20251023-STATELESS-HARDENING.P08
     * @requirement:REQ-SP4-002
     * Invoke a server tool using per-call auth resolution
     */
    async invokeServerTool(toolName, params, _config, _signal) {
        if (toolName === 'web_search') {
            const logger = this.getToolsLogger();
            logger.debug(() => `invokeServerTool: web_search called with params: ${JSON.stringify(params)}`);
            logger.debug(() => `invokeServerTool: globalConfig is ${this.globalConfig ? 'set' : 'null/undefined'}`);
            // Check for abort before auth determination
            if (_signal?.aborted) {
                const error = new Error('Operation was aborted');
                error.name = 'AbortError';
                throw error;
            }
            // Import the necessary modules dynamically
            const { GoogleGenAI } = await import('@google/genai');
            // Create the appropriate client based on auth mode
            const httpOptions = this.createHttpOptions();
            let genAI;
            // Get authentication token and mode lazily per call
            logger.debug(() => `invokeServerTool: about to call determineBestAuth()`);
            const { authMode, token: authToken } = await this.determineBestAuth();
            // Check for abort after auth determination
            if (_signal?.aborted) {
                const error = new Error('Operation was aborted');
                error.name = 'AbortError';
                throw error;
            }
            logger.debug(() => `invokeServerTool: determineBestAuth returned authMode=${authMode}`);
            switch (authMode) {
                case 'gemini-api-key': {
                    // Validate auth token
                    if (!authToken ||
                        authToken === 'USE_LOGIN_WITH_GOOGLE' ||
                        authToken === '') {
                        throw new Error('No valid Gemini API key available for web search');
                    }
                    genAI = new GoogleGenAI({
                        apiKey: authToken,
                        httpOptions: this.getBaseURL()
                            ? {
                                ...httpOptions,
                                baseUrl: this.getBaseURL(),
                            }
                            : httpOptions,
                    });
                    // Get the models interface (which is a ContentGenerator)
                    const contentGenerator = genAI.models;
                    const apiKeyRequest = {
                        model: 'gemini-2.5-flash',
                        contents: [
                            {
                                role: 'user',
                                parts: [{ text: params.query }],
                            },
                        ],
                        config: {
                            tools: [{ googleSearch: {} }],
                        },
                    };
                    // @plan PLAN-20251215-issue813: Wrap with retryWithBackoff for 429/5xx handling
                    const apiKeyResult = await retryWithBackoff(() => contentGenerator.generateContent(apiKeyRequest), {
                        shouldRetryOnError: this.shouldRetryOnError.bind(this),
                    });
                    return apiKeyResult;
                }
                case 'vertex-ai': {
                    genAI = new GoogleGenAI({
                        apiKey: authToken,
                        vertexai: true,
                        httpOptions: this.getBaseURL()
                            ? {
                                ...httpOptions,
                                baseUrl: this.getBaseURL(),
                            }
                            : httpOptions,
                    });
                    // Get the models interface (which is a ContentGenerator)
                    const vertexContentGenerator = genAI.models;
                    const vertexRequest = {
                        model: 'gemini-2.5-flash',
                        contents: [
                            {
                                role: 'user',
                                parts: [{ text: params.query }],
                            },
                        ],
                        config: {
                            tools: [{ googleSearch: {} }],
                        },
                    };
                    // @plan PLAN-20251215-issue813: Wrap with retryWithBackoff for 429/5xx handling
                    const vertexResult = await retryWithBackoff(() => vertexContentGenerator.generateContent(vertexRequest), {
                        shouldRetryOnError: this.shouldRetryOnError.bind(this),
                    });
                    return vertexResult;
                }
                case 'oauth': {
                    try {
                        logger.debug(() => `invokeServerTool: OAuth case - creating content generator`);
                        // If globalConfig is not set (e.g., when using non-Gemini provider),
                        // create a minimal config for OAuth
                        let configForOAuth = this.globalConfig;
                        if (!configForOAuth) {
                            logger.debug(() => `invokeServerTool: globalConfig is null, creating minimal config for OAuth`);
                            // Use crypto for UUID generation
                            const { randomUUID } = await import('crypto');
                            configForOAuth = new Config({
                                sessionId: randomUUID(),
                                targetDir: process.cwd(),
                                debugMode: false,
                                cwd: process.cwd(),
                                model: 'gemini-2.5-flash',
                            });
                            // The OAuth flow will handle authentication
                        }
                        // For OAuth, use the code assist content generator
                        // Note: Detailed logging is now handled by DebugLogger in codeAssist.ts with namespace llxprt:code:assist
                        const oauthContentGenerator = await this.createOAuthContentGenerator(httpOptions, configForOAuth);
                        logger.debug(() => `invokeServerTool: OAuth content generator created successfully`);
                        // For web search, always use gemini-2.5-flash regardless of the active model
                        const oauthRequest = {
                            model: 'gemini-2.5-flash',
                            contents: [
                                {
                                    role: 'user',
                                    parts: [{ text: params.query }],
                                },
                            ],
                            config: {
                                tools: [{ googleSearch: {} }],
                            },
                        };
                        logger.debug(() => `invokeServerTool: making OAuth generateContent request with query: ${params.query}`);
                        // @plan PLAN-20251215-issue813: Wrap with retryWithBackoff for 429/5xx handling
                        // PRIVACY FIX: Removed sessionId to prevent transmission to Google servers
                        const result = await retryWithBackoff(() => oauthContentGenerator.generateContent(oauthRequest, 'google-web-search-oauth'), {
                            shouldRetryOnError: this.shouldRetryOnError.bind(this),
                        });
                        logger.debug(() => `invokeServerTool: OAuth generateContent completed successfully`);
                        return result;
                    }
                    catch (error) {
                        logger.debug(() => `invokeServerTool: ERROR in OAuth case: ${error}`);
                        logger.debug(() => `invokeServerTool: Error details:`, error);
                        throw error;
                    }
                }
                default:
                    throw new Error(`Web search not supported in auth mode: ${authMode}`);
            }
        }
        else if (toolName === 'web_fetch') {
            // Check for abort before auth determination
            if (_signal?.aborted) {
                const error = new Error('Operation was aborted');
                error.name = 'AbortError';
                throw error;
            }
            // Import the necessary modules dynamically
            const { GoogleGenAI } = await import('@google/genai');
            // Get the prompt directly without any processing
            const prompt = params.prompt;
            // Create the appropriate client based on auth mode
            const httpOptions = this.createHttpOptions();
            let genAI;
            // Get authentication token and mode lazily per call
            const { authMode, token: authToken } = await this.determineBestAuth();
            // Check for abort after auth determination
            if (_signal?.aborted) {
                const error = new Error('Operation was aborted');
                error.name = 'AbortError';
                throw error;
            }
            switch (authMode) {
                case 'gemini-api-key': {
                    genAI = new GoogleGenAI({
                        apiKey: authToken,
                        httpOptions: this.getBaseURL()
                            ? {
                                ...httpOptions,
                                baseUrl: this.getBaseURL(),
                            }
                            : httpOptions,
                    });
                    // Get the models interface (which is a ContentGenerator)
                    const contentGenerator = genAI.models;
                    const apiKeyRequest = {
                        model: 'gemini-2.5-flash',
                        contents: [
                            {
                                role: 'user',
                                parts: [{ text: prompt }],
                            },
                        ],
                        config: {
                            tools: [{ urlContext: {} }],
                        },
                    };
                    // @plan PLAN-20251215-issue813: Wrap with retryWithBackoff for 429/5xx handling
                    const apiKeyResult = await retryWithBackoff(() => contentGenerator.generateContent(apiKeyRequest), {
                        shouldRetryOnError: this.shouldRetryOnError.bind(this),
                    });
                    return apiKeyResult;
                }
                case 'vertex-ai': {
                    genAI = new GoogleGenAI({
                        apiKey: authToken,
                        vertexai: true,
                        httpOptions: this.getBaseURL()
                            ? {
                                ...httpOptions,
                                baseUrl: this.getBaseURL(),
                            }
                            : httpOptions,
                    });
                    // Get the models interface (which is a ContentGenerator)
                    const vertexContentGenerator = genAI.models;
                    const vertexRequest = {
                        model: 'gemini-2.5-flash',
                        contents: [
                            {
                                role: 'user',
                                parts: [{ text: prompt }],
                            },
                        ],
                        config: {
                            tools: [{ urlContext: {} }],
                        },
                    };
                    // @plan PLAN-20251215-issue813: Wrap with retryWithBackoff for 429/5xx handling
                    const vertexResult = await retryWithBackoff(() => vertexContentGenerator.generateContent(vertexRequest), {
                        shouldRetryOnError: this.shouldRetryOnError.bind(this),
                    });
                    return vertexResult;
                }
                case 'oauth': {
                    // For OAuth, use the code assist content generator
                    const oauthContentGenerator = await this.createOAuthContentGenerator(httpOptions, this.globalConfig, this.getBaseURL());
                    // For web fetch, always use gemini-2.5-flash regardless of the active model
                    const oauthRequest = {
                        model: 'gemini-2.5-flash',
                        contents: [
                            {
                                role: 'user',
                                parts: [{ text: prompt }],
                            },
                        ],
                        config: {
                            tools: [{ urlContext: {} }],
                        },
                    };
                    // @plan PLAN-20251215-issue813: Wrap with retryWithBackoff for 429/5xx handling
                    // PRIVACY FIX: Removed sessionId to prevent transmission to Google servers
                    const result = await retryWithBackoff(() => oauthContentGenerator.generateContent(oauthRequest, 'google-web-fetch-oauth'), {
                        shouldRetryOnError: this.shouldRetryOnError.bind(this),
                    });
                    return result;
                }
                default:
                    throw new Error(`Web fetch not supported in auth mode: ${authMode}`);
            }
        }
        else {
            throw new Error(`Unknown server tool: ${toolName}`);
        }
    }
    /**
     * @plan:PLAN-20251023-STATELESS-HARDENING.P08
     * @requirement:REQ-SP4-002, REQ-SP4-003
     * Generate chat completion using per-call resolution of auth, model, and params
     * All state comes from NormalizedGenerateChatOptions, no instance caching
     */
    async *generateChatCompletionWithOptions(options) {
        const streamingEnabled = this.getStreamingPreference(options);
        const { contents: content, tools } = options;
        // Determine best auth method per call - no state storage
        const { authMode, token: authToken } = await this.determineBestAuth();
        // Model is resolved from options.resolved.model - no instance caching
        const currentModel = options.resolved.model;
        // Convert IContent directly to Gemini format
        const contents = [];
        const configForMessages = options.config ?? options.runtime?.config ?? this.globalConfig;
        for (const c of content) {
            if (c.speaker === 'human') {
                const parts = [];
                for (const block of c.blocks) {
                    if (block.type === 'text') {
                        parts.push({ text: block.text });
                    }
                }
                if (parts.length > 0) {
                    contents.push({ role: 'user', parts });
                }
            }
            else if (c.speaker === 'ai') {
                const parts = [];
                for (const block of c.blocks) {
                    if (block.type === 'text') {
                        parts.push({ text: block.text });
                    }
                    else if (block.type === 'tool_call') {
                        const tc = block;
                        parts.push({
                            functionCall: {
                                id: tc.id,
                                name: tc.name,
                                args: tc.parameters,
                            },
                        });
                    }
                }
                if (parts.length > 0) {
                    contents.push({ role: 'model', parts });
                }
            }
            else if (c.speaker === 'tool') {
                const toolResponseBlock = c.blocks.find((b) => b.type === 'tool_response');
                if (!toolResponseBlock) {
                    throw new Error('Tool content must have a tool_response block');
                }
                const payload = buildToolResponsePayload(toolResponseBlock, configForMessages);
                contents.push({
                    role: 'user',
                    parts: [
                        {
                            functionResponse: {
                                id: toolResponseBlock.callId,
                                name: toolResponseBlock.toolName,
                                response: {
                                    status: payload.status,
                                    result: payload.result,
                                    error: payload.error,
                                    truncated: payload.truncated,
                                    originalLength: payload.originalLength,
                                    limitMessage: payload.limitMessage,
                                },
                            },
                        },
                    ],
                });
            }
        }
        // Extract reasoning ephemerals for Gemini 3.x thinking support
        // @plan PLAN-20251202-THINKING.P03b @requirement REQ-THINK-006
        const earlyEphemerals = options.invocation?.ephemerals ?? {};
        // Get dump mode from ephemeral settings
        const dumpMode = earlyEphemerals.dumpcontext;
        const shouldDumpSuccess = shouldDumpSDKContext(dumpMode, false);
        const shouldDumpError = shouldDumpSDKContext(dumpMode, true);
        // Ephemerals can be stored as flat keys ('reasoning.enabled') or nested objects ('reasoning': {enabled: true})
        // Handle both formats for compatibility
        const reasoningObj = earlyEphemerals['reasoning'];
        const reasoningEnabled = earlyEphemerals['reasoning.enabled'] ===
            true || reasoningObj?.enabled === true;
        const reasoningIncludeInResponse = earlyEphemerals['reasoning.includeInResponse'] !== false && reasoningObj?.includeInResponse !== false;
        const reasoningStripFromContext = earlyEphemerals['reasoning.stripFromContext'] ??
            reasoningObj?.stripFromContext ??
            'all';
        // Extract reasoning.effort for future use (could map to thinkingLevel in Gemini 3)
        // Currently unused but extracted for completeness
        const reasoningEffort = earlyEphemerals['reasoning.effort'] ??
            reasoningObj?.effort;
        void reasoningEffort; // Mark as intentionally unused (reserved for future effort-to-thinkingLevel mapping)
        const reasoningMaxTokens = earlyEphemerals['reasoning.maxTokens'] ?? reasoningObj?.maxTokens;
        // Strip thought content from history before sending to API
        // This prevents sending previous thinking back which can cause issues
        const contentsWithThoughtsStripped = stripThoughtsFromHistory(contents, reasoningStripFromContext);
        // Gemini 3.x requires thoughtSignature on functionCall parts in the "active loop"
        // (from the last user text message to end of history). Apply synthetic signatures
        // where missing to bypass validation. See: https://ai.google.dev/gemini-api/docs/thought-signatures
        const contentsWithSignatures = ensureActiveLoopHasThoughtSignatures(contentsWithThoughtsStripped);
        // Ensure tools have proper type: 'object' for Gemini
        const geminiTools = tools
            ? tools.map((toolGroup) => ({
                functionDeclarations: toolGroup.functionDeclarations.map((decl) => {
                    let parameters = decl.parametersJsonSchema;
                    // CRITICAL FIX: Clean the JSON schema to remove unsupported properties by Gemini API.
                    // This ensures compatibility and prevents API errors when using tools.
                    // Ref: https://ai.google.dev/api/caching#Schema
                    parameters = this.cleanGeminiSchema(parameters);
                    if (parameters &&
                        typeof parameters === 'object' &&
                        !('type' in parameters)) {
                        parameters = { type: Type.OBJECT, ...parameters };
                    }
                    else if (!parameters) {
                        parameters = { type: Type.OBJECT, properties: {} };
                    }
                    return {
                        name: decl.name,
                        description: decl.description,
                        parameters: parameters,
                    };
                }),
            }))
            : undefined;
        const toolNamesForPrompt = tools === undefined
            ? undefined
            : Array.from(new Set(tools.flatMap((group) => group.functionDeclarations
                .map((decl) => decl.name)
                .filter((name) => Boolean(name)))));
        const directOverridesRaw = options.metadata?.geminiDirectOverrides;
        const directOverrides = directOverridesRaw && typeof directOverridesRaw === 'object'
            ? directOverridesRaw
            : undefined;
        const serverToolsOverride = directOverrides && 'serverTools' in directOverrides
            ? directOverrides.serverTools
            : options.config &&
                typeof options.config.serverTools !==
                    'undefined'
                ? options.config.serverTools
                : undefined;
        const serverTools = Array.isArray(serverToolsOverride)
            ? serverToolsOverride
            : ['web_search', 'web_fetch'];
        const toolConfigOverride = directOverrides && 'toolConfig' in directOverrides
            ? directOverrides.toolConfig
            : undefined;
        // @plan:PLAN-20251023-STATELESS-HARDENING.P08 @requirement:REQ-SP4-003
        // Get model params per call from ephemeral settings, not cached instance state
        const allEphemerals = options.invocation?.ephemerals ?? {};
        const { tools: _ignoredTools, gemini: geminiSpecific, ...generalEphemerals } = allEphemerals;
        const requestOverrides = {
            ...generalEphemerals,
            ...(geminiSpecific && typeof geminiSpecific === 'object'
                ? geminiSpecific
                : {}),
        };
        const requestConfig = {
            ...requestOverrides,
        };
        requestConfig.serverTools = serverTools;
        if (geminiTools) {
            requestConfig.tools = geminiTools;
        }
        if (toolConfigOverride) {
            requestConfig.toolConfig = toolConfigOverride;
        }
        // Configure thinkingConfig for Gemini models when reasoning is enabled
        // @plan PLAN-20251202-THINKING.P03b @requirement REQ-THINK-006
        // ThinkingConfig uses:
        //   - includeThoughts: boolean - whether to include thoughts in response
        //   - thinkingBudget: number - token budget (0=DISABLED, -1=AUTOMATIC, or specific number)
        if (reasoningEnabled) {
            requestConfig.thinkingConfig = {
                includeThoughts: true,
                thinkingBudget: reasoningMaxTokens ?? -1, // -1 = AUTOMATIC
            };
        }
        const requestLogger = new DebugLogger('llxprt:provider:gemini:logging');
        requestLogger.log(() => '[GeminiProvider] request config overrides', {
            hasDirectOverrides: !!directOverrides,
            serverTools,
            toolConfigOverride: toolConfigOverride ? 'present' : 'absent',
        });
        // Debug: Log thinking configuration
        const thinkingConfigLogger = new DebugLogger('llxprt:provider:gemini:thinking');
        thinkingConfigLogger.log(() => '[GeminiProvider] Thinking configuration', {
            reasoningEnabled,
            reasoningIncludeInResponse,
            reasoningStripFromContext,
            model: currentModel,
            thinkingConfig: requestConfig.thinkingConfig,
        });
        // Create appropriate client and generate content
        const baseURL = options.resolved.baseURL ?? this.getBaseURL();
        const httpOptions = this.createHttpOptions();
        const thinkingLogger = new DebugLogger('llxprt:provider:gemini:thinking');
        const mapResponseToChunks = (response, includeThoughts = true) => {
            const chunks = [];
            const parts = response.candidates?.[0]?.content?.parts || [];
            // Debug: Log all parts with their thought property for debugging
            thinkingLogger.log(() => '[GeminiProvider] Response parts received', parts.map((p) => ({
                hasText: 'text' in p,
                thought: p.thought,
                hasThoughtSignature: !!p
                    .thoughtSignature,
                hasFunctionCall: 'functionCall' in p,
                textPreview: 'text' in p
                    ? p.text.substring(0, 100)
                    : undefined,
            })));
            // Separate thought parts from non-thought text parts
            // Gemini returns thought content with `thought: true` on parts
            const thoughtParts = parts.filter((part) => 'text' in part && part.thought);
            const nonThoughtTextParts = parts.filter((part) => 'text' in part && !part.thought);
            // Extract thoughtSignature from the first part that has one (for Gemini 3.x)
            const firstPartWithSig = parts.find((part) => part.thoughtSignature);
            const thoughtSignature = firstPartWithSig
                ? firstPartWithSig
                    .thoughtSignature
                : undefined;
            const text = nonThoughtTextParts
                .map((part) => part.text)
                .join('');
            const thoughtText = thoughtParts
                .map((part) => part.text)
                .join('');
            // Debug: Log thought extraction results
            thinkingLogger.log(() => '[GeminiProvider] Thought extraction results', {
                thoughtPartsCount: thoughtParts.length,
                nonThoughtTextPartsCount: nonThoughtTextParts.length,
                thoughtTextLength: thoughtText.length,
                thoughtTextPreview: thoughtText.substring(0, 200),
                includeThoughts,
                willYieldThinkingBlock: !!(thoughtText && includeThoughts),
            });
            const functionCalls = parts
                ?.filter((part) => 'functionCall' in part)
                ?.map((part) => part.functionCall) || [];
            const usageMetadata = response.usageMetadata;
            // Yield ThinkingBlock first if there's thought content and includeThoughts is true
            if (thoughtText && includeThoughts) {
                const thinkingBlock = {
                    type: 'thinking',
                    thought: thoughtText,
                    sourceField: 'thought', // Gemini uses `thought: true` on parts
                    isHidden: false, // Not hidden since includeThoughts is true
                };
                if (thoughtSignature) {
                    thinkingBlock.signature = thoughtSignature;
                }
                const thinkingContent = {
                    speaker: 'ai',
                    blocks: [thinkingBlock],
                };
                chunks.push(thinkingContent);
            }
            if (text) {
                const textContent = {
                    speaker: 'ai',
                    blocks: [{ type: 'text', text }],
                };
                if (usageMetadata) {
                    textContent.metadata = {
                        usage: {
                            promptTokens: usageMetadata.promptTokenCount || 0,
                            completionTokens: usageMetadata.candidatesTokenCount || 0,
                            totalTokens: usageMetadata.totalTokenCount ||
                                (usageMetadata.promptTokenCount || 0) +
                                    (usageMetadata.candidatesTokenCount || 0),
                        },
                    };
                }
                chunks.push(textContent);
            }
            if (functionCalls.length > 0) {
                const blocks = functionCalls.map((call) => ({
                    type: 'tool_call',
                    id: call.id ||
                        `call_${Date.now()}_${Math.random().toString(36).substring(2, 11)}`,
                    name: call.name || 'unknown_function',
                    parameters: call.args || {},
                }));
                const toolCallContent = {
                    speaker: 'ai',
                    blocks,
                };
                if (usageMetadata) {
                    toolCallContent.metadata = {
                        usage: {
                            promptTokens: usageMetadata.promptTokenCount || 0,
                            completionTokens: usageMetadata.candidatesTokenCount || 0,
                            totalTokens: usageMetadata.totalTokenCount ||
                                (usageMetadata.promptTokenCount || 0) +
                                    (usageMetadata.candidatesTokenCount || 0),
                        },
                    };
                }
                chunks.push(toolCallContent);
            }
            if (usageMetadata && !text && functionCalls.length === 0) {
                chunks.push({
                    speaker: 'ai',
                    blocks: [],
                    metadata: {
                        usage: {
                            promptTokens: usageMetadata.promptTokenCount || 0,
                            completionTokens: usageMetadata.candidatesTokenCount || 0,
                            totalTokens: usageMetadata.totalTokenCount ||
                                (usageMetadata.promptTokenCount || 0) +
                                    (usageMetadata.candidatesTokenCount || 0),
                        },
                    },
                });
            }
            if (!usageMetadata && !text && functionCalls.length === 0) {
                chunks.push({
                    speaker: 'ai',
                    blocks: [],
                });
            }
            return chunks;
        };
        let stream = null;
        let emitted = false;
        // @plan:PLAN-20251023-STATELESS-HARDENING.P08 @requirement:REQ-SP4-002
        // No caching - create client per call based on resolved authMode
        if (authMode === 'oauth') {
            const configForOAuth = this.globalConfig || {
                getProxy: () => undefined,
                isBrowserLaunchSuppressed: () => false,
                getNoBrowser: () => false,
                getUserMemory: () => '',
            };
            // Create OAuth content generator per call - no caching
            const contentGenerator = await this.createOAuthContentGenerator(httpOptions, configForOAuth, baseURL);
            // @plan PLAN-20251023-STATELESS-HARDENING.P08: Get userMemory from normalized runtime context
            const userMemory = await resolveUserMemory(options.userMemory, () => options.invocation?.userMemory);
            const systemInstruction = await getCoreSystemPromptAsync(userMemory, currentModel, toolNamesForPrompt);
            const contentsWithSystemPrompt = [
                {
                    role: 'user',
                    parts: [
                        {
                            text: `<system>\n${systemInstruction}\n</system>\n\nUser provided conversation begins here:`,
                        },
                    ],
                },
                ...contentsWithSignatures,
            ];
            const oauthConfig = { ...requestConfig };
            const oauthRequest = {
                model: currentModel,
                contents: contentsWithSystemPrompt,
                systemInstruction,
                config: oauthConfig,
            };
            // Use runtime metadata from options for session ID
            const runtimeId = options.runtime?.runtimeId || 'default';
            const sessionId = `oauth-session:${runtimeId}:${Math.random()
                .toString(36)
                .slice(2)}`;
            const generatorWithStream = contentGenerator;
            if (!streamingEnabled && generatorWithStream.generateContent) {
                try {
                    // @plan PLAN-20251215-issue813: Wrap with retryWithBackoff for 429/5xx handling
                    const response = await retryWithBackoff(() => generatorWithStream.generateContent(oauthRequest, sessionId), {
                        shouldRetryOnError: this.shouldRetryOnError.bind(this),
                    });
                    // Dump successful non-streaming request if enabled
                    if (shouldDumpSuccess) {
                        await dumpSDKContext('gemini', '/v1/models/generateContent', oauthRequest, response, false, baseURL || 'https://generativelanguage.googleapis.com');
                    }
                    let yielded = false;
                    for (const chunk of mapResponseToChunks(response, reasoningIncludeInResponse)) {
                        yielded = true;
                        yield chunk;
                    }
                    if (!yielded) {
                        yield { speaker: 'ai', blocks: [] };
                    }
                    return;
                }
                catch (error) {
                    // Dump error if enabled
                    if (shouldDumpError) {
                        const errorMessage = error instanceof Error ? error.message : String(error);
                        await dumpSDKContext('gemini', '/v1/models/generateContent', oauthRequest, { error: errorMessage }, true, baseURL || 'https://generativelanguage.googleapis.com');
                    }
                    throw error;
                }
            }
            try {
                // @plan PLAN-20251215-issue813: Wrap with retryWithBackoff for 429/5xx handling
                // Use Promise.resolve to handle both sync and async return types from generateContentStream
                const oauthStream = await retryWithBackoff(() => Promise.resolve(generatorWithStream.generateContentStream(oauthRequest, sessionId)), {
                    shouldRetryOnError: this.shouldRetryOnError.bind(this),
                });
                // Dump successful streaming request if enabled
                if (shouldDumpSuccess) {
                    await dumpSDKContext('gemini', '/v1/models/streamGenerateContent', oauthRequest, { streaming: true }, false, baseURL || 'https://generativelanguage.googleapis.com');
                }
                stream = oauthStream;
                if (streamingEnabled) {
                    emitted = true;
                    yield {
                        speaker: 'ai',
                        blocks: [],
                        metadata: {
                            session: sessionId,
                            runtime: runtimeId,
                            authMode: 'oauth',
                        },
                    };
                }
            }
            catch (error) {
                // Dump error if enabled
                if (shouldDumpError) {
                    const errorMessage = error instanceof Error ? error.message : String(error);
                    await dumpSDKContext('gemini', '/v1/models/streamGenerateContent', oauthRequest, { error: errorMessage }, true, baseURL || 'https://generativelanguage.googleapis.com');
                }
                throw error;
            }
        }
        else {
            // @plan:PLAN-20251023-STATELESS-HARDENING.P08 @requirement:REQ-SP4-002
            // Create Google GenAI client per call - no caching
            const { GoogleGenAI } = await import('@google/genai');
            const genAI = new GoogleGenAI({
                apiKey: authToken,
                vertexai: authMode === 'vertex-ai',
                httpOptions: baseURL
                    ? { ...httpOptions, baseUrl: baseURL }
                    : httpOptions,
            });
            const contentGenerator = genAI.models;
            // @plan PLAN-20251023-STATELESS-HARDENING.P08: Get userMemory from normalized runtime context
            const userMemory = await resolveUserMemory(options.userMemory, () => options.invocation?.userMemory);
            const systemInstruction = await getCoreSystemPromptAsync(userMemory, currentModel, toolNamesForPrompt);
            const apiRequest = {
                model: currentModel,
                contents: contentsWithSignatures,
                systemInstruction,
                config: { ...requestConfig },
            };
            if (streamingEnabled) {
                try {
                    // @plan PLAN-20251215-issue813: Wrap with retryWithBackoff for 429/5xx handling
                    stream = await retryWithBackoff(() => contentGenerator.generateContentStream(apiRequest), {
                        shouldRetryOnError: this.shouldRetryOnError.bind(this),
                    });
                    // Dump successful streaming request if enabled
                    if (shouldDumpSuccess) {
                        await dumpSDKContext('gemini', '/v1/models/streamGenerateContent', apiRequest, { streaming: true }, false, baseURL || 'https://generativelanguage.googleapis.com');
                    }
                }
                catch (error) {
                    // Dump error if enabled
                    if (shouldDumpError) {
                        const errorMessage = error instanceof Error ? error.message : String(error);
                        await dumpSDKContext('gemini', '/v1/models/streamGenerateContent', apiRequest, { error: errorMessage }, true, baseURL || 'https://generativelanguage.googleapis.com');
                    }
                    throw error;
                }
            }
            else {
                try {
                    // @plan PLAN-20251215-issue813: Wrap with retryWithBackoff for 429/5xx handling
                    const response = await retryWithBackoff(() => contentGenerator.generateContent(apiRequest), {
                        shouldRetryOnError: this.shouldRetryOnError.bind(this),
                    });
                    // Dump successful non-streaming request if enabled
                    if (shouldDumpSuccess) {
                        await dumpSDKContext('gemini', '/v1/models/generateContent', apiRequest, response, false, baseURL || 'https://generativelanguage.googleapis.com');
                    }
                    let yielded = false;
                    for (const chunk of mapResponseToChunks(response, reasoningIncludeInResponse)) {
                        yielded = true;
                        yield chunk;
                    }
                    if (!yielded) {
                        yield { speaker: 'ai', blocks: [] };
                    }
                    return;
                }
                catch (error) {
                    // Dump error if enabled
                    if (shouldDumpError) {
                        const errorMessage = error instanceof Error ? error.message : String(error);
                        await dumpSDKContext('gemini', '/v1/models/generateContent', apiRequest, { error: errorMessage }, true, baseURL || 'https://generativelanguage.googleapis.com');
                    }
                    throw error;
                }
            }
        }
        if (stream) {
            const iterator = typeof stream[Symbol.asyncIterator] === 'function'
                ? stream[Symbol.asyncIterator]()
                : stream;
            while (true) {
                const { value, done } = await iterator.next();
                if (done) {
                    break;
                }
                const mapped = mapResponseToChunks(value, reasoningIncludeInResponse);
                if (mapped.length === 0) {
                    continue;
                }
                emitted = true;
                for (const chunk of mapped) {
                    yield chunk;
                }
            }
        }
        if (!emitted) {
            yield { speaker: 'ai', blocks: [] };
        }
    }
}
//# sourceMappingURL=GeminiProvider.js.map