1- import React , { useCallback , useEffect , useContext } from 'react' ;
1+ import React , { useCallback , useEffect , useContext , useRef } from 'react' ;
22import type { AssistantMessage } from '../compass-assistant-provider' ;
33import { AssistantActionsContext } from '../compass-assistant-provider' ;
44import type { Chat } from '../@ai-sdk/react/chat-react' ;
@@ -211,6 +211,10 @@ export const AssistantChat: React.FunctionComponent<AssistantChatProps> = ({
211211} ) => {
212212 const track = useTelemetry ( ) ;
213213 const darkMode = useDarkMode ( ) ;
214+ const messagesContainerRef = useRef < HTMLDivElement > ( null ) ;
215+ const previousLastMessageId = useRef < string | undefined > ( undefined ) ;
216+ const { id : lastMessageId , role : lastMessageRole } =
217+ chat . messages [ chat . messages . length - 1 ] ?? { } ;
214218
215219 const { ensureOptInAndSend } = useContext ( AssistantActionsContext ) ;
216220 const { messages, status, error, clearError, setMessages } = useChat ( {
@@ -222,6 +226,26 @@ export const AssistantChat: React.FunctionComponent<AssistantChatProps> = ({
222226 } ,
223227 } ) ;
224228
229+ const scrollToBottom = useCallback ( ( ) => {
230+ if ( messagesContainerRef . current ) {
231+ // Since the container uses flexDirection: 'column-reverse',
232+ // scrolling to the bottom means setting scrollTop to 0
233+ messagesContainerRef . current . scrollTop = 0 ;
234+ }
235+ } , [ ] ) ;
236+
237+ useEffect ( ( ) => {
238+ if (
239+ lastMessageId &&
240+ previousLastMessageId . current !== undefined &&
241+ lastMessageId !== previousLastMessageId . current &&
242+ lastMessageRole === 'user'
243+ ) {
244+ scrollToBottom ( ) ;
245+ }
246+ previousLastMessageId . current = lastMessageId ;
247+ } , [ lastMessageId , lastMessageRole , scrollToBottom ] ) ;
248+
225249 useEffect ( ( ) => {
226250 const hasExistingNonGenuineWarning = chat . messages . some (
227251 ( message ) => message . id === 'non-genuine-warning'
@@ -240,17 +264,18 @@ export const AssistantChat: React.FunctionComponent<AssistantChatProps> = ({
240264 } , [ hasNonGenuineConnections , chat , setMessages ] ) ;
241265
242266 const handleMessageSend = useCallback (
243- ( messageBody : string ) => {
267+ async ( messageBody : string ) => {
244268 const trimmedMessageBody = messageBody . trim ( ) ;
245269 if ( trimmedMessageBody ) {
270+ await chat . stop ( ) ;
246271 void ensureOptInAndSend ?.( { text : trimmedMessageBody } , { } , ( ) => {
247272 track ( 'Assistant Prompt Submitted' , {
248273 user_input_length : trimmedMessageBody . length ,
249274 } ) ;
250275 } ) ;
251276 }
252277 } ,
253- [ track , ensureOptInAndSend ]
278+ [ track , ensureOptInAndSend , chat ]
254279 ) ;
255280
256281 const handleFeedback = useCallback (
@@ -351,6 +376,7 @@ export const AssistantChat: React.FunctionComponent<AssistantChatProps> = ({
351376 < div
352377 data-testid = "assistant-chat-messages"
353378 className = { messageFeedFixesStyles }
379+ ref = { messagesContainerRef }
354380 >
355381 < div className = { messagesWrapStyles } >
356382 { messages . map ( ( message , index ) => {
@@ -450,7 +476,9 @@ export const AssistantChat: React.FunctionComponent<AssistantChatProps> = ({
450476 < div className = { inputBarStyleFixes } >
451477 < InputBar
452478 data-testid = "assistant-chat-input"
453- onMessageSend = { handleMessageSend }
479+ onMessageSend = { ( messageBody ) =>
480+ void handleMessageSend ( messageBody )
481+ }
454482 state = { status === 'submitted' ? 'loading' : undefined }
455483 textareaProps = { {
456484 placeholder : 'Ask a question' ,
0 commit comments