|
| 1 | +--- |
| 2 | +feature: tui-model-selector-search |
| 3 | +status: delivered |
| 4 | +pr: https://github.com/XiaomiMiMo/MiMo-Code/pull/932 |
| 5 | +branch: fix/model-selector-search-ui |
| 6 | +commits: 83ca130..ee30bc0 |
| 7 | +--- |
| 8 | + |
| 9 | +# TUI Model Selector Search — Final Report |
| 10 | + |
| 11 | +## What Was Built |
| 12 | + |
| 13 | +Restored the search input box in the TUI model selector dialog (`/models` command). The search box was hidden due to `skipFilter={true}` being set on the `DialogSelect` component, which suppresses the built-in filter input. Removing this prop re-enables the search UI while preserving the existing custom fuzzysort filtering logic via `onFilter`. |
| 14 | + |
| 15 | +## Architecture |
| 16 | + |
| 17 | +The model selector consists of two layers: |
| 18 | + |
| 19 | +- **`DialogModel`** (`packages/opencode/src/cli/cmd/tui/component/dialog-model.tsx`) — builds the options list (favorites, recents, provider models, "+ Add model" entries) and performs custom fuzzysort filtering via a `query` signal. |
| 20 | +- **`DialogSelect`** (`packages/opencode/src/cli/cmd/tui/ui/dialog-select.tsx`) — generic selection dialog with built-in search input, keyboard navigation, and scroll. Renders the input when `skipFilter` is not set. |
| 21 | + |
| 22 | +Data flow: |
| 23 | +``` |
| 24 | +User types → DialogSelect <input onInput> → props.onFilter(query) |
| 25 | + → DialogModel setQuery() → options() recomputes with fuzzysort |
| 26 | + → DialogSelect receives new props.options → re-renders filtered list |
| 27 | +``` |
| 28 | + |
| 29 | +### Design Decisions |
| 30 | + |
| 31 | +- **Custom filtering in DialogModel, not DialogSelect**: DialogModel uses `skipFilter` semantics — it passes pre-filtered `options` to DialogSelect rather than letting DialogSelect do the filtering. This allows model-specific logic (favorites/recents sections disappear on search, fuzzysort with weighted title/category scoring). |
| 32 | +- **"+ Add model" entries are searchable**: Each `source === "config"` provider appends a "+ Add model" option. Searching "add" surfaces all of them — this is intentional so users can identify which provider to add to. Normal model searches are unaffected by fuzzysort scoring. |
| 33 | + |
| 34 | +## Usage |
| 35 | + |
| 36 | +Press `/models` in TUI or trigger via keybind. The search input auto-focuses. Type to filter models by name or provider. Press Enter to select, Escape to close. |
| 37 | + |
| 38 | +## Verification |
| 39 | + |
| 40 | +- `bun typecheck` passes (full turbo, 12/12 packages) |
| 41 | +- CI: typecheck ✅, lint ✅, 8 test failures are all pre-existing (documented in #911) |
| 42 | +- Manual: search box renders and filters correctly in `/models` dialog |
| 43 | + |
| 44 | +## Journey Log |
| 45 | + |
| 46 | +- [lesson] `skipFilter={true}` hides the search input entirely in `DialogSelect` — this prop should only be used when search is genuinely unwanted (e.g. short fixed-option lists like worktree creation) |
| 47 | +- [lesson] When a component does its own filtering via `onFilter` callback, it still needs the input rendered — `skipFilter` controls UI visibility, not filtering logic |
0 commit comments