import { type ProviderDriverKind, type ProviderInstanceId, type ProviderOptionDescriptor, type ProviderOptionSelection, type ScopedThreadRef, type ServerProviderModel,} from "@t3tools/contracts";import { applyClaudePromptEffortPrefix, buildProviderOptionSelectionsFromDescriptors, getProviderOptionCurrentLabel, getProviderOptionCurrentValue, getProviderOptionDescriptors, isClaudeUltrathinkPrompt,} from "@t3tools/shared/model";import { memo, useCallback, useState } from "react";import type { VariantProps } from "class-variance-authority";import { ZapIcon } from "lucide-react";import { buttonVariants } from "../ui/button";import { Menu, MenuGroup, MenuPopup, MenuRadioGroup, MenuRadioItem, MenuSeparator as MenuDivider, MenuTrigger,} from "../ui/menu";import { useComposerDraftStore, DraftId } from "../../composerDraftStore";import { getProviderModelCapabilities } from "../../providerModels";import { cn } from "~/lib/utils";import { Badge } from "../ui/badge";import { ComposerControl, ComposerControlChevron, ComposerControlIcon } from "./ComposerControl"; type ProviderOptions = ReadonlyArray<ProviderOptionSelection>; type TraitsPersistence = | { threadRef?: ScopedThreadRef; draftId?: DraftId; onModelOptionsChange?: never; } | { threadRef?: undefined; onModelOptionsChange: (nextOptions: ProviderOptions | undefined) => void; }; const ULTRATHINK_PROMPT_PREFIX = "Ultrathink:\n"; function DefaultBadge() { return ( <Badge variant="outline" className="inline-flex h-4 w-fit min-w-0 items-center justify-center gap-0 border-border/70 bg-muted/60 px-1.5 py-0 font-semibold text-[10px] text-muted-foreground leading-none sm:h-4" > Default </Badge> );} function replaceDescriptorCurrentValue( descriptors: ReadonlyArray<ProviderOptionDescriptor>, descriptorId: string, currentValue: string | boolean | undefined,): ReadonlyArray<ProviderOptionDescriptor> { return descriptors.map((descriptor) => descriptor.id !== descriptorId ? descriptor : descriptor.type === "boolean" ? { ...descriptor, ...(typeof currentValue === "boolean" ? { currentValue } : {}), } : { ...descriptor, ...(typeof currentValue === "string" ? { currentValue } : {}), }, );} function getDescriptorStringValue( descriptor: Extract<ProviderOptionDescriptor, { type: "select" }> | null,): string | null { if (!descriptor) { return null; } const value = getProviderOptionCurrentValue(descriptor); return typeof value === "string" ? value : null;} function getSelectedTraits( provider: ProviderDriverKind, models: ReadonlyArray<ServerProviderModel>, model: string | null | undefined, prompt: string, modelOptions: ProviderOptions | null | undefined, allowPromptInjectedEffort: boolean,) { const caps = getProviderModelCapabilities(models, model, provider); const descriptors = getProviderOptionDescriptors({ caps, selections: modelOptions, }); const selectDescriptors = descriptors.filter( (descriptor): descriptor is Extract<ProviderOptionDescriptor, { type: "select" }> => descriptor.type === "select", ); const booleanDescriptors = descriptors.filter( (descriptor): descriptor is Extract<ProviderOptionDescriptor, { type: "boolean" }> => descriptor.type === "boolean", ); const primarySelectDescriptor = selectDescriptors[0] ?? null; const contextWindowDescriptor = selectDescriptors.find((descriptor) => descriptor.id === "contextWindow") ?? null; const agentDescriptor = selectDescriptors.find((descriptor) => descriptor.id === "agent") ?? null; const fastModeDescriptor = booleanDescriptors.find((descriptor) => descriptor.id === "fastMode") ?? null; const thinkingDescriptor = booleanDescriptors.find((descriptor) => descriptor.id === "thinking") ?? null; // Prompt-controlled effort (e.g. ultrathink in prompt text) const ultrathinkPromptControlled = allowPromptInjectedEffort && (primarySelectDescriptor?.promptInjectedValues?.length ?? 0) > 0 && isClaudeUltrathinkPrompt(prompt); // Check if "ultrathink" appears in the body text (not just our prefix) const ultrathinkInBodyText = ultrathinkPromptControlled && isClaudeUltrathinkPrompt(prompt.replace(/^Ultrathink:\s*/i, "")); const effort = (ultrathinkPromptControlled ? "ultrathink" : getDescriptorStringValue(primarySelectDescriptor)) ?? null; const thinkingEnabled = typeof thinkingDescriptor?.currentValue === "boolean" ? thinkingDescriptor.currentValue : null; const contextWindow = getDescriptorStringValue(contextWindowDescriptor); const selectedAgent = getDescriptorStringValue(agentDescriptor); const selectedAgentLabel = agentDescriptor ? getProviderOptionCurrentLabel(agentDescriptor) : null; return { caps, descriptors, selectDescriptors, booleanDescriptors, primarySelectDescriptor, contextWindowDescriptor, agentDescriptor, fastModeDescriptor, thinkingDescriptor, effort, thinkingEnabled, contextWindow, ultrathinkPromptControlled, ultrathinkInBodyText, selectedAgent, selectedAgentLabel, };} function getTraitsSectionVisibility(input: { provider: ProviderDriverKind; models: ReadonlyArray<ServerProviderModel>; model: string | null | undefined; prompt: string; modelOptions: ProviderOptions | null | undefined; allowPromptInjectedEffort?: boolean;}) { const selected = getSelectedTraits( input.provider, input.models, input.model, input.prompt, input.modelOptions, input.allowPromptInjectedEffort ?? true, ); const showEffort = selected.primarySelectDescriptor !== null; const showThinking = selected.thinkingDescriptor !== null; const showFastMode = selected.fastModeDescriptor !== null; const showContextWindow = selected.contextWindowDescriptor !== null; const showAgent = selected.agentDescriptor !== null; return { ...selected, showEffort, showThinking, showFastMode, showContextWindow, showAgent, hasAnyControls: showEffort || showThinking || showFastMode || showContextWindow || showAgent, };} export function shouldRenderTraitsControls(input: { provider: ProviderDriverKind; models: ReadonlyArray<ServerProviderModel>; model: string | null | undefined; prompt: string; modelOptions: ProviderOptions | null | undefined; allowPromptInjectedEffort?: boolean;}): boolean { return getTraitsSectionVisibility(input).hasAnyControls;} export interface TraitsMenuContentProps { provider: ProviderDriverKind; instanceId?: ProviderInstanceId; models: ReadonlyArray<ServerProviderModel>; model: string | null | undefined; prompt: string; onPromptChange: (prompt: string) => void; modelOptions?: ProviderOptions | null | undefined; allowPromptInjectedEffort?: boolean; triggerVariant?: VariantProps<typeof buttonVariants>["variant"]; triggerClassName?: string;} export const TraitsMenuContent = memo(function TraitsMenuContentImpl({ provider, instanceId, models, model, prompt, onPromptChange, modelOptions, allowPromptInjectedEffort = true, ...persistence}: TraitsMenuContentProps & TraitsPersistence) { const setProviderModelOptions = useComposerDraftStore((store) => store.setProviderModelOptions); const updateModelOptions = useCallback( (nextOptions: ProviderOptions | undefined) => { if ("onModelOptionsChange" in persistence) { persistence.onModelOptionsChange(nextOptions); return; } const threadTarget = persistence.threadRef ?? persistence.draftId; if (!threadTarget) { return; } setProviderModelOptions(threadTarget, provider, nextOptions, { ...(instanceId ? { instanceId } : {}), model, persistSticky: true, }); }, [instanceId, model, persistence, provider, setProviderModelOptions], ); const { descriptors, selectDescriptors, booleanDescriptors, primarySelectDescriptor, ultrathinkPromptControlled, ultrathinkInBodyText, hasAnyControls, } = getTraitsSectionVisibility({ provider, models, model, prompt, modelOptions, allowPromptInjectedEffort, }); const updateDescriptors = (nextDescriptors: ReadonlyArray<ProviderOptionDescriptor>) => { updateModelOptions(buildProviderOptionSelectionsFromDescriptors(nextDescriptors)); }; const handleSelectChange = ( descriptor: Extract<ProviderOptionDescriptor, { type: "select" }>, value: string, ) => { if (!value) return; if (descriptor.promptInjectedValues?.includes(value)) { const nextPrompt = prompt.trim().length === 0 ? ULTRATHINK_PROMPT_PREFIX : applyClaudePromptEffortPrefix(prompt, "ultrathink"); onPromptChange(nextPrompt); return; } if (ultrathinkInBodyText && descriptor.id === primarySelectDescriptor?.id) return; if (ultrathinkPromptControlled && descriptor.id === primarySelectDescriptor?.id) { const stripped = prompt.replace(/^Ultrathink:\s*/i, ""); onPromptChange(stripped); } updateDescriptors(replaceDescriptorCurrentValue(descriptors, descriptor.id, value)); }; if (!hasAnyControls) { return null; } return ( <> {selectDescriptors.map((descriptor, index) => { const selectedValue = ultrathinkPromptControlled && descriptor.id === primarySelectDescriptor?.id ? "ultrathink" : (getDescriptorStringValue(descriptor) ?? ""); return ( <div key={descriptor.id}> {index > 0 ? <MenuDivider /> : null} <MenuGroup> <div className="px-2 pt-1.5 pb-1 font-medium text-muted-foreground text-xs"> {descriptor.label} </div> {ultrathinkInBodyText && descriptor.id === primarySelectDescriptor?.id ? ( <div className="px-2 pb-1.5 text-muted-foreground/80 text-xs"> Your prompt contains "ultrathink" in the text. Remove it to change this option. </div> ) : null} <MenuRadioGroup value={selectedValue} onValueChange={(value) => handleSelectChange(descriptor, value)} > {descriptor.options.map((option) => ( <MenuRadioItem key={option.id} value={option.id} hideIndicator // Base UI keeps radio menus open by default. Close on pick so // the traits menu behaves like the model picker. closeOnClick disabled={ultrathinkInBodyText && descriptor.id === primarySelectDescriptor?.id} > <span className="flex w-full min-w-0 flex-col"> <span className="flex w-full min-w-0 items-center justify-between gap-3"> <span className="min-w-0 truncate"> {option.label} {option.isDefault ? ( <> {" "} <DefaultBadge /> </> ) : null} </span> </span> {option.description ? ( <span className="max-w-56 text-pretty text-muted-foreground/80 text-xs"> {option.description} </span> ) : null} </span> </MenuRadioItem> ))} </MenuRadioGroup> </MenuGroup> </div> ); })} {booleanDescriptors.map((descriptor, index) => { const selectedValue = descriptor.currentValue === true ? "on" : "off"; return ( <div key={descriptor.id}> {index > 0 || selectDescriptors.length > 0 ? <MenuDivider /> : null} <MenuGroup> <div className="px-2 py-1.5 font-medium text-muted-foreground text-xs"> {descriptor.label} </div> <MenuRadioGroup value={selectedValue} onValueChange={(value) => { updateDescriptors( replaceDescriptorCurrentValue(descriptors, descriptor.id, value === "on"), ); }} > {(["on", "off"] as const).map((value) => ( <MenuRadioItem key={value} value={value} hideIndicator closeOnClick> <span className="flex w-full min-w-0 items-center justify-between gap-3"> <span>{value === "on" ? "On" : "Off"}</span> </span> </MenuRadioItem> ))} </MenuRadioGroup> </MenuGroup> </div> ); })} </> );}); /** * Build the traits trigger's text label plus whether the fast-mode bolt should * render. Fast mode is a lightning bolt when on and nothing at all when off — * "Normal" is the near-universal case and isn't worth the horizontal space. The * one exception is when fast mode is the only trait, where a bare bolt (or bare * chevron) would leave the trigger unreadable. */export function buildTraitsTriggerDisplay(input: { provider: ProviderDriverKind; descriptors: ReadonlyArray<ProviderOptionDescriptor>; primarySelectDescriptorId: string | null; ultrathinkPromptControlled: boolean;}): { label: string; showFastModeIcon: boolean } { let hasFastMode = false; let fastModeEnabled = false; const labels: Array<string> = []; for (const descriptor of input.descriptors) { if (descriptor.id === "fastMode" && descriptor.type === "boolean") { hasFastMode = true; fastModeEnabled = descriptor.currentValue === true; continue; } if ( input.provider === "codex" && descriptor.id === "serviceTier" && descriptor.type === "select" ) { const currentValue = getProviderOptionCurrentValue(descriptor); const fastTier = descriptor.options.find(({ label }) => label === "Fast"); if (fastTier && (currentValue === "default" || currentValue === fastTier.id)) { hasFastMode = true; fastModeEnabled = currentValue === fastTier.id; continue; } } const label = input.ultrathinkPromptControlled && descriptor.id === input.primarySelectDescriptorId ? "Ultrathink" : descriptor.type === "boolean" ? `${descriptor.label} ${descriptor.currentValue === true ? "On" : "Off"}` : getProviderOptionCurrentLabel(descriptor); if (typeof label === "string" && label.length > 0) { labels.push(label); } } // Only fall back to text when fast mode is genuinely the sole trait. Keying // off an empty label list alone would also catch descriptors that resolved to // no label at all, printing a bogus "Normal" for a model without fast mode. if (labels.length === 0 && hasFastMode) { return { label: fastModeEnabled ? "Fast" : "Normal", showFastModeIcon: false }; } return { label: labels.join(" · "), showFastModeIcon: fastModeEnabled };} export const TraitsPicker = memo(function TraitsPicker({ provider, instanceId, models, model, prompt, onPromptChange, modelOptions, allowPromptInjectedEffort = true, triggerVariant, triggerClassName, ...persistence}: TraitsMenuContentProps & TraitsPersistence) { const [isMenuOpen, setIsMenuOpen] = useState(false); const { descriptors, primarySelectDescriptor, ultrathinkPromptControlled } = getTraitsSectionVisibility({ provider, models, model, prompt, modelOptions, allowPromptInjectedEffort, }); if ( !shouldRenderTraitsControls({ provider, models, model, prompt, modelOptions, allowPromptInjectedEffort, }) ) { return null; } const { label: triggerLabel, showFastModeIcon } = buildTraitsTriggerDisplay({ provider, descriptors, primarySelectDescriptorId: primarySelectDescriptor?.id ?? null, ultrathinkPromptControlled, }); const fastModeIcon = showFastModeIcon ? ( <> <ComposerControlIcon icon={ZapIcon} className={cn( "fill-current opacity-80", provider === "claudeAgent" ? "text-[#d97757]" : "text-foreground", )} /> <span className="sr-only">Fast mode on</span> </> ) : null; const isCodexStyle = provider === "codex";Lines 1–500 of 551. Load more
import { type ProviderDriverKind, type ProviderInstanceId, type ProviderOptionDescriptor, type ProviderOptionSelection, type ScopedThreadRef, type ServerProviderModel, } from "@t3tools/contracts"; import { applyClaudePromptEffortPrefix, buildProviderOptionSelectionsFromDescriptors, getProviderOptionCurrentLabel, getProviderOptionCurrentValue, getProviderOptionDescriptors, isClaudeUltrathinkPrompt, } from "@t3tools/shared/model"; import { memo, useCallback, useState } from "react"; import type { VariantProps } from "class-variance-authority"; import { ZapIcon } from "lucide-react"; import { buttonVariants } from "../ui/button"; import { Menu, MenuGroup, MenuPopup, MenuRadioGroup, MenuRadioItem, MenuSeparator as MenuDivider, MenuTrigger, } from "../ui/menu"; import { useComposerDraftStore, DraftId } from "../../composerDraftStore"; import { getProviderModelCapabilities } from "../../providerModels"; import { cn } from "~/lib/utils"; import { Badge } from "../ui/badge"; import { ComposerControl, ComposerControlChevron, ComposerControlIcon } from "./ComposerControl"; type ProviderOptions = ReadonlyArray<ProviderOptionSelection>; type TraitsPersistence = | { threadRef?: ScopedThreadRef; draftId?: DraftId; onModelOptionsChange?: never; } | { threadRef?: undefined; onModelOptionsChange: (nextOptions: ProviderOptions | undefined) => void; }; const ULTRATHINK_PROMPT_PREFIX = "Ultrathink:\n"; function DefaultBadge() { return ( <Badge variant="outline" className="inline-flex h-4 w-fit min-w-0 items-center justify-center gap-0 border-border/70 bg-muted/60 px-1.5 py-0 font-semibold text-[10px] text-muted-foreground leading-none sm:h-4" > Default </Badge> ); } function replaceDescriptorCurrentValue( descriptors: ReadonlyArray<ProviderOptionDescriptor>, descriptorId: string, currentValue: string | boolean | undefined, ): ReadonlyArray<ProviderOptionDescriptor> { return descriptors.map((descriptor) => descriptor.id !== descriptorId ? descriptor : descriptor.type === "boolean" ? { ...descriptor, ...(typeof currentValue === "boolean" ? { currentValue } : {}), } : { ...descriptor, ...(typeof currentValue === "string" ? { currentValue } : {}), }, ); } function getDescriptorStringValue( descriptor: Extract<ProviderOptionDescriptor, { type: "select" }> | null, ): string | null { if (!descriptor) { return null; } const value = getProviderOptionCurrentValue(descriptor); return typeof value === "string" ? value : null; } function getSelectedTraits( provider: ProviderDriverKind, models: ReadonlyArray<ServerProviderModel>, model: string | null | undefined, prompt: string, modelOptions: ProviderOptions | null | undefined, allowPromptInjectedEffort: boolean, ) { const caps = getProviderModelCapabilities(models, model, provider); const descriptors = getProviderOptionDescriptors({ caps, selections: modelOptions, }); const selectDescriptors = descriptors.filter( (descriptor): descriptor is Extract<ProviderOptionDescriptor, { type: "select" }> => descriptor.type === "select", ); const booleanDescriptors = descriptors.filter( (descriptor): descriptor is Extract<ProviderOptionDescriptor, { type: "boolean" }> => descriptor.type === "boolean", ); const primarySelectDescriptor = selectDescriptors[0] ?? null; const contextWindowDescriptor = selectDescriptors.find((descriptor) => descriptor.id === "contextWindow") ?? null; const agentDescriptor = selectDescriptors.find((descriptor) => descriptor.id === "agent") ?? null; const fastModeDescriptor = booleanDescriptors.find((descriptor) => descriptor.id === "fastMode") ?? null; const thinkingDescriptor = booleanDescriptors.find((descriptor) => descriptor.id === "thinking") ?? null; // Prompt-controlled effort (e.g. ultrathink in prompt text) const ultrathinkPromptControlled = allowPromptInjectedEffort && (primarySelectDescriptor?.promptInjectedValues?.length ?? 0) > 0 && isClaudeUltrathinkPrompt(prompt); // Check if "ultrathink" appears in the body text (not just our prefix) const ultrathinkInBodyText = ultrathinkPromptControlled && isClaudeUltrathinkPrompt(prompt.replace(/^Ultrathink:\s*/i, "")); const effort = (ultrathinkPromptControlled ? "ultrathink" : getDescriptorStringValue(primarySelectDescriptor)) ?? null; const thinkingEnabled = typeof thinkingDescriptor?.currentValue === "boolean" ? thinkingDescriptor.currentValue : null; const contextWindow = getDescriptorStringValue(contextWindowDescriptor); const selectedAgent = getDescriptorStringValue(agentDescriptor); const selectedAgentLabel = agentDescriptor ? getProviderOptionCurrentLabel(agentDescriptor) : null; return { caps, descriptors, selectDescriptors, booleanDescriptors, primarySelectDescriptor, contextWindowDescriptor, agentDescriptor, fastModeDescriptor, thinkingDescriptor, effort, thinkingEnabled, contextWindow, ultrathinkPromptControlled, ultrathinkInBodyText, selectedAgent, selectedAgentLabel, }; } function getTraitsSectionVisibility(input: { provider: ProviderDriverKind; models: ReadonlyArray<ServerProviderModel>; model: string | null | undefined; prompt: string; modelOptions: ProviderOptions | null | undefined; allowPromptInjectedEffort?: boolean; }) { const selected = getSelectedTraits( input.provider, input.models, input.model, input.prompt, input.modelOptions, input.allowPromptInjectedEffort ?? true, ); const showEffort = selected.primarySelectDescriptor !== null; const showThinking = selected.thinkingDescriptor !== null; const showFastMode = selected.fastModeDescriptor !== null; const showContextWindow = selected.contextWindowDescriptor !== null; const showAgent = selected.agentDescriptor !== null; return { ...selected, showEffort, showThinking, showFastMode, showContextWindow, showAgent, hasAnyControls: showEffort || showThinking || showFastMode || showContextWindow || showAgent, }; } export function shouldRenderTraitsControls(input: { provider: ProviderDriverKind; models: ReadonlyArray<ServerProviderModel>; model: string | null | undefined; prompt: string; modelOptions: ProviderOptions | null | undefined; allowPromptInjectedEffort?: boolean; }): boolean { return getTraitsSectionVisibility(input).hasAnyControls; } export interface TraitsMenuContentProps { provider: ProviderDriverKind; instanceId?: ProviderInstanceId; models: ReadonlyArray<ServerProviderModel>; model: string | null | undefined; prompt: string; onPromptChange: (prompt: string) => void; modelOptions?: ProviderOptions | null | undefined; allowPromptInjectedEffort?: boolean; triggerVariant?: VariantProps<typeof buttonVariants>["variant"]; triggerClassName?: string; } export const TraitsMenuContent = memo(function TraitsMenuContentImpl({ provider, instanceId, models, model, prompt, onPromptChange, modelOptions, allowPromptInjectedEffort = true, ...persistence }: TraitsMenuContentProps & TraitsPersistence) { const setProviderModelOptions = useComposerDraftStore((store) => store.setProviderModelOptions); const updateModelOptions = useCallback( (nextOptions: ProviderOptions | undefined) => { if ("onModelOptionsChange" in persistence) { persistence.onModelOptionsChange(nextOptions); return; } const threadTarget = persistence.threadRef ?? persistence.draftId; if (!threadTarget) { return; } setProviderModelOptions(threadTarget, provider, nextOptions, { ...(instanceId ? { instanceId } : {}), model, persistSticky: true, }); }, [instanceId, model, persistence, provider, setProviderModelOptions], ); const { descriptors, selectDescriptors, booleanDescriptors, primarySelectDescriptor, ultrathinkPromptControlled, ultrathinkInBodyText, hasAnyControls, } = getTraitsSectionVisibility({ provider, models, model, prompt, modelOptions, allowPromptInjectedEffort, }); const updateDescriptors = (nextDescriptors: ReadonlyArray<ProviderOptionDescriptor>) => { updateModelOptions(buildProviderOptionSelectionsFromDescriptors(nextDescriptors)); }; const handleSelectChange = ( descriptor: Extract<ProviderOptionDescriptor, { type: "select" }>, value: string, ) => { if (!value) return; if (descriptor.promptInjectedValues?.includes(value)) { const nextPrompt = prompt.trim().length === 0 ? ULTRATHINK_PROMPT_PREFIX : applyClaudePromptEffortPrefix(prompt, "ultrathink"); onPromptChange(nextPrompt); return; } if (ultrathinkInBodyText && descriptor.id === primarySelectDescriptor?.id) return; if (ultrathinkPromptControlled && descriptor.id === primarySelectDescriptor?.id) { const stripped = prompt.replace(/^Ultrathink:\s*/i, ""); onPromptChange(stripped); } updateDescriptors(replaceDescriptorCurrentValue(descriptors, descriptor.id, value)); }; if (!hasAnyControls) { return null; } return ( <> {selectDescriptors.map((descriptor, index) => { const selectedValue = ultrathinkPromptControlled && descriptor.id === primarySelectDescriptor?.id ? "ultrathink" : (getDescriptorStringValue(descriptor) ?? ""); return ( <div key={descriptor.id}> {index > 0 ? <MenuDivider /> : null} <MenuGroup> <div className="px-2 pt-1.5 pb-1 font-medium text-muted-foreground text-xs"> {descriptor.label} </div> {ultrathinkInBodyText && descriptor.id === primarySelectDescriptor?.id ? ( <div className="px-2 pb-1.5 text-muted-foreground/80 text-xs"> Your prompt contains "ultrathink" in the text. Remove it to change this option. </div> ) : null} <MenuRadioGroup value={selectedValue} onValueChange={(value) => handleSelectChange(descriptor, value)} > {descriptor.options.map((option) => ( <MenuRadioItem key={option.id} value={option.id} hideIndicator // Base UI keeps radio menus open by default. Close on pick so // the traits menu behaves like the model picker. closeOnClick disabled={ultrathinkInBodyText && descriptor.id === primarySelectDescriptor?.id} > <span className="flex w-full min-w-0 flex-col"> <span className="flex w-full min-w-0 items-center justify-between gap-3"> <span className="min-w-0 truncate"> {option.label} {option.isDefault ? ( <> {" "} <DefaultBadge /> </> ) : null} </span> </span> {option.description ? ( <span className="max-w-56 text-pretty text-muted-foreground/80 text-xs"> {option.description} </span> ) : null} </span> </MenuRadioItem> ))} </MenuRadioGroup> </MenuGroup> </div> ); })} {booleanDescriptors.map((descriptor, index) => { const selectedValue = descriptor.currentValue === true ? "on" : "off"; return ( <div key={descriptor.id}> {index > 0 || selectDescriptors.length > 0 ? <MenuDivider /> : null} <MenuGroup> <div className="px-2 py-1.5 font-medium text-muted-foreground text-xs"> {descriptor.label} </div> <MenuRadioGroup value={selectedValue} onValueChange={(value) => { updateDescriptors( replaceDescriptorCurrentValue(descriptors, descriptor.id, value === "on"), ); }} > {(["on", "off"] as const).map((value) => ( <MenuRadioItem key={value} value={value} hideIndicator closeOnClick> <span className="flex w-full min-w-0 items-center justify-between gap-3"> <span>{value === "on" ? "On" : "Off"}</span> </span> </MenuRadioItem> ))} </MenuRadioGroup> </MenuGroup> </div> ); })} </> ); }); /** * Build the traits trigger's text label plus whether the fast-mode bolt should * render. Fast mode is a lightning bolt when on and nothing at all when off — * "Normal" is the near-universal case and isn't worth the horizontal space. The * one exception is when fast mode is the only trait, where a bare bolt (or bare * chevron) would leave the trigger unreadable. */ export function buildTraitsTriggerDisplay(input: { provider: ProviderDriverKind; descriptors: ReadonlyArray<ProviderOptionDescriptor>; primarySelectDescriptorId: string | null; ultrathinkPromptControlled: boolean; }): { label: string; showFastModeIcon: boolean } { let hasFastMode = false; let fastModeEnabled = false; const labels: Array<string> = []; for (const descriptor of input.descriptors) { if (descriptor.id === "fastMode" && descriptor.type === "boolean") { hasFastMode = true; fastModeEnabled = descriptor.currentValue === true; continue; } if ( input.provider === "codex" && descriptor.id === "serviceTier" && descriptor.type === "select" ) { const currentValue = getProviderOptionCurrentValue(descriptor); const fastTier = descriptor.options.find(({ label }) => label === "Fast"); if (fastTier && (currentValue === "default" || currentValue === fastTier.id)) { hasFastMode = true; fastModeEnabled = currentValue === fastTier.id; continue; } } const label = input.ultrathinkPromptControlled && descriptor.id === input.primarySelectDescriptorId ? "Ultrathink" : descriptor.type === "boolean" ? `${descriptor.label} ${descriptor.currentValue === true ? "On" : "Off"}` : getProviderOptionCurrentLabel(descriptor); if (typeof label === "string" && label.length > 0) { labels.push(label); } } // Only fall back to text when fast mode is genuinely the sole trait. Keying // off an empty label list alone would also catch descriptors that resolved to // no label at all, printing a bogus "Normal" for a model without fast mode. if (labels.length === 0 && hasFastMode) { return { label: fastModeEnabled ? "Fast" : "Normal", showFastModeIcon: false }; } return { label: labels.join(" · "), showFastModeIcon: fastModeEnabled }; } export const TraitsPicker = memo(function TraitsPicker({ provider, instanceId, models, model, prompt, onPromptChange, modelOptions, allowPromptInjectedEffort = true, triggerVariant, triggerClassName, ...persistence }: TraitsMenuContentProps & TraitsPersistence) { const [isMenuOpen, setIsMenuOpen] = useState(false); const { descriptors, primarySelectDescriptor, ultrathinkPromptControlled } = getTraitsSectionVisibility({ provider, models, model, prompt, modelOptions, allowPromptInjectedEffort, }); if ( !shouldRenderTraitsControls({ provider, models, model, prompt, modelOptions, allowPromptInjectedEffort, }) ) { return null; } const { label: triggerLabel, showFastModeIcon } = buildTraitsTriggerDisplay({ provider, descriptors, primarySelectDescriptorId: primarySelectDescriptor?.id ?? null, ultrathinkPromptControlled, }); const fastModeIcon = showFastModeIcon ? ( <> <ComposerControlIcon icon={ZapIcon} className={cn( "fill-current opacity-80", provider === "claudeAgent" ? "text-[#d97757]" : "text-foreground", )} /> <span className="sr-only">Fast mode on</span> </> ) : null; const isCodexStyle = provider === "codex";