diff --git a/apps/sim/app/chat/components/message/components/markdown-renderer.tsx b/apps/sim/app/chat/components/message/components/markdown-renderer.tsx index 12254f18dd..37059ef523 100644 --- a/apps/sim/app/chat/components/message/components/markdown-renderer.tsx +++ b/apps/sim/app/chat/components/message/components/markdown-renderer.tsx @@ -1,10 +1,10 @@ -import React, { type HTMLAttributes, memo, type ReactNode, useMemo } from 'react' +import React, { type HTMLAttributes, memo, type ReactNode } from 'react' import { Streamdown } from 'streamdown' import 'streamdown/styles.css' import { CopyCodeButton, Tooltip } from '@/components/emcn' import { extractTextContent } from '@/lib/core/utils/react-node-text' -export function LinkWithPreview({ href, children }: { href: string; children: React.ReactNode }) { +function LinkWithPreview({ href, children }: { href: string; children: React.ReactNode }) { return ( @@ -24,175 +24,151 @@ export function LinkWithPreview({ href, children }: { href: string; children: Re ) } -function createCustomComponents(LinkComponent: typeof LinkWithPreview) { - return { - p: ({ children }: React.HTMLAttributes) => ( -

- {children} -

- ), - - h1: ({ children }: React.HTMLAttributes) => ( -

- {children} -

- ), - h2: ({ children }: React.HTMLAttributes) => ( -

- {children} -

- ), - h3: ({ children }: React.HTMLAttributes) => ( -

- {children} -

- ), - h4: ({ children }: React.HTMLAttributes) => ( -

- {children} -

- ), - - ul: ({ children }: React.HTMLAttributes) => ( -
    - {children} -
- ), - ol: ({ children }: React.HTMLAttributes) => ( -
    - {children} -
- ), - li: ({ children }: React.LiHTMLAttributes) => ( -
  • - {children} -
  • - ), - - pre: ({ children }: HTMLAttributes) => { - let codeProps: HTMLAttributes = {} - let codeContent: ReactNode = children - - if ( - React.isValidElement<{ className?: string; children?: ReactNode }>(children) && - children.type === 'code' - ) { - const childElement = children as React.ReactElement<{ - className?: string - children?: ReactNode - }> - codeProps = { className: childElement.props.className } - codeContent = childElement.props.children - } +const COMPONENTS = { + p: ({ children }: React.HTMLAttributes) => ( +

    + {children} +

    + ), + + h1: ({ children }: React.HTMLAttributes) => ( +

    + {children} +

    + ), + h2: ({ children }: React.HTMLAttributes) => ( +

    + {children} +

    + ), + h3: ({ children }: React.HTMLAttributes) => ( +

    + {children} +

    + ), + h4: ({ children }: React.HTMLAttributes) => ( +

    + {children} +

    + ), + + ul: ({ children }: React.HTMLAttributes) => ( +
      + {children} +
    + ), + ol: ({ children }: React.HTMLAttributes) => ( +
      + {children} +
    + ), + li: ({ children }: React.LiHTMLAttributes) => ( +
  • + {children} +
  • + ), + + pre: ({ children }: HTMLAttributes) => { + let codeProps: HTMLAttributes = {} + let codeContent: ReactNode = children + + if ( + React.isValidElement<{ className?: string; children?: ReactNode }>(children) && + children.type === 'code' + ) { + const childElement = children as React.ReactElement<{ + className?: string + children?: ReactNode + }> + codeProps = { className: childElement.props.className } + codeContent = childElement.props.children + } - return ( -
    -
    - - {codeProps.className?.replace('language-', '') || 'code'} - - -
    -
    -            {codeContent}
    -          
    + return ( +
    +
    + + {codeProps.className?.replace('language-', '') || 'code'} + +
    - ) - }, - - inlineCode: ({ children }: { children?: React.ReactNode }) => ( - - {children} - - ), - - blockquote: ({ children }: React.HTMLAttributes) => ( -
    - {children} -
    - ), - - hr: () =>
    , - - a: ({ href, children, ...props }: React.AnchorHTMLAttributes) => ( - - {children} - - ), - - table: ({ children }: React.TableHTMLAttributes) => ( -
    - - {children} -
    +
    +          {codeContent}
    +        
    - ), - thead: ({ children }: React.HTMLAttributes) => ( - {children} - ), - tbody: ({ children }: React.HTMLAttributes) => ( - - {children} - - ), - tr: ({ children }: React.HTMLAttributes) => ( - - {children} - - ), - th: ({ children }: React.ThHTMLAttributes) => ( - + ) + }, + + inlineCode: ({ children }: { children?: React.ReactNode }) => ( + + {children} + + ), + + blockquote: ({ children }: React.HTMLAttributes) => ( +
    + {children} +
    + ), + + hr: () =>
    , + + a: ({ href, children, ...props }: React.AnchorHTMLAttributes) => ( + + {children} + + ), + + table: ({ children }: React.TableHTMLAttributes) => ( +
    + {children} - - ), - td: ({ children }: React.TdHTMLAttributes) => ( - - ), - - img: ({ src, alt, ...props }: React.ImgHTMLAttributes) => ( - {alt - ), - } +
    - {children} -
    +
    + ), + thead: ({ children }: React.HTMLAttributes) => ( + {children} + ), + tbody: ({ children }: React.HTMLAttributes) => ( + + {children} + + ), + tr: ({ children }: React.HTMLAttributes) => ( + + {children} + + ), + th: ({ children }: React.ThHTMLAttributes) => ( + + {children} + + ), + td: ({ children }: React.TdHTMLAttributes) => ( + + {children} + + ), + + img: ({ src, alt, ...props }: React.ImgHTMLAttributes) => ( + {alt + ), } -const DEFAULT_COMPONENTS = createCustomComponents(LinkWithPreview) - -const MarkdownRenderer = memo(function MarkdownRenderer({ - content, - customLinkComponent, -}: { - content: string - customLinkComponent?: typeof LinkWithPreview -}) { - const components = useMemo(() => { - if (!customLinkComponent) { - return DEFAULT_COMPONENTS - } - return createCustomComponents(customLinkComponent) - }, [customLinkComponent]) - - const processedContent = content.trim() - +const MarkdownRenderer = memo(function MarkdownRenderer({ content }: { content: string }) { return (
    - - {processedContent} + + {content.trim()}
    ) diff --git a/apps/sim/app/chat/components/message/message.tsx b/apps/sim/app/chat/components/message/message.tsx index 9d02cbbcb2..f803e82c77 100644 --- a/apps/sim/app/chat/components/message/message.tsx +++ b/apps/sim/app/chat/components/message/message.tsx @@ -8,7 +8,6 @@ import { ChatFileDownloadAll, } from '@/app/chat/components/message/components/file-download' import MarkdownRenderer from '@/app/chat/components/message/components/markdown-renderer' -import { useThrottledValue } from '@/hooks/use-throttled-value' export interface ChatAttachment { id: string @@ -39,11 +38,6 @@ export interface ChatMessage { files?: ChatFile[] } -function EnhancedMarkdownRenderer({ content }: { content: string }) { - const throttled = useThrottledValue(content) - return -} - export const ClientChatMessage = memo( function ClientChatMessage({ message }: { message: ChatMessage }) { const [isCopied, setIsCopied] = useState(false) @@ -188,7 +182,7 @@ export const ClientChatMessage = memo( {JSON.stringify(cleanTextContent, null, 2)} ) : ( - + )}
    diff --git a/apps/sim/app/workspace/[workspaceId]/home/components/message-content/components/chat-content/chat-content.tsx b/apps/sim/app/workspace/[workspaceId]/home/components/message-content/components/chat-content/chat-content.tsx index 46091cd9ce..2c6fa99d5e 100644 --- a/apps/sim/app/workspace/[workspaceId]/home/components/message-content/components/chat-content/chat-content.tsx +++ b/apps/sim/app/workspace/[workspaceId]/home/components/message-content/components/chat-content/chat-content.tsx @@ -18,7 +18,6 @@ import { SpecialTags, } from '@/app/workspace/[workspaceId]/home/components/message-content/components/special-tags' import type { MothershipResource } from '@/app/workspace/[workspaceId]/home/types' -import { useStreamingText } from '@/hooks/use-streaming-text' const LANG_ALIASES: Record = { js: 'javascript', @@ -236,7 +235,6 @@ interface ChatContentProps { isStreaming?: boolean onOptionSelect?: (id: string) => void onWorkspaceResourceSelect?: (resource: MothershipResource) => void - smoothStreaming?: boolean } export function ChatContent({ @@ -244,20 +242,7 @@ export function ChatContent({ isStreaming = false, onOptionSelect, onWorkspaceResourceSelect, - smoothStreaming = true, }: ChatContentProps) { - const hydratedStreamingRef = useRef(isStreaming && content.trim().length > 0) - const previousIsStreamingRef = useRef(isStreaming) - - useEffect(() => { - if (!previousIsStreamingRef.current && isStreaming && content.trim().length > 0) { - hydratedStreamingRef.current = true - } else if (!isStreaming) { - hydratedStreamingRef.current = false - } - previousIsStreamingRef.current = isStreaming - }, [content, isStreaming]) - const onWorkspaceResourceSelectRef = useRef(onWorkspaceResourceSelect) onWorkspaceResourceSelectRef.current = onWorkspaceResourceSelect @@ -270,9 +255,7 @@ export function ChatContent({ return () => window.removeEventListener('wsres-click', handler) }, []) - const rendered = useStreamingText(content, isStreaming && smoothStreaming) - - const parsed = useMemo(() => parseSpecialTags(rendered, isStreaming), [rendered, isStreaming]) + const parsed = useMemo(() => parseSpecialTags(content, isStreaming), [content, isStreaming]) const hasSpecialContent = parsed.hasPendingTag || parsed.segments.some((s) => s.type !== 'text') if (hasSpecialContent) { @@ -322,7 +305,10 @@ export function ChatContent({ key={`inline-${i}`} className={cn(PROSE_CLASSES, '[&>:first-child]:mt-0 [&>:last-child]:mb-0')} > - + {group.markdown} @@ -343,13 +329,8 @@ export function ChatContent({ return (
    :first-child]:mt-0 [&>:last-child]:mb-0')}> - - {rendered} + + {content}
    ) diff --git a/apps/sim/app/workspace/[workspaceId]/home/components/message-content/components/special-tags/special-tags.tsx b/apps/sim/app/workspace/[workspaceId]/home/components/message-content/components/special-tags/special-tags.tsx index d526130046..0a58d8c2b3 100644 --- a/apps/sim/app/workspace/[workspaceId]/home/components/message-content/components/special-tags/special-tags.tsx +++ b/apps/sim/app/workspace/[workspaceId]/home/components/message-content/components/special-tags/special-tags.tsx @@ -415,7 +415,7 @@ function OptionsDisplay({ data, onSelect }: OptionsDisplayProps) { if (entries.length === 0) return null return ( -
    +
    {disabled ? (