From c907d2ba2765f9565912d2adaaf4dee7cef4f619 Mon Sep 17 00:00:00 2001 From: "opencode-agent[bot]" <219766164+opencode-agent[bot]@users.noreply.github.com> Date: Thu, 3 Sep 2026 23:18:09 -0500 Subject: [PATCH] fix(tui): preserve model release ordering in search (#47183) Co-authored-by: rekram1-node --- packages/tui/src/component/dialog-model.tsx | 23 +++++++++++++++---- .../test/cli/cmd/tui/model-options.test.ts | 15 ++++++++++++ 2 files changed, 33 insertions(+), 5 deletions(-) diff --git a/packages/tui/src/component/dialog-model.tsx b/packages/tui/src/component/dialog-model.tsx index c8f79db6605..832d597f9ed 100644 --- a/packages/tui/src/component/dialog-model.tsx +++ b/packages/tui/src/component/dialog-model.tsx @@ -99,11 +99,15 @@ export function DialogModel(props: { providerID?: string }) { return false return true }), + connected(), ) if (needle) { return prioritizeFavorites( - fuzzysort.go(needle, modelOptions, { keys: ["title", "category"] }).map((item) => item.obj), + sortModelOptions( + fuzzysort.go(needle, modelOptions, { keys: ["title", "category"] }).map((item) => item.obj), + false, + ), favoritePriority, ) } @@ -179,15 +183,24 @@ export function prioritizeFavorites(options: T[]) { + T extends { + providerID?: string + providerName?: string + releaseDate: string | number + title: string + footer?: string + }, +>(options: T[], grouped = true) { return options.toSorted((a, b) => { - const provider = Number(a.providerID !== "opencode") - Number(b.providerID !== "opencode") + const provider = grouped ? Number(a.providerID !== "opencode") - Number(b.providerID !== "opencode") : 0 if (provider !== 0) return provider - const name = (a.providerName ?? "").localeCompare(b.providerName ?? "") + const name = grouped ? (a.providerName ?? "").localeCompare(b.providerName ?? "") : 0 if (name !== 0) return name + const free = Number(b.footer === "Free") - Number(a.footer === "Free") + if (free !== 0) return free + const release = Number(b.releaseDate) - Number(a.releaseDate) if (release !== 0) return release diff --git a/packages/tui/test/cli/cmd/tui/model-options.test.ts b/packages/tui/test/cli/cmd/tui/model-options.test.ts index 0c8477a61b1..111f23c18f2 100644 --- a/packages/tui/test/cli/cmd/tui/model-options.test.ts +++ b/packages/tui/test/cli/cmd/tui/model-options.test.ts @@ -1,4 +1,5 @@ import { describe, expect, test } from "bun:test" +import { go } from "fuzzysort" import { prioritizeFavorites, sortModelOptions } from "../../../../src/component/dialog-model" describe("prioritizeFavorites", () => { @@ -23,6 +24,20 @@ describe("prioritizeFavorites", () => { }) describe("sortModelOptions", () => { + test.each(["browse", "search", "provider"])("orders %s results free-first, then newest-first", (mode) => { + const options = [ + { providerID: "opencode", title: "Claude Haiku 3", releaseDate: 1 }, + { providerID: "anthropic", title: "Claude Haiku 4.5", releaseDate: 2 }, + { providerID: "anthropic", title: "Claude Haiku Free", releaseDate: 0, footer: "Free" }, + ].map((item) => ({ ...item, providerID: mode === "provider" ? "anthropic" : item.providerID })) + const matches = mode === "search" ? go("haik", options, { key: "title" }).map((item) => item.obj) : options + expect(sortModelOptions(matches, mode === "provider").map((item) => item.title)).toEqual([ + "Claude Haiku Free", + "Claude Haiku 4.5", + "Claude Haiku 3", + ]) + }) + test("orders opencode models before other providers", () => { const sorted = sortModelOptions([ { providerID: "openai", providerName: "OpenAI", releaseDate: 3, title: "GPT 5" },