fix(site): enable streaming-mode Streamdown for live chat output (#23676)

This commit is contained in:
Danielle Maywood
2026-03-26 15:22:54 +00:00
committed by GitHub
parent 249ef7c567
commit 5c7057a67f
3 changed files with 49 additions and 1 deletions
@@ -103,3 +103,39 @@ export const JsxInProse: Story = {
expect(marker2).toBeInTheDocument();
},
};
// Verifies that streaming mode closes incomplete inline markdown via
// remend so the user never sees raw syntax during the reveal animation.
export const StreamingInlineMarkdown: Story = {
args: {
children: "This is **bold text that has not been close",
streaming: true,
},
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
// remend should close the unclosed ** so the text renders
// as <strong>, not as a raw "**" literal.
const el = await canvas.findByText(/bold text/);
expect(el).toBeInTheDocument();
// The raw double-asterisk should not appear as visible text.
const bodyText = canvasElement.textContent ?? "";
expect(bodyText).not.toContain("**");
},
};
// Verifies that an incomplete fenced code block in streaming mode
// renders inside a code element rather than showing raw backticks.
export const StreamingCodeFence: Story = {
args: {
children: "```ts\nconst x = 1",
streaming: true,
},
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
const codeContent = await canvas.findByText(/const x = 1/);
expect(codeContent).toBeInTheDocument();
// The raw triple-backtick should not appear as visible text.
const bodyText = canvasElement.textContent ?? "";
expect(bodyText).not.toContain("```");
},
};
@@ -15,6 +15,10 @@ import { cn } from "utils/cn";
interface ResponseProps extends Omit<ComponentPropsWithRef<"div">, "children"> {
children: string;
urlTransform?: UrlTransform;
/** Enable streaming-mode Streamdown with incomplete-markdown
* preprocessing (remend) and useTransition-based render
* scheduling. Pass true only for live-streaming output. */
streaming?: boolean;
}
// Omit rehype-raw so HTML-like syntax in LLM output is rendered as
@@ -231,6 +235,7 @@ export const Response = ({
children,
ref,
urlTransform,
streaming,
...props
}: ResponseProps) => {
const theme = useTheme();
@@ -253,6 +258,8 @@ export const Response = ({
components={components}
urlTransform={urlTransform}
rehypePlugins={chatRehypePlugins}
mode={streaming ? "streaming" : "static"}
parseIncompleteMarkdown={streaming}
>
{children}
</Streamdown>
@@ -69,6 +69,7 @@ const ReasoningDisclosure: FC<{
<Response
className="text-[11px] text-content-secondary"
urlTransform={urlTransform}
streaming={isStreaming}
>
{displayText}
</Response>
@@ -117,7 +118,11 @@ const SmoothedResponse: FC<{
bypassSmoothing: false,
streamKey,
});
return <Response urlTransform={urlTransform}>{visibleText}</Response>;
return (
<Response streaming urlTransform={urlTransform}>
{visibleText}
</Response>
);
};
const InlineTextAttachmentButton: FC<{