From 41b0d03f6afabc30696e9ccbbdbb7c3df34fd404 Mon Sep 17 00:00:00 2001 From: Dax Date: Sat, 28 Mar 2026 01:21:28 -0400 Subject: [PATCH] feat: add model variant selection dialog (#19488) --- .../cli/cmd/tui/component/dialog-model.tsx | 16 +++++++--- .../cli/cmd/tui/component/dialog-variant.tsx | 31 +++++++++++++++++++ 2 files changed, 43 insertions(+), 4 deletions(-) create mode 100644 packages/opencode/src/cli/cmd/tui/component/dialog-variant.tsx diff --git a/packages/opencode/src/cli/cmd/tui/component/dialog-model.tsx b/packages/opencode/src/cli/cmd/tui/component/dialog-model.tsx index c30b8d12a9..a06e7e0705 100644 --- a/packages/opencode/src/cli/cmd/tui/component/dialog-model.tsx +++ b/packages/opencode/src/cli/cmd/tui/component/dialog-model.tsx @@ -5,6 +5,7 @@ import { map, pipe, flatMap, entries, filter, sortBy, take } from "remeda" import { DialogSelect } from "@tui/ui/dialog-select" import { useDialog } from "@tui/ui/dialog" import { createDialogProviderOptions, DialogProvider } from "./dialog-provider" +import { DialogVariant } from "./dialog-variant" import { useKeybind } from "../context/keybind" import * as fuzzysort from "fuzzysort" @@ -50,8 +51,7 @@ export function DialogModel(props: { providerID?: string }) { disabled: provider.id === "opencode" && model.id.includes("-nano"), footer: model.cost?.input === 0 && provider.id === "opencode" ? "Free" : undefined, onSelect: () => { - dialog.clear() - local.model.set({ providerID: provider.id, modelID: model.id }, { recent: true }) + onSelect(provider.id, model.id) }, }, ] @@ -88,8 +88,7 @@ export function DialogModel(props: { providerID?: string }) { disabled: provider.id === "opencode" && model.includes("-nano"), footer: info.cost?.input === 0 && provider.id === "opencode" ? "Free" : undefined, onSelect() { - dialog.clear() - local.model.set({ providerID: provider.id, modelID: model }, { recent: true }) + onSelect(provider.id, model) }, })), filter((x) => { @@ -135,6 +134,15 @@ export function DialogModel(props: { providerID?: string }) { const title = createMemo(() => provider()?.name ?? "Select model") + function onSelect(providerID: string, modelID: string) { + local.model.set({ providerID, modelID }, { recent: true }) + if (local.model.variant.list().length > 0) { + dialog.replace(() => ) + } else { + dialog.clear() + } + } + return ( [number]["value"]> options={options()} diff --git a/packages/opencode/src/cli/cmd/tui/component/dialog-variant.tsx b/packages/opencode/src/cli/cmd/tui/component/dialog-variant.tsx new file mode 100644 index 0000000000..8d06ab6411 --- /dev/null +++ b/packages/opencode/src/cli/cmd/tui/component/dialog-variant.tsx @@ -0,0 +1,31 @@ +import { createMemo } from "solid-js" +import { useLocal } from "@tui/context/local" +import { useSync } from "@tui/context/sync" +import { DialogSelect } from "@tui/ui/dialog-select" +import { useDialog } from "@tui/ui/dialog" + +export function DialogVariant() { + const local = useLocal() + const dialog = useDialog() + + const options = createMemo(() => { + return local.model.variant.list().map((variant) => ({ + value: variant, + title: variant, + onSelect: () => { + dialog.clear() + local.model.variant.set(variant) + }, + })) + }) + + return ( + + options={options()} + title={"Select variant"} + current={local.model.variant.current()} + flat={true} + skipFilter={true} + /> + ) +}