From ecbb64b492395775424652d7760688fe50bc095a Mon Sep 17 00:00:00 2001 From: Michael Han <107991372+shimmyshimmer@users.noreply.github.com> Date: Thu, 18 Jun 2026 08:53:38 -0700 Subject: [PATCH] Studio: polish Bypass permissions toggle and add it to chat menu settings (#6442) * Studio: polish Bypass permissions toggle and add it to chat menu settings - Recolor the pill, menu item and settings caption from alarm red to a bright yellow accent via a new --bypass token (light and dark). - Use the shield icon on the composer pill (X on hover, like other pills). - Expand the composer to two rows the moment Bypass permissions is on. - Keep Bypass leftmost among tool pills; Compare still sits ahead of it. - Add a Bypass permissions row to Settings > Chat menu so it can be pinned. - Widen the "More" submenu so the label fits on one line. * Studio: use shield-ban icon and lighten the Bypass permissions pill - Swap the lucide shield-off icon for the Hugeicons shield-ban across the pill, menu item and settings row. - Lighten the pill background and deepen the yellow text a touch so the label stays readable on a near-white tint. * Studio: drop the Bypass permissions resting fill, keep it on hover Show only the yellow icon and label at rest; the rounded hover pill picks up the yellow accent like the other toggles. * Studio: lighten the Bypass permissions hover fill Drop the hover tint so the yellow label stays readable on hover. --------- Co-authored-by: Unsloth --- .../src/components/assistant-ui/thread.tsx | 25 ++++++++---- .../chat/bypass-permissions-menu-item.tsx | 12 +++--- .../src/features/chat/chat-settings-sheet.tsx | 10 ++--- .../src/features/chat/shared-composer.tsx | 40 ++++++++++++------- .../src/features/settings/tabs/chat-tab.tsx | 12 ++++++ studio/frontend/src/index.css | 19 +++++++-- 6 files changed, 82 insertions(+), 36 deletions(-) diff --git a/studio/frontend/src/components/assistant-ui/thread.tsx b/studio/frontend/src/components/assistant-ui/thread.tsx index a65a157707..f719af975e 100644 --- a/studio/frontend/src/components/assistant-ui/thread.tsx +++ b/studio/frontend/src/components/assistant-ui/thread.tsx @@ -125,6 +125,7 @@ import { Image03Icon, McpServerIcon, PencilRulerIcon, + ShieldBanIcon, } from "@hugeicons/core-free-icons"; import { HugeiconsIcon } from "@hugeicons/react"; import { useNavigate } from "@tanstack/react-router"; @@ -1247,6 +1248,7 @@ const Composer: FC<{ const artifactsEnabled = useChatRuntimeStore((s) => s.artifactsEnabled); const mcpEnabledForChat = useChatRuntimeStore((s) => s.mcpEnabledForChat); const ragEnabled = useChatRuntimeStore((s) => s.ragEnabled); + const bypassPermissions = useChatRuntimeStore((s) => s.bypassPermissions); // More than 4 pills: collapse to icons only. Search and Code always show; // Images, RAG, Canvas and MCP are conditional. const pillsCompact = @@ -1368,6 +1370,8 @@ const Composer: FC<{ }, [composerText, draftKey]); // Two-row layout shows once the input wraps or a tool is on. Tools can // pre-select before a model loads, so an active toggle expands it either way. + // Bypass permissions counts too: turning it on should drop the composer into + // the two-row layout immediately, same as Search/Code. const composerExpanded = isMultiline || hasAttachments || @@ -1377,7 +1381,8 @@ const Composer: FC<{ imageToolsEnabled || ragEnabled || artifactsEnabled || - mcpEnabledForChat; + mcpEnabledForChat || + bypassPermissions; // react-textarea-autosize re-measures only on value change or window resize, // not on the width swap from expanding, so it keeps the taller height and // leaves a stray blank row. Nudge a resize whenever input width changes. @@ -2430,7 +2435,7 @@ const ArtifactsToggle: FC = () => { ); }; -// Red pill shown while Bypass Permissions is on; click to turn it off. +// Claude gold pill shown while Bypass permissions is on; click to turn it off. // Mirror of shared-composer's badge so both composers surface the state. const BypassPermissionsToggle: FC = () => { const bypassPermissions = useChatRuntimeStore((s) => s.bypassPermissions); @@ -2445,11 +2450,17 @@ const BypassPermissionsToggle: FC = () => { className="composer-pill-btn" data-active="true" data-variant="danger" - aria-label="Disable Bypass Permissions" - title="Bypass Permissions is on (no confirmation, no sandbox). Click to turn off." + aria-label="Disable Bypass permissions" + title="Bypass permissions is on (no confirmation, no sandbox). Click to turn off." > - - Bypass Permissions + + + + Bypass permissions ); }; @@ -2959,7 +2970,7 @@ const ComposerToolsMenu: FC<{ side?: "top" | "bottom" }> = ({ More - + {overflowPlusItems.map((id) => ( {plusMenuNodes[id]} ))} diff --git a/studio/frontend/src/features/chat/bypass-permissions-menu-item.tsx b/studio/frontend/src/features/chat/bypass-permissions-menu-item.tsx index 824d946d06..2f61d07a52 100644 --- a/studio/frontend/src/features/chat/bypass-permissions-menu-item.tsx +++ b/studio/frontend/src/features/chat/bypass-permissions-menu-item.tsx @@ -1,9 +1,9 @@ // 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 { ShieldOffIcon } from "lucide-react"; import { useState } from "react"; +import { ShieldBanIcon } from "@hugeicons/core-free-icons"; import { HugeiconsIcon } from "@hugeicons/react"; import { @@ -35,7 +35,7 @@ export function BypassPermissionsMenuItem() { <> { if (bypassPermissions) { @@ -46,8 +46,8 @@ export function BypassPermissionsMenuItem() { } }} > - - Bypass Permissions + + Bypass permissions {bypassPermissions ? ( ) : null} @@ -55,9 +55,9 @@ export function BypassPermissionsMenuItem() { - Enable Bypass Permissions? + Enable Bypass permissions? - Bypass Permissions is dangerous since the AI model might delete, + Bypass permissions is dangerous since the AI model might delete, corrupt your machine, and or cause real world damage to you or the world - only accept if you are certain diff --git a/studio/frontend/src/features/chat/chat-settings-sheet.tsx b/studio/frontend/src/features/chat/chat-settings-sheet.tsx index b10c50262d..a4115d58bb 100644 --- a/studio/frontend/src/features/chat/chat-settings-sheet.tsx +++ b/studio/frontend/src/features/chat/chat-settings-sheet.tsx @@ -1762,7 +1762,7 @@ function ConfirmToolCallsToggle() { {bypassPermissions ? ( - Overridden by Bypass Permissions + Overridden by Bypass permissions ) : null} @@ -1788,7 +1788,7 @@ function BypassPermissionsToggle() {
- Bypass Permissions + Bypass permissions Dangerous. Runs every tool call with no confirmation and disables @@ -1806,16 +1806,16 @@ function BypassPermissionsToggle() { />
{bypassPermissions ? ( - + Tool calls run with no confirmation and no sandbox. ) : null} - Enable Bypass Permissions? + Enable Bypass permissions? - Bypass Permissions is dangerous since the AI model might delete, + Bypass permissions is dangerous since the AI model might delete, corrupt your machine, and or cause real world damage to you or the world - only accept if you are certain diff --git a/studio/frontend/src/features/chat/shared-composer.tsx b/studio/frontend/src/features/chat/shared-composer.tsx index 8ad355344c..13aaba11d5 100644 --- a/studio/frontend/src/features/chat/shared-composer.tsx +++ b/studio/frontend/src/features/chat/shared-composer.tsx @@ -47,6 +47,7 @@ import { Image03Icon, McpServerIcon, PencilRulerIcon, + ShieldBanIcon, } from "@hugeicons/core-free-icons"; import { useNavigate } from "@tanstack/react-router"; import { HugeiconsIcon } from "@hugeicons/react"; @@ -1593,7 +1594,7 @@ export function SharedComposer({ More - + {overflowPlusItems.map((id) => ( {plusMenuNodes[id]} ))} @@ -1616,6 +1617,29 @@ export function SharedComposer({ Compare + {/* Bypass sits immediately after Compare and ahead of every other + tool pill (Search, Code, ...) so the active danger state reads + first; only Compare outranks it. */} + {bypassPermissions && ( + + )} - )}
{/* mr-0.5 matches the send button inset from the edge in normal chat; gap-1.5 matches its control spacing. */} diff --git a/studio/frontend/src/features/settings/tabs/chat-tab.tsx b/studio/frontend/src/features/settings/tabs/chat-tab.tsx index 8a832a3bc4..3b46308bb1 100644 --- a/studio/frontend/src/features/settings/tabs/chat-tab.tsx +++ b/studio/frontend/src/features/settings/tabs/chat-tab.tsx @@ -43,6 +43,7 @@ import { Folder01Icon, McpServerIcon, PencilRulerIcon, + ShieldBanIcon, Upload01Icon, } from "@hugeicons/core-free-icons"; import { HugeiconsIcon } from "@hugeicons/react"; @@ -130,6 +131,17 @@ const PLUS_MENU_SETTINGS: { id: PlusMenuItemId; label: string; icon: ReactNode } /> ), }, + { + id: "bypassPermissions", + label: "Bypass permissions", + icon: ( + + ), + }, ]; export function ChatTab() { diff --git a/studio/frontend/src/index.css b/studio/frontend/src/index.css index 42b8bca35f..32733c6ad7 100644 --- a/studio/frontend/src/index.css +++ b/studio/frontend/src/index.css @@ -129,6 +129,8 @@ --accent: oklch(0.9596 0.0275 167.8295); --accent-foreground: oklch(0.2868 0.0649 159.9823); --destructive: oklch(0.6368 0.2078 25.3313); + /* Bypass permissions accent: bright, saturated yellow (not dark gold). */ + --bypass: #c99d00; --border: oklch(0.9208 0.0101 164.8536); --input: oklch(0.9208 0.0101 164.8536); --ring: #17b88b; @@ -251,6 +253,8 @@ --accent: #3a3d43; --accent-foreground: #ececee; --destructive: oklch(0.6368 0.2078 25.3313); + /* Bypass permissions accent: bright, saturated neon yellow on dark. */ + --bypass: #ffd60a; /* --border / --input one step lighter than --muted so outlines and form borders stay visible on muted surfaces (right config panel, export tiles, quant chips) and keep subtle contrast on card. */ @@ -344,6 +348,7 @@ --color-input: var(--input); --color-border: var(--border); --color-destructive: var(--destructive); + --color-bypass: var(--bypass); --color-accent-foreground: var(--accent-foreground); --color-accent: var(--accent); --color-muted-foreground: var(--muted-foreground); @@ -1047,10 +1052,18 @@ .composer-pill-btn[data-active="true"] { color: var(--primary); } - /* Bypass Permissions badge: red, always-visible active warning. */ + /* Bypass permissions badge: bright yellow text, no resting fill; the + rounded hover pill picks up the yellow accent like other toggles. */ .composer-pill-btn[data-variant="danger"] { - @apply bg-destructive/10 hover:bg-destructive/15; - color: var(--destructive); + background-color: transparent; + color: var(--bypass); + } + .composer-pill-btn[data-variant="danger"]:hover { + background-color: color-mix(in oklab, var(--bypass) 7%, transparent); + } + /* Match the hover-X circle to the yellow accent instead of the green primary. */ + .composer-pill-btn[data-variant="danger"] .composer-pill-x { + background-color: color-mix(in oklab, var(--bypass) 13%, transparent); } /* With more than 4 tools on, drop pill labels to icons only to cut clutter.