From 341e086d704ecaf7521e449f94a1484c75e25934 Mon Sep 17 00:00:00 2001 From: Danny Avila Date: Mon, 9 Sep 2024 20:58:15 -0400 Subject: [PATCH] =?UTF-8?q?=F0=9F=9B=A0=EF=B8=8F=20fix:=20Completion=20Edg?= =?UTF-8?q?e=20Cases=20&=20Improve=20Error=20Handling=20UX=20(#3968)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix: edge cases concerning completion response as an array * refactor: improve invalid request error UX --- api/app/clients/BaseClient.js | 6 +++++- api/app/clients/OpenAIClient.js | 6 +++--- api/server/middleware/abortMiddleware.js | 8 ++++++-- client/src/components/Messages/Content/Error.tsx | 1 + client/src/localization/languages/Eng.ts | 2 ++ packages/data-provider/src/config.ts | 5 ++++- 6 files changed, 21 insertions(+), 7 deletions(-) diff --git a/api/app/clients/BaseClient.js b/api/app/clients/BaseClient.js index 972716ee08..1d36d81d1a 100644 --- a/api/app/clients/BaseClient.js +++ b/api/app/clients/BaseClient.js @@ -3,6 +3,7 @@ const fetch = require('node-fetch'); const { supportsBalanceCheck, isAgentsEndpoint, + paramEndpoints, ErrorTypes, Constants, CacheKeys, @@ -561,6 +562,7 @@ class BaseClient { }); } + /** @type {string|string[]|undefined} */ const completion = await this.sendCompletion(payload, opts); this.abortController.requestCompleted = true; @@ -580,9 +582,11 @@ class BaseClient { if (typeof completion === 'string') { responseMessage.text = addSpaceIfNeeded(generation) + completion; - } else if (completion) { + } else if (Array.isArray(completion) && paramEndpoints.has(this.options.endpoint)) { responseMessage.text = ''; responseMessage.content = completion; + } else if (Array.isArray(completion)) { + responseMessage.text = addSpaceIfNeeded(generation) + completion.join(''); } if ( diff --git a/api/app/clients/OpenAIClient.js b/api/app/clients/OpenAIClient.js index 4338a29d5a..79582d1d38 100644 --- a/api/app/clients/OpenAIClient.js +++ b/api/app/clients/OpenAIClient.js @@ -1271,7 +1271,7 @@ ${convo} const { choices } = chatCompletion; if (!Array.isArray(choices) || choices.length === 0) { logger.warn('[OpenAIClient] Chat completion response has no choices'); - return intermediateReply; + return intermediateReply.join(''); } const { message, finish_reason } = choices[0] ?? {}; @@ -1281,7 +1281,7 @@ ${convo} if (!message) { logger.warn('[OpenAIClient] Message is undefined in chatCompletion response'); - return intermediateReply; + return intermediateReply.join(''); } if (typeof message.content !== 'string' || message.content.trim() === '') { @@ -1316,7 +1316,7 @@ ${convo} logger.error('[OpenAIClient] Known OpenAI error:', err); return intermediateReply.join(''); } else if (err instanceof OpenAI.APIError) { - if (intermediateReply) { + if (intermediateReply.length > 0) { return intermediateReply.join(''); } else { throw err; diff --git a/api/server/middleware/abortMiddleware.js b/api/server/middleware/abortMiddleware.js index 7fb84a3074..e9a12e2bf3 100644 --- a/api/server/middleware/abortMiddleware.js +++ b/api/server/middleware/abortMiddleware.js @@ -1,4 +1,4 @@ -const { isAssistantsEndpoint } = require('librechat-data-provider'); +const { isAssistantsEndpoint, ErrorTypes } = require('librechat-data-provider'); const { sendMessage, sendError, countTokens, isEnabled } = require('~/server/utils'); const { truncateText, smartTruncateText } = require('~/app/clients/prompts'); const clearPendingReq = require('~/cache/clearPendingReq'); @@ -165,10 +165,14 @@ const handleAbortError = async (res, req, error, data) => { ); } - const errorText = error?.message?.includes('"type"') + let errorText = error?.message?.includes('"type"') ? error.message : 'An error occurred while processing your request. Please contact the Admin.'; + if (error?.type === ErrorTypes.INVALID_REQUEST) { + errorText = `{"type":"${ErrorTypes.INVALID_REQUEST}"}`; + } + const respondWithError = async (partialText) => { let options = { sender, diff --git a/client/src/components/Messages/Content/Error.tsx b/client/src/components/Messages/Content/Error.tsx index 476360080f..a00bb81806 100644 --- a/client/src/components/Messages/Content/Error.tsx +++ b/client/src/components/Messages/Content/Error.tsx @@ -42,6 +42,7 @@ const errorMessages = { [ErrorTypes.NO_USER_KEY]: 'com_error_no_user_key', [ErrorTypes.INVALID_USER_KEY]: 'com_error_invalid_user_key', [ErrorTypes.NO_BASE_URL]: 'com_error_no_base_url', + [ErrorTypes.INVALID_REQUEST]: 'com_error_invalid_request', [ErrorTypes.EXPIRED_USER_KEY]: (json: TExpiredKey, localize: LocalizeFunction) => { const { expiredAt, endpoint } = json; return localize('com_error_expired_user_key', endpoint, expiredAt); diff --git a/client/src/localization/languages/Eng.ts b/client/src/localization/languages/Eng.ts index cfb16c16b8..ca6cb35a5e 100644 --- a/client/src/localization/languages/Eng.ts +++ b/client/src/localization/languages/Eng.ts @@ -22,6 +22,8 @@ export default { 'It appears that the content submitted has been flagged by our moderation system for not aligning with our community guidelines. We\'re unable to proceed with this specific topic. If you have any other questions or topics you\'d like to explore, please edit your message, or create a new conversation.', com_error_no_user_key: 'No key found. Please provide a key and try again.', com_error_no_base_url: 'No base URL found. Please provide one and try again.', + com_error_invalid_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_invalid_user_key: 'Invalid key provided. Please provide a valid key and try again.', com_error_expired_user_key: 'Provided key for {0} expired at {1}. Please provide a new key and try again.', diff --git a/packages/data-provider/src/config.ts b/packages/data-provider/src/config.ts index 7b60632fb5..277146ae90 100644 --- a/packages/data-provider/src/config.ts +++ b/packages/data-provider/src/config.ts @@ -943,11 +943,14 @@ export enum ErrorTypes { * Moderation error */ MODERATION = 'moderation', - /** * Prompt exceeds max length */ INPUT_LENGTH = 'INPUT_LENGTH', + /** + * Invalid request error, API rejected request + */ + INVALID_REQUEST = 'invalid_request_error', } /**