+
Saving a preset also stores current load settings (context length,
KV cache dtype, speculative decoding, GPU layers).
{currentLoadSummary ? (
diff --git a/studio/frontend/src/features/chat/hooks/use-chat-model-runtime.ts b/studio/frontend/src/features/chat/hooks/use-chat-model-runtime.ts
index 76a310ac33..bb19223a6a 100644
--- a/studio/frontend/src/features/chat/hooks/use-chat-model-runtime.ts
+++ b/studio/frontend/src/features/chat/hooks/use-chat-model-runtime.ts
@@ -1271,12 +1271,19 @@ export function useChatModelRuntime() {
prog.expected_bytes,
dlSamples,
);
- setLoadProgress({
- percent: pct,
- label: progressLabel,
- phase: "downloading",
- });
- if (loadToastDismissedRef.current) return;
+ // loadProgress state is only read by the dismissed-toast inline
+ // status. Writing it while the toast is visible re-renders the
+ // whole chat page every poll — cheap in Chrome, janky in the
+ // desktop WebView2 (laggy typing). Feed the toast directly and
+ // only touch state when the inline view is actually live.
+ if (loadToastDismissedRef.current) {
+ setLoadProgress({
+ percent: pct,
+ label: progressLabel,
+ phase: "downloading",
+ });
+ return;
+ }
toast(null, {
id: toastId,
...modelLoadToastOptions(
@@ -1298,19 +1305,23 @@ export function useChatModelRuntime() {
const est = estimate(dlSamples, prog.downloaded_bytes, 0);
const rateSuffix =
est.stable ? ` • ${formatRate(est.rate)}` : "";
- setLoadProgress({
- percent: null,
- label: `${dlGb.toFixed(1)} GB downloaded${rateSuffix}`,
- phase: "downloading",
- });
+ // Inline-status-only state; skip the chat-page re-render unless it's shown.
+ if (loadToastDismissedRef.current) {
+ setLoadProgress({
+ percent: null,
+ label: `${dlGb.toFixed(1)} GB downloaded${rateSuffix}`,
+ phase: "downloading",
+ });
+ }
} else if (prog.progress >= 1 && hasShownProgress) {
downloadComplete = true;
- setLoadProgress({
- percent: 100,
- label: "Download complete",
- phase: "starting",
- });
- if (!loadToastDismissedRef.current) {
+ if (loadToastDismissedRef.current) {
+ setLoadProgress({
+ percent: 100,
+ label: "Download complete",
+ phase: "starting",
+ });
+ } else {
toast(null, {
id: toastId,
...modelLoadToastOptions(
@@ -1364,12 +1375,17 @@ export function useChatModelRuntime() {
formatEta(est.eta) !== "--" ? ` • ${formatEta(est.eta)} left` : ""
}`
: base;
- setLoadProgress({
- percent: pct,
- label,
- phase: "starting",
- });
- if (loadToastDismissedRef.current) return;
+ // Inline-status-only state (see pollDownload): while the toast is
+ // up, skip the state write so the chat page doesn't re-render every
+ // poll during "Starting model" — the desktop WebView2 typing-lag fix.
+ if (loadToastDismissedRef.current) {
+ setLoadProgress({
+ percent: pct,
+ label,
+ phase: "starting",
+ });
+ return;
+ }
toast(null, {
id: toastId,
...modelLoadToastOptions(
diff --git a/studio/frontend/src/features/chat/permission-mode-select.tsx b/studio/frontend/src/features/chat/permission-mode-select.tsx
index f3e1594795..2fafeab7d6 100644
--- a/studio/frontend/src/features/chat/permission-mode-select.tsx
+++ b/studio/frontend/src/features/chat/permission-mode-select.tsx
@@ -1,13 +1,8 @@
// SPDX-License-Identifier: AGPL-3.0-only
// Copyright 2026-present the Unsloth AI Inc. team. All rights reserved. See /studio/LICENSE.AGPL-3.0
-import {
- ChevronDown,
- CircleAlert,
- CircleOff,
- Hand,
- ShieldCheck,
-} from "lucide-react";
+import { ChevronDown, CircleAlert, Hand, ShieldCheck } from "lucide-react";
+import type { ComponentType } from "react";
import { useState } from "react";
import {
@@ -29,6 +24,7 @@ import {
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
import { ChevronDownStandardIcon } from "@/lib/chevron-icons";
+import { SparklesGlyph } from "@/lib/sparkles-icon";
import { Tick02Icon } from "@/lib/tick-icon";
import { cn } from "@/lib/utils";
import { HugeiconsIcon } from "@hugeicons/react";
@@ -45,7 +41,7 @@ export const PERMISSION_MODE_OPTIONS: readonly {
value: PermissionMode;
label: string;
description: string;
- icon: typeof Hand;
+ icon: ComponentType<{ className?: string; strokeWidth?: number }>;
}[] = [
{
value: "ask",
@@ -63,7 +59,7 @@ export const PERMISSION_MODE_OPTIONS: readonly {
value: "off",
label: "Run automatically",
description: "Run tool calls without approval prompts inside the sandbox",
- icon: CircleOff,
+ icon: SparklesGlyph,
},
{
value: "full",
diff --git a/studio/frontend/src/features/model-picker/components/model-selector.tsx b/studio/frontend/src/features/model-picker/components/model-selector.tsx
index cda6e49e24..9ae7e59a1f 100644
--- a/studio/frontend/src/features/model-picker/components/model-selector.tsx
+++ b/studio/frontend/src/features/model-picker/components/model-selector.tsx
@@ -301,12 +301,12 @@ const HUB_SECTION_TABS: { value: string; label: string; icon?: ReactNode }[] = [
{
value: "recommended",
label: "Recommended",
- icon: