import { type ProviderDriverKind, type ProviderInstanceId, type ProviderOptionDescriptor, type ProviderOptionSelection, type ScopedThreadRef, type ServerProviderModel,} from "@t3tools/contracts";import { applyClaudePromptEffortPrefix, buildProviderOptionSelectionsFromDescriptors, getProviderOptionCurrentLabel, getProviderOptionCurrentValue, getProviderOptionDescriptors, isClaudeUltrathinkPrompt, normalizeModelSlug,} 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>; const SAVED_OPTION_LABELS: Readonly<Record<string, string>> = { agent: "Agent", effort: "Effort", reasoningEffort: "Reasoning effort", variant: "Variant",}; function savedOptionLabel(id: string): string { return ( SAVED_OPTION_LABELS[id] ?? id.replace(/([a-z0-9])([A-Z])/g, "$1 $2").replace(/^./, (character) => character.toUpperCase()) );} /** Read-only descriptors for saved values whose OpenCode model metadata is unavailable. */export function buildUnavailableModelOptionDescriptors( selections: ProviderOptions | null | undefined,): ReadonlyArray<ProviderOptionDescriptor> { return (selections ?? []).map((selection) => typeof selection.value === "boolean" ? { id: selection.id, label: savedOptionLabel(selection.id), type: "boolean" as const, currentValue: selection.value, } : { id: selection.id, label: savedOptionLabel(selection.id), type: "select" as const, options: [{ id: selection.value, label: selection.value }], currentValue: selection.value, }, );} 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, planModeEnabled: boolean,) { const caps = getProviderModelCapabilities(models, model, provider, planModeEnabled); const modelIsUnavailable = provider === "opencode" && !models.some((candidate) => candidate.slug === normalizeModelSlug(model, provider)); const descriptors = modelIsUnavailable ? buildUnavailableModelOptionDescriptors( planModeEnabled ? modelOptions : modelOptions?.filter((option) => option.id !== "agent" || option.value !== "plan"), ) : 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, modelIsUnavailable, };} function getTraitsSectionVisibility(input: { provider: ProviderDriverKind; models: ReadonlyArray<ServerProviderModel>; model: string | null | undefined; prompt: string; modelOptions: ProviderOptions | null | undefined; allowPromptInjectedEffort?: boolean; planModeEnabled: boolean;}) { const selected = getSelectedTraits( input.provider, input.models, input.model, input.prompt, input.modelOptions, input.allowPromptInjectedEffort ?? true, input.planModeEnabled, ); 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 || (selected.modelIsUnavailable && selected.descriptors.length > 0), };} export function shouldRenderTraitsControls(input: { provider: ProviderDriverKind; models: ReadonlyArray<ServerProviderModel>; model: string | null | undefined; prompt: string; modelOptions: ProviderOptions | null | undefined; allowPromptInjectedEffort?: boolean; planModeEnabled: 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; planModeEnabled: boolean; triggerVariant?: VariantProps<typeof buttonVariants>["variant"]; triggerClassName?: string;} export const TraitsMenuContent = memo(function TraitsMenuContentImpl({ provider, instanceId, models, model, prompt, onPromptChange, modelOptions, allowPromptInjectedEffort = true, planModeEnabled, ...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, modelIsUnavailable, } = getTraitsSectionVisibility({ provider, models, model, prompt, modelOptions, allowPromptInjectedEffort, planModeEnabled, }); 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; } if (modelIsUnavailable) { return ( <> {descriptors.map((descriptor, index) => { const value = getProviderOptionCurrentLabel(descriptor); if (!value) return null; 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> <div className="px-2 pb-1.5 text-muted-foreground/80 text-xs">{value}</div> </MenuGroup> </div> ); })} </> ); } 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. Claude and Cursor expose fast mode as a boolean, while Codex exposes * it through the Standard/Fast service tiers. In either form, fast mode is a * lightning bolt when on and nothing at all when off. 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 fastModeFallbackLabel: string | null = null; let fastModeEnabled = false; const labels: Array<string> = []; for (const descriptor of input.descriptors) { if (descriptor.id === "fastMode" && descriptor.type === "boolean") { fastModeEnabled = descriptor.currentValue === true; fastModeFallbackLabel = fastModeEnabled ? "Fast" : "Normal"; continue; } if ( input.provider === "codex" && descriptor.id === "serviceTier" && descriptor.type === "select" ) {Lines 1–500 of 641. 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, normalizeModelSlug, } 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>; const SAVED_OPTION_LABELS: Readonly<Record<string, string>> = { agent: "Agent", effort: "Effort", reasoningEffort: "Reasoning effort", variant: "Variant", }; function savedOptionLabel(id: string): string { return ( SAVED_OPTION_LABELS[id] ?? id.replace(/([a-z0-9])([A-Z])/g, "$1 $2").replace(/^./, (character) => character.toUpperCase()) ); } /** Read-only descriptors for saved values whose OpenCode model metadata is unavailable. */ export function buildUnavailableModelOptionDescriptors( selections: ProviderOptions | null | undefined, ): ReadonlyArray<ProviderOptionDescriptor> { return (selections ?? []).map((selection) => typeof selection.value === "boolean" ? { id: selection.id, label: savedOptionLabel(selection.id), type: "boolean" as const, currentValue: selection.value, } : { id: selection.id, label: savedOptionLabel(selection.id), type: "select" as const, options: [{ id: selection.value, label: selection.value }], currentValue: selection.value, }, ); } 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, planModeEnabled: boolean, ) { const caps = getProviderModelCapabilities(models, model, provider, planModeEnabled); const modelIsUnavailable = provider === "opencode" && !models.some((candidate) => candidate.slug === normalizeModelSlug(model, provider)); const descriptors = modelIsUnavailable ? buildUnavailableModelOptionDescriptors( planModeEnabled ? modelOptions : modelOptions?.filter((option) => option.id !== "agent" || option.value !== "plan"), ) : 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, modelIsUnavailable, }; } function getTraitsSectionVisibility(input: { provider: ProviderDriverKind; models: ReadonlyArray<ServerProviderModel>; model: string | null | undefined; prompt: string; modelOptions: ProviderOptions | null | undefined; allowPromptInjectedEffort?: boolean; planModeEnabled: boolean; }) { const selected = getSelectedTraits( input.provider, input.models, input.model, input.prompt, input.modelOptions, input.allowPromptInjectedEffort ?? true, input.planModeEnabled, ); 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 || (selected.modelIsUnavailable && selected.descriptors.length > 0), }; } export function shouldRenderTraitsControls(input: { provider: ProviderDriverKind; models: ReadonlyArray<ServerProviderModel>; model: string | null | undefined; prompt: string; modelOptions: ProviderOptions | null | undefined; allowPromptInjectedEffort?: boolean; planModeEnabled: 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; planModeEnabled: boolean; triggerVariant?: VariantProps<typeof buttonVariants>["variant"]; triggerClassName?: string; } export const TraitsMenuContent = memo(function TraitsMenuContentImpl({ provider, instanceId, models, model, prompt, onPromptChange, modelOptions, allowPromptInjectedEffort = true, planModeEnabled, ...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, modelIsUnavailable, } = getTraitsSectionVisibility({ provider, models, model, prompt, modelOptions, allowPromptInjectedEffort, planModeEnabled, }); 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; } if (modelIsUnavailable) { return ( <> {descriptors.map((descriptor, index) => { const value = getProviderOptionCurrentLabel(descriptor); if (!value) return null; 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> <div className="px-2 pb-1.5 text-muted-foreground/80 text-xs">{value}</div> </MenuGroup> </div> ); })} </> ); } 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. Claude and Cursor expose fast mode as a boolean, while Codex exposes * it through the Standard/Fast service tiers. In either form, fast mode is a * lightning bolt when on and nothing at all when off. 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 fastModeFallbackLabel: string | null = null; let fastModeEnabled = false; const labels: Array<string> = []; for (const descriptor of input.descriptors) { if (descriptor.id === "fastMode" && descriptor.type === "boolean") { fastModeEnabled = descriptor.currentValue === true; fastModeFallbackLabel = fastModeEnabled ? "Fast" : "Normal"; continue; } if ( input.provider === "codex" && descriptor.id === "serviceTier" && descriptor.type === "select" ) {