Model picker

Lets people choose which model answers and how hard it thinks: an effort slider with a model list, a searchable list grouped by provider with a separate effort menu, a detailed list, or a quick three-way switch.

Loading preview…

Install

  1. 1

    Run this command in your Tailwind CSS project. It adds components/ai/model-picker-effort.tsx and installs its dependencies.

    $ npx shadcn@latest add https://gradientdeck.com/ai-components/r/model-picker-effort.json

Usage & API

Example

model-picker-effort.tsx
import { EffortPicker } from "@/components/ai/model-picker-effort"

<EffortPicker
  models={[]}
  model="…"
  onModelChange={() => {}}
  effort={effort}
  onEffortChange={() => {}}
  fast={true}
  onFastChange={() => {}}
/>

Props EffortPicker

PropType & descriptionRequired
modelsModelOption[]Required
modelstringRequired
onModelChange(id: string) => voidRequired
effortEffortLevelRequired
onEffortChange(effort: EffortLevel) => voidRequired
fastbooleanRequired
onFastChange(fast: boolean) => voidRequired
defaultEffortEffortLevelOptional
initialViewViewStart with a panel open, for demos.Optional

Dependencies

  • React
  • Tailwind CSS
  • motion
  • lucide-react
Implementation notes

Effort slider exports EffortPicker. Props are models, model, onModelChange, effort, onEffortChange, fast, onFastChange, defaultEffort and initialView. A model is an id, a name and a note. defaultEffort starts at Medium. initialView can be closed, effort or models, for demos. The trigger is a dialog button. The panel morphs between the effort view and the model list. Fast mode is a pressed toggle. Reset is labelled Reset to the default effort. The track is labelled Reasoning effort. Dragging or the arrow keys snap to the six stops. Home and End jump to the ends. In fast mode, bubbles drift through the fill, and more of them appear as the index rises. Without fast mode, small stops stay visible inside the fill. Ultra uses a violet gradient. The model list's first row shows its note inline. Other notes appear in a tooltip beside the row, hidden below the sm breakpoint. Choosing a model returns to the effort view. The first demo model is Default, with the note Picks a model for each task. A popover tries to stay inside the nearest data-popover-bounds element.

Choosing a layout

Use Effort slider when reasoning effort is the decision people make on every message and the model is a second step. The trigger shows the model name and the level, or the words Select effort while that panel is open. Use By provider when you have more than one vendor, favorites, and older models that should stay collapsed. Use Dropdown when a short list with speed and cost is enough and effort is not a separate choice. Use Segmented when you would rather offer three speeds than a catalog. It is the one to put in a toolbar next to Prompt input if a full menu is too much.

Prompt input's card only prints a model string. Its workspace menu is a short radio list of Low, Medium and High plus whatever model names you pass, with no notes and no favorites. Reach for Model picker when that menu is too small. Context meter does not belong here. It shows tokens, not a choice. The pickers also do not disable themselves when a model is down. You would swap the whole control, or ignore a choice, in the parent.

Why does effort mean something different on Effort slider and By provider?

They are different types. Effort slider's EffortLevel is Minimal, Low, Medium, High, Extra high or Ultra, and the slider's aria-valuetext is that word. By provider's Effort is Low, Medium, High or Max, chosen by clicking a bar, with a sentence under the bars that changes on hover before you commit. Segmented does not use either scale. If you store one effort field in your app, map it at the boundary. Do not pass Ultra into T3Picker.

Does the shortcut on By provider still work when the menu is closed?

No. The Ctrl or Command plus 1 to 9 listener is attached only while a menu is open, and it only fires for the model menu. It looks up the shortcut number painted on the current rows, which is at most the first nine model rows. A legacy-models row does not take a number. Favorites and a search each build their own row list, so the numbers follow whatever is on screen, not a fixed catalog order.