diff --git a/apps/ai-game-creator-shell/src/components/ChatMarkdownMessage/index.tsx b/apps/ai-game-creator-shell/src/components/ChatMarkdownMessage/index.tsx
index 90bf6f82d..ad2ebaa39 100644
--- a/apps/ai-game-creator-shell/src/components/ChatMarkdownMessage/index.tsx
+++ b/apps/ai-game-creator-shell/src/components/ChatMarkdownMessage/index.tsx
@@ -15,6 +15,16 @@ export type ChatMarkdownMessageProps = {
streaming?: boolean;
};
+/** 只压缩普通 Markdown 正文里多余的空行;代码块中的换行必须原样保留。 */
+function normalizeMarkdownBlankLines(text: string) {
+ return text
+ .split(/(```[\s\S]*?```)/g)
+ .map((part, index) =>
+ index % 2 === 1 ? part : part.replace(/\n{3,}/g, '\n\n'),
+ )
+ .join('');
+}
+
type MarkdownErrorBoundaryProps = {
fallbackText: string;
children: ReactNode;
@@ -76,7 +86,7 @@ function MarkdownUnorderedList({ children }: { children?: ReactNode }) {
{/* 用真正的列表标记(`list-disc`)而不是手写 `'- '` 文本:手写前缀既没有悬挂缩进
(换行后的第二行会顶回最左边),也不算列表语义(读屏读成普通文本)。 */}
-
@@ -95,7 +105,7 @@ function MarkdownOrderedList({
{children}
@@ -111,8 +121,8 @@ function MarkdownParagraph({ children }: { children?: ReactNode }) {
paragraphPosition === 'first'
? 'inline'
: paragraphPosition === 'continuation'
- ? 'mt-1'
- : 'mt-1 first:mt-0'
+ ? 'mt-2'
+ : 'mt-2 first:mt-0'
}`}
>
{children}
@@ -128,8 +138,8 @@ function StreamingMarkdownParagraph({ children }: { children?: ReactNode }) {
paragraphPosition === 'first'
? 'inline'
: paragraphPosition === 'continuation'
- ? 'mt-1'
- : 'mt-1 first:mt-0'
+ ? 'mt-2'
+ : 'mt-2 first:mt-0'
}`}
>
{children}
@@ -265,7 +275,7 @@ export function ChatMarkdownMessage({
streaming ? streamingMarkdownComponents : markdownComponents
}
>
- {text}
+ {normalizeMarkdownBlankLines(text)}
);