UNPKG

simple-ai-provider

Version:

A simple and extensible AI provider package for easy integration of multiple AI services

293 lines (292 loc) 11.2 kB
/** * Abstract Base Provider for AI Services * * This module provides the foundation for all AI provider implementations, * ensuring consistency, proper error handling, and maintainable code structure. * * Design Principles: * - Template Method Pattern: Define algorithm structure, let subclasses implement specifics * - Fail-Fast: Validate inputs early and provide clear error messages * - Separation of Concerns: Configuration, validation, execution are clearly separated * - Type Safety: Comprehensive TypeScript support for better DX * * @author Jan-Marlon Leibl * @version 1.0.0 */ import type { AIProviderConfig, CompletionParams, CompletionResponse, CompletionChunk, ProviderInfo } from '../types/index.js'; import { AIProviderError } from '../types/index.js'; /** * Abstract base class that all AI providers must extend. * * This class implements the Template Method pattern, providing a consistent * interface and workflow while allowing providers to implement their specific * logic in protected abstract methods. * * Lifecycle: * 1. Construction: validateConfig() called automatically * 2. Initialization: initialize() must be called before use * 3. Usage: complete() and stream() methods available * 4. Error Handling: All errors are normalized to AIProviderError * * @example * ```typescript * class MyProvider extends BaseAIProvider { * protected async doInitialize(): Promise<void> { * // Initialize your client/connection here * } * * protected async doComplete(params: CompletionParams): Promise<CompletionResponse> { * // Implement completion logic here * } * * // ... other required methods * } * ``` */ export declare abstract class BaseAIProvider { /** Validated configuration object for this provider instance */ protected readonly config: AIProviderConfig; /** Internal flag tracking initialization state */ private initialized; /** * Constructs a new provider instance with validated configuration. * * @param config - Provider configuration object * @throws {AIProviderError} If configuration is invalid * * @example * ```typescript * const provider = new MyProvider({ * apiKey: 'your-api-key', * timeout: 30000, * maxRetries: 3 * }); * ``` */ constructor(config: AIProviderConfig); /** * Initializes the provider for use. * * This method must be called before any completion requests. It handles * provider-specific setup such as client initialization and connection testing. * * @returns Promise that resolves when initialization is complete * @throws {AIProviderError} If initialization fails * * @example * ```typescript * await provider.initialize(); * // Provider is now ready for use * ``` */ initialize(): Promise<void>; /** * Checks if the provider has been initialized. * * @returns true if the provider is ready for use, false otherwise */ isInitialized(): boolean; /** * Generates a text completion based on the provided parameters. * * This method handles validation, error normalization, and delegates to * the provider-specific implementation via the Template Method pattern. * * @param params - Completion parameters including messages, model options, etc. * @returns Promise resolving to the completion response * @throws {AIProviderError} If the request fails or parameters are invalid * * @example * ```typescript * const response = await provider.complete({ * messages: [{ role: 'user', content: 'Hello!' }], * maxTokens: 100, * temperature: 0.7 * }); * console.log(response.content); * ``` */ complete<T>(params: CompletionParams<T>): Promise<CompletionResponse<T>>; complete(params: CompletionParams): Promise<CompletionResponse<string>>; /** * Generates a streaming text completion. * * This method returns an async iterable that yields chunks of the response * as they become available, enabling real-time UI updates. * * @param params - Completion parameters * @returns AsyncIterable yielding completion chunks * @throws {AIProviderError} If the request fails or parameters are invalid * * @example * ```typescript * for await (const chunk of provider.stream(params)) { * if (!chunk.isComplete) { * process.stdout.write(chunk.content); * } else { * console.log('\nDone! Usage:', chunk.usage); * } * } * ``` */ stream<T = any>(params: CompletionParams<T>): AsyncIterable<CompletionChunk>; /** * Returns information about this provider and its capabilities. * * This method provides metadata about the provider including supported * models, context length, streaming support, and special capabilities. * * @returns Provider information object */ abstract getInfo(): ProviderInfo; /** * Provider-specific initialization logic. * * Subclasses should implement this method to handle their specific * initialization requirements such as: * - Creating API clients * - Testing connections * - Validating credentials * - Setting up authentication * * @protected * @returns Promise that resolves when initialization is complete * @throws {Error} If initialization fails (will be normalized to AIProviderError) */ protected abstract doInitialize(): Promise<void>; /** * Provider-specific completion implementation. * * Subclasses should implement this method to handle text completion * using their specific API. The base class handles validation and * error normalization. * * @protected * @param params - Validated completion parameters * @returns Promise resolving to completion response * @throws {Error} If completion fails (will be normalized to AIProviderError) */ protected abstract doComplete(params: CompletionParams): Promise<CompletionResponse<string>>; /** * Provider-specific streaming implementation. * * Subclasses should implement this method to handle streaming completions * using their specific API. The base class handles validation and * error normalization. * * @protected * @param params - Validated completion parameters * @returns AsyncIterable yielding completion chunks * @throws {Error} If streaming fails (will be normalized to AIProviderError) */ protected abstract doStream<T = any>(params: CompletionParams<T>): AsyncIterable<CompletionChunk>; /** * Regex patterns that valid model names should match. * Empty array (the default) skips validation entirely. */ protected getModelNamePatterns(): RegExp[]; /** * Send a minimal request to verify the API key and connectivity. * The default does nothing; SDK-based providers override this and the * base `validateConnection` handles error mapping. */ protected sendValidationProbe(): Promise<void>; /** * Map a provider-specific error to a normalized AIProviderError, or * return null to let the base error mapping handle it generically. * Override to recognize provider-specific message patterns (e.g. "API * key", "quota", "model not found"). */ protected mapProviderError(_error: any): AIProviderError | null; /** * Per-HTTP-status message overrides used by `normalizeError` when no * provider-specific mapping applies. Lets providers add brand-flavored * hints (console URLs, etc.) without re-implementing the status switch. */ protected providerErrorMessages(): Partial<Record<number, string>>; /** * Human-readable provider name used in warning messages. * Default derives from getInfo(); override if construction order makes * getInfo() unsafe to call here. */ protected get providerName(): string; /** * Validates a model name against the patterns returned by * `getModelNamePatterns()`. Throws for invalid input, warns for * non-matching names (since model lists change frequently). */ protected validateModelName(modelName: string): void; /** * Wraps `sendValidationProbe()` with consistent error handling: throws * AIProviderError for provider-recognized failures, warns and continues * for transient ones. */ protected validateConnection(): Promise<void>; /** * Validates and normalizes provider configuration. * * This method ensures all required fields are present and sets sensible * defaults for optional fields. It follows the fail-fast principle. * * @protected * @param config - Raw configuration object * @returns Validated and normalized configuration * @throws {AIProviderError} If configuration is invalid */ protected validateAndNormalizeConfig(config: AIProviderConfig): AIProviderConfig; /** * Validates an optional numeric parameter against a range. * Skips validation when value is undefined so callers can apply defaults afterward. */ private validateNumberInRange; private describeRange; /** * Ensures the provider has been initialized before use. * * @protected * @throws {AIProviderError} If the provider is not initialized */ protected ensureInitialized(): void; /** * Validates completion parameters comprehensively. * * This method performs thorough validation of all completion parameters * to ensure they meet the requirements and constraints. * * @protected * @param params - Parameters to validate * @throws {AIProviderError} If any parameter is invalid */ protected validateCompletionParams<T = any>(params: CompletionParams<T>): void; /** * Validates the messages array parameter. * * @private * @param messages - Messages array to validate * @throws {AIProviderError} If messages are invalid */ private validateMessages; private validateStopSequences; /** * Processes completion parameters to include response type instructions. * * This method automatically adds system prompt instructions when a response * type is specified, ensuring the AI understands the expected output format. * * @protected * @param params - Original completion parameters * @returns Processed parameters with response type instructions */ protected processResponseType<T>(params: CompletionParams<T>): CompletionParams<T>; /** * Normalizes any error into a standardized AIProviderError. * * This method provides consistent error handling across all providers, * mapping various error types and status codes to appropriate categories. * * @protected * @param error - The original error to normalize * @returns Normalized AIProviderError with appropriate type and context */ protected normalizeError(error: Error): AIProviderError; }