diff --git a/component/src/services/openAI/openAIAssistantIO.ts b/component/src/services/openAI/openAIAssistantIO.ts index 27ae6e2ad..684031d1e 100644 --- a/component/src/services/openAI/openAIAssistantIO.ts +++ b/component/src/services/openAI/openAIAssistantIO.ts @@ -3,6 +3,7 @@ import {OpenAIAssistantUtils, UploadedFile} from './utils/openAIAssistantUtils'; import {MessageStream} from '../../views/chat/messages/stream/messageStream'; import {FileMessageUtils} from '../../views/chat/messages/fileMessageUtils'; import {OpenAIConverseBodyInternal} from '../../types/openAIInternal'; +import {History} from '../../views/chat/messages/history/history'; import {DirectConnection} from '../../types/directConnection'; import {MessageLimitUtils} from '../utils/messageLimitUtils'; import {MessageContentI} from '../../types/messagesInternal'; @@ -44,7 +45,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', 'Please send text']; + permittedErrorPrefixes = ['Incorrect', 'Please send text', History.FAILED_ERROR_MESSAGE]; private messages?: Messages; private run_id?: string; private searchedForThreadId = false; @@ -88,7 +89,7 @@ export class OpenAIAssistantIO extends DirectServiceIO { this.deepChat.disableSubmitButton(false); return threadMessages; } catch (e) { - return [{error: 'failed to fetch thread history'}]; + return [{error: 'Failed to fetch history'}]; } } diff --git a/component/src/services/serviceIO.ts b/component/src/services/serviceIO.ts index 44e9d88a4..01dac2ba5 100644 --- a/component/src/services/serviceIO.ts +++ b/component/src/services/serviceIO.ts @@ -79,7 +79,7 @@ export interface ServiceIO { introPanelMarkUp?: string; - // the reason why we use a Set of prefixes to allow certain errors is because some errors can change + // the reason why we use a set of prefixes to allow certain errors is because some errors can change // depending on the input e.g. incorrect image dimensions or formatting, hence we identify the permitted // service errors via prefixes permittedErrorPrefixes?: CustomErrors; diff --git a/component/src/services/utils/baseServiceIO.ts b/component/src/services/utils/baseServiceIO.ts index ebf709bea..9a4182ae2 100644 --- a/component/src/services/utils/baseServiceIO.ts +++ b/component/src/services/utils/baseServiceIO.ts @@ -1,4 +1,5 @@ import {CameraFilesServiceConfig, MicrophoneFilesServiceConfig} from '../../types/fileServiceConfigs'; +import {History} from '../../views/chat/messages/history/history'; import {MessageContentI} from '../../types/messagesInternal'; import {Messages} from '../../views/chat/messages/messages'; import {RequestUtils} from '../../utils/HTTP/requestUtils'; @@ -53,6 +54,7 @@ export class BaseServiceIO implements ServiceIO { if (this.demo) this.connectSettings.url ??= Demo.URL; if (this.connectSettings.websocket) Websocket.setup(this); this.stream = this.deepChat.connect?.stream || Legacy.checkForStream(this.deepChat); + if (deepChat.loadHistory) History.addErrorPrefix(this); } private static canSendMessage(text?: string, files?: File[], isProgrammatic?: boolean) { diff --git a/component/src/views/chat/messages/history/history.ts b/component/src/views/chat/messages/history/history.ts index f2105a102..4b35c6fca 100644 --- a/component/src/views/chat/messages/history/history.ts +++ b/component/src/views/chat/messages/history/history.ts @@ -10,6 +10,7 @@ import {Messages} from '../messages'; export class History { private readonly _messages: Messages; + public static readonly FAILED_ERROR_MESSAGE = 'Failed to load history'; private _isLoading = false; private _isPaginationComplete = false; private _index = 0; @@ -33,7 +34,6 @@ export class History { private processLoadedHistory(historyMessages: HistoryMessage[]) { const firstMessageEl = this._messages.messageElementRefs[0]?.outerContainer; const currentScrollTop = this._messages.elementRef.scrollTop; - // WORK - don't add at start if intro message historyMessages ?.reverse() .map((message) => { @@ -56,10 +56,17 @@ export class History { if (!this._isLoading && !this._isPaginationComplete && this._messages.elementRef.scrollTop === 0) { this._isLoading = true; const loadingElements = LoadingHistory.addLoadHistoryMessage(this._messages, false); - const messages = await loadHistory(this._index++); - this._messages.removeMessage(loadingElements); - this.processLoadedHistory(messages); - this._isLoading = false; + try { + const messages = await loadHistory(this._index++); + this._messages.removeMessage(loadingElements); + this.processLoadedHistory(messages); + this._isLoading = false; + } catch (e) { + this._messages.removeMessage(loadingElements); + this._isPaginationComplete = true; + this._messages.addNewErrorMessage('service', History.FAILED_ERROR_MESSAGE, true); + console.error(e); + } } }; } @@ -74,17 +81,23 @@ export class History { private async loadInitialHistory(loadHistory: LoadHistory) { this._isLoading = true; const loadingElements = LoadingHistory.addLoadHistoryMessage(this._messages); - // WORK - error handling - const messages = await loadHistory(this._index++); - const scrollTop = this._messages.elementRef.scrollTop; - this._messages.removeMessage(loadingElements); - this._isPaginationComplete = !!messages.find((message) => !message); - const messageContent = messages.filter((message) => !!message); - this.processLoadedHistory(messageContent as MessageContent[]); - // force scroll to bottom if user has not scrolled anywhere themselves, otherwise keep at current location - if (scrollTop === 0) { - // https://github.com/OvidijusParsiunas/deep-chat/issues/84 - setTimeout(() => ElementUtils.scrollToBottom(this._messages.elementRef), 0); + try { + const messages = await loadHistory(this._index++); + const scrollTop = this._messages.elementRef.scrollTop; + this._messages.removeMessage(loadingElements); + this._isPaginationComplete = !!messages.find((message) => !message); + const messageContent = messages.filter((message) => !!message); + this.processLoadedHistory(messageContent as MessageContent[]); + // force scroll to bottom if user has not scrolled anywhere themselves, otherwise keep at current location + if (scrollTop === 0) { + // https://github.com/OvidijusParsiunas/deep-chat/issues/84 + setTimeout(() => ElementUtils.scrollToBottom(this._messages.elementRef), 0); + } + } catch (e) { + this._messages.removeMessage(loadingElements); + this._isPaginationComplete = true; + this._messages.addNewErrorMessage('service', History.FAILED_ERROR_MESSAGE, true); + console.error(e); } this._isLoading = false; } @@ -99,4 +112,9 @@ export class History { this._index += 1; } } + + public static addErrorPrefix(io: ServiceIO) { + io.permittedErrorPrefixes ??= []; + io.permittedErrorPrefixes.push(History.FAILED_ERROR_MESSAGE); + } } diff --git a/component/src/views/chat/messages/messages.ts b/component/src/views/chat/messages/messages.ts index 00c29eeb8..0a726f1d4 100644 --- a/component/src/views/chat/messages/messages.ts +++ b/component/src/views/chat/messages/messages.ts @@ -182,20 +182,19 @@ export class Messages extends MessagesBase { } // prettier-ignore - public addNewErrorMessage(type: keyof Omit, message?: ErrorResp) { + public addNewErrorMessage(type: keyof Omit, message?: ErrorResp, isTop = false) { this.removeMessageOnError(); - const messageElements = Messages.createBaseElements(); - const {outerContainer, bubbleElement} = messageElements; - bubbleElement.classList.add('error-message-text'); const text = this.getPermittedMessage(message) || this._errorMessageOverrides?.[type] || this._errorMessageOverrides?.default || 'Error, please try again.'; + const messageElements = this.createMessageElementsOnOrientation(text, '', isTop); + const {bubbleElement, outerContainer} = messageElements; + bubbleElement.classList.add('error-message-text'); this.renderText(bubbleElement, text); const fontElementStyles = MessageStyleUtils.extractParticularSharedStyles(['fontSize', 'fontFamily'], this.messageStyles?.default); MessageStyleUtils.applyCustomStylesToElements(messageElements, false, fontElementStyles); MessageStyleUtils.applyCustomStylesToElements(messageElements, false, this.messageStyles?.error); - this.elementRef.appendChild(outerContainer); - ElementUtils.scrollToBottom(this.elementRef); + if (!isTop) this.elementRef.appendChild(outerContainer); if (this.textToSpeech) TextToSpeech.speak(text, this.textToSpeech); this._onError?.(text); }