Skip to content

Commit 1ed9235

Browse files
committed
feat: optimize code blocker
1 parent a7c6bdd commit 1ed9235

File tree

1 file changed

+51
-2
lines changed

1 file changed

+51
-2
lines changed

src/renderer/src/components/message/MessageList.vue

Lines changed: 51 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
ref="dynamicScrollerRef"
55
class="message-list-container relative flex-1 scrollbar-hide overflow-y-auto w-full h-full pr-12 lg:pr-12 transition-opacity duration-300"
66
:class="{ 'opacity-0': !visible }"
7-
:items="items"
7+
:items="virtualItems"
88
list-class="w-full pt-4"
99
:min-item-size="48"
1010
:buffer="200"
@@ -44,6 +44,21 @@
4444
</DynamicScrollerItem>
4545
</template>
4646
<template #after>
47+
<template :active="false" v-for="streamItem in streamingTailItems" :key="streamItem.id">
48+
<div
49+
v-if="streamItem.message?.role === 'assistant'"
50+
@mouseenter="minimap.handleHover(streamItem.id)"
51+
@mouseleave="minimap.handleHover(null)"
52+
>
53+
<MessageItemAssistant
54+
:message="streamItem.message as AssistantMessage"
55+
:is-capturing-image="capture.isCapturing.value"
56+
@copy-image="handleCopyImage"
57+
@variant-changed="wrapScrollToMessage"
58+
@trace="handleTrace"
59+
/>
60+
</div>
61+
</template>
4762
<div ref="scrollAnchor" class="h-8" />
4863
</template>
4964
</DynamicScroller>
@@ -175,6 +190,36 @@ const minimapMessages = computed(() => {
175190
return chatStore.variantAwareMessages
176191
})
177192
193+
const isStreamingMessage = (message: Message) => {
194+
if (message.role !== 'assistant') return false
195+
if (message.status === 'pending') return true
196+
197+
const blocks = (message as AssistantMessage).content
198+
if (!Array.isArray(blocks)) return false
199+
return blocks.some((block) =>
200+
['loading', 'reading', 'optimizing', 'pending'].includes(block.status)
201+
)
202+
}
203+
204+
const streamingTailItems = computed(() => {
205+
const tail: MessageListItem[] = []
206+
for (let index = props.items.length - 1; index >= 0; index--) {
207+
const item = props.items[index]
208+
const message = item.message
209+
if (!message || !isStreamingMessage(message)) break
210+
tail.unshift(item)
211+
}
212+
return tail
213+
})
214+
215+
const streamingTailIds = computed(() => new Set(streamingTailItems.value.map((item) => item.id)))
216+
217+
const virtualItems = computed(() => {
218+
const streamingIds = streamingTailIds.value
219+
if (!streamingIds.size) return props.items
220+
return props.items.filter((item) => !streamingIds.has(item.id))
221+
})
222+
178223
// === Constants ===
179224
const HIGHLIGHT_CLASS = 'selection-highlight'
180225
const HIGHLIGHT_ACTIVE_CLASS = 'selection-highlight-active'
@@ -554,7 +599,7 @@ const refreshVirtualScroller = async (messageId?: string) => {
554599
await new Promise((resolve) => requestAnimationFrame(resolve))
555600
556601
const scroller = dynamicScrollerRef.value
557-
if (messageId && scroller?.scrollToItem) {
602+
if (messageId && !streamingTailIds.value.has(messageId) && scroller?.scrollToItem) {
558603
const index = props.items.findIndex((item) => item.id === messageId)
559604
if (index !== -1) {
560605
scroller.scrollToItem(index)
@@ -566,6 +611,10 @@ const refreshVirtualScroller = async (messageId?: string) => {
566611
567612
const wrapScrollToMessage = async (messageId: string) => {
568613
void chatStore.ensureMessagesLoadedByIds([messageId])
614+
if (streamingTailIds.value.has(messageId)) {
615+
scrollToBottom(true)
616+
return
617+
}
569618
scrollToMessage(messageId, () => props.items)
570619
await refreshVirtualScroller(messageId)
571620
}

0 commit comments

Comments
 (0)