Skip to content

Commit d7cec6d

Browse files
authored
Model selector tweaks (#1527)
1 parent 6593009 commit d7cec6d

2 files changed

Lines changed: 64 additions & 14 deletions

File tree

components/ai-elements/model-selector.tsx

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,13 @@ export const ModelSelectorTrigger = (props: ModelSelectorTriggerProps) => (
3131
);
3232

3333
export type ModelSelectorContentProps = ComponentProps<typeof PopoverContent> & {
34+
commandDefaultValue?: ComponentProps<typeof Command>["defaultValue"];
3435
title?: ReactNode;
3536
};
3637

3738
export const ModelSelectorContent = ({
3839
className,
40+
commandDefaultValue,
3941
children,
4042
title: _title,
4143
...props
@@ -50,7 +52,10 @@ export const ModelSelectorContent = ({
5052
sideOffset={8}
5153
{...props}
5254
>
53-
<Command className="**:data-[slot=command-input-wrapper]:h-auto">
55+
<Command
56+
className="**:data-[slot=command-input-wrapper]:h-auto"
57+
defaultValue={commandDefaultValue}
58+
>
5459
{children}
5560
</Command>
5661
</PopoverContent>

components/chat/multimodal-input.tsx

Lines changed: 58 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import {
1616
type ChangeEvent,
1717
type Dispatch,
1818
memo,
19+
type ReactNode,
1920
type SetStateAction,
2021
useCallback,
2122
useEffect,
@@ -52,6 +53,7 @@ import {
5253
PromptInputTools,
5354
} from "../ai-elements/prompt-input";
5455
import { Button } from "../ui/button";
56+
import { Tooltip, TooltipContent, TooltipTrigger } from "../ui/tooltip";
5557
import { PaperclipIcon, StopIcon } from "./icons";
5658
import { PreviewAttachment } from "./preview-attachment";
5759
import {
@@ -695,6 +697,22 @@ function ModelSelectorOption({
695697
setOpen: Dispatch<SetStateAction<boolean>>;
696698
}) {
697699
const [logoProvider] = model.id.split("/");
700+
const maybeWithTooltip = (icon: ReactNode, label: string) => {
701+
if (!curated) {
702+
return icon;
703+
}
704+
705+
return (
706+
<Tooltip>
707+
<TooltipTrigger asChild>
708+
<span className="inline-flex">{icon}</span>
709+
</TooltipTrigger>
710+
<TooltipContent side="top" sideOffset={8}>
711+
{label}
712+
</TooltipContent>
713+
</Tooltip>
714+
);
715+
};
698716
const handleSelect = useCallback(() => {
699717
if (!curated) {
700718
return;
@@ -709,33 +727,60 @@ function ModelSelectorOption({
709727
}, 50);
710728
}, [curated, model.id, onModelChange, setOpen]);
711729

712-
return (
730+
const option = (
713731
<ModelSelectorItem
732+
aria-disabled={!curated}
714733
className={cn(
715-
"flex w-full",
734+
"flex w-full transition-colors",
716735
model.id === selectedModelId &&
717736
"border-b border-dashed border-foreground/50",
718-
!curated && "opacity-40 cursor-default"
737+
curated
738+
? "data-[selected=true]:bg-muted data-[selected=true]:text-foreground"
739+
: "cursor-not-allowed opacity-40 data-[selected=true]:bg-transparent data-[selected=true]:opacity-60 data-[selected=true]:ring-1 data-[selected=true]:ring-muted-foreground/30 data-[selected=true]:ring-inset"
719740
)}
720741
onSelect={handleSelect}
721742
value={model.id}
722743
>
723744
<ModelSelectorLogo provider={logoProvider} />
724745
<ModelSelectorName>{model.name}</ModelSelectorName>
725746
<div className="ml-auto flex items-center gap-2 text-foreground/70">
726-
{capabilities?.[model.id]?.tools ? (
727-
<WrenchIcon className="size-3.5" />
728-
) : null}
729-
{capabilities?.[model.id]?.vision ? (
730-
<EyeIcon className="size-3.5" />
731-
) : null}
732-
{capabilities?.[model.id]?.reasoning ? (
733-
<BrainIcon className="size-3.5" />
734-
) : null}
747+
{capabilities?.[model.id]?.tools
748+
? maybeWithTooltip(
749+
<WrenchIcon className="size-3.5" />,
750+
"Supports tool use"
751+
)
752+
: null}
753+
{capabilities?.[model.id]?.vision
754+
? maybeWithTooltip(
755+
<EyeIcon className="size-3.5" />,
756+
"Supports vision"
757+
)
758+
: null}
759+
{capabilities?.[model.id]?.reasoning
760+
? maybeWithTooltip(
761+
<BrainIcon className="size-3.5" />,
762+
"Supports reasoning"
763+
)
764+
: null}
735765
{!curated && <LockIcon className="size-3 text-muted-foreground/50" />}
736766
</div>
737767
</ModelSelectorItem>
738768
);
769+
770+
if (curated) {
771+
return option;
772+
}
773+
774+
return (
775+
<Tooltip>
776+
<TooltipTrigger asChild>
777+
<div className="w-full cursor-not-allowed">{option}</div>
778+
</TooltipTrigger>
779+
<TooltipContent side="right" sideOffset={8}>
780+
This model is not available in the demo.
781+
</TooltipContent>
782+
</Tooltip>
783+
);
739784
}
740785

741786
function PureModelSelectorCompact({
@@ -775,7 +820,7 @@ function PureModelSelectorCompact({
775820
<ModelSelectorName>{selectedModel.name}</ModelSelectorName>
776821
</Button>
777822
</ModelSelectorTrigger>
778-
<ModelSelectorContent>
823+
<ModelSelectorContent commandDefaultValue={selectedModel.id}>
779824
<ModelSelectorInput placeholder="Search models..." />
780825
<ModelSelectorList>
781826
{(() => {

0 commit comments

Comments
 (0)