import { type ReactElement, Fragment, useMemo } from "react"; import { Text } from "react-native"; import type { ThreadUserMessagePart, ThreadAssistantMessagePart, ToolCallMessagePart, DataMessagePart, } from "@assistant-ui/core"; import { useAui, useAuiState } from "@assistant-ui/store"; import type { ToolCallMessagePartProps, DataMessagePartProps, } from "@assistant-ui/core/react"; type MessageContentPart = ThreadUserMessagePart | ThreadAssistantMessagePart; export type MessageContentProps = { renderText?: (props: { part: Extract; index: number; }) => ReactElement; renderToolCall?: (props: { part: Extract; index: number; }) => ReactElement; renderImage?: (props: { part: Extract; index: number; }) => ReactElement; renderReasoning?: (props: { part: Extract; index: number; }) => ReactElement; renderSource?: (props: { part: Extract; index: number; }) => ReactElement; renderFile?: (props: { part: Extract; index: number; }) => ReactElement; renderData?: (props: { part: Extract; index: number; }) => ReactElement; }; const DefaultTextRenderer = ({ part, }: { part: Extract; }) => { return {part.text}; }; const ToolUIDisplay = ({ Fallback, part, index, }: { Fallback: | ((props: { part: ToolCallMessagePart; index: number }) => ReactElement) | undefined; part: ToolCallMessagePart; index: number; }) => { const aui = useAui(); const Render = useAuiState( (s) => s.tools.toolUIs[part.toolName]?.[0]?.render, ); const partMethods = useMemo(() => aui.message.part({ index }), [aui, index]); if (Render) { return ( ); } if (Fallback) return ; return null; }; const DataUIDisplay = ({ Fallback, part, index, }: { Fallback: | ((props: { part: DataMessagePart; index: number }) => ReactElement) | undefined; part: DataMessagePart; index: number; }) => { const Render = useAuiState((s) => { const renders = s.dataRenderers.renderers[part.name]; if (Array.isArray(renders)) return renders[0]; return renders; }); if (Render) return ; if (Fallback) return ; return null; }; export const MessageContent = ({ renderText, renderToolCall, renderImage, renderReasoning, renderSource, renderFile, renderData, }: MessageContentProps) => { const content = useAuiState((s) => s.message.content); return ( <> {content.map((part, index) => { const key = `${part.type}-${index}`; switch (part.type) { case "text": return ( {renderText ? ( renderText({ part, index }) ) : ( )} ); case "tool-call": return ( ); case "image": if (!renderImage) return null; return ( {renderImage({ part, index })} ); case "reasoning": if (!renderReasoning) return null; return ( {renderReasoning({ part, index })} ); case "source": if (!renderSource) return null; return ( {renderSource({ part, index })} ); case "file": if (!renderFile) return null; return {renderFile({ part, index })}; case "data": return ( ); default: return null; } })} ); };