From 69c043a83a209afd57a44b672eb33eb3578e9f9c Mon Sep 17 00:00:00 2001 From: Ovidijus Parsiunas Date: Sun, 26 May 2024 22:06:26 +0100 Subject: [PATCH] improving error handling functionality for services --- .../src/services/openAI/openAIAssistantIO.ts | 15 +++++--- .../openAI/utils/openAIAssistantUtils.ts | 3 ++ component/src/types/errorInternal.ts | 3 ++ component/src/utils/HTTP/customHandler.ts | 2 +- component/src/utils/HTTP/requestUtils.ts | 9 ++++- component/src/views/chat/messages/messages.ts | 38 ++++++++++++++----- 6 files changed, 53 insertions(+), 17 deletions(-) create mode 100644 component/src/types/errorInternal.ts diff --git a/component/src/services/openAI/openAIAssistantIO.ts b/component/src/services/openAI/openAIAssistantIO.ts index ba1d719eb..dcb40c672 100644 --- a/component/src/services/openAI/openAIAssistantIO.ts +++ b/component/src/services/openAI/openAIAssistantIO.ts @@ -44,7 +44,7 @@ export class OpenAIAssistantIO extends DirectServiceIO { private static readonly NEW_ASSISTANT_URL = 'https://api.openai.com/v1/assistants'; private static readonly POLLING_TIMEOUT_MS = 800; private readonly _functionHandler?: AssistantFunctionHandler; - permittedErrorPrefixes = ['Incorrect']; + permittedErrorPrefixes = ['Incorrect', 'Please send text']; private messages?: Messages; private run_id?: string; private searchedForThreadId = false; @@ -108,7 +108,7 @@ export class OpenAIAssistantIO extends DirectServiceIO { return undefined; } - private static processFileSearchMessage( + private static processAttachmentsMessage( processedMessage: MessageContentI, uploadedFiles: UploadedFile[], toolType: OpenAIAssistant['files_tool_type'] @@ -126,10 +126,10 @@ export class OpenAIAssistantIO extends DirectServiceIO { // https://platform.openai.com/docs/api-reference/messages/createMessage if (uploadedFiles && uploadedFiles.length > 0) { if (this.filesToolType === 'file_search') { - return OpenAIAssistantIO.processFileSearchMessage(processedMessage, uploadedFiles, 'file_search'); + return OpenAIAssistantIO.processAttachmentsMessage(processedMessage, uploadedFiles, 'file_search'); } if (this.filesToolType === 'code_interpreter') { - return OpenAIAssistantIO.processFileSearchMessage(processedMessage, uploadedFiles, 'code_interpreter'); + return OpenAIAssistantIO.processAttachmentsMessage(processedMessage, uploadedFiles, 'code_interpreter'); } const imageMessage = OpenAIAssistantIO.processImageMessage(processedMessage, uploadedFiles); if (imageMessage) return imageMessage; @@ -200,7 +200,12 @@ export class OpenAIAssistantIO extends DirectServiceIO { if (this.waitingForStreamResponse || (this.isSSEStream && this.sessionId)) { return await this.handleStream(result); } - if (result.error) throw result.error.message; + if (result.error) { + if (result.error.message.startsWith(OpenAIAssistantUtils.FILES_WITH_TEXT_ERROR)) { + throw Error('Please send text with your file(s)'); + } + throw result.error.message; + } await this.assignThreadAndRun(result); // https://platform.openai.com/docs/api-reference/runs/getRun const url = `${OpenAIAssistantIO.THREAD_PREFIX}/${this.sessionId}/runs/${this.run_id}`; diff --git a/component/src/services/openAI/utils/openAIAssistantUtils.ts b/component/src/services/openAI/utils/openAIAssistantUtils.ts index e95f7237e..7b5486574 100644 --- a/component/src/services/openAI/utils/openAIAssistantUtils.ts +++ b/component/src/services/openAI/utils/openAIAssistantUtils.ts @@ -12,6 +12,9 @@ type FileDetails = {fileId: string; path?: string; name?: string}[]; export type UploadedFile = {id: string; name: string}; export class OpenAIAssistantUtils { + // triggered ONLY for file_search and code_interceptor + public static readonly FILES_WITH_TEXT_ERROR = 'content with type `text` must have `text` values'; + public static async storeFiles(serviceIO: ServiceIO, messages: Messages, files: File[]) { const headers = serviceIO.connectSettings.headers; if (!headers) return; diff --git a/component/src/types/errorInternal.ts b/component/src/types/errorInternal.ts new file mode 100644 index 000000000..7370d6fae --- /dev/null +++ b/component/src/types/errorInternal.ts @@ -0,0 +1,3 @@ +import {Response} from './response'; + +export type ErrorResp = string | string[] | Error | Response; diff --git a/component/src/utils/HTTP/customHandler.ts b/component/src/utils/HTTP/customHandler.ts index 7c5f79142..dd8c74003 100644 --- a/component/src/utils/HTTP/customHandler.ts +++ b/component/src/utils/HTTP/customHandler.ts @@ -45,7 +45,7 @@ export class CustomHandler { stream.finaliseStreamedMessage(); } catch (error) { console.error(error); - messages.addNewErrorMessage('service', error as string); + messages.addNewErrorMessage('service', error as Error); } } diff --git a/component/src/utils/HTTP/requestUtils.ts b/component/src/utils/HTTP/requestUtils.ts index 1ef420383..68508542a 100644 --- a/component/src/utils/HTTP/requestUtils.ts +++ b/component/src/utils/HTTP/requestUtils.ts @@ -1,6 +1,7 @@ import {Messages} from '../../views/chat/messages/messages'; import {Response as ResponseI} from '../../types/response'; import {RequestDetails} from '../../types/interceptors'; +import {ErrorResp} from '../../types/errorInternal'; import {ServiceIO} from '../../services/serviceIO'; import {GenericObject} from '../../types/object'; import {Connect} from '../../types/connect'; @@ -35,9 +36,15 @@ export class RequestUtils { return result; } - public static displayError(messages: Messages, err: object | string, defMessage = 'Service error, please try again.') { + public static displayError(messages: Messages, err: ErrorResp, defMessage = 'Service error, please try again.') { console.error(err); if (typeof err === 'object') { + if (err instanceof Error) { + return messages.addNewErrorMessage('service', err.message); + } + if (Array.isArray(err) || typeof err.error === 'string') { + return messages.addNewErrorMessage('service', err); + } if (Object.keys(err).length === 0) { return messages.addNewErrorMessage('service', defMessage); } diff --git a/component/src/views/chat/messages/messages.ts b/component/src/views/chat/messages/messages.ts index f58e60077..a8378ba42 100644 --- a/component/src/views/chat/messages/messages.ts +++ b/component/src/views/chat/messages/messages.ts @@ -8,6 +8,7 @@ import {FireEvents} from '../../../utils/events/fireEvents'; import {ErrorMessageOverrides} from '../../../types/error'; import {ResponseI} from '../../../types/responseInternal'; import {TextToSpeech} from './textToSpeech/textToSpeech'; +import {ErrorResp} from '../../../types/errorInternal'; import {Demo, DemoResponse} from '../../../types/demo'; import {MessageStyleUtils} from './messageStyleUtils'; import {IntroMessage} from '../../../types/messages'; @@ -197,7 +198,7 @@ export class Messages extends MessagesBase { } // prettier-ignore - public addNewErrorMessage(type: keyof Omit, message?: string) { + public addNewErrorMessage(type: keyof Omit, message?: ErrorResp) { this.removeMessageOnError(); const messageElements = Messages.createBaseElements(); const {outerContainer, bubbleElement} = messageElements; @@ -222,16 +223,33 @@ export class Messages extends MessagesBase { return undefined; } - private getPermittedMessage(message?: string) { + private static extractErrorMessages(message: ErrorResp): string[] { + if (Array.isArray(message)) { + return message; + } + if (message instanceof Error) { + return [message.message]; + } + if (typeof message === 'string') { + return [message]; + } + if (typeof message === 'object' && message.error) { + return [message.error]; + } + return []; + } + + private getPermittedMessage(message?: ErrorResp): string | undefined { if (message) { - if (this._displayServiceErrorMessages) return message; - if (typeof message === 'string' && this._permittedErrorPrefixes) { - const result = Messages.checkPermittedErrorPrefixes(this._permittedErrorPrefixes, message); - if (result) return result; - } else if (Array.isArray(message) && this._permittedErrorPrefixes) { - for (let i = 0; i < message.length; i += 1) { - const result = Messages.checkPermittedErrorPrefixes(this._permittedErrorPrefixes, message[i]); - if (result) return result; + const messages = Messages.extractErrorMessages(message); // turning all into array for convenience + for (let i = 0; i < messages.length; i += 1) { + const messageStr = messages[i]; + if (typeof messageStr === 'string') { + if (this._displayServiceErrorMessages) return messageStr; + if (this._permittedErrorPrefixes) { + const result = Messages.checkPermittedErrorPrefixes(this._permittedErrorPrefixes, messageStr); + if (result) return result; + } } } }