/**
 * Base Provider
 *
 * Abstract base class and interface for AI providers.
 * Defines the contract that all LLM providers (Grok, Claude, OpenAI, etc.) must fulfill.
 */
import { EventEmitter } from 'events';
import { measureLatency, getStreamingOptimizer, } from '../optimization/latency-optimizer.js';
// ============================================================================
// Base Provider Implementation
// ============================================================================
/**
 * Abstract base class that implements common functionality for AI providers.
 * Concrete provider implementations should extend this class.
 */
export class BaseProvider extends EventEmitter {
    config = null;
    ready = false;
    /**
     * Initializes the provider.
     * Validates configuration and emits a 'ready' event upon success.
     */
    async initialize(config) {
        this.config = config;
        await this.validateConfig();
        this.ready = true;
        this.emit('ready');
    }
    isReady() {
        return this.ready;
    }
    /**
     * Validates the provided configuration.
     * Throws an error if required fields (like apiKey) are missing.
     * Can be overridden by subclasses for specific validation logic.
     */
    async validateConfig() {
        if (!this.config?.apiKey) {
            // Local providers might not need API key
            if (this.type !== 'ollama' && this.type !== 'lm-studio') {
                throw new Error(`${this.name} API key is required`);
            }
        }
    }
    /**
     * Standard chat completion method.
     * Delegates to the abstract `complete` method which must be implemented by subclasses.
     * Wrapped with latency measurement for performance tracking.
     */
    async chat(options) {
        // Determine if this is a simple or complex response based on message count
        const operationType = (options.messages?.length || 0) > 3 ? 'complex_response' : 'simple_response';
        return measureLatency(operationType, () => this.complete(options));
    }
    /**
     * Wraps a stream with latency tracking for first-token and total time.
     * Use this in provider implementations to get streaming metrics.
     */
    async *trackStreamLatency(streamIterable) {
        const streamingOptimizer = getStreamingOptimizer();
        const startTime = Date.now();
        let firstChunkTime = null;
        for await (const chunk of streamIterable) {
            if (firstChunkTime === null) {
                firstChunkTime = Date.now() - startTime;
                streamingOptimizer.recordFirstToken(firstChunkTime);
            }
            yield chunk;
        }
        const totalTime = Date.now() - startTime;
        streamingOptimizer.recordTotalTime(totalTime);
    }
    async getModels() {
        return [this.defaultModel];
    }
    supports(feature) {
        // Default support for most features, override in specific providers
        switch (feature) {
            case 'streaming':
                return true;
            case 'tools':
            case 'function_calling':
                return true; // Most modern LLMs support tools
            case 'vision':
                return false; // Default to false
            case 'json_mode':
                return false;
            default:
                return false;
        }
    }
    estimateTokens(content) {
        const text = typeof content === 'string'
            ? content
            : content.map(m => m.content).join(' ');
        // Rough estimate: ~4 chars per token
        return Math.ceil(text.length / 4);
    }
    dispose() {
        this.ready = false;
        this.config = null;
        this.removeAllListeners();
    }
}
//# sourceMappingURL=base-provider.js.map