11<script setup lang="ts">
22import { useToast } from ' @/composables/useToast' ;
33import { LOCAL_STORAGE_CHAT_HUB_SELECTED_MODEL } from ' @/constants' ;
4- import {
5- findOneFromModelsResponse ,
6- restoreConversationModelFromMessageOrSession ,
7- } from ' @/features/ai/chatHub/chat.utils' ;
4+ import { findOneFromModelsResponse , unflattenModel } from ' @/features/ai/chatHub/chat.utils' ;
85import ChatConversationHeader from ' @/features/ai/chatHub/components/ChatConversationHeader.vue' ;
96import ChatMessage from ' @/features/ai/chatHub/components/ChatMessage.vue' ;
107import ChatPrompt from ' @/features/ai/chatHub/components/ChatPrompt.vue' ;
@@ -29,7 +26,7 @@ import {
2926import { N8nIconButton , N8nScrollArea } from ' @n8n/design-system' ;
3027import { useLocalStorage , useMediaQuery , useScroll } from ' @vueuse/core' ;
3128import { v4 as uuidv4 } from ' uuid' ;
32- import { computed , ref , useTemplateRef , watch } from ' vue' ;
29+ import { computed , nextTick , ref , useTemplateRef , watch } from ' vue' ;
3330import { useRoute , useRouter } from ' vue-router' ;
3431import { useChatStore } from ' ./chat.store' ;
3532import { useDocumentTitle } from ' @/composables/useDocumentTitle' ;
@@ -60,9 +57,12 @@ const currentConversation = computed(() =>
6057 : undefined ,
6158);
6259const currentConversationTitle = computed (() => currentConversation .value ?.title );
60+ const readyToShowMessages = computed (() => chatStore .agentsReady );
6361
64- const { arrivedState } = useScroll (scrollContainerRef , { throttle: 100 , offset: { bottom: 100 } });
65-
62+ const { arrivedState, measure } = useScroll (scrollContainerRef , {
63+ throttle: 100 ,
64+ offset: { bottom: 100 },
65+ });
6666const defaultModel = useLocalStorage <ChatHubConversationModel | null >(
6767 LOCAL_STORAGE_CHAT_HUB_SELECTED_MODEL (usersStore .currentUserId ?? ' anonymous' ),
6868 null ,
@@ -109,13 +109,17 @@ const selectedModel = computed<ChatModelDto | undefined>(() => {
109109 return modelFromQuery .value ;
110110 }
111111
112- if (! currentConversation .value ?.provider ) {
113- return defaultModel .value ? chatStore .getAgent (defaultModel .value ) : undefined ;
112+ if (currentConversation .value ?.provider ) {
113+ const model = unflattenModel (currentConversation .value );
114+
115+ return model ? chatStore .getAgent (model ) : undefined ;
114116 }
115117
116- const model = restoreConversationModelFromMessageOrSession (currentConversation .value );
118+ if (chatStore .streaming ?.sessionId === sessionId .value ) {
119+ return chatStore .getAgent (chatStore .streaming .model );
120+ }
117121
118- return model ? chatStore .getAgent (model ) : undefined ;
122+ return defaultModel . value ? chatStore .getAgent (defaultModel . value ) : undefined ;
119123});
120124
121125const { credentialsByProvider, selectCredential } = useChatCredentials (
@@ -170,26 +174,22 @@ function scrollToMessage(messageId: ChatMessageId) {
170174
171175// Scroll to the bottom when a new message is added
172176watch (
173- () => chatMessages .value [chatMessages .value .length - 1 ]?.id ,
174- (lastMessageId ) => {
175- if (! lastMessageId ) {
176- return ;
177- }
178-
179- const currentMessage = chatStore .lastMessage (sessionId .value );
180- if (lastMessageId !== currentMessage ?.id ) {
181- scrollToBottom (currentMessage !== null );
177+ [readyToShowMessages , () => chatMessages .value [chatMessages .value .length - 1 ]?.id ],
178+ ([ready , lastMessageId ]) => {
179+ if (! ready || ! lastMessageId ) {
182180 return ;
183181 }
184182
185- const message = chatStore
186- .getActiveMessages (sessionId .value )
187- .find ((m ) => m .id === lastMessageId );
183+ // Prevent "scroll to bottom" button from appearing when not necessary
184+ void nextTick (measure );
188185
189- if (message ?. previousMessageId ) {
186+ if (chatStore . streaming ?. sessionId === sessionId . value ) {
190187 // Scroll to user's prompt when the message is being generated
191- scrollToMessage (message .previousMessageId );
188+ scrollToMessage (chatStore .streaming .promptId );
189+ return ;
192190 }
191+
192+ scrollToBottom (false );
193193 },
194194 { immediate: true , flush: ' post' },
195195);
@@ -286,7 +286,7 @@ function handleCancelEditMessage() {
286286
287287function handleEditMessage(message : ChatHubMessageDto ) {
288288 if (
289- chatStore . isResponding ( message . sessionId ) ||
289+ isResponding . value ||
290290 ! [' human' , ' ai' ].includes (message .type ) ||
291291 ! selectedModel .value ||
292292 ! credentialsForSelectedProvider .value
@@ -308,7 +308,7 @@ function handleEditMessage(message: ChatHubMessageDto) {
308308
309309function handleRegenerateMessage(message : ChatHubMessageDto ) {
310310 if (
311- chatStore . isResponding ( message . sessionId ) ||
311+ isResponding . value ||
312312 message .type !== ' ai' ||
313313 ! selectedModel .value ||
314314 ! credentialsForSelectedProvider .value
@@ -400,7 +400,7 @@ function closeAgentEditor() {
400400 />
401401
402402 <N8nScrollArea
403- v-if =" chatStore.agentsReady "
403+ v-if =" readyToShowMessages "
404404 type =" scroll"
405405 :enable-vertical-scroll =" true"
406406 :enable-horizontal-scroll =" false"
0 commit comments