mirror of
https://github.com/Sea-Haven-Industries/open-swe.git
synced 2026-10-05 06:02:15 +00:00
fix: contain markdown render crashes with an error boundary (#1586)
Streamdown bundles Mermaid and renders ```mermaid blocks itself; a diagram it can't parse throws during render and, with no boundary, white-screens the whole review page. Wrap the markdown render so any crash falls back to the raw text instead. Co-authored-by: open-swe[bot] <open-swe@users.noreply.github.com>
This commit is contained in:
parent
f54fc154ca
commit
609e5551c4
1 changed files with 54 additions and 12 deletions
|
|
@ -1,4 +1,4 @@
|
||||||
import { memo, useMemo } from "react";
|
import { Component, memo, useMemo } from "react";
|
||||||
import { Streamdown } from "streamdown";
|
import { Streamdown } from "streamdown";
|
||||||
import type { ReactNode } from "react";
|
import type { ReactNode } from "react";
|
||||||
import "streamdown/styles.css";
|
import "streamdown/styles.css";
|
||||||
|
|
@ -76,6 +76,46 @@ const STREAMDOWN_COMPONENTS = {
|
||||||
|
|
||||||
const SHIKI_THEME: ["github-light", "github-dark"] = ["github-light", "github-dark"];
|
const SHIKI_THEME: ["github-light", "github-dark"] = ["github-light", "github-dark"];
|
||||||
|
|
||||||
|
interface BoundaryProps {
|
||||||
|
content: string;
|
||||||
|
children: ReactNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface BoundaryState {
|
||||||
|
failed: boolean;
|
||||||
|
key: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Streamdown bundles Mermaid and renders ```mermaid blocks itself; a diagram it
|
||||||
|
// can't parse throws during render and, with no boundary, white-screens the
|
||||||
|
// whole page. Contain it and fall back to the raw markdown text.
|
||||||
|
class MarkdownErrorBoundary extends Component<BoundaryProps, BoundaryState> {
|
||||||
|
state: BoundaryState = { failed: false, key: this.props.content };
|
||||||
|
|
||||||
|
static getDerivedStateFromError(): Partial<BoundaryState> {
|
||||||
|
return { failed: true };
|
||||||
|
}
|
||||||
|
|
||||||
|
static getDerivedStateFromProps(
|
||||||
|
props: BoundaryProps,
|
||||||
|
state: BoundaryState
|
||||||
|
): Partial<BoundaryState> | null {
|
||||||
|
if (props.content !== state.key) return { failed: false, key: props.content };
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
render(): ReactNode {
|
||||||
|
if (this.state.failed) {
|
||||||
|
return (
|
||||||
|
<pre className="whitespace-pre-wrap break-words [overflow-wrap:anywhere] font-sans text-[color:var(--ui-text)]">
|
||||||
|
{this.props.content}
|
||||||
|
</pre>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return this.props.children;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export const Markdown = memo(function Markdown({
|
export const Markdown = memo(function Markdown({
|
||||||
content,
|
content,
|
||||||
isLive = false,
|
isLive = false,
|
||||||
|
|
@ -99,17 +139,19 @@ export const Markdown = memo(function Markdown({
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="min-w-0 max-w-full text-[13px] leading-6 break-words [overflow-wrap:anywhere] [&_.streamdown]:text-[color:var(--ui-text)]">
|
<div className="min-w-0 max-w-full text-[13px] leading-6 break-words [overflow-wrap:anywhere] [&_.streamdown]:text-[color:var(--ui-text)]">
|
||||||
<Streamdown
|
<MarkdownErrorBoundary content={content}>
|
||||||
mode={isLive ? "streaming" : "static"}
|
<Streamdown
|
||||||
parseIncompleteMarkdown={isLive}
|
mode={isLive ? "streaming" : "static"}
|
||||||
isAnimating={isLive}
|
parseIncompleteMarkdown={isLive}
|
||||||
animated={isLive ? STREAMDOWN_ANIMATED : false}
|
isAnimating={isLive}
|
||||||
shikiTheme={SHIKI_THEME}
|
animated={isLive ? STREAMDOWN_ANIMATED : false}
|
||||||
className="streamdown-agent min-w-0 max-w-full"
|
shikiTheme={SHIKI_THEME}
|
||||||
components={components}
|
className="streamdown-agent min-w-0 max-w-full"
|
||||||
>
|
components={components}
|
||||||
{content}
|
>
|
||||||
</Streamdown>
|
{content}
|
||||||
|
</Streamdown>
|
||||||
|
</MarkdownErrorBoundary>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue