/**
 * @license
 * Copyright 2025 Vybestack LLC
 * SPDX-License-Identifier: Apache-2.0
 */
/**
 * Base provider class with authentication precedence logic
 */
import { AsyncLocalStorage } from 'node:async_hooks';
import { DebugLogger } from '../debug/index.js';
import { AuthPrecedenceResolver, } from '../auth/precedence.js';
import { peekActiveProviderRuntimeContext, setActiveProviderRuntimeContext, } from '../runtime/providerRuntimeContext.js';
import { createRuntimeInvocationContext, } from '../runtime/RuntimeInvocationContext.js';
import { SettingsService } from '../settings/SettingsService.js';
import { getSettingsService } from '../settings/settingsServiceInstance.js';
import { MissingProviderRuntimeError } from './errors.js';
import { resolveRuntimeAuthToken } from './utils/authToken.js';
/**
 * Abstract base provider class that implements authentication precedence logic
 * This class provides lazy OAuth triggering and proper authentication precedence
 */
export class BaseProvider {
    name;
    authResolver;
    baseProviderConfig;
    providerConfig;
    /**
     * @plan PLAN-20250218-STATELESSPROVIDER.P05
     * @requirement REQ-SP-001
     * @pseudocode provider-invocation.md lines 8-15
     */
    defaultSettingsService;
    defaultConfig;
    activeCallContext = new AsyncLocalStorage();
    // Callback for tracking throttle wait times (set by LoggingProviderWrapper)
    throttleTracker;
    get globalConfig() {
        return this.defaultConfig;
    }
    set globalConfig(config) {
        this.defaultConfig = config;
    }
    constructor(config, providerConfig, globalConfig, settingsService) {
        this.name = config.name;
        this.baseProviderConfig = config;
        this.providerConfig = providerConfig;
        this.defaultConfig = globalConfig;
        let fallbackSettingsService;
        if (settingsService) {
            fallbackSettingsService = settingsService;
        }
        else {
            try {
                fallbackSettingsService = getSettingsService();
            }
            catch {
                fallbackSettingsService = new SettingsService();
            }
        }
        this.defaultSettingsService = fallbackSettingsService;
        const precedenceConfig = {
            apiKey: config.apiKey,
            envKeyNames: config.envKeyNames || [],
            isOAuthEnabled: config.isOAuthEnabled ?? false,
            // Use supportsOAuth from config if provided (for cases where method can't be used in constructor)
            supportsOAuth: config.supportsOAuth ?? this.supportsOAuth(),
            oauthProvider: config.oauthProvider,
            providerId: this.name,
        };
        this.authResolver = new AuthPrecedenceResolver(precedenceConfig, config.oauthManager, fallbackSettingsService);
    }
    /**
     * @plan PLAN-20251018-STATELESSPROVIDER2.P06
     * @plan:PLAN-20251018-STATELESSPROVIDER2.P06
     * @requirement REQ-SP2-001
     * @pseudocode base-provider-call-contract.md lines 1-2
     */
    setRuntimeSettingsService(settingsService) {
        if (!settingsService) {
            return;
        }
        this.defaultSettingsService = settingsService;
        this.authResolver.setSettingsService(settingsService);
    }
    /**
     * @plan PLAN-20251018-STATELESSPROVIDER2.P06
     * @plan:PLAN-20251023-STATELESS-HARDENING.P05
     * @requirement REQ-SP2-001
     * @requirement:REQ-SP4-001
     * @pseudocode base-provider-call-contract.md lines 1-3
     */
    resolveSettingsService() {
        const activeOptions = this.activeCallContext.getStore();
        if (activeOptions?.settings) {
            return activeOptions.settings;
        }
        if (this.defaultSettingsService) {
            return this.defaultSettingsService;
        }
        throw new MissingProviderRuntimeError({
            providerKey: `BaseProvider.${this.name}`,
            missingFields: ['settings'],
            stage: 'resolveSettingsService',
            metadata: {
                requirement: 'REQ-SP4-001',
                hint: 'Provider runtime guard expects ProviderManager to set runtime settings.',
            },
        });
    }
    /**
     * Set throttle tracking callback (used by LoggingProviderWrapper)
     */
    setThrottleTracker(tracker) {
        this.throttleTracker = tracker;
        // Debug logging to verify tracker is being set
        const logger = new DebugLogger('llxprt:provider:base');
        logger.debug(() => `Throttle tracker set for provider`);
    }
    /**
     * @plan PLAN-20251018-STATELESSPROVIDER2.P06
     * @requirement REQ-SP2-001
     * @pseudocode base-provider-call-contract.md lines 2-3
     * Gets the base URL with proper precedence:
     * 1. Ephemeral settings (highest priority - from /baseurl or profile)
     * 2. Provider-specific settings in SettingsService
     * 3. Provider config (from IProviderConfig)
     * 4. Base provider config (initial constructor value)
     * 5. undefined (use provider default)
     */
    getBaseURL() {
        const activeOptions = this.activeCallContext.getStore();
        if (activeOptions) {
            return activeOptions.resolved.baseURL;
        }
        const settingsService = this.resolveSettingsService();
        return this.computeBaseURL(settingsService);
    }
    /**
     * @plan PLAN-20251018-STATELESSPROVIDER2.P06
     * @requirement REQ-SP2-001
     * @pseudocode base-provider-call-contract.md lines 2-3
     * Gets the current model with proper precedence:
     * 1. Ephemeral settings (highest priority)
     * 2. Provider-specific settings in SettingsService
     * 3. Provider config
     * 4. Default model
     */
    getModel() {
        const activeOptions = this.activeCallContext.getStore();
        if (activeOptions) {
            return activeOptions.resolved.model;
        }
        const settingsService = this.resolveSettingsService();
        return this.computeModel(settingsService);
    }
    computeBaseURL(settingsService) {
        const normalizeBaseUrl = (value) => {
            if (typeof value !== 'string') {
                return undefined;
            }
            const trimmed = value.trim();
            if (!trimmed || trimmed.toLowerCase() === 'none') {
                return undefined;
            }
            return trimmed;
        };
        const rawActiveProvider = settingsService.get('activeProvider');
        const activeProvider = typeof rawActiveProvider === 'string' && rawActiveProvider.trim()
            ? rawActiveProvider.trim()
            : undefined;
        if (!activeProvider || activeProvider === this.name) {
            const ephemeralBaseUrl = normalizeBaseUrl(settingsService.get('base-url'));
            if (ephemeralBaseUrl) {
                return ephemeralBaseUrl;
            }
        }
        const providerSettings = settingsService.getProviderSettings(this.name);
        const providerBaseUrl = normalizeBaseUrl(providerSettings?.baseUrl) ??
            normalizeBaseUrl(providerSettings?.baseURL);
        if (providerBaseUrl) {
            return providerBaseUrl;
        }
        const configBaseUrl = normalizeBaseUrl(this.providerConfig?.baseUrl);
        if (configBaseUrl) {
            return configBaseUrl;
        }
        const defaultBaseUrl = normalizeBaseUrl(this.baseProviderConfig.baseURL);
        if (defaultBaseUrl) {
            return defaultBaseUrl;
        }
        return undefined;
    }
    computeModel(settingsService) {
        const ephemeralModel = settingsService.get('model');
        if (ephemeralModel) {
            return ephemeralModel;
        }
        const providerSettings = settingsService.getProviderSettings(this.name);
        const providerModel = providerSettings?.model;
        if (providerModel) {
            return providerModel;
        }
        if (this.providerConfig?.defaultModel) {
            return this.providerConfig.defaultModel;
        }
        return this.getDefaultModel();
    }
    /**
     * @plan PLAN-20251018-STATELESSPROVIDER2.P06
     * @requirement REQ-SP2-001
     * @pseudocode base-provider-call-contract.md lines 1-3
     * Gets authentication token using the precedence chain
     * This method implements lazy OAuth triggering - only triggers OAuth when actually making API calls
     * Returns empty string if no auth is available (for local/self-hosted endpoints)
     */
    async getAuthToken() {
        const activeOptions = this.activeCallContext.getStore();
        if (activeOptions) {
            const runtimeToken = await resolveRuntimeAuthToken(activeOptions.resolved.authToken);
            if (runtimeToken) {
                return runtimeToken;
            }
        }
        const settingsService = this.resolveSettingsService();
        // IMPORTANT: includeOAuth: false for config-time checks
        // OAuth should ONLY trigger during actual prompt sends
        const token = (await this.authResolver.resolveAuthentication({
            settingsService,
            includeOAuth: false,
        })) ?? '';
        return token;
    }
    /**
     * Get auth token for prompt send - CAN trigger OAuth if needed
     * Use this method ONLY when actually sending a prompt to the API
     */
    async getAuthTokenForPrompt() {
        const activeOptions = this.activeCallContext.getStore();
        if (activeOptions) {
            const runtimeToken = await resolveRuntimeAuthToken(activeOptions.resolved.authToken);
            if (runtimeToken) {
                return runtimeToken;
            }
        }
        const settingsService = this.resolveSettingsService();
        // includeOAuth: true - OAuth is allowed during prompt send
        const token = (await this.authResolver.resolveAuthentication({
            settingsService,
            includeOAuth: true,
        })) ?? '';
        return token;
    }
    /**
     * Checks if OAuth is enabled for this provider
     */
    isOAuthEnabled() {
        // OAuth is enabled if we have a manager AND it's enabled for this provider
        if (this.baseProviderConfig.oauthManager) {
            // First check the manager's state (which reads from settings)
            const manager = this.baseProviderConfig.oauthManager;
            if (manager.isOAuthEnabled &&
                typeof manager.isOAuthEnabled === 'function') {
                const oauthProvider = this.baseProviderConfig.oauthProvider || this.name;
                return manager.isOAuthEnabled(oauthProvider);
            }
            // Fall back to local config
            return this.baseProviderConfig.isOAuthEnabled === true;
        }
        return false;
    }
    /**
     * @plan PLAN-20251018-STATELESSPROVIDER2.P06
     * @requirement REQ-SP2-001
     * @pseudocode base-provider-call-contract.md lines 1-3
     * Checks if authentication is available without triggering OAuth
     */
    async hasNonOAuthAuthentication() {
        return this.authResolver.hasNonOAuthAuthentication({
            settingsService: this.resolveSettingsService(),
        });
    }
    /**
     * @plan PLAN-20251018-STATELESSPROVIDER2.P06
     * @requirement REQ-SP2-001
     * @pseudocode base-provider-call-contract.md lines 1-3
     * Checks if OAuth is the only available authentication method
     */
    async isOAuthOnlyAvailable() {
        return this.authResolver.isOAuthOnlyAvailable({
            settingsService: this.resolveSettingsService(),
        });
    }
    /**
     * @plan PLAN-20251018-STATELESSPROVIDER2.P06
     * @requirement REQ-SP2-001
     * @pseudocode base-provider-call-contract.md lines 1-3
     * Gets the current authentication method name for debugging
     */
    async getAuthMethodName() {
        return this.authResolver.getAuthMethodName({
            settingsService: this.resolveSettingsService(),
        });
    }
    /**
     * Clears authentication (used when removing keys/keyfiles)
     */
    clearAuth() {
        const settingsService = this.resolveSettingsService();
        settingsService.set('auth-key', undefined);
        settingsService.set('auth-keyfile', undefined);
        this.clearAuthCache();
    }
    /**
     * Updates OAuth configuration
     */
    updateOAuthConfig(isEnabled, provider, manager) {
        this.baseProviderConfig.isOAuthEnabled = isEnabled;
        this.baseProviderConfig.oauthProvider = provider;
        this.baseProviderConfig.oauthManager = manager;
        this.authResolver.updateConfig({
            isOAuthEnabled: isEnabled,
            supportsOAuth: this.supportsOAuth(),
            oauthProvider: provider,
        });
        if (manager) {
            this.authResolver.updateOAuthManager(manager);
        }
        this.clearAuthCache();
    }
    /**
     * Clears the authentication token cache
     */
    clearAuthCache() {
        // Legacy no-op retained for compatibility with existing logout flows.
    }
    /**
     * Checks if the provider is authenticated using any available method
     */
    async isAuthenticated() {
        try {
            // Check non-OAuth authentication first (API keys, environment variables, etc.)
            const nonOAuthToken = (await this.authResolver.resolveAuthentication({
                settingsService: this.resolveSettingsService(),
                includeOAuth: false,
            })) ?? '';
            if (nonOAuthToken !== '') {
                return true;
            }
            // If no non-OAuth auth found, check if OAuth token exists without triggering flow
            if (this.baseProviderConfig.isOAuthEnabled &&
                this.baseProviderConfig.oauthManager &&
                this.baseProviderConfig.oauthProvider) {
                return await this.baseProviderConfig.oauthManager.isAuthenticated(this.baseProviderConfig.oauthProvider);
            }
            return false;
        }
        catch {
            return false;
        }
    }
    /**
     * @plan PLAN-20251018-STATELESSPROVIDER2.P06
     * @requirement REQ-SP2-001
     * @pseudocode base-provider-call-contract.md lines 1-5
     */
    generateChatCompletion(contentsOrOptions, maybeTools) {
        const normalizedPromise = this.normalizeGenerateChatOptions(contentsOrOptions, maybeTools);
        const previousRuntimeContext = peekActiveProviderRuntimeContext();
        let preparedIteratorPromise = null;
        let normalizedOptions;
        let underlyingIterator;
        const prepareIterator = async () => {
            if (!preparedIteratorPromise) {
                preparedIteratorPromise = (async () => {
                    normalizedOptions = await normalizedPromise;
                    underlyingIterator = this.invokeWithNormalizedOptions(normalizedOptions, previousRuntimeContext ?? null);
                })();
            }
            await preparedIteratorPromise;
        };
        const withContext = (operation) => {
            if (!normalizedOptions) {
                throw new Error('Normalized options are not prepared');
            }
            return this.activeCallContext.run(normalizedOptions, operation);
        };
        const adapter = {
            next: async (...args) => {
                await prepareIterator();
                const iterator = underlyingIterator;
                if (!iterator) {
                    throw new Error('Provider iterator not initialised');
                }
                return withContext(() => iterator.next(...args));
            },
            return: async (value) => {
                await prepareIterator();
                const iterator = underlyingIterator;
                if (!iterator) {
                    throw new Error('Provider iterator not initialised');
                }
                if (iterator.return) {
                    return withContext(() => iterator.return(value));
                }
                return { done: true, value: undefined };
            },
            throw: async (error) => {
                await prepareIterator();
                const iterator = underlyingIterator;
                if (!iterator) {
                    throw new Error('Provider iterator not initialised');
                }
                if (iterator.throw) {
                    return withContext(() => iterator.throw(error));
                }
                throw error;
            },
            [Symbol.asyncIterator]() {
                return this;
            },
        };
        return adapter;
    }
    /**
     * @plan PLAN-20251018-STATELESSPROVIDER2.P06
     * @requirement REQ-SP2-001
     * @pseudocode base-provider-call-contract.md lines 3-5
     */
    invokeWithNormalizedOptions(normalized, previousContext) {
        const needsContextSwap = !previousContext ||
            previousContext.settingsService !== normalized.settings ||
            (normalized.config && previousContext.config !== normalized.config);
        const mergedMetadata = normalized.runtime
            ? {
                ...(normalized.runtime.metadata ?? {}),
                ...normalized.metadata,
            }
            : {
                ...(previousContext?.metadata ?? {}),
                ...normalized.metadata,
            };
        if (!('source' in mergedMetadata)) {
            mergedMetadata.source = 'BaseProvider.generateChatCompletion';
        }
        const runtimeContext = normalized.runtime
            ? {
                ...normalized.runtime,
                settingsService: normalized.settings,
                config: normalized.config ?? normalized.runtime.config,
                metadata: mergedMetadata,
            }
            : {
                settingsService: normalized.settings,
                config: normalized.config ?? previousContext?.config,
                runtimeId: previousContext?.runtimeId ?? 'base-provider.normalized-call',
                metadata: mergedMetadata,
            };
        return async function* () {
            if (needsContextSwap) {
                setActiveProviderRuntimeContext(runtimeContext);
            }
            try {
                const iterator = this.generateChatCompletionWithOptions(normalized);
                for await (const chunk of iterator) {
                    yield chunk;
                }
            }
            finally {
                if (needsContextSwap) {
                    setActiveProviderRuntimeContext(previousContext ?? null);
                }
                normalized.resolved.authToken = '';
                this.authResolver.setSettingsService(this.defaultSettingsService);
            }
        }.call(this);
    }
    /**
     * @plan PLAN-20251018-STATELESSPROVIDER2.P06
     * @plan:PLAN-20251023-STATELESS-HARDENING.P05
     * @requirement REQ-SP2-001
     * @requirement:REQ-SP4-001
     * @pseudocode base-provider-call-contract.md lines 1-3
     */
    async normalizeGenerateChatOptions(contentsOrOptions, maybeTools) {
        const providedOptions = Array.isArray(contentsOrOptions)
            ? { contents: contentsOrOptions, tools: maybeTools }
            : contentsOrOptions;
        const settings = providedOptions.settings ?? this.defaultSettingsService ?? null;
        if (!settings) {
            throw new MissingProviderRuntimeError({
                providerKey: `BaseProvider.${this.name}`,
                missingFields: ['settings'],
                stage: 'normalizeGenerateChatOptions',
                metadata: {
                    hint: 'ProviderManager must supply settings via GenerateChatOptions or setRuntimeSettingsService.',
                    requirement: 'REQ-SP4-001',
                },
            });
        }
        const runtimeConfig = providedOptions.runtime?.config ?? null;
        const configCandidate = providedOptions.config ?? runtimeConfig ?? this.defaultConfig ?? null;
        const runtimeMetadata = providedOptions.runtime?.metadata ?? {};
        const metadataFromOptions = providedOptions.metadata ?? {};
        const metadata = {
            ...runtimeMetadata,
            ...metadataFromOptions,
        };
        const resolvedModel = this.computeModel(settings);
        const resolvedBaseURL = this.computeBaseURL(settings);
        // CRITICAL: includeOAuth: true for prompt sends - OAuth is allowed here
        const resolvedAuth = (await this.authResolver.resolveAuthentication({
            settingsService: settings,
            includeOAuth: true,
        })) ?? '';
        const providerSettings = settings.getProviderSettings(this.name) ??
            {};
        const resolvedTemperature = providedOptions.resolved?.temperature ??
            providerSettings?.temperature;
        const resolvedMaxTokens = providedOptions.resolved?.maxTokens ??
            providerSettings?.maxTokens;
        const resolvedStreaming = providedOptions.resolved?.streaming ??
            providerSettings?.streaming;
        // Use provided authToken if specified (e.g., from LoadBalancingProvider),
        // otherwise fall back to resolved auth from auth resolver
        const finalAuthToken = providedOptions.resolved?.authToken ?? resolvedAuth;
        // Same for model and baseURL - providedOptions.resolved takes precedence
        const finalModel = providedOptions.resolved?.model ?? resolvedModel;
        const finalBaseURL = providedOptions.resolved?.baseURL ?? resolvedBaseURL;
        const resolved = {
            model: finalModel,
            baseURL: finalBaseURL,
            authToken: finalAuthToken,
            telemetry: providedOptions.resolved?.telemetry,
            temperature: resolvedTemperature,
            maxTokens: resolvedMaxTokens,
            streaming: resolvedStreaming,
        };
        const guard = this.assertRuntimeContext({
            providerKey: `BaseProvider.${this.name}`,
            settings,
            config: configCandidate,
            runtime: providedOptions.runtime,
            metadata,
            resolved,
            stage: 'normalizeGenerateChatOptions',
        });
        const finalConfig = guard.runtime.config ?? configCandidate ?? undefined;
        const normalizedRuntime = {
            ...guard.runtime,
            metadata: guard.metadata,
            config: finalConfig,
        };
        const invocation = providedOptions.invocation ??
            createRuntimeInvocationContext({
                runtime: normalizedRuntime,
                settings,
                providerName: this.name,
                ephemeralsSnapshot: this.buildEphemeralsSnapshot(settings),
                telemetry: resolved.telemetry,
                metadata: guard.metadata,
                userMemory: typeof providedOptions.userMemory === 'string'
                    ? providedOptions.userMemory
                    : undefined,
                fallbackRuntimeId: `${this.name}:normalizeGenerateChatOptions`,
            });
        return {
            ...providedOptions,
            contents: providedOptions.contents,
            tools: providedOptions.tools ?? maybeTools,
            settings,
            config: finalConfig,
            runtime: normalizedRuntime,
            metadata: guard.metadata,
            resolved,
            invocation,
        };
    }
    buildEphemeralsSnapshot(settings) {
        const snapshot = {
            ...settings.getAllGlobalSettings(),
        };
        const providerEphemerals = settings.getProviderSettings(this.name);
        snapshot[this.name] = { ...providerEphemerals };
        return snapshot;
    }
    /**
     * @plan:PLAN-20251023-STATELESS-HARDENING.P05
     * @requirement:REQ-SP4-001
     * @pseudocode base-provider-fallback-removal.md lines 11-14
     */
    assertRuntimeContext(input) {
        const missing = [];
        if (!input.settings) {
            missing.push('settings');
        }
        if (!input.config) {
            missing.push('config');
        }
        const resolvedMissing = [];
        if (!input.resolved) {
            resolvedMissing.push('resolved');
        }
        else {
            if (typeof input.resolved.model !== 'string' ||
                input.resolved.model.trim() === '') {
                resolvedMissing.push('resolved.model');
            }
            if (input.resolved.baseURL !== undefined &&
                input.resolved.baseURL !== null &&
                typeof input.resolved.baseURL !== 'string') {
                resolvedMissing.push('resolved.baseURL');
            }
            if (input.resolved.authToken === undefined ||
                input.resolved.authToken === null) {
                resolvedMissing.push('resolved.authToken');
            }
        }
        const missingFields = [...missing, ...resolvedMissing];
        if (missingFields.length > 0) {
            throw new MissingProviderRuntimeError({
                providerKey: input.providerKey,
                missingFields,
                stage: input.stage,
                metadata: {
                    ...(input.metadata ?? {}),
                    requirement: 'REQ-SP4-001',
                },
            });
        }
        const metadata = {
            ...(input.runtime?.metadata ?? {}),
            ...(input.metadata ?? {}),
            requirement: 'REQ-SP4-001',
            stage: input.stage,
        };
        const runtimeMetadata = metadata;
        const currentRuntimeId = typeof runtimeMetadata.runtimeId === 'string'
            ? runtimeMetadata.runtimeId
            : undefined;
        const runtime = input.runtime
            ? {
                ...input.runtime,
                settingsService: input.settings,
                config: input.runtime.config ?? input.config ?? undefined,
                metadata,
            }
            : {
                settingsService: input.settings,
                config: input.config ?? undefined,
                runtimeId: currentRuntimeId && currentRuntimeId.trim()
                    ? currentRuntimeId
                    : `${input.providerKey}:${input.stage}`,
                metadata,
            };
        return { runtime, metadata };
    }
    // Optional methods with default implementations
    getCurrentModel() {
        // Use the same logic as getModel() to check ephemeral settings
        return this.getModel();
    }
    getToolFormat() {
        return 'default';
    }
    isPaidMode() {
        return false;
    }
    clearState() {
        this.clearAuthCache();
    }
    setConfig(config) {
        if (!config || typeof config !== 'object') {
            return;
        }
        const maybeConfig = config;
        if (typeof maybeConfig.getUserMemory === 'function' &&
            typeof maybeConfig.getModel === 'function') {
            this.defaultConfig = config;
            return;
        }
        this.providerConfig = config;
    }
    getServerTools() {
        return [];
    }
    async invokeServerTool(toolName, _params, _config, _signal) {
        throw new Error(`Server tool '${toolName}' not supported by ${this.name} provider`);
    }
    getModelParams() {
        return undefined;
    }
    /**
     * Get setting value from SettingsService
     */
    async getProviderSetting(key, fallback) {
        const settingsService = this.resolveSettingsService();
        try {
            const settings = await settingsService.getSettings(this.name);
            return settings[key] || fallback;
        }
        catch (error) {
            if (process.env.DEBUG) {
                console.error(`Failed to get ${key} from SettingsService for ${this.name}:`, error);
            }
            return fallback;
        }
    }
    /**
     * Set setting value in SettingsService
     */
    async setProviderSetting(key, value) {
        const settingsService = this.resolveSettingsService();
        try {
            await settingsService.updateSettings(this.name, {
                [key]: value,
            });
            const updatedSettings = await settingsService.getSettings(this.name);
            if (updatedSettings[key] !== value) {
                settingsService.set(`providers.${this.name}.${String(key)}`, value);
            }
        }
        catch (error) {
            if (process.env.DEBUG) {
                console.error(`Failed to set ${key} in SettingsService for ${this.name}:`, error);
            }
        }
    }
    /**
     * Get API key from SettingsService if available
     */
    async getApiKeyFromSettings() {
        return this.getProviderSetting('apiKey');
    }
    /**
     * Set API key in SettingsService if available
     */
    async setApiKeyInSettings(apiKey) {
        await this.setProviderSetting('apiKey', apiKey);
    }
    /**
     * Get model from SettingsService if available
     */
    async getModelFromSettings() {
        return this.getProviderSetting('model');
    }
    /**
     * Set model in SettingsService if available
     */
    async setModelInSettings(model) {
        await this.setProviderSetting('model', model);
    }
    /**
     * Get base URL from SettingsService if available
     */
    async getBaseUrlFromSettings() {
        return this.getProviderSetting('baseUrl');
    }
    /**
     * Set base URL in SettingsService if available
     */
    async setBaseUrlInSettings(baseUrl) {
        await this.setProviderSetting('baseUrl', baseUrl);
    }
    /**
     * Get model parameters from SettingsService
     */
    async getModelParamsFromSettings() {
        const settingsService = this.resolveSettingsService();
        try {
            const settings = await settingsService.getSettings(this.name);
            // Extract model parameters from settings, excluding standard fields
            const { enabled: _enabled, apiKey: _apiKey, baseUrl: _baseUrl, model: _model, maxTokens, temperature, ...additionalSettings } = settings;
            // Include temperature and maxTokens as model params if they exist
            const params = {};
            if (temperature !== undefined)
                params.temperature = temperature;
            if (maxTokens !== undefined)
                params.max_tokens = maxTokens;
            return Object.keys(params).length > 0 ||
                Object.keys(additionalSettings).length > 0
                ? { ...params, ...additionalSettings }
                : undefined;
        }
        catch (error) {
            if (process.env.DEBUG) {
                console.error(`Failed to get model params from SettingsService for ${this.name}:`, error);
            }
            return undefined;
        }
    }
    /**
     * Set model parameters in SettingsService
     */
    async setModelParamsInSettings(params) {
        const settingsService = this.resolveSettingsService();
        try {
            if (params === undefined) {
                // Clear model parameters by setting them to undefined
                await settingsService.updateSettings(this.name, {
                    temperature: undefined,
                    maxTokens: undefined,
                });
                return;
            }
            // Convert standard model params to settings format
            const updates = {};
            if ('temperature' in params)
                updates.temperature = params.temperature;
            if ('max_tokens' in params)
                updates.maxTokens = params.max_tokens;
            if ('maxTokens' in params)
                updates.maxTokens = params.maxTokens;
            // Store other parameters as custom fields
            for (const [key, value] of Object.entries(params)) {
                if (!['temperature', 'max_tokens', 'maxTokens'].includes(key)) {
                    updates[key] = value;
                }
            }
            if (Object.keys(updates).length > 0) {
                await settingsService.updateSettings(this.name, updates);
            }
        }
        catch (error) {
            if (process.env.DEBUG) {
                console.error(`Failed to set model params in SettingsService for ${this.name}:`, error);
            }
        }
    }
    /**
     * Get custom headers from provider configuration and ephemeral settings.
     *
     * This merges:
     * - Provider config `customHeaders`
     * - Ephemeral `custom-headers`
     * - Ephemeral `user-agent` (mapped into a `User-Agent` header)
     */
    getCustomHeaders() {
        const baseHeaders = this.providerConfig?.customHeaders &&
            typeof this.providerConfig.customHeaders === 'object'
            ? { ...this.providerConfig.customHeaders }
            : undefined;
        const ephemeralSettings = this.providerConfig?.getEphemeralSettings?.();
        const ephemeralValue = ephemeralSettings && typeof ephemeralSettings === 'object'
            ? ephemeralSettings['custom-headers']
            : undefined;
        const userAgent = ephemeralSettings && typeof ephemeralSettings === 'object'
            ? ephemeralSettings['user-agent']
            : undefined;
        const combined = {
            ...(baseHeaders ?? {}),
            ...(ephemeralValue ?? {}),
        };
        if (typeof userAgent === 'string' && userAgent.trim()) {
            combined['User-Agent'] = userAgent.trim();
        }
        return Object.keys(combined).length > 0 ? combined : undefined;
    }
}
//# sourceMappingURL=BaseProvider.js.map