'use client' import { useState, useRef, useEffect, useCallback } from 'react' import { useThread } from '@standardagents/react' export function MessageInput() { const [input, setInput] = useState('') const [sending, setSending] = useState(false) const { runStatus, sendMessage, stopExecution, addAttachment, attachments, removeAttachment, } = useThread() const textareaRef = useRef(null) // Pushed by the runtime; drives the stop button instead of history loading. const running = runStatus?.state === 'running' const fileInputRef = useRef(null) const handleSubmit = useCallback(async (e: React.FormEvent) => { e.preventDefault() if ((!input.trim() && attachments.length === 0) || running || sending) return const message = input setInput('') setSending(true) try { // SDK's sendMessage automatically includes queued attachments and clears them await sendMessage({ role: 'user', content: message }) } catch (error) { console.error('Failed to send message:', error) setInput(message) } finally { setSending(false) } }, [input, attachments.length, running, sending, sendMessage]) const handleFileSelect = useCallback(async (e: React.ChangeEvent) => { const files = e.target.files if (!files || files.length === 0) return // SDK handles base64 encoding, dimensions, and preview URLs for (const file of Array.from(files)) { await addAttachment(file) } // Reset file input and refocus textarea if (fileInputRef.current) { fileInputRef.current.value = '' } textareaRef.current?.focus() }, [addAttachment]) // Auto-resize textarea useEffect(() => { const textarea = textareaRef.current if (textarea) { textarea.style.height = 'auto' const newHeight = Math.min(Math.max(textarea.scrollHeight, 24), 200) textarea.style.height = newHeight + 'px' } }, [input]) // Focus textarea when not loading useEffect(() => { if (!running && !sending) { textareaRef.current?.focus() } }, [running, sending]) const isDisabled = running || sending const canSend = (input.trim() || attachments.length > 0) && !isDisabled return (
{/* Attachment drawer - extends from top of input */} {attachments.length > 0 && (
{attachments.map((attachment) => { const previewUrl = attachment.previewUrl const isImage = attachment.isImage return (
{isImage && previewUrl ? ( {attachment.name} ) : (
{attachment.name}
)}
) })}
)} {/* Input row */}
{/* Attachment button */} {/* Textarea */}