
@@ -459,15 +477,69 @@ const ReasoningToggle: FC = () => {
const modelLoaded = useChatRuntimeStore(
(s) => !!s.params.checkpoint && !s.modelLoading,
);
+ const checkpoint = useChatRuntimeStore((s) => s.params.checkpoint);
const supportsReasoning = useChatRuntimeStore((s) => s.supportsReasoning);
+ const reasoningAlwaysOn = useChatRuntimeStore((s) => s.reasoningAlwaysOn);
const reasoningEnabled = useChatRuntimeStore((s) => s.reasoningEnabled);
const setReasoningEnabled = useChatRuntimeStore((s) => s.setReasoningEnabled);
const reasoningStyle = useChatRuntimeStore((s) => s.reasoningStyle);
const reasoningEffort = useChatRuntimeStore((s) => s.reasoningEffort);
+ const supportsReasoningOff = useChatRuntimeStore((s) => s.supportsReasoningOff);
+ const reasoningEffortLevels = useChatRuntimeStore((s) => s.reasoningEffortLevels);
const setReasoningEffort = useChatRuntimeStore((s) => s.setReasoningEffort);
- const disabled = !(modelLoaded && supportsReasoning);
+ const lastOpenRouterChosenModel = useChatRuntimeStore(
+ (s) => s.lastOpenRouterChosenModel,
+ );
+ const externalProviders = useExternalProvidersStore((s) => s.providers);
+ const externalSelection = parseExternalModelId(checkpoint);
+ const selectedExternalProvider =
+ externalSelection != null
+ ? externalProviders.find((p) => p.id === externalSelection.providerId)
+ : undefined;
+ const effectiveExternalModelId =
+ selectedExternalProvider?.providerType === "openrouter" &&
+ externalSelection?.modelId === "openrouter/free" &&
+ lastOpenRouterChosenModel
+ ? lastOpenRouterChosenModel
+ : externalSelection?.modelId;
+ const externalReasoningCaps =
+ externalSelection != null
+ ? getExternalReasoningCapabilities(
+ selectedExternalProvider?.providerType,
+ effectiveExternalModelId,
+ )
+ : null;
+ const effectiveReasoningStyle =
+ externalReasoningCaps?.reasoningStyle ?? reasoningStyle;
+ const effectiveReasoningAlwaysOn =
+ externalReasoningCaps?.reasoningAlwaysOn ?? reasoningAlwaysOn;
+ const effectiveSupportsReasoningOff =
+ externalReasoningCaps?.supportsReasoningOff ?? supportsReasoningOff;
+ const effectiveReasoningEffortLevels =
+ externalReasoningCaps?.reasoningEffortLevels ?? reasoningEffortLevels;
+ const effectiveSupportsReasoning =
+ externalReasoningCaps?.supportsReasoning ?? supportsReasoning;
+ const reasoningLockedOn =
+ effectiveSupportsReasoning &&
+ (effectiveReasoningAlwaysOn || !effectiveSupportsReasoningOff);
+ const effectiveReasoningEnabled = reasoningLockedOn ? true : reasoningEnabled;
+ const effectiveReasoningVisualEnabled =
+ effectiveReasoningEnabled && reasoningEffort !== "none";
+ const disabled = !(modelLoaded && effectiveSupportsReasoning);
+ const formatEffortLabel = (level: typeof reasoningEffort): string => {
+ if (level !== "xhigh") return level.charAt(0).toUpperCase() + level.slice(1);
+ const normalized = externalSelection?.modelId?.trim().toLowerCase() ?? "";
+ if (
+ normalized.startsWith("claude-opus-4-6") ||
+ normalized.startsWith("claude-sonnet-4-6")
+ ) {
+ return "Max";
+ }
+ return "Extra High";
+ };
+ const effortLabel = formatEffortLabel(reasoningEffort);
- if (reasoningStyle === "reasoning_effort") {
+ if (effectiveReasoningStyle === "reasoning_effort") {
return (
@@ -478,26 +550,47 @@ const ReasoningToggle: FC = () => {
"flex items-center gap-1.5 rounded-full px-2.5 py-1 text-xs font-medium transition-colors",
disabled
? "cursor-not-allowed opacity-40"
- : "bg-primary/10 text-primary hover:bg-primary/20",
+ : effectiveReasoningVisualEnabled
+ ? "bg-primary/10 text-primary hover:bg-primary/20"
+ : "text-muted-foreground hover:bg-muted-foreground/15",
)}
aria-label={`Reasoning effort: ${reasoningEffort}`}
>
-
+ {effectiveReasoningVisualEnabled ? (
+
+ ) : (
+
+ )}
- Think:{" "}
- {reasoningEffort.charAt(0).toUpperCase() +
- reasoningEffort.slice(1)}
+ Think: {effectiveReasoningVisualEnabled ? effortLabel : "None"}
- {(["low", "medium", "high"] as const).map((level) => (
+ {effectiveSupportsReasoningOff && (
+ {
+ setReasoningEnabled(false);
+ applyQwenThinkingParams(false);
+ }}
+ >
+ None
+ {!effectiveReasoningVisualEnabled ? " \u2713" : ""}
+
+ )}
+ {effectiveReasoningEffortLevels
+ .filter((level) => level !== "none")
+ .map((level) => (
setReasoningEffort(level)}
+ onSelect={() => {
+ setReasoningEffort(level);
+ setReasoningEnabled(true);
+ applyQwenThinkingParams(true);
+ }}
>
- {level.charAt(0).toUpperCase() + level.slice(1)}
- {reasoningEffort === level ? " \u2713" : ""}
+ {formatEffortLabel(level)}
+ {effectiveReasoningVisualEnabled && reasoningEffort === level ? " \u2713" : ""}
))}
@@ -508,17 +601,34 @@ const ReasoningToggle: FC = () => {
return (
);
}
diff --git a/studio/frontend/src/features/settings/settings-dialog.tsx b/studio/frontend/src/features/settings/settings-dialog.tsx
index ad91c83f6b..4e0764c5f2 100644
--- a/studio/frontend/src/features/settings/settings-dialog.tsx
+++ b/studio/frontend/src/features/settings/settings-dialog.tsx
@@ -10,6 +10,7 @@ import {
import { cn } from "@/lib/utils";
import {
Cancel01Icon,
+ CloudIcon,
Globe02Icon,
HelpCircleIcon,
Message01Icon,
@@ -20,11 +21,15 @@ import {
import { HugeiconsIcon } from "@hugeicons/react";
import { motion, useReducedMotion } from "motion/react";
import { useEffect, useRef } from "react";
-import { useSettingsDialogStore, type SettingsTab } from "./stores/settings-dialog-store";
+import {
+ useSettingsDialogStore,
+ type SettingsTab,
+} from "./stores/settings-dialog-store";
import { AboutTab } from "./tabs/about-tab";
import { ApiKeysTab } from "./tabs/api-keys-tab";
import { AppearanceTab } from "./tabs/appearance-tab";
import { ChatTab } from "./tabs/chat-tab";
+import { ConnectionsTab } from "./tabs/connections-tab";
import { GeneralTab } from "./tabs/general-tab";
import { ProfileTab } from "./tabs/profile-tab";
@@ -40,6 +45,7 @@ const TABS: TabDef[] = [
{ id: "profile", label: "Profile", icon: UserIcon },
{ id: "appearance", label: "Appearance", icon: PaintBrush02Icon },
{ id: "chat", label: "Chat", icon: Message01Icon },
+ { id: "connections", label: "Cloud", icon: CloudIcon, badge: "New" },
{ id: "api-keys", label: "API", icon: Globe02Icon, badge: "New" },
{ id: "about", label: "Help", icon: HelpCircleIcon },
];
@@ -54,6 +60,8 @@ function renderTab(tab: SettingsTab) {
return
;
case "chat":
return
;
+ case "connections":
+ return
;
case "api-keys":
return
;
case "about":
@@ -72,6 +80,7 @@ export function SettingsDialog() {
profile: null,
appearance: null,
chat: null,
+ connections: null,
"api-keys": null,
about: null,
});
@@ -100,9 +109,9 @@ export function SettingsDialog() {
Manage your Unsloth Studio preferences.
-
-