From 514b9eaf42536ffdda622536966ca3c508453ed1 Mon Sep 17 00:00:00 2001 From: Natalia Venditto Date: Sat, 4 Nov 2023 12:34:19 +0100 Subject: [PATCH 01/13] chore: add ids to query elements to scroll --- packages/chat-component/src/main.ts | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/packages/chat-component/src/main.ts b/packages/chat-component/src/main.ts index 4fd9799d..82ede1df 100644 --- a/packages/chat-component/src/main.ts +++ b/packages/chat-component/src/main.ts @@ -7,7 +7,7 @@ import { chatHttpOptions, globalConfig, requestOptions } from './config/global-c import { getAPIResponse } from './core/http/index.js'; import { parseStreamedMessages } from './core/parser/index.js'; import { mainStyle } from './style.js'; -import { getTimestamp, processText } from './utils/index.js'; +import { getTimestamp, processText, scrollToFooter } from './utils/index.js'; import { unsafeSVG } from 'lit/directives/unsafe-svg.js'; // TODO: allow host applications to customize these icons @@ -140,6 +140,7 @@ export class ChatComponent extends LitElement { this.chatThoughts = result.thoughts; this.chatDataPoints = result.data_points; this.canShowThoughtProcess = true; + scrollToFooter(this.shadowRoot?.getElementById('chat-list-footer') as HTMLElement); return true; } @@ -158,6 +159,7 @@ export class ChatComponent extends LitElement { isUserMessage, }, ]; + // scroll to the bottom of the chat return true; }; @@ -408,7 +410,7 @@ export class ChatComponent extends LitElement { `; } - + // eslint-disable-next-line no-debugger return ''; } @@ -431,7 +433,7 @@ export class ChatComponent extends LitElement { ${unsafeSVG(iconDelete)} - - + ` : ''} ${this.isAwaitingResponse && !this.hasAPIError diff --git a/packages/chat-component/src/style.ts b/packages/chat-component/src/style.ts index 21a879ae..6787f85d 100644 --- a/packages/chat-component/src/style.ts +++ b/packages/chat-component/src/style.ts @@ -320,9 +320,10 @@ export const mainStyle = css` color: var(--text-color); display: flex; flex-direction: column; - padding: 0; - margin-bottom: 50px; - padding-bottom: 120px; + } + .chat__footer { + width: 100%; + height: 70px; } .chat__listItem { max-width: 80%; diff --git a/packages/chat-component/src/utils/index.ts b/packages/chat-component/src/utils/index.ts index 0305fc78..a38df281 100644 --- a/packages/chat-component/src/utils/index.ts +++ b/packages/chat-component/src/utils/index.ts @@ -86,5 +86,5 @@ export const mustScrollEvent = new CustomEvent('must-scroll', { // Scroll to last message export function scrollToFooter(element: HTMLElement): void { - element.scrollIntoView({ behavior: 'smooth', block: 'end' }); + element.scrollIntoView({ behavior: 'smooth', block: 'center' }); } From a7a3b635c43ea8997b4dc6c16ea3b99c5d37503a Mon Sep 17 00:00:00 2001 From: Natalia Venditto Date: Sat, 4 Nov 2023 13:46:53 +0100 Subject: [PATCH 06/13] chore: delete chat component from this version --- .../src/components/chat-component.ts | 565 ------------------ 1 file changed, 565 deletions(-) delete mode 100644 packages/chat-component/src/components/chat-component.ts diff --git a/packages/chat-component/src/components/chat-component.ts b/packages/chat-component/src/components/chat-component.ts deleted file mode 100644 index 8673538d..00000000 --- a/packages/chat-component/src/components/chat-component.ts +++ /dev/null @@ -1,565 +0,0 @@ -/* eslint-disable unicorn/template-indent */ -import { LitElement, html } from 'lit'; -import DOMPurify from 'dompurify'; -import { customElement, property, query, state } from 'lit/decorators.js'; -import { unsafeHTML } from 'lit/directives/unsafe-html.js'; -import { chatHttpOptions, globalConfig, requestOptions } from '../config/global-config.js'; -import { getAPIResponse } from '../core/http/index.js'; -import { parseStreamedMessages } from '../core/parser/index.js'; -import { chatStyle } from '../styles/chat-component.js'; -import { getTimestamp, processText } from '../utils/index.js'; -import { unsafeSVG } from 'lit/directives/unsafe-svg.js'; -// TODO: allow host applications to customize these icons - -import iconLightBulb from '../../public/svg/lightbulb-icon.svg?raw'; -import iconDelete from '../../public/svg/delete-icon.svg?raw'; -import iconSuccess from '../../public/svg/success-icon.svg?raw'; -import iconCopyToClipboard from '../../public/svg/copy-icon.svg?raw'; -import iconSend from '../../public/svg/send-icon.svg?raw'; -import iconClose from '../../public/svg/close-icon.svg?raw'; -import iconQuestion from '../../public/svg/question-icon.svg?raw'; - -/** - * A chat component that allows the user to ask questions and get answers from an API. - * The component also displays default prompts that the user can click on to ask a question. - * The component is built as a custom element that extends LitElement. - * - * Labels and other aspects are configurable via properties that get their values from the global config file. - * @element chat-component - * @fires chat-component#questionSubmitted - Fired when the user submits a question - * @fires chat-component#defaultQuestionClicked - Fired when the user clicks on a default question - * */ - -@customElement('chat-component') -export class ChatComponent extends LitElement { - //-- - // Public attributes - // -- - - @property({ type: String, attribute: 'data-input-position' }) - inputPosition = 'sticky'; - - @property({ type: String, attribute: 'data-interaction-model' }) - interactionModel: 'ask' | 'chat' = 'chat'; - - @property({ type: String, attribute: 'data-api-url' }) - apiUrl = chatHttpOptions.url; - - @property({ type: String, attribute: 'data-use-stream', converter: (value) => value?.toLowerCase() === 'true' }) - useStream: boolean = chatHttpOptions.stream; - - @property({ type: String, attribute: 'data-overrides', converter: (value) => JSON.parse(value || '{}') }) - overrides: RequestOverrides = {}; - - //-- - - @property({ type: String }) - currentQuestion = ''; - - @query('#question-input') - questionInput!: HTMLInputElement; - - // Default prompts to display in the chat - @state() - isDisabled = false; - - @state() - isChatStarted = false; - - @state() - isResetInput = false; - - // The program is awaiting response from API - @state() - isAwaitingResponse = false; - - // Show error message to the end-user, if API call fails - @property({ type: Boolean }) - hasAPIError = false; - - // Has the response been copied to the clipboard - @state() - isResponseCopied = false; - - // Is showing thought process panel - @state() - isShowingThoughtProcess = false; - - @state() - canShowThoughtProcess = false; - - @state() - isDefaultPromptsEnabled: boolean = globalConfig.IS_DEFAULT_PROMPTS_ENABLED && !this.isChatStarted; - - // api response - apiResponse = {} as BotResponse | Response; - // These are the chat bubbles that will be displayed in the chat - chatThread: ChatThreadEntry[] = []; - defaultPrompts: string[] = globalConfig.DEFAULT_PROMPTS; - defaultPromptsHeading: string = globalConfig.DEFAULT_PROMPTS_HEADING; - chatButtonLabelText: string = globalConfig.CHAT_BUTTON_LABEL_TEXT; - chatThoughts: string | null = ''; - chatDataPoints: string[] = []; - - chatRequestOptions: ChatRequestOptions = requestOptions; - chatHttpOptions: ChatHttpOptions = chatHttpOptions; - - static override styles = [chatStyle]; - - // Send the question to the Open AI API and render the answer in the chat - - // Add a message to the chat, when the user or the API sends a message - async processApiResponse({ message, isUserMessage }: { message: string; isUserMessage: boolean }) { - const citations: Citation[] = []; - const followingSteps: string[] = []; - const followupQuestions: string[] = []; - // Get the timestamp for the message - const timestamp = getTimestamp(); - const updateChatWithMessageOrChunk = async (part: string, isChunk: boolean) => { - if (isChunk) { - // we need to prepare an empty instance of the chat message so that we can start populating it - this.chatThread = [ - ...this.chatThread, - { - text: [{ value: '', followingSteps: [] }], - followupQuestions: [], - citations: [], - timestamp: timestamp, - isUserMessage, - }, - ]; - - const result = await parseStreamedMessages({ - chatThread: this.chatThread, - apiResponseBody: (this.apiResponse as Response).body, - visit: () => { - // NOTE: this function is called whenever we mutate sub-properties of the array - this.requestUpdate('chatThread'); - }, - // this will be processing thought process only with streaming enabled - }); - this.chatThoughts = result.thoughts; - this.chatDataPoints = result.data_points; - this.canShowThoughtProcess = true; - return true; - } - - this.chatThread = [ - ...this.chatThread, - { - text: [ - { - value: part, - followingSteps, - }, - ], - followupQuestions, - citations: [...new Set(citations)], - timestamp: timestamp, - isUserMessage, - }, - ]; - return true; - }; - - // Check if message is a bot message to process citations and follow-up questions - if (isUserMessage) { - updateChatWithMessageOrChunk(message, false); - } else { - if (this.useStream) { - await updateChatWithMessageOrChunk(message, true); - } else { - // non-streamed response - const processedText = processText(message, [citations, followingSteps, followupQuestions]); - message = processedText.replacedText; - // Push all lists coming from processText to the corresponding arrays - citations.push(...(processedText.arrays[0] as unknown as Citation[])); - followingSteps.push(...(processedText.arrays[1] as string[])); - followupQuestions.push(...(processedText.arrays[2] as string[])); - updateChatWithMessageOrChunk(message, false); - } - } - } - - // This function is only necessary when default prompts are enabled - // and we're rendering a teaser list component - // TODO: move to utils - handleOnTeaserClick(event): void { - this.questionInput.value = DOMPurify.sanitize(event?.detail.question || ''); - this.currentQuestion = this.questionInput.value; - } - - // Handle the click on the chat button and send the question to the API - async handleUserChatSubmit(event: Event): Promise { - event.preventDefault(); - const question = DOMPurify.sanitize(this.questionInput.value); - if (question) { - this.currentQuestion = question; - try { - const type = this.interactionModel; - // Remove default prompts - this.isChatStarted = true; - this.isDefaultPromptsEnabled = false; - // Disable the input field and submit button while waiting for the API response - this.isDisabled = true; - // Show loading indicator while waiting for the API response - - this.isAwaitingResponse = true; - if (type === 'chat') { - this.processApiResponse({ message: question, isUserMessage: true }); - } - - this.apiResponse = await getAPIResponse( - { - ...this.chatRequestOptions, - overrides: { - ...this.chatRequestOptions.overrides, - ...this.overrides, - }, - question, - type, - }, - { - // use defaults - ...this.chatHttpOptions, - - // override if the user has provided different values - url: this.apiUrl, - stream: this.useStream, - }, - ); - - this.questionInput.value = ''; - this.isAwaitingResponse = false; - this.isDisabled = false; - this.isResetInput = false; - const response = this.apiResponse as BotResponse; - // adds thought process support when streaming is disabled - if (!this.useStream) { - this.chatThoughts = response.choices[0].message.context?.thoughts ?? ''; - this.chatDataPoints = response.choices[0].message.context?.data_points ?? []; - this.canShowThoughtProcess = true; - } - await this.processApiResponse({ - message: this.useStream ? '' : response.choices[0].message.content, - isUserMessage: false, - }); - } catch (error) { - console.error(error); - this.handleAPIError(); - } - } - } - - // Reset the input field and the current question - resetInputField(event: Event): void { - event.preventDefault(); - this.questionInput.value = ''; - this.currentQuestion = ''; - this.isResetInput = false; - } - - // Reset the chat and show the default prompts - resetCurrentChat(event: Event): void { - this.isChatStarted = false; - this.chatThread = []; - this.isDisabled = false; - this.isDefaultPromptsEnabled = true; - this.isResponseCopied = false; - this.hideThoughtProcess(event); - } - - // Show the default prompts when enabled - showDefaultPrompts(event: Event): void { - if (!this.isDefaultPromptsEnabled) { - this.resetCurrentChat(event); - } - } - - // Handle the change event on the input field - handleOnInputChange(): void { - this.isResetInput = !!this.questionInput.value; - } - - // Handle API error - handleAPIError(): void { - this.hasAPIError = true; - this.isDisabled = false; - } - - // Copy response to clipboard - copyResponseToClipboard(): void { - const response = this.chatThread.at(-1)?.text.at(-1)?.value as string; - navigator.clipboard.writeText(response); - this.isResponseCopied = true; - } - - // show thought process aside - expandAside(event: Event): void { - event.preventDefault(); - this.isShowingThoughtProcess = true; - this.shadowRoot?.querySelector('#overlay')?.classList.add('active'); - this.shadowRoot?.querySelector('#chat__containerWrapper')?.classList.add('aside-open'); - } - // hide thought process aside - hideThoughtProcess(event: Event): void { - event.preventDefault(); - this.isShowingThoughtProcess = false; - this.shadowRoot?.querySelector('#chat__containerWrapper')?.classList.remove('aside-open'); - this.shadowRoot?.querySelector('#overlay')?.classList.remove('active'); - } - - // Render text entries in bubbles - renderTextEntry(textEntry: ChatMessageText) { - const entries = [html`

${unsafeHTML(textEntry.value)}

`]; - - // render steps - if (textEntry.followingSteps && textEntry.followingSteps.length > 0) { - entries.push( - html`
    - ${textEntry.followingSteps.map( - (followingStep) => html`
  1. ${unsafeHTML(followingStep)}
  2. `, - )} -
`, - ); - } - - return entries; - } - - renderCitation(citations: Citation[] | undefined) { - // render citations - if (citations && citations.length > 0) { - return html` -
    - ${citations.map( - (citation) => html` -
  1. - ${citation.ref}. ${citation.text} -
  2. - `, - )} -
- `; - } - - return ''; - } - - renderFollowupQuestions(followupQuestions: string[] | undefined) { - // render followup questions - // need to fix first after decoupling of teaserlist - if (followupQuestions && followupQuestions.length > 0) { - return html` -
- ${unsafeSVG(iconQuestion)} -
    - ${followupQuestions.map( - (followupQuestion) => html` -
  • - ${followupQuestion} -
  • - `, - )} -
-
- `; - } - - return ''; - } - - // Render the chat component as a web component - override render() { - return html` -
-
-
- ${ - this.isChatStarted - ? html` -
- -
-
    - ${this.chatThread.map( - (message) => html` -
  • -
    - ${message.isUserMessage - ? '' - : html`
    - - -
    `} - ${message.text.map((textEntry) => this.renderTextEntry(textEntry))} - ${this.renderCitation(message.citations)} - ${this.renderFollowupQuestions(message.followupQuestions)} -
    -

    - ${message.timestamp}, - ${message.isUserMessage ? 'You' : globalConfig.USER_IS_BOT} -

    -
  • - `, - )} - ${this.hasAPIError - ? html` -
  • -

    ${globalConfig.API_ERROR_MESSAGE}

    -
  • - ` - : ''} -
- ` - : '' - } - ${ - this.isAwaitingResponse && !this.hasAPIError - ? html` -
-
-
-
-
- ` - : '' - } - -
- - ${ - this.isDefaultPromptsEnabled - ? html` - - ` - : '' - } -
-
- - - -
- - ${ - this.isDefaultPromptsEnabled - ? '' - : html`
- -
` - } -
-
- ${ - this.isShowingThoughtProcess - ? html` - - ` - : '' - } -
- `; - } -} From 26d8053e268cd68b4fadadf72a7ed13a18168eb2 Mon Sep 17 00:00:00 2001 From: Natalia Venditto Date: Sat, 4 Nov 2023 20:54:26 +0100 Subject: [PATCH 07/13] chore: debounce event trigger --- packages/chat-component/src/main.ts | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/packages/chat-component/src/main.ts b/packages/chat-component/src/main.ts index 97662b3d..3924a89f 100644 --- a/packages/chat-component/src/main.ts +++ b/packages/chat-component/src/main.ts @@ -113,7 +113,15 @@ export class ChatComponent extends LitElement { this.handleOnMustScroll(); }); } - + // debounce dispatching must-scroll event + debounceDispatchMustScrollEvent(): void { + let timeout: any = 0; + clearTimeout(timeout); + timeout = setTimeout(() => { + this.dispatchEvent(mustScrollEvent); + }, 500); + } + // handle must scroll event handleOnMustScroll(): void { const footer = this.shadowRoot?.querySelector('#chat-list-footer') as HTMLElement; if (footer) { @@ -370,7 +378,7 @@ export class ChatComponent extends LitElement { `, ); } - this.dispatchEvent(mustScrollEvent); + this.debounceDispatchMustScrollEvent(); return entries; } @@ -396,7 +404,6 @@ export class ChatComponent extends LitElement { `; } - this.dispatchEvent(mustScrollEvent); return ''; } @@ -423,7 +430,6 @@ export class ChatComponent extends LitElement { `; } - this.dispatchEvent(mustScrollEvent); return ''; } From a877fe879ad72943c38a195e4717c79b7aec82c9 Mon Sep 17 00:00:00 2001 From: Natalia Venditto Date: Sat, 4 Nov 2023 22:31:12 +0100 Subject: [PATCH 08/13] chore: remove reference to custom events util file --- packages/chat-component/src/utils/index.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/chat-component/src/utils/index.ts b/packages/chat-component/src/utils/index.ts index a38df281..2bce9d2b 100644 --- a/packages/chat-component/src/utils/index.ts +++ b/packages/chat-component/src/utils/index.ts @@ -77,8 +77,7 @@ export function getTimestamp() { }); } -// Define needs scroll event -// custom-events.js +// Define must scroll event export const mustScrollEvent = new CustomEvent('must-scroll', { bubbles: true, composed: true, From f19ba29a96f49c7c54eefe45e98e601933149cd8 Mon Sep 17 00:00:00 2001 From: Natalia Venditto Date: Mon, 6 Nov 2023 12:36:18 +0100 Subject: [PATCH 09/13] fix: replace vanilla query with Lit query --- packages/chat-component/src/main.ts | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/packages/chat-component/src/main.ts b/packages/chat-component/src/main.ts index 3924a89f..32d22812 100644 --- a/packages/chat-component/src/main.ts +++ b/packages/chat-component/src/main.ts @@ -60,6 +60,9 @@ export class ChatComponent extends LitElement { @query('#question-input') questionInput!: HTMLInputElement; + @query('#chat-list-footer') + chatFooter!: HTMLElement; + // Default prompts to display in the chat @property({ type: Boolean }) isDisabled = false; @@ -123,9 +126,8 @@ export class ChatComponent extends LitElement { } // handle must scroll event handleOnMustScroll(): void { - const footer = this.shadowRoot?.querySelector('#chat-list-footer') as HTMLElement; - if (footer) { - scrollToFooter(footer); + if (this.chatFooter) { + scrollToFooter(this.chatFooter); } } // Send the question to the Open AI API and render the answer in the chat From 88b299ab83b0122ddce3aab0fc53c8f45e487f3e Mon Sep 17 00:00:00 2001 From: Natalia Venditto Date: Mon, 6 Nov 2023 14:02:29 +0100 Subject: [PATCH 10/13] fix: remove event and utils --- packages/chat-component/src/main.ts | 18 ++++++------------ packages/chat-component/src/utils/index.ts | 11 ----------- 2 files changed, 6 insertions(+), 23 deletions(-) diff --git a/packages/chat-component/src/main.ts b/packages/chat-component/src/main.ts index 32d22812..7a91f308 100644 --- a/packages/chat-component/src/main.ts +++ b/packages/chat-component/src/main.ts @@ -7,7 +7,7 @@ import { chatHttpOptions, globalConfig, requestOptions } from './config/global-c import { getAPIResponse } from './core/http/index.js'; import { parseStreamedMessages } from './core/parser/index.js'; import { mainStyle } from './style.js'; -import { getTimestamp, processText, mustScrollEvent, scrollToFooter } from './utils/index.js'; +import { getTimestamp, processText } from './utils/index.js'; import { unsafeSVG } from 'lit/directives/unsafe-svg.js'; // TODO: allow host applications to customize these icons @@ -108,28 +108,22 @@ export class ChatComponent extends LitElement { static override styles = [mainStyle]; - override connectedCallback(): void { + /* override connectedCallback(): void { super.connectedCallback(); // add event listener to know when to scroll chat list footer into view this.addEventListener('must-scroll', () => { this.handleOnMustScroll(); }); - } + } */ // debounce dispatching must-scroll event - debounceDispatchMustScrollEvent(): void { + debounceScrollIntoView(): void { let timeout: any = 0; clearTimeout(timeout); timeout = setTimeout(() => { - this.dispatchEvent(mustScrollEvent); + this.chatFooter.scrollIntoView({ behavior: 'smooth', block: 'center' }); }, 500); } - // handle must scroll event - handleOnMustScroll(): void { - if (this.chatFooter) { - scrollToFooter(this.chatFooter); - } - } // Send the question to the Open AI API and render the answer in the chat // Add a message to the chat, when the user or the API sends a message async processApiResponse({ message, isUserMessage }: { message: string; isUserMessage: boolean }) { @@ -380,7 +374,7 @@ export class ChatComponent extends LitElement { `, ); } - this.debounceDispatchMustScrollEvent(); + this.debounceScrollIntoView(); return entries; } diff --git a/packages/chat-component/src/utils/index.ts b/packages/chat-component/src/utils/index.ts index 2bce9d2b..a0e4a98b 100644 --- a/packages/chat-component/src/utils/index.ts +++ b/packages/chat-component/src/utils/index.ts @@ -76,14 +76,3 @@ export function getTimestamp() { hour12: true, }); } - -// Define must scroll event -export const mustScrollEvent = new CustomEvent('must-scroll', { - bubbles: true, - composed: true, -}); - -// Scroll to last message -export function scrollToFooter(element: HTMLElement): void { - element.scrollIntoView({ behavior: 'smooth', block: 'center' }); -} From 2b28eadf6bb286ffea37fbbb2e0fdf13cb799dbd Mon Sep 17 00:00:00 2001 From: Natalia Venditto Date: Mon, 6 Nov 2023 14:05:23 +0100 Subject: [PATCH 11/13] chore: clean code up --- packages/chat-component/src/main.ts | 8 -------- 1 file changed, 8 deletions(-) diff --git a/packages/chat-component/src/main.ts b/packages/chat-component/src/main.ts index 7a91f308..4a559999 100644 --- a/packages/chat-component/src/main.ts +++ b/packages/chat-component/src/main.ts @@ -108,14 +108,6 @@ export class ChatComponent extends LitElement { static override styles = [mainStyle]; - /* override connectedCallback(): void { - super.connectedCallback(); - - // add event listener to know when to scroll chat list footer into view - this.addEventListener('must-scroll', () => { - this.handleOnMustScroll(); - }); - } */ // debounce dispatching must-scroll event debounceScrollIntoView(): void { let timeout: any = 0; From 36a95afed15eed5105f585af2f29eab5a0cadfa8 Mon Sep 17 00:00:00 2001 From: Natalia Venditto Date: Mon, 6 Nov 2023 14:07:13 +0100 Subject: [PATCH 12/13] chore: add test for element --- packages/chat-component/src/main.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/chat-component/src/main.ts b/packages/chat-component/src/main.ts index 4a559999..90cb2ba0 100644 --- a/packages/chat-component/src/main.ts +++ b/packages/chat-component/src/main.ts @@ -113,7 +113,9 @@ export class ChatComponent extends LitElement { let timeout: any = 0; clearTimeout(timeout); timeout = setTimeout(() => { - this.chatFooter.scrollIntoView({ behavior: 'smooth', block: 'center' }); + if (this.chatFooter) { + this.chatFooter.scrollIntoView({ behavior: 'smooth', block: 'center' }); + } }, 500); } // Send the question to the Open AI API and render the answer in the chat From 3ddf76fe1b0b6ed7d6b7f4ed41d787563899929d Mon Sep 17 00:00:00 2001 From: Natalia Venditto Date: Mon, 6 Nov 2023 14:08:51 +0100 Subject: [PATCH 13/13] chore: remove unnecessary comment --- packages/chat-component/src/main.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/chat-component/src/main.ts b/packages/chat-component/src/main.ts index 90cb2ba0..c9084371 100644 --- a/packages/chat-component/src/main.ts +++ b/packages/chat-component/src/main.ts @@ -170,7 +170,6 @@ export class ChatComponent extends LitElement { isUserMessage, }, ]; - // scroll to the bottom of the chat return true; }; @@ -368,6 +367,7 @@ export class ChatComponent extends LitElement { `, ); } + // scroll to the bottom of the chat this.debounceScrollIntoView(); return entries; }