From 7d4d70673811bebfa07b5e0ed884d2149d1024b1 Mon Sep 17 00:00:00 2001 From: Henry Li Date: Thu, 22 Jan 2026 13:43:45 +0800 Subject: [PATCH] feat: put all options into '+' --- frontend/src/app/layout.tsx | 7 +- .../app/workspace/chats/[thread_id]/page.tsx | 12 +- .../components/ai-elements/prompt-input.tsx | 3 +- .../src/components/workspace/input-box.tsx | 260 +++++++++++------- frontend/src/core/i18n/locales/en-US.ts | 20 +- frontend/src/core/i18n/locales/types.ts | 18 +- frontend/src/core/i18n/locales/zh-CN.ts | 18 +- 7 files changed, 197 insertions(+), 141 deletions(-) diff --git a/frontend/src/app/layout.tsx b/frontend/src/app/layout.tsx index 578238b..4d4b144 100644 --- a/frontend/src/app/layout.tsx +++ b/frontend/src/app/layout.tsx @@ -30,12 +30,7 @@ export default async function RootLayout({ suppressHydrationWarning > - + {children} diff --git a/frontend/src/app/workspace/chats/[thread_id]/page.tsx b/frontend/src/app/workspace/chats/[thread_id]/page.tsx index a3ca0ef..69bb9e9 100644 --- a/frontend/src/app/workspace/chats/[thread_id]/page.tsx +++ b/frontend/src/app/workspace/chats/[thread_id]/page.tsx @@ -147,21 +147,12 @@ export default function ChatPage() {
- {isNewThread && ( -
- -
- )}
} onContextChange={(context) => setSettings("context", context) } diff --git a/frontend/src/components/ai-elements/prompt-input.tsx b/frontend/src/components/ai-elements/prompt-input.tsx index 254ce11..efa1663 100644 --- a/frontend/src/components/ai-elements/prompt-input.tsx +++ b/frontend/src/components/ai-elements/prompt-input.tsx @@ -44,6 +44,7 @@ import { PaperclipIcon, PlusIcon, SquareIcon, + UploadIcon, XIcon, } from "lucide-react"; import { nanoid } from "nanoid"; @@ -422,7 +423,7 @@ export const PromptInputActionAddAttachments = ({ attachments.openFileDialog(); }} > - {label} + {label} ); }; diff --git a/frontend/src/components/workspace/input-box.tsx b/frontend/src/components/workspace/input-box.tsx index 373005c..29e00d2 100644 --- a/frontend/src/components/workspace/input-box.tsx +++ b/frontend/src/components/workspace/input-box.tsx @@ -1,18 +1,36 @@ "use client"; import type { ChatStatus } from "ai"; -import { CheckIcon, LightbulbIcon, ListTodoIcon } from "lucide-react"; +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"; @@ -28,13 +46,12 @@ import { ModelSelectorTrigger, } from "../ai-elements/model-selector"; -import { Tooltip } from "./tooltip"; - export function InputBox({ className, autoFocus, status = "ready", context, + extraHeader, onContextChange, onSubmit, onStop, @@ -55,6 +72,19 @@ export function InputBox({ () => 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; @@ -67,18 +97,30 @@ export function InputBox({ }, [selectedModel?.supports_thinking, onContextChange, context], ); - const handleThinkingToggle = useCallback(() => { - onContextChange?.({ - ...context, - thinking_enabled: !context.thinking_enabled, - }); - }, [onContextChange, context]); - const handlePlanModeToggle = useCallback(() => { - onContextChange?.({ - ...context, - is_plan_mode: !context.is_plan_mode, - }); - }, [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") { @@ -103,6 +145,16 @@ export function InputBox({ onSubmit={handleSubmit} {...props} > + {extraHeader && ( +
+
+ {extraHeader} +
+
+ )} + + {(attachment) => } + -
- -
{t.inputBox.thinkingEnabled}
-
- {t.inputBox.clickToDisableThinking} -
-
- ) : ( -
-
{t.inputBox.thinkingDisabled}
-
- {t.inputBox.clickToEnableThinking} -
-
- ) - } - > - {selectedModel?.supports_thinking && ( - - <> - {context.thinking_enabled ? ( - - ) : ( - - )} - + + + + + + + + {t.inputBox.mode} + + + handleModeSelect("flash")} > - {t.inputBox.thinking} - - - - )} - - -
{t.inputBox.planMode}
-
- {t.inputBox.clickToDisablePlanMode} -
-
- ) : ( -
-
{t.inputBox.planMode}
-
- {t.inputBox.clickToEnablePlanMode} -
-
- ) - } - > - {selectedModel?.supports_thinking && ( - - <> - {context.is_plan_mode ? ( - - ) : ( - +
+
+ + {t.inputBox.flashMode} +
+
+ {t.inputBox.flashModeDescription} +
+
+ {mode === "flash" ? ( + + ) : ( +
+ )} + + {supportThinking && ( + handleModeSelect("thinking")} + > +
+
+ + {t.inputBox.reasoningMode} +
+
+ {t.inputBox.reasoningModeDescription} +
+
+ {mode === "thinking" ? ( + + ) : ( +
+ )} + )} - handleModeSelect("pro")} > - {t.inputBox.planMode} - - - - )} - -
-
+
+
+ + {t.inputBox.proMode} +
+
+ {t.inputBox.proModeDescription} +
+
+ {mode === "pro" ? ( + + ) : ( +
+ )} + + + + + + + -
+ ); diff --git a/frontend/src/core/i18n/locales/en-US.ts b/frontend/src/core/i18n/locales/en-US.ts index 8d1b82f..a30de91 100644 --- a/frontend/src/core/i18n/locales/en-US.ts +++ b/frontend/src/core/i18n/locales/en-US.ts @@ -39,16 +39,16 @@ export const enUS: Translations = { // Input Box inputBox: { placeholder: "How can I assist you today?", - thinking: "Thinking", - thinkingEnabled: "Thinking is enabled", - thinkingDisabled: "Thinking is disabled", - clickToDisableThinking: "Click to disable thinking", - clickToEnableThinking: "Click to enable thinking", - planMode: "Plan mode", - planModeEnabled: "Plan mode is enabled", - planModeDisabled: "Plan mode is disabled", - clickToDisablePlanMode: "Click to disable plan mode", - clickToEnablePlanMode: "Click to enable plan mode", + addAttachments: "Add attachments", + mode: "Mode", + flashMode: "Flash", + flashModeDescription: "Fast and efficient", + reasoningMode: "Reasoning", + reasoningModeDescription: + "Reasoning before action, balance between time and accuracy", + proMode: "Pro", + proModeDescription: + "Reasoning, planning and executing, get more accurate results, may take more time", searchModels: "Search models...", }, diff --git a/frontend/src/core/i18n/locales/types.ts b/frontend/src/core/i18n/locales/types.ts index 0c08144..716230f 100644 --- a/frontend/src/core/i18n/locales/types.ts +++ b/frontend/src/core/i18n/locales/types.ts @@ -36,16 +36,14 @@ export interface Translations { // Input Box inputBox: { placeholder: string; - thinking: string; - thinkingEnabled: string; - thinkingDisabled: string; - clickToDisableThinking: string; - clickToEnableThinking: string; - planMode: string; - planModeEnabled: string; - planModeDisabled: string; - clickToDisablePlanMode: string; - clickToEnablePlanMode: string; + addAttachments: string; + mode: string; + flashMode: string; + flashModeDescription: string; + reasoningMode: string; + reasoningModeDescription: string; + proMode: string; + proModeDescription: string; searchModels: string; }; diff --git a/frontend/src/core/i18n/locales/zh-CN.ts b/frontend/src/core/i18n/locales/zh-CN.ts index 6cd644a..67a8d3b 100644 --- a/frontend/src/core/i18n/locales/zh-CN.ts +++ b/frontend/src/core/i18n/locales/zh-CN.ts @@ -39,16 +39,14 @@ export const zhCN: Translations = { // Input Box inputBox: { placeholder: "今天我能为你做些什么?", - thinking: "思考", - thinkingEnabled: "思考功能已启用", - thinkingDisabled: "思考功能已禁用", - clickToDisableThinking: "点击禁用思考功能", - clickToEnableThinking: "点击启用思考功能", - planMode: "To-do 模式", - planModeEnabled: "To-do 模式已启用", - planModeDisabled: "To-do 模式已禁用", - clickToDisablePlanMode: "点击禁用 To-do 模式", - clickToEnablePlanMode: "点击启用 To-do 模式", + addAttachments: "添加附件", + mode: "模式", + flashMode: "闪速", + flashModeDescription: "快速且高效的完成任务,但可能不够精准", + reasoningMode: "思考", + reasoningModeDescription: "思考后再行动,在时间与准确性之间取得平衡", + proMode: "专业", + proModeDescription: "思考、计划再执行,获得更精准的结果,可能需要更多时间", searchModels: "搜索模型...", },