+ {messages.length === 0 && (
+
+ )}
+
+ {messages.length > 0 && (
+
+
+ {messages.map((message, messageIndex) => (
+
+
+
+ {message.parts.map((part, i) => {
+ switch (part.type) {
+ case "data-modelDownloadProgress":
+ // Only show if message is not empty (hiding completed/cleared progress)
+ if (!part.data.message) return null
+ // Don't show the entire div when actively streaming
+ if (status === "ready") return null
+ return (
+
+
+
+
+ {part.data.message}
+
+
+ {part.data.status === "downloading" && part.data.progress !== undefined && (
+
+ )}
+
+ )
+ case "file":
+ if (part.mediaType?.startsWith("image/"))
+ return (
+
+
+
+ )
+ return null
+ case "text":
+ return {part.text}
+ case "reasoning":
+ return (
+
+
+ {part.text}
+
+ )
+ default:
+ return null
+ }
+ })}
+ {(message.role === "assistant" || message.role === "system") &&
+ messageIndex === messages.length - 1 &&
+ status === "ready" && (
+
+
copyMessageToClipboard(message)}
+ className="text-muted-foreground hover:text-foreground size-4"
+ >
+
+
+
regenerate()}
+ className="text-muted-foreground hover:text-foreground size-4"
+ >
+
+
+
+ )}
+
+
+
+ ))}
+ {/* Loading state */}
+ {status === "submitted" && (
+
+
+
+
+ Thinking...
+
+
+
+ )}
+
+
+
+ )}
+
+
+ {messages.length === 0 && (
+
+ {suggestions.map((suggestion) => (
+
+ ))}
+
+ )}
+
+ setInput(e.target.value)}
+ value={input}
+ />
+
+
+ <>
+ imageInputRef.current?.click()}>
+
+
+
+ >
+ {
+ setSelectedModel(value);
+ }}
+ value={selectedModel}
+ >
+
+
+
+
+ {MODELS.map((model) => (
+
+ {model.name}
+
+ ))}
+
+
+
+
+
+ {files && files.length > 0 && (
+
+ {Array.from(files).map((file, index) => (
+
+ {file.type.startsWith("image/") && (
+
+
+
+ )}
+
removeImage(index)}
+ className="absolute -top-1.5 -right-1.5 text-white cursor-pointer bg-red-500 hover:bg-red-600 w-4 h-4 rounded-full flex items-center justify-center"
+ type="button"
+ >
+
+
+
+ ))}
+
+ )}
+
+
+