diff --git a/frontend/src/components/workspace/messages/message-list-item.tsx b/frontend/src/components/workspace/messages/message-list-item.tsx index 52c4fa0d..7cc04ea2 100644 --- a/frontend/src/components/workspace/messages/message-list-item.tsx +++ b/frontend/src/components/workspace/messages/message-list-item.tsx @@ -28,6 +28,7 @@ import { resolveArtifactURL } from "@/core/artifacts/utils"; import { useI18n } from "@/core/i18n/hooks"; import { extractContentFromMessage, + normalizeHumanMessageDisplayText, extractReasoningContentFromMessage, parseUploadedFiles, stripPriorityHintSuffix, @@ -167,9 +168,11 @@ function MessageContent_({ const contentToDisplay = useMemo(() => { if (isHuman) { - return rawContent - ? stripPriorityHintSuffix(stripUploadedFilesTag(rawContent)) - : ""; + if (!rawContent) { + return ""; + } + const cleaned = stripPriorityHintSuffix(stripUploadedFilesTag(rawContent)); + return normalizeHumanMessageDisplayText(cleaned); } return rawContent ?? ""; }, [rawContent, isHuman]); diff --git a/frontend/src/core/messages/utils.ts b/frontend/src/core/messages/utils.ts index fe174166..37c89480 100644 --- a/frontend/src/core/messages/utils.ts +++ b/frontend/src/core/messages/utils.ts @@ -364,6 +364,20 @@ export function stripPriorityHintSuffix(content: string): string { .trim(); } +/** + * Normalize human-authored message text for markdown rendering. + * - Decode literal "\n" into real line breaks. + * - Split Chinese-numbered items (e.g. "1)...") into separate paragraphs. + */ +export function normalizeHumanMessageDisplayText(content: string): string { + return content + .replace(/\\n/g, "\n") + .replace(/\r\n?/g, "\n") + .replace(/\n(?=\d+[))]\s*)/g, "\n\n") + .replace(/\n{3,}/g, "\n\n") + .trim(); +} + export function parseUploadedFiles(content: string): FileInMessage[] { // Match ... tag const uploadedFilesRegex = /([\s\S]*?)<\/uploaded_files>/;