UNPKG

conductor-tasks

Version:

Task Manager for AI Development

126 lines 6.53 kB
import OpenAI from 'openai'; import process from 'process'; import { ErrorHandler, ErrorCategory, ErrorSeverity, TaskError } from '../../core/errorHandler.js'; const errorHandler = ErrorHandler.getInstance(); export class OpenAIClient { constructor(model, apiKey, baseURL) { this.maxRetries = 3; this.apiKey = apiKey || process.env.OPENAI_API_KEY; this.baseURL = baseURL; if (!this.apiKey) { throw new Error('API key is required for OpenAI client (either passed or via OPENAI_API_KEY env var)'); } const optionsForOpenAI = { apiKey: this.apiKey, }; if (this.baseURL) { optionsForOpenAI.baseURL = this.baseURL; } this.client = new OpenAI(optionsForOpenAI); this.model = model || process.env.MODEL || 'gpt-4o'; if (process.env.LLM_MAX_RETRIES) { this.maxRetries = parseInt(process.env.LLM_MAX_RETRIES, 10); } } async complete(options) { const { prompt, maxTokens = 4000, temperature = 0.7, topP, presencePenalty, frequencyPenalty, stream, onStreamUpdate, systemPrompt } = options; const params = { model: this.model, messages: systemPrompt ? [ { role: 'system', content: systemPrompt }, { role: 'user', content: prompt } ] : [{ role: 'user', content: prompt }], max_tokens: maxTokens, temperature: temperature, top_p: topP, presence_penalty: presencePenalty, frequency_penalty: frequencyPenalty, stream: stream, }; let retryCount = 0; let lastError = null; while (retryCount <= this.maxRetries) { try { if (retryCount > 0) { const backoffMs = Math.min(1000 * Math.pow(2, retryCount - 1), 10000); await new Promise(resolve => setTimeout(resolve, backoffMs)); errorHandler.handleError(new TaskError(`OpenAI API error (retry ${retryCount}/${this.maxRetries}): ${lastError instanceof Error ? lastError.message : String(lastError)}`, ErrorCategory.LLM, ErrorSeverity.WARNING, { operation: 'openai-complete', additionalInfo: { retry: retryCount } }, lastError instanceof Error ? lastError : undefined), true); } if (stream && onStreamUpdate) { const stream = await this.client.chat.completions.create({ ...params, stream: true, }); let fullResponse = ''; let finishReason = null; for await (const chunk of stream) { const content = chunk.choices[0]?.delta?.content || ''; if (content) { fullResponse += content; onStreamUpdate(content); } if (chunk.choices[0]?.finish_reason) { finishReason = chunk.choices[0].finish_reason; } } return { text: fullResponse, usage: null, model: this.model, finishReason: finishReason || undefined, }; } else { const response = await this.client.chat.completions.create({ ...params, stream: false, }); const text = response.choices[0]?.message?.content || ''; const usage = response.usage ? { promptTokens: response.usage.prompt_tokens, completionTokens: response.usage.completion_tokens, totalTokens: response.usage.total_tokens, } : null; return { text: text, usage: usage, model: response.model, finishReason: response.choices[0]?.finish_reason || undefined, }; } } catch (error) { lastError = error; const isRetryable = error instanceof Error && (error.message.includes('network') || error.message.includes('timeout') || error.message.includes('rate') || error.message.includes('limit') || error.message.includes('429') || error.message.includes('500') || error.message.includes('502') || error.message.includes('503') || error.message.includes('504')); if (isRetryable && retryCount < this.maxRetries) { retryCount++; continue; } errorHandler.handleError(new TaskError(`OpenAI API error: ${error instanceof Error ? error.message : String(error)}`, ErrorCategory.LLM, ErrorSeverity.ERROR, { operation: 'openai-complete' }, error instanceof Error ? error : undefined)); throw new TaskError(`OpenAI API error: ${error instanceof Error ? error.message : String(error)}`, ErrorCategory.LLM, ErrorSeverity.ERROR, { operation: 'openai-complete' }, error instanceof Error ? error : undefined); } } errorHandler.handleError(new TaskError(`OpenAI API error (after ${this.maxRetries} retries): ${lastError instanceof Error ? lastError.message : String(lastError)}`, ErrorCategory.LLM, ErrorSeverity.ERROR, { operation: 'openai-complete', additionalInfo: { maxRetriesExceeded: true } }, lastError instanceof Error ? lastError : undefined)); throw new TaskError(`OpenAI API error (after ${this.maxRetries} retries): ${lastError instanceof Error ? lastError.message : String(lastError)}`, ErrorCategory.LLM, ErrorSeverity.ERROR, { operation: 'openai-complete', additionalInfo: { maxRetriesExceeded: true } }, lastError instanceof Error ? lastError : undefined); } getProviderName() { return 'OpenAI'; } getModelName() { return this.model; } } //# sourceMappingURL=openai.js.map