import { UIMessage as VercelMessage } from '@ai-sdk/react' import { type DynamicToolUIPart, type ReasoningUIPart, type TextUIPart, type ToolUIPart } from 'ai' import { BrainIcon, CheckIcon, Loader2 } from 'lucide-react' import { cn } from 'ui' import { DisplayBlockRenderer } from './DisplayBlockRenderer' import { EdgeFunctionRenderer } from './EdgeFunctionRenderer' import { Tool } from './elements/Tool' import { useMessageActionsContext, useMessageInfoContext } from './Message.Context' import { deployEdgeFunctionInputSchema, deployEdgeFunctionOutputSchema, parseExecuteSqlChartResult, } from './Message.utils' import { MessageMarkdown } from './MessageMarkdown' function MessagePartText({ textPart }: { textPart: TextUIPart }) { const { id, isLoading, readOnly, isUserMessage, state } = useMessageInfoContext() return ( div]:my-4 prose-h1:text-xl prose-h1:mt-6 prose-h2:text-lg prose-h2:font-medium prose-h3:no-underline prose-h3:text-base prose-h3:mb-4 prose-strong:font-medium prose-strong:text-foreground prose-ol:space-y-3 prose-ul:space-y-3 prose-li:my-0 wrap-break-word [&>p:not(:last-child)]:mb-2! [&>*>p:first-child]:mt-0! [&>*>p:last-child]:mb-0! [&>*>*>p:first-child]:mt-0! [&>*>*>p:last-child]:mb-0! [&>ol>li]:pl-4!', isUserMessage && 'text-foreground [&>p]:font-medium', state === 'editing' && 'animate-pulse' )} > {textPart.text} ) } function MessagePartDynamicTool({ toolPart }: { toolPart: DynamicToolUIPart }) { return ( ) : ( ) } label={
{toolPart.state === 'input-streaming' ? 'Running ' : 'Ran '} {`${toolPart.toolName}`}
} /> ) } function MessagePartTool({ toolPart }: { toolPart: ToolUIPart }) { return ( ) : ( ) } label={
{toolPart.state === 'input-streaming' ? 'Running ' : 'Ran '} {`${toolPart.type.replace('tool-', '')}`}
} /> ) } function MessagePartReasoning({ reasoningPart }: { reasoningPart: ReasoningUIPart }) { return ( ) : ( ) } label={reasoningPart.state === 'streaming' ? 'Thinking...' : 'Reasoned'} > {reasoningPart.text} ) } function ToolDisplayExecuteSqlLoading({ label = 'Writing SQL...' }: { label?: string }) { return (
{label}
) } function ToolDisplayExecuteSqlFailure() { return
Failed to execute SQL.
} function MessagePartExecuteSql({ toolPart, isLastPart, }: { toolPart: ToolUIPart isLastPart?: boolean }) { const { id, isLastMessage } = useMessageInfoContext() const { addToolApprovalResponse } = useMessageActionsContext() const { toolCallId, state, input, output } = toolPart if (state === 'input-streaming') { return } if (state === 'output-error') { return } const { data: chart, success } = parseExecuteSqlChartResult(input) if (!success) return null if ( state === 'input-available' || state === 'approval-requested' || state === 'approval-responded' || state === 'output-denied' || state === 'output-available' ) { const approvalId = state === 'approval-requested' ? toolPart.approval?.id : undefined return (
addToolApprovalResponse?.({ id: approvalId, approved: true }) : undefined } onDeny={ approvalId ? () => addToolApprovalResponse?.({ id: approvalId, approved: false }) : undefined } />
) } return null } const TOOL_DEPLOY_EDGE_FUNCTION_STATES_WITH_INPUT = new Set([ 'input-available', 'approval-requested', 'approval-responded', 'output-denied', 'output-available', ]) function MessagePartDeployEdgeFunction({ toolPart }: { toolPart: ToolUIPart }) { const { state, input, output } = toolPart const { addToolApprovalResponse } = useMessageActionsContext() if (state === 'input-streaming') { return (
Writing Edge Function...
) } if (state === 'output-error') { return

Failed to deploy Edge Function.

} if (!TOOL_DEPLOY_EDGE_FUNCTION_STATES_WITH_INPUT.has(state)) return null const parsedInput = deployEdgeFunctionInputSchema.safeParse(input) if (!parsedInput.success) return null const parsedOutput = deployEdgeFunctionOutputSchema.safeParse(output) const isInitiallyDeployed = state === 'output-available' && parsedOutput.success && parsedOutput.data.success === true const approvalId = state === 'approval-requested' ? toolPart.approval?.id : undefined return ( addToolApprovalResponse?.({ id: approvalId, approved: true }) : undefined } onDeny={ approvalId ? () => addToolApprovalResponse?.({ id: approvalId, approved: false }) : undefined } /> ) } const MessagePart = { Text: MessagePartText, Dynamic: MessagePartDynamicTool, Tool: MessagePartTool, Reasoning: MessagePartReasoning, ExecuteSql: MessagePartExecuteSql, DeployEdgeFunction: MessagePartDeployEdgeFunction, } as const export function MessagePartSwitcher({ part, isLastPart, }: { part: NonNullable[number] isLastPart?: boolean }) { switch (part.type) { case 'dynamic-tool': { return } case 'tool-list_policies': case 'tool-search_docs': case 'tool-get_active_incidents': case 'tool-load_knowledge': { return } case 'reasoning': return case 'text': return case 'tool-execute_sql': { return } case 'tool-deploy_edge_function': { return } case 'source-url': case 'source-document': case 'file': default: return null } }