🚀 feat: o1 (#4019)

* feat: o1 default response sender string

* feat: add o1 models to default openai models list, add `no_system_messages` error type; refactor: use error type as localization key

* refactor(MessageEndpointIcon): differentiate openAI icon model color for o1 models

* refactor(AnthropicClient): use new input/output tokens keys; add prompt caching for claude-3-opus

* refactor(BaseClient): to use new input/output tokens keys; update typedefs

* feat: initial o1 model handling, including token cost complexity

* EXPERIMENTAL: special handling for o1 model with custom instructions
This commit is contained in:
Danny Avila 2024-09-12 18:15:43 -04:00 committed by GitHub
parent 9a393be012
commit 45b42830a5
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
12 changed files with 229 additions and 36 deletions

View file

@ -64,6 +64,12 @@ class AnthropicClient extends BaseClient {
/** Whether or not the model supports Prompt Caching /** Whether or not the model supports Prompt Caching
* @type {boolean} */ * @type {boolean} */
this.supportsCacheControl; this.supportsCacheControl;
/** The key for the usage object's input tokens
* @type {string} */
this.inputTokensKey = 'input_tokens';
/** The key for the usage object's output tokens
* @type {string} */
this.outputTokensKey = 'output_tokens';
} }
setOptions(options) { setOptions(options) {
@ -200,7 +206,7 @@ class AnthropicClient extends BaseClient {
} }
/** /**
* Calculates the correct token count for the current message based on the token count map and API usage. * Calculates the correct token count for the current user message based on the token count map and API usage.
* Edge case: If the calculation results in a negative value, it returns the original estimate. * Edge case: If the calculation results in a negative value, it returns the original estimate.
* If revisiting a conversation with a chat history entirely composed of token estimates, * If revisiting a conversation with a chat history entirely composed of token estimates,
* the cumulative token count going forward should become more accurate as the conversation progresses. * the cumulative token count going forward should become more accurate as the conversation progresses.
@ -208,7 +214,7 @@ class AnthropicClient extends BaseClient {
* @param {Record<string, number>} params.tokenCountMap - A map of message IDs to their token counts. * @param {Record<string, number>} params.tokenCountMap - A map of message IDs to their token counts.
* @param {string} params.currentMessageId - The ID of the current message to calculate. * @param {string} params.currentMessageId - The ID of the current message to calculate.
* @param {AnthropicStreamUsage} params.usage - The usage object returned by the API. * @param {AnthropicStreamUsage} params.usage - The usage object returned by the API.
* @returns {number} The correct token count for the current message. * @returns {number} The correct token count for the current user message.
*/ */
calculateCurrentTokenCount({ tokenCountMap, currentMessageId, usage }) { calculateCurrentTokenCount({ tokenCountMap, currentMessageId, usage }) {
const originalEstimate = tokenCountMap[currentMessageId] || 0; const originalEstimate = tokenCountMap[currentMessageId] || 0;
@ -680,7 +686,11 @@ class AnthropicClient extends BaseClient {
*/ */
checkPromptCacheSupport(modelName) { checkPromptCacheSupport(modelName) {
const modelMatch = matchModelName(modelName, EModelEndpoint.anthropic); const modelMatch = matchModelName(modelName, EModelEndpoint.anthropic);
if (modelMatch === 'claude-3-5-sonnet' || modelMatch === 'claude-3-haiku') { if (
modelMatch === 'claude-3-5-sonnet' ||
modelMatch === 'claude-3-haiku' ||
modelMatch === 'claude-3-opus'
) {
return true; return true;
} }
return false; return false;

View file

@ -42,6 +42,12 @@ class BaseClient {
this.conversationId; this.conversationId;
/** @type {string} */ /** @type {string} */
this.responseMessageId; this.responseMessageId;
/** The key for the usage object's input tokens
* @type {string} */
this.inputTokensKey = 'prompt_tokens';
/** The key for the usage object's output tokens
* @type {string} */
this.outputTokensKey = 'completion_tokens';
} }
setOptions() { setOptions() {
@ -604,8 +610,8 @@ class BaseClient {
* @type {StreamUsage | null} */ * @type {StreamUsage | null} */
const usage = this.getStreamUsage != null ? this.getStreamUsage() : null; const usage = this.getStreamUsage != null ? this.getStreamUsage() : null;
if (usage != null && Number(usage.output_tokens) > 0) { if (usage != null && Number(usage[this.outputTokensKey]) > 0) {
responseMessage.tokenCount = usage.output_tokens; responseMessage.tokenCount = usage[this.outputTokensKey];
completionTokens = responseMessage.tokenCount; completionTokens = responseMessage.tokenCount;
await this.updateUserMessageTokenCount({ usage, tokenCountMap, userMessage, opts }); await this.updateUserMessageTokenCount({ usage, tokenCountMap, userMessage, opts });
} else { } else {
@ -655,7 +661,7 @@ class BaseClient {
/** @type {boolean} */ /** @type {boolean} */
const shouldUpdateCount = const shouldUpdateCount =
this.calculateCurrentTokenCount != null && this.calculateCurrentTokenCount != null &&
Number(usage.input_tokens) > 0 && Number(usage[this.inputTokensKey]) > 0 &&
(this.options.resendFiles || (this.options.resendFiles ||
(!this.options.resendFiles && !this.options.attachments?.length)) && (!this.options.resendFiles && !this.options.attachments?.length)) &&
!this.options.promptPrefix; !this.options.promptPrefix;

View file

@ -19,6 +19,7 @@ const {
constructAzureURL, constructAzureURL,
getModelMaxTokens, getModelMaxTokens,
genAzureChatCompletion, genAzureChatCompletion,
getModelMaxOutputTokens,
} = require('~/utils'); } = require('~/utils');
const { const {
truncateText, truncateText,
@ -64,6 +65,9 @@ class OpenAIClient extends BaseClient {
/** @type {string | undefined} - The API Completions URL */ /** @type {string | undefined} - The API Completions URL */
this.completionsUrl; this.completionsUrl;
/** @type {OpenAIUsageMetadata | undefined} */
this.usage;
} }
// TODO: PluginsClient calls this 3x, unneeded // TODO: PluginsClient calls this 3x, unneeded
@ -138,7 +142,8 @@ class OpenAIClient extends BaseClient {
const { model } = this.modelOptions; const { model } = this.modelOptions;
this.isChatCompletion = this.useOpenRouter || !!reverseProxy || model.includes('gpt'); this.isChatCompletion =
/\bo1\b/i.test(model) || model.includes('gpt') || this.useOpenRouter || !!reverseProxy;
this.isChatGptModel = this.isChatCompletion; this.isChatGptModel = this.isChatCompletion;
if ( if (
model.includes('text-davinci') || model.includes('text-davinci') ||
@ -169,7 +174,14 @@ class OpenAIClient extends BaseClient {
logger.debug('[OpenAIClient] maxContextTokens', this.maxContextTokens); logger.debug('[OpenAIClient] maxContextTokens', this.maxContextTokens);
} }
this.maxResponseTokens = this.modelOptions.max_tokens || 1024; this.maxResponseTokens =
this.modelOptions.max_tokens ??
getModelMaxOutputTokens(
model,
this.options.endpointType ?? this.options.endpoint,
this.options.endpointTokenConfig,
) ??
1024;
this.maxPromptTokens = this.maxPromptTokens =
this.options.maxPromptTokens || this.maxContextTokens - this.maxResponseTokens; this.options.maxPromptTokens || this.maxContextTokens - this.maxResponseTokens;
@ -533,7 +545,8 @@ class OpenAIClient extends BaseClient {
promptPrefix = this.augmentedPrompt + promptPrefix; promptPrefix = this.augmentedPrompt + promptPrefix;
} }
if (promptPrefix) { const isO1Model = /\bo1\b/i.test(this.modelOptions.model);
if (promptPrefix && !isO1Model) {
promptPrefix = `Instructions:\n${promptPrefix.trim()}`; promptPrefix = `Instructions:\n${promptPrefix.trim()}`;
instructions = { instructions = {
role: 'system', role: 'system',
@ -561,6 +574,16 @@ class OpenAIClient extends BaseClient {
messages, messages,
}; };
/** EXPERIMENTAL */
if (promptPrefix && isO1Model) {
const lastUserMessageIndex = payload.findLastIndex((message) => message.role === 'user');
if (lastUserMessageIndex !== -1) {
payload[
lastUserMessageIndex
].content = `${promptPrefix}\n${payload[lastUserMessageIndex].content}`;
}
}
if (tokenCountMap) { if (tokenCountMap) {
tokenCountMap.instructions = instructions?.tokenCount; tokenCountMap.instructions = instructions?.tokenCount;
result.tokenCountMap = tokenCountMap; result.tokenCountMap = tokenCountMap;
@ -885,6 +908,56 @@ ${convo}
return title; return title;
} }
/**
* Get stream usage as returned by this client's API response.
* @returns {OpenAIUsageMetadata} The stream usage object.
*/
getStreamUsage() {
if (
typeof this.usage === 'object' &&
typeof this.usage.completion_tokens_details === 'object'
) {
const outputTokens = Math.abs(
this.usage.completion_tokens_details.reasoning_tokens - this.usage[this.outputTokensKey],
);
return {
...this.usage.completion_tokens_details,
[this.inputTokensKey]: this.usage[this.inputTokensKey],
[this.outputTokensKey]: outputTokens,
};
}
return this.usage;
}
/**
* Calculates the correct token count for the current user message based on the token count map and API usage.
* Edge case: If the calculation results in a negative value, it returns the original estimate.
* If revisiting a conversation with a chat history entirely composed of token estimates,
* the cumulative token count going forward should become more accurate as the conversation progresses.
* @param {Object} params - The parameters for the calculation.
* @param {Record<string, number>} params.tokenCountMap - A map of message IDs to their token counts.
* @param {string} params.currentMessageId - The ID of the current message to calculate.
* @param {OpenAIUsageMetadata} params.usage - The usage object returned by the API.
* @returns {number} The correct token count for the current user message.
*/
calculateCurrentTokenCount({ tokenCountMap, currentMessageId, usage }) {
const originalEstimate = tokenCountMap[currentMessageId] || 0;
if (!usage || typeof usage[this.inputTokensKey] !== 'number') {
return originalEstimate;
}
tokenCountMap[currentMessageId] = 0;
const totalTokensFromMap = Object.values(tokenCountMap).reduce((sum, count) => {
const numCount = Number(count);
return sum + (isNaN(numCount) ? 0 : numCount);
}, 0);
const totalInputTokens = usage[this.inputTokensKey] ?? 0;
const currentMessageTokens = totalInputTokens - totalTokensFromMap;
return currentMessageTokens > 0 ? currentMessageTokens : originalEstimate;
}
async summarizeMessages({ messagesToRefine, remainingContextTokens }) { async summarizeMessages({ messagesToRefine, remainingContextTokens }) {
logger.debug('[OpenAIClient] Summarizing messages...'); logger.debug('[OpenAIClient] Summarizing messages...');
let context = messagesToRefine; let context = messagesToRefine;
@ -1000,7 +1073,16 @@ ${convo}
} }
} }
async recordTokenUsage({ promptTokens, completionTokens, context = 'message' }) { /**
* @param {object} params
* @param {number} params.promptTokens
* @param {number} params.completionTokens
* @param {OpenAIUsageMetadata} [params.usage]
* @param {string} [params.model]
* @param {string} [params.context='message']
* @returns {Promise<void>}
*/
async recordTokenUsage({ promptTokens, completionTokens, usage, context = 'message' }) {
await spendTokens( await spendTokens(
{ {
context, context,
@ -1011,6 +1093,19 @@ ${convo}
}, },
{ promptTokens, completionTokens }, { promptTokens, completionTokens },
); );
if (typeof usage === 'object' && typeof usage.reasoning_tokens === 'number') {
await spendTokens(
{
context: 'reasoning',
model: this.modelOptions.model,
conversationId: this.conversationId,
user: this.user ?? this.options.req.user?.id,
endpointTokenConfig: this.options.endpointTokenConfig,
},
{ completionTokens: usage.reasoning_tokens },
);
}
} }
getTokenCountForResponse(response) { getTokenCountForResponse(response) {
@ -1191,6 +1286,10 @@ ${convo}
/** @type {(value: void | PromiseLike<void>) => void} */ /** @type {(value: void | PromiseLike<void>) => void} */
let streamResolve; let streamResolve;
if (modelOptions.stream && /\bo1\b/i.test(modelOptions.model)) {
delete modelOptions.stream;
}
if (modelOptions.stream) { if (modelOptions.stream) {
streamPromise = new Promise((resolve) => { streamPromise = new Promise((resolve) => {
streamResolve = resolve; streamResolve = resolve;
@ -1269,6 +1368,8 @@ ${convo}
} }
const { choices } = chatCompletion; const { choices } = chatCompletion;
this.usage = chatCompletion.usage;
if (!Array.isArray(choices) || choices.length === 0) { if (!Array.isArray(choices) || choices.length === 0) {
logger.warn('[OpenAIClient] Chat completion response has no choices'); logger.warn('[OpenAIClient] Chat completion response has no choices');
return intermediateReply.join(''); return intermediateReply.join('');

View file

@ -37,6 +37,9 @@ const tokenValues = Object.assign(
'4k': { prompt: 1.5, completion: 2 }, '4k': { prompt: 1.5, completion: 2 },
'16k': { prompt: 3, completion: 4 }, '16k': { prompt: 3, completion: 4 },
'gpt-3.5-turbo-1106': { prompt: 1, completion: 2 }, 'gpt-3.5-turbo-1106': { prompt: 1, completion: 2 },
'o1-preview': { prompt: 15, completion: 60 },
'o1-mini': { prompt: 3, completion: 12 },
o1: { prompt: 15, completion: 60 },
'gpt-4o-2024-08-06': { prompt: 2.5, completion: 10 }, 'gpt-4o-2024-08-06': { prompt: 2.5, completion: 10 },
'gpt-4o-mini': { prompt: 0.15, completion: 0.6 }, 'gpt-4o-mini': { prompt: 0.15, completion: 0.6 },
'gpt-4o': { prompt: 5, completion: 15 }, 'gpt-4o': { prompt: 5, completion: 15 },
@ -95,6 +98,12 @@ const getValueKey = (model, endpoint) => {
return 'gpt-3.5-turbo-1106'; return 'gpt-3.5-turbo-1106';
} else if (modelName.includes('gpt-3.5')) { } else if (modelName.includes('gpt-3.5')) {
return '4k'; return '4k';
} else if (modelName.includes('o1-preview')) {
return 'o1-preview';
} else if (modelName.includes('o1-mini')) {
return 'o1-mini';
} else if (modelName.includes('o1')) {
return 'o1';
} else if (modelName.includes('gpt-4o-2024-08-06')) { } else if (modelName.includes('gpt-4o-2024-08-06')) {
return 'gpt-4o-2024-08-06'; return 'gpt-4o-2024-08-06';
} else if (modelName.includes('gpt-4o-mini')) { } else if (modelName.includes('gpt-4o-mini')) {

View file

@ -173,6 +173,10 @@ const handleAbortError = async (res, req, error, data) => {
errorText = `{"type":"${ErrorTypes.INVALID_REQUEST}"}`; errorText = `{"type":"${ErrorTypes.INVALID_REQUEST}"}`;
} }
if (error?.message?.includes('does not support \'system\'')) {
errorText = `{"type":"${ErrorTypes.NO_SYSTEM_MESSAGES}"}`;
}
const respondWithError = async (partialText) => { const respondWithError = async (partialText) => {
let options = { let options = {
sender, sender,

View file

@ -1443,7 +1443,19 @@
*/ */
/** /**
* @typedef {AnthropicStreamUsage} StreamUsage - Stream usage for all providers (currently only Anthropic) * @exports OpenAIUsageMetadata
* @typedef {Object} OpenAIUsageMetadata - Usage statistics related to the run. This value will be `null` if the run is not in a terminal state (i.e. `in_progress`, `queued`, etc.).
* @property {number} [usage.completion_tokens] - Number of completion tokens used over the course of the run.
* @property {number} [usage.prompt_tokens] - Number of prompt tokens used over the course of the run.
* @property {number} [usage.total_tokens] - Total number of tokens used (prompt + completion).
* @property {number} [usage.reasoning_tokens] - Total number of tokens used for reasoning (OpenAI o1 models).
* @property {Object} [usage.completion_tokens_details] - Further details on the completion tokens used (OpenAI o1 models).
* @property {number} [usage.completion_tokens_details.reasoning_tokens] - Total number of tokens used for reasoning (OpenAI o1 models).
* @memberof typedefs
*/
/**
* @typedef {AnthropicStreamUsage | OpenAIUsageMetadata | UsageMetadata} StreamUsage - Stream usage for all providers (currently only Anthropic, OpenAI, LangChain)
*/ */
/* Native app/client methods */ /* Native app/client methods */

View file

@ -2,6 +2,9 @@ const z = require('zod');
const { EModelEndpoint } = require('librechat-data-provider'); const { EModelEndpoint } = require('librechat-data-provider');
const openAIModels = { const openAIModels = {
o1: 127500, // -500 from max
'o1-mini': 127500, // -500 from max
'o1-preview': 127500, // -500 from max
'gpt-4': 8187, // -5 from max 'gpt-4': 8187, // -5 from max
'gpt-4-0613': 8187, // -5 from max 'gpt-4-0613': 8187, // -5 from max
'gpt-4-32k': 32758, // -10 from max 'gpt-4-32k': 32758, // -10 from max
@ -113,6 +116,19 @@ const maxTokensMap = {
[EModelEndpoint.bedrock]: bedrockModels, [EModelEndpoint.bedrock]: bedrockModels,
}; };
const modelMaxOutputs = {
o1: 32268, // -500 from max: 32,768
'o1-mini': 65136, // -500 from max: 65,536
'o1-preview': 32268, // -500 from max: 32,768
system_default: 1024,
};
const maxOutputTokensMap = {
[EModelEndpoint.azureOpenAI]: modelMaxOutputs,
[EModelEndpoint.openAI]: modelMaxOutputs,
[EModelEndpoint.custom]: modelMaxOutputs,
};
/** /**
* Finds the first matching pattern in the tokens map. * Finds the first matching pattern in the tokens map.
* @param {string} modelName * @param {string} modelName
@ -132,27 +148,15 @@ function findMatchingPattern(modelName, tokensMap) {
} }
/** /**
* Retrieves the maximum tokens for a given model name. If the exact model name isn't found, * Retrieves a token value for a given model name from a tokens map.
* it searches for partial matches within the model name, checking keys in reverse order.
* *
* @param {string} modelName - The name of the model to look up. * @param {string} modelName - The name of the model to look up.
* @param {string} endpoint - The endpoint (default is 'openAI'). * @param {EndpointTokenConfig | Record<string, number>} tokensMap - The map of model names to token values.
* @param {EndpointTokenConfig} [endpointTokenConfig] - Token Config for current endpoint to use for max tokens lookup * @param {string} [key='context'] - The key to look up in the tokens map.
* @returns {number|undefined} The maximum tokens for the given model or undefined if no match is found. * @returns {number|undefined} The token value for the given model or undefined if no match is found.
*
* @example
* getModelMaxTokens('gpt-4-32k-0613'); // Returns 32767
* getModelMaxTokens('gpt-4-32k-unknown'); // Returns 32767
* getModelMaxTokens('unknown-model'); // Returns undefined
*/ */
function getModelMaxTokens(modelName, endpoint = EModelEndpoint.openAI, endpointTokenConfig) { function getModelTokenValue(modelName, tokensMap, key = 'context') {
if (typeof modelName !== 'string') { if (typeof modelName !== 'string' || !tokensMap) {
return undefined;
}
/** @type {EndpointTokenConfig | Record<string, number>} */
const tokensMap = endpointTokenConfig ?? maxTokensMap[endpoint];
if (!tokensMap) {
return undefined; return undefined;
} }
@ -168,10 +172,36 @@ function getModelMaxTokens(modelName, endpoint = EModelEndpoint.openAI, endpoint
if (matchedPattern) { if (matchedPattern) {
const result = tokensMap[matchedPattern]; const result = tokensMap[matchedPattern];
return result?.context ?? result; return result?.[key] ?? result ?? tokensMap.system_default;
} }
return undefined; return tokensMap.system_default;
}
/**
* Retrieves the maximum tokens for a given model name.
*
* @param {string} modelName - The name of the model to look up.
* @param {string} endpoint - The endpoint (default is 'openAI').
* @param {EndpointTokenConfig} [endpointTokenConfig] - Token Config for current endpoint to use for max tokens lookup
* @returns {number|undefined} The maximum tokens for the given model or undefined if no match is found.
*/
function getModelMaxTokens(modelName, endpoint = EModelEndpoint.openAI, endpointTokenConfig) {
const tokensMap = endpointTokenConfig ?? maxTokensMap[endpoint];
return getModelTokenValue(modelName, tokensMap);
}
/**
* Retrieves the maximum output tokens for a given model name.
*
* @param {string} modelName - The name of the model to look up.
* @param {string} endpoint - The endpoint (default is 'openAI').
* @param {EndpointTokenConfig} [endpointTokenConfig] - Token Config for current endpoint to use for max tokens lookup
* @returns {number|undefined} The maximum output tokens for the given model or undefined if no match is found.
*/
function getModelMaxOutputTokens(modelName, endpoint = EModelEndpoint.openAI, endpointTokenConfig) {
const tokensMap = endpointTokenConfig ?? maxOutputTokensMap[endpoint];
return getModelTokenValue(modelName, tokensMap, 'output');
} }
/** /**
@ -298,7 +328,8 @@ module.exports = {
maxTokensMap, maxTokensMap,
inputSchema, inputSchema,
modelSchema, modelSchema,
getModelMaxTokens,
matchModelName, matchModelName,
processModelData, processModelData,
getModelMaxTokens,
getModelMaxOutputTokens,
}; };

View file

@ -17,6 +17,14 @@ import {
import { IconProps } from '~/common'; import { IconProps } from '~/common';
import { cn } from '~/utils'; import { cn } from '~/utils';
function getOpenAIColor(_model: string | null | undefined) {
const model = _model?.toLowerCase() ?? '';
if (model && /\bo1\b/i.test(model)) {
return '#000000';
}
return model.includes('gpt-4') ? '#AB68FF' : '#19C37D';
}
function getGoogleIcon(model: string | null | undefined, size: number) { function getGoogleIcon(model: string | null | undefined, size: number) {
if (model?.toLowerCase().includes('code') === true) { if (model?.toLowerCase().includes('code') === true) {
return <CodeyIcon size={size * 0.75} />; return <CodeyIcon size={size * 0.75} />;
@ -119,8 +127,7 @@ const MessageEndpointIcon: React.FC<IconProps> = (props) => {
}, },
[EModelEndpoint.openAI]: { [EModelEndpoint.openAI]: {
icon: <GPTIcon size={size * 0.5555555555555556} />, icon: <GPTIcon size={size * 0.5555555555555556} />,
bg: bg: getOpenAIColor(model),
typeof model === 'string' && model.toLowerCase().includes('gpt-4') ? '#AB68FF' : '#19C37D',
name: 'ChatGPT', name: 'ChatGPT',
}, },
[EModelEndpoint.gptPlugins]: { [EModelEndpoint.gptPlugins]: {

View file

@ -42,7 +42,8 @@ const errorMessages = {
[ErrorTypes.NO_USER_KEY]: 'com_error_no_user_key', [ErrorTypes.NO_USER_KEY]: 'com_error_no_user_key',
[ErrorTypes.INVALID_USER_KEY]: 'com_error_invalid_user_key', [ErrorTypes.INVALID_USER_KEY]: 'com_error_invalid_user_key',
[ErrorTypes.NO_BASE_URL]: 'com_error_no_base_url', [ErrorTypes.NO_BASE_URL]: 'com_error_no_base_url',
[ErrorTypes.INVALID_REQUEST]: 'com_error_invalid_request', [ErrorTypes.INVALID_REQUEST]: `com_error_${ErrorTypes.INVALID_REQUEST}`,
[ErrorTypes.NO_SYSTEM_MESSAGES]: `com_error_${ErrorTypes.NO_SYSTEM_MESSAGES}`,
[ErrorTypes.EXPIRED_USER_KEY]: (json: TExpiredKey, localize: LocalizeFunction) => { [ErrorTypes.EXPIRED_USER_KEY]: (json: TExpiredKey, localize: LocalizeFunction) => {
const { expiredAt, endpoint } = json; const { expiredAt, endpoint } = json;
return localize('com_error_expired_user_key', endpoint, expiredAt); return localize('com_error_expired_user_key', endpoint, expiredAt);

View file

@ -24,8 +24,10 @@ export default {
com_error_no_base_url: 'No base URL found. Please provide one and try again.', com_error_no_base_url: 'No base URL found. Please provide one and try again.',
com_warning_resubmit_unsupported: com_warning_resubmit_unsupported:
'Resubmitting the AI message is not supported for this endpoint.', 'Resubmitting the AI message is not supported for this endpoint.',
com_error_invalid_request: com_error_invalid_request_error:
'The AI service rejected the request due to an error. This could be caused by an invalid API key or an improperly formatted request.', 'The AI service rejected the request due to an error. This could be caused by an invalid API key or an improperly formatted request.',
com_error_no_system_messages:
'The selected AI service or model does not support system messages. Try using prompts instead of custom instructions.',
com_error_invalid_user_key: 'Invalid key provided. Please provide a valid key and try again.', com_error_invalid_user_key: 'Invalid key provided. Please provide a valid key and try again.',
com_error_expired_user_key: com_error_expired_user_key:
'Provided key for {0} expired at {1}. Please provide a new key and try again.', 'Provided key for {0} expired at {1}. Please provide a new key and try again.',

View file

@ -11,6 +11,10 @@ export const defaultSocialLogins = ['google', 'facebook', 'openid', 'github', 'd
export const defaultRetrievalModels = [ export const defaultRetrievalModels = [
'gpt-4o', 'gpt-4o',
'o1-preview-2024-09-12',
'o1-preview',
'o1-mini-2024-09-12',
'o1-mini',
'chatgpt-4o-latest', 'chatgpt-4o-latest',
'gpt-4o-2024-05-13', 'gpt-4o-2024-05-13',
'gpt-4o-2024-08-06', 'gpt-4o-2024-08-06',
@ -951,6 +955,10 @@ export enum ErrorTypes {
* Invalid request error, API rejected request * Invalid request error, API rejected request
*/ */
INVALID_REQUEST = 'invalid_request_error', INVALID_REQUEST = 'invalid_request_error',
/**
* Invalid request error, API rejected request
*/
NO_SYSTEM_MESSAGES = 'no_system_messages',
} }
/** /**

View file

@ -240,6 +240,8 @@ export const getResponseSender = (endpointOption: t.TEndpointOption): string =>
) { ) {
if (chatGptLabel) { if (chatGptLabel) {
return chatGptLabel; return chatGptLabel;
} else if (model && /\bo1\b/i.test(model)) {
return 'o1';
} else if (model && model.includes('gpt-3')) { } else if (model && model.includes('gpt-3')) {
return 'GPT-3.5'; return 'GPT-3.5';
} else if (model && model.includes('gpt-4o')) { } else if (model && model.includes('gpt-4o')) {