fix(tui): keep model search order stable (#40753)

This commit is contained in:
Kit Langton 2026-08-05 18:19:26 -04:00 committed by GitHub
parent 73581b3c3b
commit 56c33e84a3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 22 additions and 11 deletions

View file

@ -7,12 +7,14 @@ import { DialogVariant } from "./dialog-variant"
import * as fuzzysort from "fuzzysort"
import { useConnected } from "./use-connected"
import { useData } from "../context/data"
import { modelPreferenceKey } from "../model-preference"
export function DialogModel(props: { providerID?: string }) {
const local = useLocal()
const data = useData()
const dialog = useDialog()
const [query, setQuery] = createSignal("")
const favoritePriority = new Set(local.model.favorite().map(modelPreferenceKey))
const connected = useConnected()
const providers = createMemo(() => new Map((data.location.provider.list() ?? []).map((item) => [item.id, item])))
@ -63,14 +65,14 @@ export function DialogModel(props: { providerID?: string }) {
.filter((model) => (props.providerID ? model.providerID === props.providerID : true))
.map((model) => {
const provider = providers().get(model.providerID)
const favorite = favorites.some((item) => item.providerID === model.providerID && item.modelID === model.id)
const key = modelPreferenceKey({ providerID: model.providerID, modelID: model.id })
const favorite = favorites.some((item) => modelPreferenceKey(item) === key)
return {
value: { providerID: model.providerID, modelID: model.id },
providerID: model.providerID,
providerName: provider?.name ?? model.providerID,
title: model.name,
releaseDate: model.time.released,
favorite,
description: favorite ? "(Favorite)" : undefined,
category: connected() ? (provider?.name ?? model.providerID) : undefined,
footer: free(model) ? "Free" : undefined,
@ -98,6 +100,7 @@ export function DialogModel(props: { providerID?: string }) {
if (needle) {
return prioritizeFavorites(
fuzzysort.go(needle, modelOptions, { keys: ["title", "category"] }).map((item) => item.obj),
favoritePriority,
)
}
@ -162,8 +165,13 @@ export function DialogModel(props: { providerID?: string }) {
)
}
export function prioritizeFavorites<T extends { favorite: boolean }>(options: T[]) {
return options.toSorted((a, b) => Number(b.favorite) - Number(a.favorite))
export function prioritizeFavorites<T extends { value: { providerID: string; modelID: string } }>(
options: T[],
favorites: Set<string>,
) {
return options.toSorted(
(a, b) => Number(favorites.has(modelPreferenceKey(b.value))) - Number(favorites.has(modelPreferenceKey(a.value))),
)
}
export function sortModelOptions<

View file

@ -2,13 +2,16 @@ import { describe, expect, test } from "bun:test"
import { prioritizeFavorites, sortModelOptions } from "../../../../src/component/dialog-model"
describe("prioritizeFavorites", () => {
test("moves favorites first while preserving fuzzy result order", () => {
const prioritized = prioritizeFavorites([
{ title: "Best match", favorite: false },
{ title: "Favorite match", favorite: true },
{ title: "Second best match", favorite: false },
{ title: "Second favorite match", favorite: true },
])
test("uses the favorite order captured when the dialog opened", () => {
const prioritized = prioritizeFavorites(
[
{ title: "Best match", value: { providerID: "test", modelID: "best" } },
{ title: "Favorite match", value: { providerID: "test", modelID: "favorite" } },
{ title: "Second best match", value: { providerID: "test", modelID: "second-best" } },
{ title: "Second favorite match", value: { providerID: "test", modelID: "second-favorite" } },
],
new Set(["test/favorite", "test/second-favorite"]),
)
expect(prioritized.map((model) => model.title)).toEqual([
"Favorite match",