diff --git a/studio/frontend/src/components/assistant-ui/thread.tsx b/studio/frontend/src/components/assistant-ui/thread.tsx index bece2930b3..5d22f82f92 100644 --- a/studio/frontend/src/components/assistant-ui/thread.tsx +++ b/studio/frontend/src/components/assistant-ui/thread.tsx @@ -176,6 +176,7 @@ import { } from "react"; import { create } from "zustand"; import { extractTaggedText, updateThreadMessage } from "@/features/chat/utils/update-thread-message"; +import { useIsMobile } from "@/hooks/use-mobile"; // True while a file is dragged anywhere over the chat page, so the composer // can show its "Drop files here" affordance. @@ -1436,14 +1437,16 @@ const Composer: FC<{ const mcpEnabledForChat = useChatRuntimeStore((s) => s.mcpEnabledForChat); const ragEnabled = useChatRuntimeStore((s) => s.ragEnabled); // More than 4 pills: collapse to icons only. Search, Code, and permissions - // always show; Images, RAG, Canvas and MCP are conditional. - const pillsCompact = + // always show; Images, RAG, Canvas and MCP are conditional. Narrow viewports + // collapse too: the labelled row is wider than a phone-width composer. + const isMobile = useIsMobile(); + const pillCount = 3 + - (ragEnabled ? 1 : 0) + - (supportsBuiltinImageGeneration ? 1 : 0) + - (artifactsEnabled ? 1 : 0) + - (mcpEnabledForChat ? 1 : 0) > - 4; + (ragEnabled ? 1 : 0) + + (supportsBuiltinImageGeneration ? 1 : 0) + + (artifactsEnabled ? 1 : 0) + + (mcpEnabledForChat ? 1 : 0); + const pillsCompact = isMobile || pillCount > 4; const activeThreadId = useChatRuntimeStore((s) => s.activeThreadId); const setPendingImageEditReference = useChatRuntimeStore( (s) => s.setPendingImageEditReference, diff --git a/studio/frontend/src/features/chat/shared-composer.tsx b/studio/frontend/src/features/chat/shared-composer.tsx index a72d21aa6b..3156a6411a 100644 --- a/studio/frontend/src/features/chat/shared-composer.tsx +++ b/studio/frontend/src/features/chat/shared-composer.tsx @@ -98,6 +98,7 @@ import { providerTypeSupportsVision, } from "./external-providers"; import { useExternalProvidersStore } from "./stores/external-providers-store"; +import { useIsMobile } from "@/hooks/use-mobile"; import { PLUS_MENU_ORDER, type PlusMenuItemId, @@ -813,15 +814,17 @@ export function SharedComposer({ const ragDisabled = modelLoaded && (isExternalModel || !supportsTools); const showRagPill = !isExternalModel; // Above 4 pills, collapse to icons only. Compare, Search, Code, and - // permissions always show; the rest are conditional. - const pillsCompact = + // permissions always show; the rest are conditional. Narrow viewports + // collapse too: the labelled row is wider than a phone-width composer. + const isMobile = useIsMobile(); + const pillCount = 4 + - (showImagePill ? 1 : 0) + - (showRagPill && ragEnabled ? 1 : 0) + - (showWebFetchPill ? 1 : 0) + - (artifactsEnabled ? 1 : 0) + - (mcpEnabledForChat ? 1 : 0) > - 4; + (showImagePill ? 1 : 0) + + (showRagPill && ragEnabled ? 1 : 0) + + (showWebFetchPill ? 1 : 0) + + (artifactsEnabled ? 1 : 0) + + (mcpEnabledForChat ? 1 : 0); + const pillsCompact = isMobile || pillCount > 4; // Backwards-compatible alias for call sites still referencing // `toolsDisabled` (rare; both pills used it before). const toolsDisabled = codeDisabled; @@ -1781,7 +1784,7 @@ export function SharedComposer({ />