const OpenAI = require('openai'); const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY, organization: process.env.OPENAI_ORG_ID, }); class OpenAIService { constructor() { if (!process.env.OPENAI_API_KEY || process.env.OPENAI_API_KEY.includes('your-actual')) { console.warn('⚠️ OpenAI API key not configured properly'); } } async createResponse(messages, assistantConfig = {}) { try { const { model = 'gpt-4o', temperature = 0.7, maxTokens = 4000, stream = false, reasoningEffort = 'medium', } = assistantConfig; console.log(`Making OpenAI request with model: ${model}`); const requestParams = { model, messages, temperature, stream, }; // GPT-5 uses max_completion_tokens instead of max_tokens and requires temperature = 1 if (model === 'gpt-5') { console.log(`GPT-5 detected, using max_completion_tokens, temperature = 1, and reasoning_effort = ${reasoningEffort}`); requestParams.max_completion_tokens = maxTokens; requestParams.temperature = 1; // GPT-5 only supports temperature = 1 requestParams.reasoning_effort = reasoningEffort; // GPT-5 reasoning effort from agent config } else { requestParams.max_tokens = maxTokens; } const response = await openai.chat.completions.create(requestParams); return response; } catch (error) { console.error('OpenAI Responses API Error:', { model: assistantConfig.model, error: error.message, status: error.status, code: error.code, type: error.type }); throw error; } } async createStreamingResponse(messages, assistantConfig = {}) { try { const { model = 'gpt-4o', temperature = 0.7, maxTokens = 4000, reasoningEffort = 'medium', } = assistantConfig; console.log(`Making streaming OpenAI request with model: ${model}`); const requestParams = { model, messages, temperature, stream: true, }; // GPT-5 uses max_completion_tokens instead of max_tokens and requires temperature = 1 if (model === 'gpt-5') { console.log(`GPT-5 detected for streaming, using max_completion_tokens, temperature = 1, and reasoning_effort = ${reasoningEffort}`); requestParams.max_completion_tokens = maxTokens; requestParams.temperature = 1; // GPT-5 only supports temperature = 1 requestParams.reasoning_effort = reasoningEffort; // GPT-5 reasoning effort from agent config } else { requestParams.max_tokens = maxTokens; } const stream = await openai.chat.completions.create(requestParams); return stream; } catch (error) { console.error('OpenAI Streaming Responses API Error:', { model: assistantConfig.model, error: error.message, status: error.status, code: error.code, type: error.type }); throw error; } } formatMessagesForAPI(messages) { return messages.map(msg => ({ role: msg.role, content: msg.content, })); } buildSystemMessage(systemPrompt) { return { role: 'system', content: systemPrompt, }; } async generateConversationTitle(userMessage, assistantResponse, agentName) { try { if (!process.env.ENABLE_TITLE_GENERATION || process.env.ENABLE_TITLE_GENERATION !== 'true') { console.log('Title generation disabled, using fallback'); return `Chat with ${agentName}`; } const titlePrompt = `Based on this conversation between a user and an AI assistant called "${agentName}", generate a short, descriptive title (3-6 words) that captures what the user is asking about or discussing. Be specific and concise. User message: "${userMessage}" Assistant response: "${assistantResponse}" Generate only the title, nothing else. Examples: - "Marketing Campaign Ideas" - "JavaScript Function Help" - "Travel Planning Advice" - "Budget Analysis Discussion"`; const response = await openai.chat.completions.create({ model: 'gpt-4o-mini', // Use cheaper model for title generation messages: [ { role: 'user', content: titlePrompt } ], temperature: 0.3, // Lower temperature for more consistent titles max_tokens: 20, // Short titles only }); const title = response.choices[0]?.message?.content?.trim(); if (!title) { console.warn('No title generated, using fallback'); return `Chat with ${agentName}`; } // Clean up the title - remove quotes if present const cleanTitle = title.replace(/^["']|["']$/g, ''); console.log(`Generated title: "${cleanTitle}"`); return cleanTitle; } catch (error) { console.error('Error generating conversation title:', error); return `Chat with ${agentName}`; // Fallback title } } async testConnection() { try { const response = await this.createResponse([ { role: 'user', content: 'Hello, this is a test message.' } ], { maxTokens: 50 }); console.log('✅ OpenAI Responses API connection test successful'); return { success: true, response }; } catch (error) { console.error('❌ OpenAI Responses API connection test failed:', error.message); return { success: false, error: error.message }; } } } module.exports = new OpenAIService();