diff --git a/app/frontend/src/components/ModelManager.jsx b/app/frontend/src/components/ModelManager.jsx index 5ef227b..c3a84ab 100644 --- a/app/frontend/src/components/ModelManager.jsx +++ b/app/frontend/src/components/ModelManager.jsx @@ -398,6 +398,7 @@ function ModelManager({ backendMode: sdStatus.settings?.backendMode || sdStatus.loading?.backendMode || "", backendBinary: sdStatus.settings?.backendBinary || sdStatus.loading?.backendBinary || "", backendDevice: sdStatus.settings?.backendDevice || sdStatus.loading?.device || "", + llmBackendMode: llmStatus.settings?.backendMode || llmStatus.settings?.backendBinary || "", }); if (llmStatus.ready) { @@ -1002,6 +1003,13 @@ function ModelManager({

The local C++ llama.cpp server is running. Chat requests can be sent via the Text Chat interface.

+ {backendInfo.llmBackendMode && ( +
+ + {backendInfo.llmBackendMode} + +
+ )} diff --git a/app/frontend/src/components/Settings.jsx b/app/frontend/src/components/Settings.jsx index 3b3ca4a..fd23622 100644 --- a/app/frontend/src/components/Settings.jsx +++ b/app/frontend/src/components/Settings.jsx @@ -1,6 +1,6 @@ -import React, { memo, useEffect } from "react"; +import React, { memo, useEffect, useState } from "react"; import { Crop, Sliders, Cpu, Info, MessageSquare, SlidersHorizontal, Zap } from "lucide-react"; -import { stopServer, formatBytes } from "../services/api"; +import { stopServer, formatBytes, getLlmStatus } from "../services/api"; const ASPECT_RATIOS = [ { id: "1:1", label: "1:1 Square", width: 512, height: 512, sdxl_width: 1024, sdxl_height: 1024, desc: "Social posts & avatars" }, @@ -55,6 +55,26 @@ function Settings({ const cleanupBytes = (cleanupItems || []).reduce((sum, item) => sum + Number(item.sizeBytes || 0), 0); const showReadinessPanel = Boolean(health && (readinessIssues.length > 0 || (cleanupItems && cleanupItems.length > 0))); + const [llmStatus, setLlmStatus] = useState({ ready: false, settings: {} }); + + useEffect(() => { + let cancelled = false; + const fetchLlmStatus = async () => { + try { + const status = await getLlmStatus(); + if (!cancelled) setLlmStatus(status); + } catch (_) {} + }; + fetchLlmStatus(); + const interval = setInterval(fetchLlmStatus, 3000); + return () => { + cancelled = true; + clearInterval(interval); + }; + }, []); + + const supportsThinking = Boolean(llmStatus.ready && llmStatus.settings?.supportsThinking); + useEffect(() => { if (isOpenVinoNpu && constraints.steps > 8) { setConstraints((prev) => ({ ...prev, steps: 8, npuSteps: 8 })); @@ -523,7 +543,8 @@ function Settings({ - {/* Show Thinking Process toggle */} + {/* Show Thinking Process toggle - only for models that support it */} + {supportsThinking && (
+ )} + {!supportsThinking && llmStatus.ready && ( +
+ Thinking not supported. The loaded model does not support reasoning/thinking output. DeepThink is only available for models like DeepSeek-R1, Qwen3, Gemma-4-E2B, and other reasoning-capable models. +
+ )} {/* Temperature slider */}
diff --git a/app/frontend/src/components/TextChat.jsx b/app/frontend/src/components/TextChat.jsx index 5c2c7d9..2e0ccba 100644 --- a/app/frontend/src/components/TextChat.jsx +++ b/app/frontend/src/components/TextChat.jsx @@ -147,6 +147,7 @@ function TextChat({ const [attachments, setAttachments] = useState([]); const fileInputRef = useRef(null); const supportsVision = Boolean(status.ready && status.settings?.supportsVision); + const supportsThinking = Boolean(status.ready && status.settings?.supportsThinking); const isImage = (file) => { return /\.(jpe?g|png|webp)$/i.test(file.name) || file.type.startsWith("image/"); @@ -888,7 +889,7 @@ function TextChat({ rows={1} /> - {status.ready && ( + {status.ready && supportsThinking && (