Skip to content

Commit 7342f9e

Browse files
authored
fix: optimize chat UI performance and message handling (#869)
1 parent 68dc2eb commit 7342f9e

File tree

5 files changed

+40
-45
lines changed

5 files changed

+40
-45
lines changed

src/api/providers/zgsm.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -378,7 +378,7 @@ export class ZgsmAiHandler extends BaseProvider implements SingleCompletionHandl
378378
convertedMessages = convertToR1Format([{ role: "user", content: systemPrompt }, ...messages])
379379
} else if (isArk || isLegacyFormat) {
380380
convertedMessages = [{ role: "system", content: systemPrompt }, ...convertToSimpleMessages(messages)]
381-
} else if (_mid?.includes("glm-4.7")) {
381+
} else if (_mid?.includes("glm") || isMiniMax || _mid?.includes("claude")) {
382382
convertedMessages = [
383383
{ role: "system", content: systemPrompt },
384384
...convertToZAiFormat(messages, { mergeToolResultText: true }),

webview-ui/src/components/chat/ChatRow.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1501,7 +1501,7 @@ export const ChatRowContent = ({
15011501
case "api_req_finished":
15021502
return null // we should never see this message type
15031503
case "text":
1504-
return (
1504+
return !message?.text?.trim() ? null : (
15051505
<div>
15061506
<div style={headerStyle}>
15071507
<MessageCircle className="w-4 shrink-0" aria-label="Speech bubble icon" />

webview-ui/src/components/chat/ChatView.tsx

Lines changed: 21 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1227,23 +1227,28 @@ const ChatViewComponent: React.ForwardRefRenderFunction<ChatViewRef, ChatViewPro
12271227
[handleSetExpandedRow],
12281228
)
12291229

1230-
const handleRowHeightChange = useCallback(
1231-
(isTaller: boolean) => {
1232-
// Don't auto-scroll if the user is actively expanding/collapsing content
1233-
// This prevents scroll conflicts when user manually expands the last message
1234-
// or expands Markdown content
1235-
if (userExpandingRef.current || markdownExpandingRef.current) {
1236-
return
1237-
}
1230+
const handleRowHeightChange = useMemo(
1231+
() =>
1232+
debounce(
1233+
(isTaller: boolean) => {
1234+
// Don't auto-scroll if the user is actively expanding/collapsing content
1235+
// This prevents scroll conflicts when user manually expands the last message
1236+
// or expands Markdown content
1237+
if (userExpandingRef.current || markdownExpandingRef.current) {
1238+
return
1239+
}
12381240

1239-
if (isAtBottom) {
1240-
if (isTaller) {
1241-
scrollToBottomSmooth()
1242-
} else {
1243-
setTimeout(() => scrollToBottomAuto(), 0)
1244-
}
1245-
}
1246-
},
1241+
if (isAtBottom) {
1242+
if (isTaller) {
1243+
scrollToBottomSmooth()
1244+
} else {
1245+
setTimeout(() => scrollToBottomAuto(), 0)
1246+
}
1247+
}
1248+
},
1249+
100, // 50ms debounce to batch rapid height changes
1250+
{ immediate: false },
1251+
),
12471252
[scrollToBottomSmooth, scrollToBottomAuto, isAtBottom],
12481253
)
12491254

webview-ui/src/components/chat/ReasoningBlock.tsx

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -57,12 +57,7 @@ export const ReasoningBlock = ({ content, isStreaming, isLast }: ReasoningBlockP
5757
)}
5858
</div>
5959
<div className="flex items-center gap-2">
60-
<ChevronUp
61-
className={cn(
62-
"w-4 transition-all opacity-0 group-hover:opacity-100",
63-
isCollapsed && "-rotate-180",
64-
)}
65-
/>
60+
<ChevronUp className={cn("w-4 transition-all", isCollapsed && "-rotate-180")} />
6661
</div>
6762
</div>
6863
{(content?.trim()?.length ?? 0) > 0 && !isCollapsed && (

webview-ui/src/components/common/CodeBlock.tsx

Lines changed: 16 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { memo, useEffect, useRef, useCallback, useState } from "react"
22
import styled from "styled-components"
33
import { useCopyToClipboard } from "@src/utils/clipboard"
4+
import { useDebounceEffect } from "@src/utils/useDebounceEffect"
45
import { getHighlighter, isLanguageLoaded, normalizeLanguage } from "@src/utils/highlighter"
56
import type { ShikiTransformer } from "shiki"
67
import { toJsxRuntime } from "hast-util-to-jsx-runtime"
@@ -290,14 +291,19 @@ const CodeBlock = memo(
290291
}, [source, currentLanguage, collapsedHeight])
291292

292293
// Check if content height exceeds collapsed height whenever content changes
293-
useEffect(() => {
294-
const codeBlock = codeBlockRef.current
294+
// Debounced to avoid excessive DOM measurements during rapid scrolling
295+
useDebounceEffect(
296+
() => {
297+
const codeBlock = codeBlockRef.current
295298

296-
if (codeBlock) {
297-
const actualHeight = codeBlock.scrollHeight
298-
setShowCollapseButton(actualHeight >= WINDOW_SHADE_SETTINGS.collapsedHeight)
299-
}
300-
}, [highlightedCode])
299+
if (codeBlock) {
300+
const actualHeight = codeBlock.scrollHeight
301+
setShowCollapseButton(actualHeight >= WINDOW_SHADE_SETTINGS.collapsedHeight)
302+
}
303+
},
304+
100, // 100ms debounce delay
305+
[highlightedCode],
306+
)
301307

302308
// Ref to track if user was scrolled up *before* the source update
303309
// potentially changes scrollHeight
@@ -658,29 +664,18 @@ const CodeBlock = memo(
658664
side="top">
659665
<CodeBlockButton
660666
onClick={() => {
661-
// Get the current code block element
662-
const codeBlock = codeBlockRef.current // Capture ref early
663667
// Toggle window shade state
664668
setWindowShade(!windowShade)
665669

666670
// Clear any previous timeouts
667671
if (collapseTimeout1Ref.current) clearTimeout(collapseTimeout1Ref.current)
668672
if (collapseTimeout2Ref.current) clearTimeout(collapseTimeout2Ref.current)
669673

670-
// After UI updates, ensure code block is visible and update button position
674+
// After UI transition completes, update button position
675+
// Let ChatView/Virtuoso handle scrolling to avoid conflicts
671676
collapseTimeout1Ref.current = setTimeout(
672677
() => {
673-
if (codeBlock) {
674-
// Check if codeBlock element still exists
675-
codeBlock.scrollIntoView({ behavior: "smooth", block: "nearest" })
676-
677-
// Wait for scroll to complete before updating button position
678-
collapseTimeout2Ref.current = setTimeout(() => {
679-
// updateCodeBlockButtonPosition itself should also check for refs if needed
680-
updateCodeBlockButtonPosition()
681-
collapseTimeout2Ref.current = null
682-
}, 50)
683-
}
678+
updateCodeBlockButtonPosition()
684679
collapseTimeout1Ref.current = null
685680
},
686681
WINDOW_SHADE_SETTINGS.transitionDelayS * 1000 + 50,

0 commit comments

Comments
 (0)