diff --git a/api/app/clients/OpenAIClient.js b/api/app/clients/OpenAIClient.js index 4ea4bc8d35..93fbe3c5bb 100644 --- a/api/app/clients/OpenAIClient.js +++ b/api/app/clients/OpenAIClient.js @@ -65,7 +65,7 @@ class OpenAIClient extends BaseClient { /** @type {OpenAIUsageMetadata | undefined} */ this.usage; /** @type {boolean|undefined} */ - this.isO1Model; + this.isOmni; /** @type {SplitStreamHandler | undefined} */ this.streamHandler; } @@ -105,8 +105,8 @@ class OpenAIClient extends BaseClient { this.checkVisionRequest(this.options.attachments); } - const o1Pattern = /\bo1\b/i; - this.isO1Model = o1Pattern.test(this.modelOptions.model); + const omniPattern = /\b(o1|o3)\b/i; + this.isOmni = omniPattern.test(this.modelOptions.model); const { OPENROUTER_API_KEY, OPENAI_FORCE_PROMPT } = process.env ?? {}; if (OPENROUTER_API_KEY && !this.azure) { @@ -146,7 +146,7 @@ class OpenAIClient extends BaseClient { const { model } = this.modelOptions; this.isChatCompletion = - o1Pattern.test(model) || model.includes('gpt') || this.useOpenRouter || !!reverseProxy; + omniPattern.test(model) || model.includes('gpt') || this.useOpenRouter || !!reverseProxy; this.isChatGptModel = this.isChatCompletion; if ( model.includes('text-davinci') || @@ -475,7 +475,7 @@ class OpenAIClient extends BaseClient { promptPrefix = this.augmentedPrompt + promptPrefix; } - if (promptPrefix && this.isO1Model !== true) { + if (promptPrefix && this.isOmni !== true) { promptPrefix = `Instructions:\n${promptPrefix.trim()}`; instructions = { role: 'system', @@ -503,7 +503,7 @@ class OpenAIClient extends BaseClient { }; /** EXPERIMENTAL */ - if (promptPrefix && this.isO1Model === true) { + if (promptPrefix && this.isOmni === true) { const lastUserMessageIndex = payload.findLastIndex((message) => message.role === 'user'); if (lastUserMessageIndex !== -1) { payload[ @@ -1200,7 +1200,7 @@ ${convo} opts.defaultHeaders = { ...opts.defaultHeaders, 'api-key': this.apiKey }; } - if (this.isO1Model === true && modelOptions.max_tokens != null) { + if (this.isOmni === true && modelOptions.max_tokens != null) { modelOptions.max_completion_tokens = modelOptions.max_tokens; delete modelOptions.max_tokens; } @@ -1280,13 +1280,13 @@ ${convo} let streamResolve; if ( - this.isO1Model === true && + this.isOmni === true && (this.azure || /o1(?!-(?:mini|preview)).*$/.test(modelOptions.model)) && modelOptions.stream ) { delete modelOptions.stream; delete modelOptions.stop; - } else if (!this.isO1Model && modelOptions.reasoning_effort != null) { + } else if (!this.isOmni && modelOptions.reasoning_effort != null) { delete modelOptions.reasoning_effort; } @@ -1366,7 +1366,7 @@ ${convo} for await (const chunk of stream) { // Add finish_reason: null if missing in any choice if (chunk.choices) { - chunk.choices.forEach(choice => { + chunk.choices.forEach((choice) => { if (!('finish_reason' in choice)) { choice.finish_reason = null; } diff --git a/api/models/tx.js b/api/models/tx.js index eb467f875e..776fac123c 100644 --- a/api/models/tx.js +++ b/api/models/tx.js @@ -75,8 +75,9 @@ const tokenValues = Object.assign( '4k': { prompt: 1.5, completion: 2 }, '16k': { prompt: 3, completion: 4 }, 'gpt-3.5-turbo-1106': { prompt: 1, completion: 2 }, + 'o3-mini': { prompt: 1.1, completion: 4.4 }, + 'o1-mini': { prompt: 1.1, completion: 4.4 }, 'o1-preview': { prompt: 15, completion: 60 }, - 'o1-mini': { prompt: 3, completion: 12 }, o1: { prompt: 15, completion: 60 }, 'gpt-4o-mini': { prompt: 0.15, completion: 0.6 }, 'gpt-4o': { prompt: 2.5, completion: 10 }, diff --git a/api/utils/tokens.js b/api/utils/tokens.js index 72151fcb19..b1c3a1e5a8 100644 --- a/api/utils/tokens.js +++ b/api/utils/tokens.js @@ -2,6 +2,7 @@ const z = require('zod'); const { EModelEndpoint } = require('librechat-data-provider'); const openAIModels = { + 'o3-mini': 195000, // -5000 from max o1: 195000, // -5000 from max 'o1-mini': 127500, // -500 from max 'o1-preview': 127500, // -500 from max diff --git a/client/src/components/Endpoints/MessageEndpointIcon.tsx b/client/src/components/Endpoints/MessageEndpointIcon.tsx index a5155a3569..6652aa0007 100644 --- a/client/src/components/Endpoints/MessageEndpointIcon.tsx +++ b/client/src/components/Endpoints/MessageEndpointIcon.tsx @@ -25,7 +25,7 @@ type EndpointIcon = { function getOpenAIColor(_model: string | null | undefined) { const model = _model?.toLowerCase() ?? ''; - if (model && /\bo1\b/i.test(model)) { + if (model && /\b(o1|o3)\b/i.test(model)) { return '#000000'; } return model.includes('gpt-4') ? '#AB68FF' : '#19C37D'; diff --git a/packages/data-provider/src/config.ts b/packages/data-provider/src/config.ts index 525c16a659..738fafcccd 100644 --- a/packages/data-provider/src/config.ts +++ b/packages/data-provider/src/config.ts @@ -778,9 +778,9 @@ export const supportsBalanceCheck = { }; export const visionModels = [ - 'o1', 'gpt-4o', 'gpt-4o-mini', + 'o1', 'gpt-4-turbo', 'gpt-4-vision', 'llava', diff --git a/packages/data-provider/src/parsers.ts b/packages/data-provider/src/parsers.ts index 5ce44cfc75..8ec18d5617 100644 --- a/packages/data-provider/src/parsers.ts +++ b/packages/data-provider/src/parsers.ts @@ -240,6 +240,8 @@ export const getResponseSender = (endpointOption: t.TEndpointOption): string => return modelLabel; } else if (model && /\bo1\b/i.test(model)) { return 'o1'; + } else if (model && /\bo3\b/i.test(model)) { + return 'o3'; } else if (model && model.includes('gpt-3')) { return 'GPT-3.5'; } else if (model && model.includes('gpt-4o')) {