feat(chat): smooth streaming output
This commit is contained in:
@@ -21,7 +21,9 @@ type AgentWorkspaceProps = {
|
||||
messages: Message[];
|
||||
isStreaming: boolean;
|
||||
isLoadingSession?: boolean;
|
||||
scrollContainerRef?: React.RefObject<HTMLDivElement | null>;
|
||||
bottomRef: React.RefObject<HTMLDivElement | null>;
|
||||
onScrollStateChange?: (isNearBottom: boolean) => void;
|
||||
speakingMessageId: string | null;
|
||||
speechState: SpeechState;
|
||||
onSpeak: (messageId: string, text: string) => void;
|
||||
@@ -51,6 +53,9 @@ type TurnListProps = {
|
||||
onRejectQuestion: (requestId: string) => void;
|
||||
};
|
||||
|
||||
const STREAMING_BOTTOM_RESERVE_PX = 180;
|
||||
const STREAMING_NEAR_BOTTOM_THRESHOLD_PX = STREAMING_BOTTOM_RESERVE_PX + 120;
|
||||
|
||||
const sameMessages = (left: Message[], right: Message[]) =>
|
||||
left.length === right.length &&
|
||||
left.every((message, index) => message === right[index]);
|
||||
@@ -293,7 +298,9 @@ export const AgentWorkspace = ({
|
||||
messages,
|
||||
isStreaming,
|
||||
isLoadingSession = false,
|
||||
scrollContainerRef,
|
||||
bottomRef,
|
||||
onScrollStateChange,
|
||||
speakingMessageId,
|
||||
speechState,
|
||||
onSpeak,
|
||||
@@ -321,9 +328,24 @@ export const AgentWorkspace = ({
|
||||
: undefined;
|
||||
const historyMessages =
|
||||
streamingMessage !== undefined ? messages.slice(0, -1) : messages;
|
||||
const handleScroll = React.useCallback(
|
||||
(event: React.UIEvent<HTMLDivElement>) => {
|
||||
if (!onScrollStateChange) return;
|
||||
const target = event.currentTarget;
|
||||
const distanceToBottom =
|
||||
target.scrollHeight - target.scrollTop - target.clientHeight;
|
||||
onScrollStateChange(
|
||||
distanceToBottom <
|
||||
(isStreaming ? STREAMING_NEAR_BOTTOM_THRESHOLD_PX : 96),
|
||||
);
|
||||
},
|
||||
[isStreaming, onScrollStateChange],
|
||||
);
|
||||
|
||||
return (
|
||||
<Box
|
||||
ref={scrollContainerRef}
|
||||
onScroll={handleScroll}
|
||||
sx={{
|
||||
flex: 1,
|
||||
overflowY: "auto",
|
||||
@@ -331,6 +353,7 @@ export const AgentWorkspace = ({
|
||||
py: 2,
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
scrollbarGutter: "stable",
|
||||
zIndex: 5,
|
||||
}}
|
||||
>
|
||||
@@ -346,7 +369,7 @@ export const AgentWorkspace = ({
|
||||
<Box sx={{ display: "flex", flexDirection: "column", gap: 2 }}>
|
||||
<TurnList
|
||||
messages={historyMessages}
|
||||
isStreaming={isStreaming}
|
||||
isStreaming={false}
|
||||
speakingMessageId={speakingMessageId}
|
||||
speechState={speechState}
|
||||
onSpeak={onSpeak}
|
||||
@@ -361,21 +384,23 @@ export const AgentWorkspace = ({
|
||||
/>
|
||||
|
||||
{streamingMessage ? (
|
||||
<TurnList
|
||||
messages={[streamingMessage]}
|
||||
isStreaming={isStreaming}
|
||||
speakingMessageId={speakingMessageId}
|
||||
speechState={speechState}
|
||||
onSpeak={onSpeak}
|
||||
onPauseSpeech={onPauseSpeech}
|
||||
onResumeSpeech={onResumeSpeech}
|
||||
onStopSpeech={onStopSpeech}
|
||||
isTtsSupported={isTtsSupported}
|
||||
onCreateBranch={onCreateBranch}
|
||||
onReplyPermission={onReplyPermission}
|
||||
onReplyQuestion={onReplyQuestion}
|
||||
onRejectQuestion={onRejectQuestion}
|
||||
/>
|
||||
<Box sx={{ width: "100%" }}>
|
||||
<TurnList
|
||||
messages={[streamingMessage]}
|
||||
isStreaming={isStreaming}
|
||||
speakingMessageId={speakingMessageId}
|
||||
speechState={speechState}
|
||||
onSpeak={onSpeak}
|
||||
onPauseSpeech={onPauseSpeech}
|
||||
onResumeSpeech={onResumeSpeech}
|
||||
onStopSpeech={onStopSpeech}
|
||||
isTtsSupported={isTtsSupported}
|
||||
onCreateBranch={onCreateBranch}
|
||||
onReplyPermission={onReplyPermission}
|
||||
onReplyQuestion={onReplyQuestion}
|
||||
onRejectQuestion={onRejectQuestion}
|
||||
/>
|
||||
</Box>
|
||||
) : null}
|
||||
</Box>
|
||||
) : null}
|
||||
@@ -403,7 +428,13 @@ export const AgentWorkspace = ({
|
||||
</motion.div>
|
||||
) : null}
|
||||
|
||||
<div ref={bottomRef} style={{ height: 1 }} />
|
||||
<div
|
||||
ref={bottomRef}
|
||||
style={{
|
||||
flexShrink: 0,
|
||||
height: isStreaming ? STREAMING_BOTTOM_RESERVE_PX : 1,
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user