From 99d41d8c8d84c7efe0e2da27eb5b5b14be12df15 Mon Sep 17 00:00:00 2001 From: LE Quoc Dat Date: Fri, 18 Apr 2025 17:17:11 +0100 Subject: [PATCH] improve UI of models selection --- frontend/src/components/thread/chat-input.tsx | 171 ++++++++---------- 1 file changed, 73 insertions(+), 98 deletions(-) diff --git a/frontend/src/components/thread/chat-input.tsx b/frontend/src/components/thread/chat-input.tsx index e118ec08..117c3221 100644 --- a/frontend/src/components/thread/chat-input.tsx +++ b/frontend/src/components/thread/chat-input.tsx @@ -3,7 +3,7 @@ import React, { useState, useRef, useEffect } from 'react'; import { Textarea } from "@/components/ui/textarea"; import { Button } from "@/components/ui/button"; -import { Send, Square, Loader2, File, Upload, X, Paperclip, FileText, ChevronDown } from "lucide-react"; +import { Send, Square, Loader2, File, Upload, X, Paperclip, FileText, ChevronDown, Cpu } from "lucide-react"; import { createClient } from "@/lib/supabase/client"; import { toast } from "sonner"; import { AnimatePresence, motion } from "framer-motion"; @@ -26,7 +26,6 @@ const API_URL = process.env.NEXT_PUBLIC_BACKEND_URL || ''; // Local storage keys const STORAGE_KEY_MODEL = 'suna-preferred-model'; -const STORAGE_KEY_THINKING = 'suna-enable-thinking'; interface ChatInputProps { onSubmit: (message: string, options?: { model_name?: string; enable_thinking?: boolean }) => void; @@ -63,52 +62,39 @@ export function ChatInput({ }: ChatInputProps) { const [inputValue, setInputValue] = useState(value || ""); const [selectedModel, setSelectedModel] = useState("sonnet-3.7"); - const [enableThinking, setEnableThinking] = useState(false); const textareaRef = useRef(null); const fileInputRef = useRef(null); const [uploadedFiles, setUploadedFiles] = useState([]); const [isUploading, setIsUploading] = useState(false); const [isDraggingOver, setIsDraggingOver] = useState(false); - // Load saved preferences from localStorage on mount useEffect(() => { if (typeof window !== 'undefined') { try { - // Load selected model const savedModel = localStorage.getItem(STORAGE_KEY_MODEL); if (savedModel) { setSelectedModel(savedModel); } - - // Load thinking preference - const savedThinking = localStorage.getItem(STORAGE_KEY_THINKING); - if (savedThinking === 'true') { - setEnableThinking(true); - } } catch (error) { console.warn('Failed to load preferences from localStorage:', error); } } }, []); - // Allow controlled or uncontrolled usage const isControlled = value !== undefined && onChange !== undefined; - // Update local state if controlled and value changes useEffect(() => { if (isControlled && value !== inputValue) { setInputValue(value); } }, [value, isControlled, inputValue]); - // Auto-focus on textarea when component loads useEffect(() => { if (autoFocus && textareaRef.current) { textareaRef.current.focus(); } }, [autoFocus]); - // Adjust textarea height based on content useEffect(() => { const textarea = textareaRef.current; if (!textarea) return; @@ -121,34 +107,15 @@ export function ChatInput({ adjustHeight(); - // Adjust on window resize too window.addEventListener('resize', adjustHeight); return () => window.removeEventListener('resize', adjustHeight); }, [inputValue]); const handleModelChange = (model: string) => { setSelectedModel(model); - // Save to localStorage if (typeof window !== 'undefined') { localStorage.setItem(STORAGE_KEY_MODEL, model); } - - // Reset thinking when changing away from sonnet-3.7 - if (model !== "sonnet-3.7") { - setEnableThinking(false); - if (typeof window !== 'undefined') { - localStorage.setItem(STORAGE_KEY_THINKING, 'false'); - } - } - }; - - const toggleThinking = () => { - const newValue = !enableThinking; - setEnableThinking(newValue); - // Save to localStorage - if (typeof window !== 'undefined') { - localStorage.setItem(STORAGE_KEY_THINKING, newValue.toString()); - } }; const handleSubmit = async (e: React.FormEvent) => { @@ -162,7 +129,6 @@ export function ChatInput({ let message = inputValue; - // Add file information to the message if files were uploaded if (uploadedFiles.length > 0) { const fileInfo = uploadedFiles.map(file => `[Uploaded file: ${file.name} (${formatFileSize(file.size)}) at ${file.path}]` @@ -170,16 +136,22 @@ export function ChatInput({ message = message ? `${message}\n\n${fileInfo}` : fileInfo; } + let baseModelName = selectedModel; + let thinkingEnabled = false; + if (selectedModel === "sonnet-3.7-thinking") { + baseModelName = "sonnet-3.7"; + thinkingEnabled = true; + } + onSubmit(message, { - model_name: selectedModel, - enable_thinking: enableThinking + model_name: baseModelName, + enable_thinking: thinkingEnabled }); if (!isControlled) { setInputValue(""); } - // Reset the uploaded files after sending setUploadedFiles([]); }; @@ -236,7 +208,6 @@ export function ChatInput({ const files = Array.from(event.target.files); await uploadFiles(files); - // Reset the input event.target.value = ''; }; @@ -252,11 +223,9 @@ export function ChatInput({ continue; } - // Create a FormData object const formData = new FormData(); formData.append('file', file); - // Upload to workspace root by default const uploadPath = `/workspace/${file.name}`; formData.append('path', uploadPath); @@ -267,7 +236,6 @@ export function ChatInput({ throw new Error('No access token available'); } - // Upload using FormData const response = await fetch(`${API_URL}/sandboxes/${sandboxId}/files`, { method: 'POST', headers: { @@ -280,7 +248,6 @@ export function ChatInput({ throw new Error(`Upload failed: ${response.statusText}`); } - // Add to uploaded files newUploadedFiles.push({ name: file.name, path: uploadPath, @@ -290,7 +257,6 @@ export function ChatInput({ toast.success(`File uploaded: ${file.name}`); } - // Update the uploaded files state setUploadedFiles(prev => [...prev, ...newUploadedFiles]); } catch (error) { @@ -334,9 +300,9 @@ export function ChatInput({ } }; - // Map of model display names - const modelDisplayNames = { + const modelDisplayNames: { [key: string]: string } = { "sonnet-3.7": "Sonnet 3.7", + "sonnet-3.7-thinking": "Sonnet 3.7 (Thinking)", "gpt-4.1": "GPT-4.1", "gemini-flash-2.5": "Gemini Flash 2.5" }; @@ -393,54 +359,6 @@ export function ChatInput({
- {/* Left side - Model selector and Think button */} - {!isAgentRunning && ( -
- {/* Model selector button with dropdown */} - - - - - - handleModelChange("sonnet-3.7")} className="hover:bg-gray-800"> - Sonnet 3.7 - - handleModelChange("gpt-4.1")} className="hover:bg-gray-800"> - GPT-4.1 - - handleModelChange("gemini-flash-2.5")} className="hover:bg-gray-800"> - Gemini Flash 2.5 - - - - - {/* Think button - only for Sonnet 3.7 */} - {selectedModel === "sonnet-3.7" && ( - - )} -
- )} - - {/* Input field */}