([]);
const [isUploading, setIsUploading] = useState(false);
const [isDraggingOver, setIsDraggingOver] = useState(false);
- // Allow controlled or uncontrolled usage
+ useEffect(() => {
+ if (typeof window !== 'undefined') {
+ try {
+ const savedModel = localStorage.getItem(STORAGE_KEY_MODEL);
+ if (savedModel) {
+ setSelectedModel(savedModel);
+ }
+ } catch (error) {
+ console.warn('Failed to load preferences from localStorage:', error);
+ }
+ }
+ }, []);
+
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;
const adjustHeight = () => {
textarea.style.height = 'auto';
- const newHeight = Math.min(textarea.scrollHeight, 200); // Max height of 200px
+ const newHeight = Math.min(Math.max(textarea.scrollHeight, 50), 200); // Min 50px, max 200px
textarea.style.height = `${newHeight}px`;
};
adjustHeight();
- // Adjust on window resize too
window.addEventListener('resize', adjustHeight);
return () => window.removeEventListener('resize', adjustHeight);
}, [inputValue]);
+ const handleModelChange = (model: string) => {
+ setSelectedModel(model);
+ if (typeof window !== 'undefined') {
+ localStorage.setItem(STORAGE_KEY_MODEL, model);
+ }
+ };
+
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
if ((!inputValue.trim() && uploadedFiles.length === 0) || loading || (disabled && !isAgentRunning)) return;
@@ -104,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}]`
@@ -112,13 +136,22 @@ export function ChatInput({
message = message ? `${message}\n\n${fileInfo}` : fileInfo;
}
- onSubmit(message);
+ let baseModelName = selectedModel;
+ let thinkingEnabled = false;
+ if (selectedModel === "sonnet-3.7-thinking") {
+ baseModelName = "sonnet-3.7";
+ thinkingEnabled = true;
+ }
+
+ onSubmit(message, {
+ model_name: baseModelName,
+ enable_thinking: thinkingEnabled
+ });
if (!isControlled) {
setInputValue("");
}
- // Reset the uploaded files after sending
setUploadedFiles([]);
};
@@ -175,7 +208,6 @@ export function ChatInput({
const files = Array.from(event.target.files);
await uploadFiles(files);
- // Reset the input
event.target.value = '';
};
@@ -191,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);
@@ -206,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: {
@@ -219,7 +248,6 @@ export function ChatInput({
throw new Error(`Upload failed: ${response.statusText}`);
}
- // Add to uploaded files
newUploadedFiles.push({
name: file.name,
path: uploadPath,
@@ -229,7 +257,6 @@ export function ChatInput({
toast.success(`File uploaded: ${file.name}`);
}
- // Update the uploaded files state
setUploadedFiles(prev => [...prev, ...newUploadedFiles]);
} catch (error) {
@@ -273,11 +300,18 @@ export function ChatInput({
}
};
+ 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"
+ };
+
return (
0 ? "border-border" : "border-input",
+ "w-full border rounded-xl transition-all duration-200 shadow-sm bg-[#1a1a1a] border-gray-800",
+ uploadedFiles.length > 0 ? "border-border" : "border-gray-800",
isDraggingOver ? "border-primary border-dashed bg-primary/5" : ""
)}
onDragOver={handleDragOver}
@@ -300,18 +334,18 @@ export function ChatInput({
animate={{ opacity: 1, scale: 1 }}
exit={{ opacity: 0, scale: 0.9 }}
transition={{ duration: 0.15 }}
- className="px-2 py-1 bg-secondary/20 rounded-full flex items-center gap-1.5 group border border-secondary/30 hover:border-secondary/50 transition-colors text-sm"
+ className="px-2 py-1 bg-gray-800 rounded-full flex items-center gap-1.5 group border border-gray-700 hover:border-gray-600 transition-colors text-sm"
>
{getFileIcon(file.name)}
- {file.name}
-
+ {file.name}
+
({formatFileSize(file.size)})
-
+
)}
-
- {isDraggingOver && (
-
-
-
-
Drop files to upload
-
-
- )}
+