feat(chat): chat preference to disable smooth streaming (#10460) to release v3.2 (#10468)

This commit is contained in:
Nikolas Garza authored and GitHub committed 2026-04-22 13:08:33 -07:00
1 parent 7cce3b8987
commit 9840afa912
4 files changed
+66 -1

No files matched your search

@@ -28,6 +28,7 @@ import { CodeBlock } from "@/app/app/message/CodeBlock";
import { InMessageImage } from "@/app/app/components/files/images/InMessageImage";
import { extractChatImageFileId } from "@/app/app/components/files/images/utils";
import { cn, transformLinkUri } from "@/lib/utils";
import { useSmoothStreaming } from "@/hooks/useSmoothStreaming";
/** Maps a visible-char count to a markdown index (skips formatting chars,
* extends to word boundary). Used by the voice-sync reveal path only. */
@@ -96,6 +97,8 @@ export const MessageTextRenderer: MessageRenderer<
stopReason,
children,
}) => {
const { enabled: smoothStreamingEnabled } = useSmoothStreaming();
const lastStableSyncedContentRef = useRef("");
const lastVisibleContentRef = useRef("");
@@ -247,7 +250,8 @@ export const MessageTextRenderer: MessageRenderer<
const isStreamingAnimationEnabled =
animate &&
!shouldUseAutoPlaybackSync &&
stopReason !== StopReason.USER_CANCELLED;
stopReason !== StopReason.USER_CANCELLED &&
smoothStreamingEnabled;
const isStreamFinished = isFinalAnswerComplete(packets);
+42
View File
@@ -0,0 +1,42 @@
import Cookies from "js-cookie";
import { useCallback, useEffect, useState } from "react";
import { SMOOTH_STREAMING_COOKIE_NAME } from "@/lib/constants";
const CHANGE_EVENT = "smoothStreaming:change";
const DEFAULT_ENABLED = true;
const COOKIE_EXPIRES_DAYS = 365;
function readCookie(): boolean {
const value = Cookies.get(SMOOTH_STREAMING_COOKIE_NAME);
if (value === undefined) return DEFAULT_ENABLED;
return value !== "false";
}
interface UseSmoothStreamingResult {
enabled: boolean;
setEnabled: (next: boolean) => void;
}
export function useSmoothStreaming(): UseSmoothStreamingResult {
const [enabled, setEnabledState] = useState<boolean>(() =>
typeof window === "undefined" ? DEFAULT_ENABLED : readCookie()
);
useEffect(() => {
setEnabledState(readCookie());
const handler = () => setEnabledState(readCookie());
window.addEventListener(CHANGE_EVENT, handler);
return () => window.removeEventListener(CHANGE_EVENT, handler);
}, []);
const setEnabled = useCallback((next: boolean) => {
Cookies.set(SMOOTH_STREAMING_COOKIE_NAME, String(next), {
expires: COOKIE_EXPIRES_DAYS,
});
setEnabledState(next);
window.dispatchEvent(new Event(CHANGE_EVENT));
}, []);
return { enabled, setEnabled };
}
+4
View File
@@ -81,6 +81,10 @@ export const NEXT_PUBLIC_FORGOT_PASSWORD_ENABLED =
export const NEXT_PUBLIC_TEST_ENV =
process.env.NEXT_PUBLIC_TEST_ENV?.toLowerCase() === "true";
// Cookie controlling the per-character typewriter reveal in chat.
// "false" disables smooth streaming — chunks render as they arrive.
export const SMOOTH_STREAMING_COOKIE_NAME = "smoothStreamingEnabled";
export const NEXT_PUBLIC_INCLUDE_ERROR_POPUP_SUPPORT_LINK =
process.env.NEXT_PUBLIC_INCLUDE_ERROR_POPUP_SUPPORT_LINK?.toLowerCase() ===
"true";
+15
View File
@@ -63,6 +63,7 @@ import { usePaidEnterpriseFeaturesEnabled } from "@/components/settings/usePaidE
import { useSettingsContext } from "@/providers/SettingsProvider";
import SimpleTooltip from "@/refresh-components/SimpleTooltip";
import { useCloudSubscription } from "@/hooks/useCloudSubscription";
import { useSmoothStreaming } from "@/hooks/useSmoothStreaming";
interface PAT {
id: number;
@@ -755,6 +756,10 @@ function ChatPreferencesSettings() {
const settings = useSettingsContext();
const { isSearchModeAvailable: searchUiEnabled } = settings;
const llmManager = useLlmManager();
const {
enabled: smoothStreamingEnabled,
setEnabled: setSmoothStreamingEnabled,
} = useSmoothStreaming();
const {
personalizationValues,
@@ -850,6 +855,16 @@ function ChatPreferencesSettings() {
/>
</InputLayouts.Horizontal>
<InputLayouts.Horizontal
title="Smooth Streaming"
description="Animate streamed responses character-by-character. Disable to render chunks as they arrive."
>
<Switch
checked={smoothStreamingEnabled}
onCheckedChange={setSmoothStreamingEnabled}
/>
</InputLayouts.Horizontal>
{isPaidEnterpriseFeaturesEnabled && (
<SimpleTooltip
tooltip={