"use client"; import type { ChatStatus } from "ai"; import { CheckIcon, GraduationCapIcon, LightbulbIcon, ZapIcon, } from "lucide-react"; import { useCallback, useMemo, useState, type ComponentProps } from "react"; import { PromptInput, PromptInputActionAddAttachments, PromptInputActionMenu, PromptInputActionMenuContent, PromptInputActionMenuItem, PromptInputActionMenuTrigger, PromptInputAttachment, PromptInputAttachments, PromptInputBody, PromptInputButton, PromptInputFooter, PromptInputSubmit, PromptInputTextarea, PromptInputTools, type PromptInputMessage, } from "@/components/ai-elements/prompt-input"; import { DropdownMenuGroup, DropdownMenuLabel, DropdownMenuSeparator, } from "@/components/ui/dropdown-menu"; import { useI18n } from "@/core/i18n/hooks"; import { useModels } from "@/core/models/hooks"; import type { AgentThreadContext } from "@/core/threads"; import { cn } from "@/lib/utils"; import { ModelSelector, ModelSelectorContent, ModelSelectorInput, ModelSelectorItem, ModelSelectorList, ModelSelectorName, ModelSelectorTrigger, } from "../ai-elements/model-selector"; export function InputBox({ className, disabled, autoFocus, status = "ready", context, extraHeader, isNewThread, onContextChange, onSubmit, onStop, ...props }: Omit, "onSubmit"> & { assistantId?: string | null; status?: ChatStatus; disabled?: boolean; context: Omit; extraHeader?: React.ReactNode; isNewThread?: boolean; onContextChange?: (context: Omit) => void; onSubmit?: (message: PromptInputMessage) => void; onStop?: () => void; }) { const { t } = useI18n(); const [modelDialogOpen, setModelDialogOpen] = useState(false); const { models } = useModels(); const selectedModel = useMemo( () => models.find((m) => m.name === context.model_name), [context.model_name, models], ); const supportThinking = useMemo( () => selectedModel?.supports_thinking ?? false, [selectedModel], ); const mode = useMemo(() => { if (context.is_plan_mode) { return "pro"; } if (context.thinking_enabled) { return "thinking"; } return "flash"; }, [context.thinking_enabled, context.is_plan_mode]); const handleModelSelect = useCallback( (model_name: string) => { const supports_thinking = selectedModel?.supports_thinking ?? false; onContextChange?.({ ...context, model_name, thinking_enabled: supports_thinking && context.thinking_enabled, }); setModelDialogOpen(false); }, [selectedModel?.supports_thinking, onContextChange, context], ); const handleModeSelect = useCallback( (mode: "flash" | "thinking" | "pro") => { if (mode === "flash") { onContextChange?.({ ...context, thinking_enabled: false, is_plan_mode: false, }); } else if (mode === "thinking") { onContextChange?.({ ...context, thinking_enabled: true, is_plan_mode: false, }); } else if (mode === "pro") { onContextChange?.({ ...context, thinking_enabled: true, is_plan_mode: true, }); } }, [onContextChange, context], ); const handleSubmit = useCallback( async (message: PromptInputMessage) => { if (status === "streaming") { onStop?.(); return; } if (!message.text) { return; } onSubmit?.(message); }, [onSubmit, onStop, status], ); return ( {extraHeader && (
{extraHeader}
)} {(attachment) => } {t.inputBox.mode} handleModeSelect("flash")} >
{t.inputBox.flashMode}
{t.inputBox.flashModeDescription}
{mode === "flash" ? ( ) : (
)} {supportThinking && ( handleModeSelect("thinking")} >
{t.inputBox.reasoningMode}
{t.inputBox.reasoningModeDescription}
{mode === "thinking" ? ( ) : (
)} )} handleModeSelect("pro")} >
{t.inputBox.proMode}
{t.inputBox.proModeDescription}
{mode === "pro" ? ( ) : (
)} {selectedModel?.display_name} {models.map((m) => ( handleModelSelect(m.name)} > {m.display_name} {m.name === context.model_name ? ( ) : (
)} ))} {!isNewThread && (
)} ); }