11<script setup lang="ts">
22import type { ChatAssistantMessage , ChatHistoryItem , ContextMessage } from ' ../../../../types/chat'
33
4- import { computed , onMounted , provide , ref , watch } from ' vue'
4+ import { computed , provide , ref } from ' vue'
55import { useI18n } from ' vue-i18n'
66
77import ChatAssistantItem from ' ./assistant-item.vue'
88import ChatErrorItem from ' ./error-item.vue'
99import ChatUserItem from ' ./user-item.vue'
1010
11+ import { useChatHistoryScroll } from ' ../composables/use-chat-history-scroll'
1112import { chatScrollContainerKey } from ' ../constants'
1213import { getChatHistoryItemKey } from ' ../utils'
1314
@@ -39,21 +40,6 @@ const labels = computed(() => ({
3940 error: props .errorLabel ?? t (' stage.chat.message.character-name.core-system' ),
4041}))
4142
42- function scrollToBottom() {
43- requestAnimationFrame (() => {
44- requestAnimationFrame (() => {
45- if (! chatHistoryRef .value )
46- return
47-
48- chatHistoryRef .value .scrollTop = chatHistoryRef .value .scrollHeight
49- })
50- })
51- }
52-
53- watch ([() => props .messages , () => props .streamingMessage ], scrollToBottom , { deep: true , flush: ' post' })
54- watch (() => props .sending , scrollToBottom , { flush: ' post' })
55- onMounted (scrollToBottom )
56-
5743const streaming = computed <ChatAssistantMessage & { context? : ContextMessage } & { createdAt? : number }>(() => props .streamingMessage ?? { role: ' assistant' , content: ' ' , slices: [], tool_results: [], createdAt: Date .now () })
5844const showStreamingPlaceholder = computed (() => (streaming .value .slices ?.length ?? 0 ) === 0 && ! streaming .value .content )
5945const streamingTs = computed (() => streaming .value ?.createdAt )
@@ -79,6 +65,12 @@ const renderMessages = computed<ChatHistoryItem[]>(() => {
7965 return [... props .messages , streaming .value ]
8066})
8167
68+ useChatHistoryScroll ({
69+ containerRef: chatHistoryRef ,
70+ messages: renderMessages ,
71+ getKey: getChatHistoryItemKey ,
72+ })
73+
8274function emitCopyMessage(message : ChatHistoryItem , index : number ) {
8375 emit (' copyMessage' , {
8476 message ,
@@ -99,30 +91,31 @@ function emitDeleteMessage(message: ChatHistoryItem, index: number) {
9991<template >
10092 <div ref =" chatHistoryRef" v-auto-animate flex =" ~ col" relative h-full w-full overflow-y-auto rounded-xl px =" <sm:2" py =" <sm:2" :class =" variant === 'mobile' ? 'gap-1' : 'gap-2'" >
10193 <template v-for =" (message , index ) in renderMessages " :key =" getChatHistoryItemKey (message , index )" >
102- <div v-if =" message.role === 'error'" >
94+ <div
95+ :data-chat-message-index =" index"
96+ :data-chat-message-key =" String(getChatHistoryItemKey(message, index))"
97+ :data-chat-message-role =" message.role"
98+ >
10399 <ChatErrorItem
100+ v-if =" message.role === 'error'"
104101 :message =" message"
105102 :label =" labels.error"
106103 :show-placeholder =" sending && index === renderMessages.length - 1"
107104 :variant =" variant"
108105 @copy =" emitCopyMessage(message, index)"
109106 @delete =" emitDeleteMessage(message, index)"
110107 />
111- </div >
112-
113- <div v-else-if =" message.role === 'assistant'" >
114108 <ChatAssistantItem
109+ v-else-if =" message.role === 'assistant'"
115110 :message =" message"
116111 :label =" labels.assistant"
117112 :show-placeholder =" shouldShowPlaceholder(message) && showStreamingPlaceholder"
118113 :variant =" variant"
119114 @copy =" emitCopyMessage(message, index)"
120115 @delete =" emitDeleteMessage(message, index)"
121116 />
122- </div >
123-
124- <div v-else-if =" message.role === 'user'" >
125117 <ChatUserItem
118+ v-else-if =" message.role === 'user'"
126119 :message =" message"
127120 :label =" labels.user"
128121 :variant =" variant"
0 commit comments