UNPKG

llmforge

Version:

One API, every AI model, instant switching. Change from GPT-4 to Gemini to local models with a single config update. LLMForge is the lightweight, TypeScript-first solution for multi-provider AI applications with zero vendor lock-in.

249 lines 10.5 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.OpenAIClient = void 0; const http_client_1 = require("../core/http-client"); const expo_1 = require("../strategies/retry/expo"); const ai_builder_1 = require("../builder/ai.builder"); const openai_stream_1 = require("../strategies/stream/openai.stream"); const logger_1 = require("../utils/logger"); const comman_1 = require("./comman"); class OpenAIClient { constructor(config) { var _a, _b, _c, _d, _e; this.retryHandler = new expo_1.RetryHandler({ maxRetries: (_b = (_a = config.retryConfig) === null || _a === void 0 ? void 0 : _a.maxRetries) !== null && _b !== void 0 ? _b : 1, retryDelay: (_d = (_c = config.retryConfig) === null || _c === void 0 ? void 0 : _c.retryDelay) !== null && _d !== void 0 ? _d : 0, }); this.httpClient = new http_client_1.HttpClient(config, (_e = config.baseUrl) !== null && _e !== void 0 ? _e : 'https://api.openai.com', this.retryHandler); this.streamProcessor = new openai_stream_1.OpenAIStreamProcessor(); } convertToOpenAIRequest(request) { var _a; const openAIRequest = { model: this.httpClient.getConfig().model, input: comman_1.CommanMethods.omitModelToAssistantInContents(request.contents), text: { format: { type: 'text', }, }, }; if (request.generationConfig) { const config = request.generationConfig; if (config.temperature !== undefined) openAIRequest.temperature = config.temperature; if (config.maxOutputTokens !== undefined) openAIRequest.max_tokens = config.maxOutputTokens; if (config.topP !== undefined) openAIRequest.top_p = config.topP; if (config.stopSequences !== undefined) openAIRequest.stop = config.stopSequences; // Handle thinking/reasoning config if (((_a = config.thinkingConfig) === null || _a === void 0 ? void 0 : _a.thinkingBudget) !== undefined) { const budget = config.thinkingConfig.thinkingBudget; openAIRequest.reasoning = { effort: budget === -1 ? 'medium' : budget > 1000 ? 'high' : 'low', }; } // Handle JSON schema format if (config.responseMimeType === 'application/json') { openAIRequest.text = { format: { type: 'json_schema', name: 'response_format', strict: true, schema: { type: 'object', properties: { content: { type: 'string' }, }, required: ['content'], additionalProperties: false, }, }, }; } } // Handle tools if (request.tools && request.tools.length > 0) { openAIRequest.tools = this.convertToolsToOpenAI(request.tools); } // Handle system instruction if (request.systemInstruction) { const systemMessage = { role: 'system', content: request.systemInstruction.parts.map((part) => part.text).join('\n'), }; if (openAIRequest.messages) { openAIRequest.messages.unshift(systemMessage); } else { openAIRequest.messages = [systemMessage]; } } return openAIRequest; } convertToolsToOpenAI(tools) { return tools.flatMap(tool => { if (tool.functionDeclarations) { return tool.functionDeclarations.map((func) => ({ type: 'function', function: { name: func.name, description: func.description, parameters: func.parameters, }, })); } return []; }); } convertFromOpenAIResponse(response) { var _a, _b, _c; logger_1.logger.info('OpenAI Response:', JSON.stringify(response, null, 2)); logger_1.logger.info('OpenAI Response ID:', JSON.stringify((_a = response.output[0]) === null || _a === void 0 ? void 0 : _a.id, null, 2) || 'N/A'); logger_1.logger.info('OpenAI Response Output:', ((_b = response.output[0]) === null || _b === void 0 ? void 0 : _b.content[0].text) || 'N/A'); return { resp_id: response.id, output: ((_c = response.output[0]) === null || _c === void 0 ? void 0 : _c.content[0].text) || '', status: (response === null || response === void 0 ? void 0 : response.status) == 'completed' ? 'success' : (response === null || response === void 0 ? void 0 : response.status) || 'unknown', created_at: response.created_at, model: response.model, usage: response.usage ? { input_tokens: response.usage.input_tokens, output_tokens: response.usage.output_tokens, total_tokens: response.usage.total_tokens, } : undefined, }; } async generateContent(request) { ai_builder_1.MessageValidator.validateContents(request.contents); logger_1.logger.info('Static generation'); const openAIRequest = this.convertToOpenAIRequest(request); logger_1.logger.info('OpenAI Request:', JSON.stringify(openAIRequest, null, 2)); const response = await this.httpClient.request({ method: 'POST', body: JSON.stringify(openAIRequest), headers: { Authorization: `Bearer ${this.httpClient.getConfig().apiKey}`, 'Content-Type': 'application/json', }, }, false, `/v1/responses`); return this.convertFromOpenAIResponse(response); } async *generateContentStreamAsync(request) { logger_1.logger.info('Generating content stream asynchronously for request: %j', request); try { ai_builder_1.MessageValidator.validateContents(request.contents); logger_1.logger.info('Streaming generation (async)'); const openAIRequest = { ...this.convertToOpenAIRequest(request), stream: true }; const response = await this.httpClient.streamRequest({ method: 'POST', body: JSON.stringify(openAIRequest), headers: { Authorization: `Bearer ${this.httpClient.getConfig().apiKey}`, 'Content-Type': 'application/json', }, }, '/v1/responses'); yield* this.streamProcessor.createAsyncGenerator(comman_1.CommanMethods.convertReadableToResponse(response)); } catch (error) { console.error('Error in generateContentStreamAsync:', error); throw error; } } async chat(message, options = {}) { const contents = ai_builder_1.ContentBuilder.textOnly(message); const request = { contents, generationConfig: options.generationConfig, tools: options.tools, }; if (options.systemInstruction) { request.systemInstruction = { parts: [{ text: options.systemInstruction }], }; } return this.generateContent(request); } async continueConversation(contents, options = {}) { const request = { contents, generationConfig: options.generationConfig, tools: options.tools, }; return this.generateContent(request); } async callFunction(message, tools, options = {}) { const request = { contents: ai_builder_1.ContentBuilder.textOnly(message), tools, generationConfig: options.generationConfig, }; if (options.systemInstruction) { request.systemInstruction = { parts: [{ text: options.systemInstruction }], }; } return this.generateContent(request); } // OpenAI-specific thinking/reasoning mode // async generateWithThinking( // message: string, // thinkingBudget: number = -1, // options: { // systemInstruction?: string; // onThinking?: (thinking: string) => void; // effort?: 'low' | 'medium' | 'high'; // jsonSchema?: any; // } = {} // ): Promise<GenerateContentResponse> { // const request: GenerateContentRequest = { // contents: ContentBuilder.textOnly(message), // generationConfig: { // thinkingConfig: { // thinkingBudget, // }, // }, // }; // if (options.effort) { // request.generationConfig!.thinkingConfig = { // thinkingBudget: options.effort === 'high' ? 2000 : options.effort === 'low' ? 100 : 1000, // }; // } // if (options.jsonSchema) { // request.generationConfig!.responseMimeType = 'application/json'; // } // if (options.systemInstruction) { // request.systemInstruction = { // parts: [{ text: options.systemInstruction }], // }; // } // return this.generateContentStream(request, { // onThinking: options.onThinking, // }); // } async handleOpenAIRequest(openAIRequest) { return this.httpClient.request({ method: 'POST', body: JSON.stringify(openAIRequest), headers: { Authorization: `Bearer ${this.httpClient.getConfig().apiKey}`, 'Content-Type': 'application/json', }, }, false, `/v1/responses`); } get stream() { return this.streamProcessor; } updateConfig(newConfig) { this.httpClient.updateConfig(newConfig); } getConfig() { return this.httpClient.getConfig(); } } exports.OpenAIClient = OpenAIClient; //# sourceMappingURL=openai.adapter.js.map