diff --git a/studio/frontend/src/components/assistant-ui/thread.tsx b/studio/frontend/src/components/assistant-ui/thread.tsx
index b3396d9a00..ad5016aae1 100644
--- a/studio/frontend/src/components/assistant-ui/thread.tsx
+++ b/studio/frontend/src/components/assistant-ui/thread.tsx
@@ -2270,6 +2270,7 @@ const ReasoningToggle: FC<{ side?: "top" | "bottom" }> = ({
type="button"
disabled={disabled}
className="unsloth-thinking-pill"
+ data-pill-label="Thinking settings"
data-active={activeLook ? "true" : "false"}
aria-label={thinkEffortAriaLabel({
modelLoaded,
@@ -2279,9 +2280,11 @@ const ReasoningToggle: FC<{ side?: "top" | "bottom" }> = ({
>
{activeLook ? (
- {isEffort ? `Thinking · ${effortLabel}` : "Thinking"}
+
+ {isEffort ? `Thinking · ${effortLabel}` : "Thinking"}
+
) : null}
-
+
= ({
}
}}
className="unsloth-thinking-pill"
+ data-pill-label="Thinking"
data-active={activeLook ? "true" : "false"}
aria-label={thinkToggleAriaLabel({
reasoningLockedOn,
@@ -2432,7 +2436,9 @@ const ReasoningToggle: FC<{ side?: "top" | "bottom" }> = ({
- {activeLook ? Thinking : null}
+ {activeLook ? (
+ Thinking
+ ) : null}
);
};
diff --git a/studio/frontend/src/features/chat/shared-composer.tsx b/studio/frontend/src/features/chat/shared-composer.tsx
index babff892bb..da0285ef49 100644
--- a/studio/frontend/src/features/chat/shared-composer.tsx
+++ b/studio/frontend/src/features/chat/shared-composer.tsx
@@ -1890,6 +1890,7 @@ export function SharedComposer({
type="button"
disabled={reasoningDisabled}
className="unsloth-thinking-pill"
+ data-pill-label="Thinking settings"
data-active={thinkingActiveLook ? "true" : "false"}
aria-label={thinkEffortAriaLabel({
modelLoaded,
@@ -1899,7 +1900,7 @@ export function SharedComposer({
>
{thinkingActiveLook ? (
-
+
{isEffort
? `Thinking · ${formatReasoningEffortLabel(
reasoningEffort,
@@ -1908,7 +1909,7 @@ export function SharedComposer({
: "Thinking"}
) : null}
-
+
- {thinkingActiveLook ? Thinking : null}
+ {thinkingActiveLook ? (
+ Thinking
+ ) : null}
)
) : null}
diff --git a/studio/frontend/src/index.css b/studio/frontend/src/index.css
index bcc3f6f9d3..159eba743f 100644
--- a/studio/frontend/src/index.css
+++ b/studio/frontend/src/index.css
@@ -1409,6 +1409,7 @@ html[data-chat-font] .aui-root {
.chat-composer-surface {
@apply relative flex w-full flex-col rounded-[32px] bg-background dark:bg-card px-1 pt-2 outline-none transition-shadow;
+ container-type: inline-size;
font-family: var(--font-sans);
background-clip: padding-box;
background-color: #ffffff;
@@ -1569,6 +1570,7 @@ html[data-chat-font] .aui-root {
/* Pill composer; own classes so compare-mode keeps its stacked layout. */
.unsloth-composer-surface {
@apply relative flex w-full flex-col rounded-[32px] bg-background dark:bg-card px-3 py-3 outline-none transition-shadow;
+ container-type: inline-size;
font-family: var(--font-sans);
background-clip: padding-box;
background-color: #ffffff;
@@ -1744,6 +1746,28 @@ html[data-chat-font] .aui-root {
cursor: pointer;
}
+ /* Keep Thinking on the control row in narrow split layouts. */
+ @container (max-width: 36rem) {
+ .unsloth-thinking-pill {
+ @apply size-8 justify-center gap-0 px-0;
+ min-height: 2rem;
+ }
+
+ .unsloth-thinking-label,
+ .unsloth-thinking-caret {
+ display: none;
+ }
+
+ .unsloth-thinking-pill[data-pill-label] {
+ position: relative;
+ }
+
+ .unsloth-thinking-pill[data-pill-label]:not([data-state="open"]):hover::after {
+ content: attr(data-pill-label);
+ @apply pointer-events-none absolute bottom-[calc(100%+6px)] left-1/2 z-50 -translate-x-1/2 rounded-full bg-black px-2.5 py-1.5 text-[11px] font-medium leading-snug whitespace-nowrap text-white shadow-md;
+ }
+ }
+
/* Smaller tick for selected Thinking options. */
.unsloth-tick {
width: 0.8rem !important;
diff --git a/tests/studio/test_chat_thinking_compact_layout.py b/tests/studio/test_chat_thinking_compact_layout.py
new file mode 100644
index 0000000000..23b6797782
--- /dev/null
+++ b/tests/studio/test_chat_thinking_compact_layout.py
@@ -0,0 +1,33 @@
+"""Responsive contract for the composer Thinking control."""
+
+from pathlib import Path
+
+
+REPO = Path(__file__).resolve().parents[2]
+THREAD_TSX = REPO / "studio/frontend/src/components/assistant-ui/thread.tsx"
+SHARED_TSX = REPO / "studio/frontend/src/features/chat/shared-composer.tsx"
+INDEX_CSS = REPO / "studio/frontend/src/index.css"
+
+
+def test_thinking_control_has_compact_hooks_in_both_composers():
+ for path in (THREAD_TSX, SHARED_TSX):
+ source = path.read_text(encoding = "utf-8")
+ assert 'className="unsloth-thinking-label"' in source
+ assert "unsloth-thinking-caret size-[15px]" in source
+ assert 'data-pill-label="Thinking settings"' in source
+
+
+def test_narrow_composer_collapses_thinking_to_the_bulb():
+ css = INDEX_CSS.read_text(encoding = "utf-8")
+
+ # Query the composer width instead of the full viewport.
+ assert css.count("container-type: inline-size;") >= 2
+ compact_start = css.index("@container (max-width: 36rem)")
+ compact_end = css.index("/* Smaller tick", compact_start)
+ compact_rule = css[compact_start:compact_end]
+
+ assert ".unsloth-thinking-pill" in compact_rule
+ assert "@apply size-8" in compact_rule
+ assert ".unsloth-thinking-label" in compact_rule
+ assert ".unsloth-thinking-caret" in compact_rule
+ assert "display: none;" in compact_rule