feat(canvas): add deep-thinking toggle for image mode and polish video mode icon
Some checks failed
Lint / build (20) (push) Has been cancelled
Playwright Tests / test (push) Has been cancelled

This commit is contained in:
Your Name 2026-02-20 20:13:30 +08:00
parent b5f6fd3842
commit a1691fbd39
4 changed files with 52 additions and 14 deletions

View File

@ -1503,6 +1503,7 @@ export async function POST(request: Request) {
selectedVisibilityType,
hiddenPrompt,
autoContext,
deepThinkingEnabled,
}: {
id: string;
message: ChatMessage;
@ -1510,6 +1511,7 @@ export async function POST(request: Request) {
selectedVisibilityType: VisibilityType;
hiddenPrompt?: string;
autoContext?: string;
deepThinkingEnabled?: boolean;
} = requestBody;
const now = Date.now();
@ -1552,6 +1554,7 @@ export async function POST(request: Request) {
let smartAutoHistoryImages: string[] = []; // 从历史对话中提取的图片URL(支持多张)
let smartAutoNeedsClarification = false; // 是否需要先追问用户
let smartAutoClarificationQuestion: string | undefined;
const deepThinkingOn = deepThinkingEnabled !== false;
let shouldRunAgentConversation = finalModelId === "auto";
let shouldKeepSelectedModel = false;
const requestedModelId = selectedChatModel;
@ -1604,17 +1607,23 @@ export async function POST(request: Request) {
? fixedImageProviderTypes.has(selectedModelProviderType)
: false));
if (isAiModelAgentAuto(selectedModelConfig)) {
shouldRunAgentConversation = true;
shouldKeepSelectedModel = false;
if (deepThinkingOn) {
if (isAiModelAgentAuto(selectedModelConfig)) {
shouldRunAgentConversation = true;
shouldKeepSelectedModel = false;
console.log(
`[Smart Auto Mode] 🧠 Agent-only model detected, force auto routing: ${selectedModelConfig.displayName}`
);
} else if (isFixedVisualModel) {
shouldRunAgentConversation = true;
shouldKeepSelectedModel = true;
console.log(
`[Smart Auto Mode] 🎯 Agent conversation enabled for fixed visual model: ${selectedModelConfig.displayName} (${selectedModelProviderType || "unknown"})`
);
}
} else if (isFixedVisualModel || isAiModelAgentAuto(selectedModelConfig)) {
console.log(
`[Smart Auto Mode] 🧠 Agent-only model detected, force auto routing: ${selectedModelConfig.displayName}`
);
} else if (isFixedVisualModel) {
shouldRunAgentConversation = true;
shouldKeepSelectedModel = true;
console.log(
`[Smart Auto Mode] 🎯 Agent conversation enabled for fixed visual model: ${selectedModelConfig.displayName} (${selectedModelProviderType || "unknown"})`
`[Smart Auto Mode] ⏭️ Deep thinking disabled, skip agent analysis for: ${selectedModelConfig.displayName}`
);
}
}

View File

@ -55,6 +55,7 @@ export const postRequestBodySchema = z.object({
// 支持预定义模型名称或数据库中的模型 UUID
selectedChatModel: z.string().min(1).max(128),
selectedVisibilityType: z.enum(["public", "private"]),
deepThinkingEnabled: z.boolean().optional(),
videoParams: videoParamsSchema, // 视频参数
imageParams: imageParamsSchema, // 🆕 图片生成参数
});

View File

@ -5,7 +5,7 @@ import { DefaultChatTransport } from "ai";
import { useEffect, useRef, useState, useCallback, useMemo } from "react";
import { createPortal } from "react-dom";
import useSWR from "swr";
import { Send, Loader2, ImagePlus, Paperclip, X, User, Bot, Plus, History, LayoutGrid, Maximize2, RefreshCw, Globe, Box, ArrowUp, Video, Sparkles, Check, ChevronDown, ChevronUp, AlertCircle, CheckCircle2 } from "lucide-react";
import { Send, Loader2, ImagePlus, Paperclip, X, User, Bot, Plus, History, LayoutGrid, Maximize2, RefreshCw, Globe, Box, ArrowUp, Video, Sparkles, Check, ChevronDown, ChevronUp, AlertCircle, CheckCircle2, Brain } from "lucide-react";
import { Button } from "@/components/ui/button";
import { Textarea } from "@/components/ui/textarea";
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
@ -808,8 +808,10 @@ export function CanvasChatPanel({ chatId, initialMessages = [], onClose, onOpenF
const [videoSlotUploading, setVideoSlotUploading] = useState<number | null>(null);
const [lastImageModelId, setLastImageModelId] = useState<string | null>(null);
const [lastVideoModelId, setLastVideoModelId] = useState<string | null>(null);
const [deepThinkingEnabled, setDeepThinkingEnabled] = useState(true);
const imageParamsRef = useRef(imageParams);
const videoParamsRef = useRef(videoParams);
const deepThinkingEnabledRef = useRef(deepThinkingEnabled);
// 🆕 保存图片参数到 localStorage
const handleImageParamsChange = (params: ImageGenerationParams) => {
@ -1614,6 +1616,10 @@ export function CanvasChatPanel({ chatId, initialMessages = [], onClose, onOpenF
videoParamsRef.current = videoParams;
}, [videoParams]);
useEffect(() => {
deepThinkingEnabledRef.current = deepThinkingEnabled;
}, [deepThinkingEnabled]);
useEffect(() => {
isVideoModelRef.current = isVideoModel;
}, [isVideoModel]);
@ -1898,6 +1904,10 @@ export function CanvasChatPanel({ chatId, initialMessages = [], onClose, onOpenF
message: request.messages.at(-1),
selectedChatModel: currentModelIdRef.current,
selectedVisibilityType: "private",
deepThinkingEnabled:
isVideoModelRef.current || currentModelIdRef.current === "auto"
? undefined
: deepThinkingEnabledRef.current,
videoParams: isVideoModelRef.current ? videoParamsRef.current || undefined : undefined,
imageParams: isVideoModelRef.current ? undefined : imageParamsRef.current || undefined,
hiddenPrompt,
@ -5400,6 +5410,24 @@ export function CanvasChatPanel({ chatId, initialMessages = [], onClose, onOpenF
</div>
<div className="flex items-center gap-2 flex-shrink-0">
{activeComposerMode === "image" ? (
<Button
variant="ghost"
size="icon"
title={`深度思考:${deepThinkingEnabled ? "开" : "关"}`}
className={cn(
"h-8 w-8 rounded-full border transition-colors",
deepThinkingEnabled
? "border-[#8ab0ff] bg-[#eef4ff] text-[#3b5bcc] hover:bg-[#e5efff]"
: "border-[#d8dce3] bg-white text-[#6b7280] hover:bg-[#f4f6f8]"
)}
onClick={() => setDeepThinkingEnabled((prev) => !prev)}
disabled={isSubmitting}
>
<Brain className="h-4 w-4" />
</Button>
) : null}
{activeComposerMode !== "agent" ? (
<Select
value={modelSelectValue}

View File

@ -29,7 +29,7 @@ import {
Camera,
Clock,
Settings2,
Maximize2,
Clapperboard,
Monitor,
Ratio,
} from "lucide-react";
@ -277,7 +277,7 @@ const getImageUploadConfig = () => {
className="h-8 px-2 focus-visible:ring-0 focus-visible:ring-offset-0"
title={`模式:${modeOptions.find((option) => option.value === params.mode)?.label || MODE_LABELS[params.mode]}`}
>
<Maximize2 size={14} />
<Clapperboard size={14} />
<span className="sr-only">
{`模式:${modeOptions.find((option) => option.value === params.mode)?.label || MODE_LABELS[params.mode]}`}
</span>
@ -563,7 +563,7 @@ const getImageUploadConfig = () => {
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="ghost" size="sm" className="gap-1 px-2 h-8 focus-visible:ring-0 focus-visible:ring-offset-0">
<Maximize2 size={14} />
<Clapperboard size={14} />
{modeOptions.find((option) => option.value === params.mode)?.label || MODE_LABELS[params.mode]}
<ChevronDown size={12} className="opacity-50" />
</Button>