UNPKG

@entro314labs/ai-changelog-generator

Version:

AI-powered changelog generator with MCP server support - works with most providers, online and local models

128 lines (127 loc) 5.06 kB
import { OpenAI } from 'openai'; import { BaseProvider } from '../core/base-provider.js'; import { applyMixins, ProviderResponseHandler } from '../utils/base-provider-helpers.js'; export class OpenAIProvider extends BaseProvider { constructor(config) { super(config); this.openai = null; if (this.isAvailable()) { this.initializeClient(); } } initializeClient() { const clientOptions = this.buildClientOptions({ timeout: 60000, maxRetries: 2, }); this.openai = new OpenAI({ apiKey: clientOptions.OPENAI_API_KEY, organization: clientOptions.OPENAI_ORGANIZATION, project: clientOptions.OPENAI_PROJECT, timeout: clientOptions.timeout, maxRetries: clientOptions.maxRetries, }); } getName() { return 'openai'; } isAvailable() { const apiKey = this.config.OPENAI_API_KEY; return apiKey && apiKey.trim() !== '' && apiKey.startsWith('sk-'); } getRequiredEnvVars() { return ['OPENAI_API_KEY']; } async generateCompletion(messages, options = {}) { return ProviderResponseHandler.executeWithErrorHandling(this, 'generate_completion', async () => { const modelConfig = this.getProviderModelConfig(); const params = { model: options.model || modelConfig.standardModel || this.getDefaultModel(), messages, max_tokens: options.max_tokens || 1000, temperature: options.temperature || 0.3, }; // Add tool calling if provided if (options.tools) { params.tools = options.tools; params.tool_choice = options.tool_choice || 'auto'; } // Add streaming if requested if (options.stream) { params.stream = true; const stream = await this.openai.chat.completions.create(params); return { stream, model: params.model }; } const completion = await this.openai.chat.completions.create(params); return { text: completion.choices[0].message.content, content: completion.choices[0].message.content, model: completion.model, usage: completion.usage, tokens: completion.usage.total_tokens, finish_reason: completion.choices[0].finish_reason, tool_calls: completion.choices[0].message.tool_calls, }; }, { model: options.model }); } async getAvailableModels() { try { const models = await this.openai.models.list(); return models.data .filter((m) => m.id.includes('gpt') || /^o\d/.test(m.id)) .map((m) => ({ name: m.id, id: m.id, description: `OpenAI ${m.id}`, })); } catch { // Offline fallback catalogue: current GPT-5.6 family plus the nearest // still-available tiers. Live `models.list()` is preferred whenever the // API is reachable. return [ { id: 'gpt-5.6-terra', name: 'gpt-5.6-terra', description: 'GPT-5.6 Terra - balanced intelligence and cost', contextWindow: 1050000, maxOutput: 128000, }, { id: 'gpt-5.6-sol', name: 'gpt-5.6-sol', description: 'GPT-5.6 Sol - flagship tier for complex reasoning and coding', contextWindow: 1050000, maxOutput: 128000, features: ['advanced_reasoning', 'agentic_coding'], }, { id: 'gpt-5.6-luna', name: 'gpt-5.6-luna', description: 'GPT-5.6 Luna - high-volume, cost-sensitive workloads', contextWindow: 1050000, maxOutput: 128000, }, { id: 'gpt-5.3-codex', name: 'gpt-5.3-codex', description: 'GPT-5.3 Codex - agentic coding model', features: ['agentic_coding'], }, { id: 'gpt-5.5', name: 'gpt-5.5', description: 'GPT-5.5 - previous flagship generation', contextWindow: 400000, }, { id: 'gpt-5.4-nano', name: 'gpt-5.4-nano', description: 'GPT-5.4 Nano - lightweight tier for simple tasks', }, ]; } } } // Apply mixins to add standard provider functionality export default applyMixins ? applyMixins(OpenAIProvider, 'openai') : OpenAIProvider;