import { memo, Suspense, useMemo } from 'react';
import { useRecoilValue } from 'recoil';
import { DelayedRender } from '@librechat/client';
import type { TMessage } from 'librechat-data-provider';
import type { TMessageContentProps, TDisplayProps } from '~/common';
import Error from '~/components/Messages/Content/Error';
import { useMessageContext } from '~/Providers';
import MarkdownLite from './MarkdownLite';
import EditMessage from './EditMessage';
import Thinking from './Parts/Thinking';
import { useLocalize } from '~/hooks';
import Container from './Container';
import Markdown from './Markdown';
import { cn } from '~/utils';
import store from '~/store';
const ERROR_CONNECTION_TEXT = 'Error connecting to server, try refreshing the page.';
const DELAYED_ERROR_TIMEOUT = 5500;
const UNFINISHED_DELAY = 250;
const parseThinkingContent = (text: string) => {
const thinkingMatch = text.match(/:::thinking([\s\S]*?):::/);
return {
thinkingContent: thinkingMatch ? thinkingMatch[1].trim() : '',
regularContent: thinkingMatch ? text.replace(/:::thinking[\s\S]*?:::/, '').trim() : text,
};
};
const LoadingFallback = () => (
);
const ErrorBox = ({
children,
className = '',
}: {
children: React.ReactNode;
className?: string;
}) => (
{children}
);
const ConnectionError = ({ message }: { message?: TMessage }) => {
const localize = useLocalize();
return (
}>
{localize('com_ui_error_connection')}
);
};
export const ErrorMessage = ({
text,
message,
className = '',
}: Pick & { message?: TMessage }) => {
if (text === ERROR_CONNECTION_TEXT) {
return ;
}
return (
);
};
const DisplayMessage = ({ text, isCreatedByUser, message, showCursor }: TDisplayProps) => {
const { isSubmitting = false, isLatestMessage = false } = useMessageContext();
const enableUserMsgMarkdown = useRecoilValue(store.enableUserMsgMarkdown);
const showCursorState = useMemo(
() => showCursor === true && isSubmitting,
[showCursor, isSubmitting],
);
const content = useMemo(() => {
if (!isCreatedByUser) {
return ;
}
if (enableUserMsgMarkdown) {
return ;
}
return <>{text}>;
}, [isCreatedByUser, enableUserMsgMarkdown, text, isLatestMessage]);
return (
0 && 'result-streaming',
isCreatedByUser && !enableUserMsgMarkdown && 'whitespace-pre-wrap',
isCreatedByUser ? 'dark:text-gray-20' : 'dark:text-gray-100',
)}
>
{content}
);
};
export const UnfinishedMessage = ({ message }: { message: TMessage }) => (
);
const MessageContent = ({
text,
edit,
error,
unfinished,
isSubmitting,
isLast,
...props
}: TMessageContentProps) => {
const { message } = props;
const { messageId } = message;
const { thinkingContent, regularContent } = useMemo(() => parseThinkingContent(text), [text]);
const showRegularCursor = useMemo(() => isLast && isSubmitting, [isLast, isSubmitting]);
const unfinishedMessage = useMemo(
() =>
!isSubmitting && unfinished ? (
) : null,
[isSubmitting, unfinished, message],
);
if (error) {
return ;
}
if (edit) {
return ;
}
return (
<>
{thinkingContent.length > 0 && (
{thinkingContent}
)}
{unfinishedMessage}
>
);
};
export default memo(MessageContent);