import type { ChatMessage, ChatCompletionResponse, ChatCompletionChunk, ChatToolDefinition, ChatToolChoice, Platform, } from '@freellmapi/shared/types.js'; export interface CompletionOptions { model?: string; temperature?: number; max_tokens?: number; top_p?: number; tools?: ChatToolDefinition[]; tool_choice?: ChatToolChoice; parallel_tool_calls?: boolean; } export abstract class BaseProvider { abstract readonly platform: Platform; abstract readonly name: string; abstract chatCompletion( apiKey: string, messages: ChatMessage[], modelId: string, options?: CompletionOptions, ): Promise; abstract streamChatCompletion( apiKey: string, messages: ChatMessage[], modelId: string, options?: CompletionOptions, ): AsyncGenerator; abstract validateKey(apiKey: string): Promise; protected async fetchWithTimeout( url: string, init: RequestInit, timeoutMs = 15000, ): Promise { const controller = new AbortController(); const timeout = setTimeout(() => controller.abort(), timeoutMs); try { return await fetch(url, { ...init, signal: controller.signal }); } finally { clearTimeout(timeout); } } protected makeId(): string { return `chatcmpl-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`; } }