UNPKG

contextual-agent-sdk

Version:

SDK for building AI agents with seamless voice-text context switching

281 lines 12.1 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.OpenAIProvider = void 0; const BaseLLMProvider_1 = require("./BaseLLMProvider"); const ToolConverter_1 = require("../tools/ToolConverter"); const openai_1 = __importDefault(require("openai")); class OpenAIProvider extends BaseLLMProvider_1.BaseLLMProvider { type = 'openai'; name = 'OpenAI'; config; client; constructor(config) { super(); this.config = config; if (config.apiKey) { this.client = new openai_1.default({ apiKey: config.apiKey, organization: config.organization, baseURL: config.baseURL }); console.log('🎯 OpenAI Provider initialized with official SDK'); } } supportsTools() { return true; } supportsStreaming() { return true; } async generateResponse(options) { if (!this.client) { throw new Error('OpenAI provider not configured. Please provide an API key.'); } try { const completion = await this.client.chat.completions.create({ model: options.model || this.config.model || 'gpt-4', messages: options.messages .filter(msg => msg.role !== 'tool') .map(msg => ({ role: msg.role, content: msg.content })), temperature: options.temperature ?? this.config.defaultOptions?.temperature ?? 0.7, max_tokens: options.maxTokens ?? this.config.defaultOptions?.maxTokens ?? 500, presence_penalty: options.presencePenalty ?? this.config.defaultOptions?.presencePenalty, frequency_penalty: options.frequencyPenalty ?? this.config.defaultOptions?.frequencyPenalty, stop: options.stop ?? this.config.defaultOptions?.stop }); const choice = completion.choices[0]; if (!choice?.message?.content) { throw new Error('No response content from OpenAI'); } return { content: choice.message.content, finishReason: choice.finish_reason, usage: completion.usage ? { promptTokens: completion.usage.prompt_tokens, completionTokens: completion.usage.completion_tokens, totalTokens: completion.usage.total_tokens } : undefined }; } catch (error) { throw new Error(`OpenAI API error: ${error.message}`); } } async generateWithTools(options) { if (!this.client) { throw new Error('OpenAI provider not configured. Please provide an API key.'); } if (!options.tools || options.tools.length === 0) { const response = await this.generateResponse(options); return { ...response, toolCalls: [], stopReason: 'stop' }; } try { console.log('🔧 OpenAI Function Calling Request:', { model: this.config.model || 'gpt-4', messages: options.messages.length, functions: options.tools.map(t => ({ name: t.function.name, description: t.function.description })) }); const completion = await this.client.chat.completions.create({ model: options.model || this.config.model || 'gpt-4', messages: options.messages .filter(msg => msg.role !== 'tool') .map(msg => ({ role: msg.role, content: msg.content })), functions: options.tools.map(tool => ({ name: tool.function.name, description: tool.function.description, parameters: tool.function.parameters })), function_call: options.toolChoice === 'none' ? 'none' : options.toolChoice && typeof options.toolChoice === 'object' ? { name: options.toolChoice.function.name } : 'auto', temperature: options.temperature ?? this.config.defaultOptions?.temperature ?? 0.7, max_tokens: options.maxTokens ?? this.config.defaultOptions?.maxTokens ?? 1000 }); console.log('🔧 OpenAI Function Calling Response:', { content_length: completion.choices[0]?.message?.content?.length || 0, finish_reason: completion.choices[0]?.finish_reason, function_call: !!completion.choices[0]?.message?.function_call, usage: completion.usage }); const choice = completion.choices[0]; if (!choice) { throw new Error('No response from OpenAI'); } const content = choice.message.content || ''; const toolCalls = choice.message.function_call ? [{ id: `call_${Date.now()}`, type: 'function', function: { name: choice.message.function_call.name, arguments: choice.message.function_call.arguments || '{}' } }] : []; const stopReason = choice.finish_reason === 'function_call' ? 'tool_calls' : choice.finish_reason === 'length' ? 'length' : 'stop'; console.log('🎯 Extracted Function Calls:', toolCalls.map(tc => ({ id: tc.id, name: tc.function.name, args: tc.function.arguments }))); return { content, usage: completion.usage ? { promptTokens: completion.usage.prompt_tokens, completionTokens: completion.usage.completion_tokens, totalTokens: completion.usage.total_tokens } : undefined, finishReason: choice.finish_reason, toolCalls, stopReason, conversation: options.conversation }; } catch (error) { console.error('❌ OpenAI Function Calling Error:', error); throw new Error(`Failed to generate response with functions: ${error.message}`); } } async handleToolLoop(conversation, tools) { const maxIterations = 10; let iteration = 0; console.log(`🔄 Starting OpenAI Function Loop with ${tools.length} tools`); while (iteration < maxIterations) { iteration++; console.log(`🔄 Function Loop Iteration ${iteration}/${maxIterations}`); const messages = this.conversationManager.getConversationHistory(conversation.id); const response = await this.generateWithTools({ messages, tools: ToolConverter_1.ToolConverter.toOpenAIFunctions(tools), conversation, maxTokens: this.config.defaultOptions?.maxTokens || 1000 }); if (!response.toolCalls || response.toolCalls.length === 0) { console.log('✅ Function loop complete - no more function calls'); return response; } console.log(`🔧 Executing ${response.toolCalls.length} function call(s):`, response.toolCalls.map(tc => tc.function.name)); const toolResults = await ToolConverter_1.ToolConverter.executeToolCalls(response.toolCalls, tools, ToolConverter_1.ToolConverter.createToolContext(conversation.metadata?.agentId || 'unknown', conversation.id, conversation.metadata?.userId)); this.conversationManager.addMessage(conversation.id, { role: 'assistant', content: response.content || '', metadata: { toolCalls: response.toolCalls } }); for (let i = 0; i < response.toolCalls.length; i++) { const toolCall = response.toolCalls[i]; const result = toolResults[i]; const resultContent = result.success ? (typeof result.data === 'string' ? result.data : JSON.stringify(result.data)) : `Error: ${result.error}`; this.conversationManager.addMessage(conversation.id, { role: 'user', content: `Function ${toolCall.function.name} result: ${resultContent}`, metadata: { isFunctionResult: true, functionCallId: toolCall.id, functionResult: result } }); console.log(`🎯 Function ${toolCall.function.name} result:`, { success: result.success, hasData: !!result.data, error: result.error }); } const criticalFailure = toolResults.find(result => !result.success && result.metadata?.critical); if (criticalFailure) { console.error('❌ Critical function failure:', criticalFailure); return { ...response, content: `Function execution failed: ${criticalFailure.error}`, stopReason: 'stop' }; } } throw new Error(`Function execution loop exceeded maximum iterations (${maxIterations})`); } async *streamResponse(options) { if (!this.client) { throw new Error('OpenAI provider not configured. Please provide an API key.'); } try { const stream = await this.client.chat.completions.create({ model: options.model || this.config.model || 'gpt-4', messages: options.messages .filter(msg => msg.role !== 'tool') .map(msg => ({ role: msg.role, content: msg.content })), temperature: options.temperature ?? this.config.defaultOptions?.temperature ?? 0.7, max_tokens: options.maxTokens ?? this.config.defaultOptions?.maxTokens ?? 1000, stream: true }); for await (const chunk of stream) { const choice = chunk.choices[0]; if (choice?.delta?.content) { yield { type: 'content', content: choice.delta.content }; } } yield { type: 'done', done: true }; } catch (error) { yield { type: 'error', error: error.message }; } } getMaxTokens() { const model = this.config.model || 'gpt-4'; if (model.includes('gpt-4o')) return 128000; if (model.includes('gpt-4-turbo')) return 128000; if (model.includes('gpt-4')) return 8192; if (model.includes('gpt-3.5-turbo-16k')) return 16384; if (model.includes('gpt-3.5-turbo')) return 4096; return 4096; } async isAvailable() { return !!this.client && !!this.config.apiKey; } isConfigured() { return !!this.client; } getSupportedModels() { return [ 'gpt-4o', 'gpt-4o-mini', 'gpt-4-turbo', 'gpt-4-turbo-preview', 'gpt-4', 'gpt-3.5-turbo', 'gpt-3.5-turbo-16k' ]; } } exports.OpenAIProvider = OpenAIProvider; //# sourceMappingURL=OpenAIProvider.js.map