({ message, className }: ChatMessageProps)
| 101 | } |
| 102 | |
| 103 | export function ChatMessage({ message, className }: ChatMessageProps) { |
| 104 | const role = message.role; |
| 105 | |
| 106 | const isUser = role === "user"; |
| 107 | const isAssistant = role === "assistant"; |
| 108 | const isAction = role === "action"; |
| 109 | const isSystem = role === "system"; |
| 110 | const isError = "isError" in message && message.isError; |
| 111 | |
| 112 | if (isSystem) { |
| 113 | return ( |
| 114 | <div className={cn("w-full flex justify-center", className)}> |
| 115 | <Badge variant={isError ? "error" : "muted"}>{message.content}</Badge> |
| 116 | </div> |
| 117 | ); |
| 118 | } |
| 119 | |
| 120 | if (isAction) { |
| 121 | return ( |
| 122 | <ActionMessageDisplay |
| 123 | message={message as ActionChatMessage} |
| 124 | className={className} |
| 125 | /> |
| 126 | ); |
| 127 | } |
| 128 | |
| 129 | const getRoleIcon = () => { |
| 130 | if (isUser) return <User className="h-3 w-3" />; |
| 131 | if (isAssistant) { |
| 132 | return <OpenAiLogo className="h-3 w-3" />; |
| 133 | } |
| 134 | return <Info className="h-3 w-3" />; |
| 135 | }; |
| 136 | |
| 137 | const roleLabel = isUser ? "You" : isAssistant ? "Assistant" : "System"; |
| 138 | |
| 139 | return ( |
| 140 | <div |
| 141 | className={cn( |
| 142 | "flex", |
| 143 | isUser ? "justify-end" : "justify-start", |
| 144 | className |
| 145 | )} |
| 146 | > |
| 147 | <Card |
| 148 | className={cn( |
| 149 | "max-w-[85%] overflow-hidden border", |
| 150 | messageVariants({ role }) |
| 151 | )} |
| 152 | variant="slate" |
| 153 | > |
| 154 | <CardContent className="p-3"> |
| 155 | <div className="text-xs mb-2 font-mono uppercase tracking-wider text-fg-300 flex items-center gap-1"> |
| 156 | {getRoleIcon()} |
| 157 | <span>{roleLabel}</span> |
| 158 | </div> |
| 159 | <div className="whitespace-pre-wrap break-words font-sans text-sm tracking-wide"> |
| 160 | {message.content} |
nothing calls this directly
no test coverage detected