Add searchable model picker

This commit is contained in:
武阳
2026-05-08 11:56:30 +08:00
parent e4c3b973d4
commit c8ea2bad6d
@@ -27,6 +27,7 @@ import {
MoreHorizontalIcon,
PencilIcon,
RefreshCwIcon,
SearchIcon,
SquareIcon,
WrenchIcon,
} from "lucide-react";
@@ -92,6 +93,8 @@ type ClawStoredSession = {
type ModelOption = {
id: string;
provider?: string;
model_type?: string;
};
type ContextBudget = {
@@ -589,6 +592,19 @@ function ModelPickerButton({
setModel: (model: string) => Promise<void>;
};
}) {
const [query, setQuery] = useState("");
const normalizedQuery = query.trim().toLowerCase();
const filteredModels = useMemo(() => {
if (!normalizedQuery) return status.models;
return status.models.filter((model) => {
const provider = model.provider ?? modelProvider(model.id);
return (
model.id.toLowerCase().includes(normalizedQuery) ||
provider.toLowerCase().includes(normalizedQuery)
);
});
}, [normalizedQuery, status.models]);
return (
<PopoverPrimitive.Root>
<PopoverPrimitive.Trigger asChild>
@@ -608,13 +624,25 @@ function ModelPickerButton({
side="top"
align="end"
sideOffset={10}
className="z-50 w-72 rounded-2xl border bg-popover p-2 text-popover-foreground shadow-lg outline-none"
className="z-50 w-[min(36rem,calc(100vw-2rem))] rounded-2xl border bg-popover p-2 text-popover-foreground shadow-lg outline-none"
>
<div className="px-2 py-1.5 font-medium text-muted-foreground text-xs">
</div>
<div className="relative mb-2">
<SearchIcon className="-translate-y-1/2 pointer-events-none absolute top-1/2 left-2.5 size-3.5 text-muted-foreground" />
<input
type="search"
value={query}
onChange={(event) => setQuery(event.target.value)}
placeholder="搜索模型或来源"
className="h-8 w-full rounded-lg border bg-background pr-2.5 pl-8 text-sm outline-none transition-colors placeholder:text-muted-foreground focus:border-ring"
/>
</div>
{status.models.length ? (
status.models.map((model) => (
<div className="h-[min(24rem,calc(100vh-12rem))] overflow-y-auto pr-1">
{filteredModels.length ? (
filteredModels.map((model) => (
<button
key={model.id}
type="button"
@@ -623,13 +651,19 @@ function ModelPickerButton({
>
<span className="min-w-0 flex-1 truncate">{model.id}</span>
<span className="shrink-0 text-muted-foreground text-xs">
{modelProvider(model.id)}
{model.provider ?? modelProvider(model.id)}
</span>
{model.id === status.model ? (
<CheckIcon className="size-3.5 shrink-0" />
) : null}
</button>
))
) : (
<div className="px-2 py-8 text-center text-muted-foreground text-sm">
</div>
)}
</div>
) : (
<div className="px-2 py-2 text-muted-foreground text-sm">