fix(models): sort free models by launch priority
This commit is contained in:
parent
ac8e686f33
commit
e97308cd57
9 changed files with 142 additions and 27 deletions
|
|
@ -9,6 +9,7 @@ import { popularProviders } from "@/hooks/use-providers"
|
|||
import { useLanguage } from "@/context/language"
|
||||
import { useDialog } from "@opencode-ai/ui/context/dialog"
|
||||
import { DialogSelectProvider } from "./dialog-select-provider"
|
||||
import { sortModels } from "@/utils/model-sort"
|
||||
|
||||
export const DialogManageModels: Component = () => {
|
||||
const local = useLocal()
|
||||
|
|
@ -44,7 +45,7 @@ export const DialogManageModels: Component = () => {
|
|||
key={(x) => `${x?.provider?.id}:${x?.id}`}
|
||||
items={local.model.list()}
|
||||
filterKeys={["provider.name", "name", "id"]}
|
||||
sortBy={(a, b) => a.name.localeCompare(b.name)}
|
||||
sortBy={sortModels}
|
||||
groupBy={(x) => x.provider.id}
|
||||
groupHeader={(group) => {
|
||||
const provider = group.items[0].provider
|
||||
|
|
|
|||
|
|
@ -12,9 +12,7 @@ import { List } from "@opencode-ai/ui/list"
|
|||
import { Tooltip } from "@opencode-ai/ui/tooltip"
|
||||
import { ModelTooltip } from "./model-tooltip"
|
||||
import { useLanguage } from "@/context/language"
|
||||
|
||||
const isFree = (provider: string, cost: { input: number } | undefined) =>
|
||||
provider === "opencode" && (!cost || cost.input === 0)
|
||||
import { isFreeModel, sortModels } from "@/utils/model-sort"
|
||||
|
||||
type ModelState = ReturnType<typeof useLocal>["model"]
|
||||
|
||||
|
|
@ -44,7 +42,7 @@ const ModelList: Component<{
|
|||
items={models}
|
||||
current={model.current()}
|
||||
filterKeys={["provider.name", "name", "id"]}
|
||||
sortBy={(a, b) => a.name.localeCompare(b.name)}
|
||||
sortBy={sortModels}
|
||||
groupBy={(x) => x.provider.name}
|
||||
sortGroupsBy={(a, b) => {
|
||||
const aProvider = a.items[0].provider.id
|
||||
|
|
@ -58,7 +56,7 @@ const ModelList: Component<{
|
|||
class="w-full"
|
||||
placement="right-start"
|
||||
gutter={12}
|
||||
value={<ModelTooltip model={item} latest={item.latest} free={isFree(item.provider.id, item.cost)} />}
|
||||
value={<ModelTooltip model={item} latest={item.latest} free={isFreeModel(item)} />}
|
||||
>
|
||||
{node}
|
||||
</Tooltip>
|
||||
|
|
@ -73,7 +71,7 @@ const ModelList: Component<{
|
|||
{(i) => (
|
||||
<div class="w-full flex items-center gap-x-2 text-13-regular">
|
||||
<span class="truncate">{i.name}</span>
|
||||
<Show when={isFree(i.provider.id, i.cost)}>
|
||||
<Show when={isFreeModel(i)}>
|
||||
<Tag>{language.t("model.tag.free")}</Tag>
|
||||
</Show>
|
||||
<Show when={i.latest}>
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import { useLanguage } from "@/context/language"
|
|||
import { useModels } from "@/context/models"
|
||||
import { popularProviders } from "@/hooks/use-providers"
|
||||
import { SettingsList } from "./settings-list"
|
||||
import { sortModels } from "@/utils/model-sort"
|
||||
|
||||
type ModelItem = ReturnType<ReturnType<typeof useModels>["list"]>[number]
|
||||
|
||||
|
|
@ -39,7 +40,7 @@ export const SettingsModels: Component = () => {
|
|||
items: (_filter) => models.list(),
|
||||
key: (x) => `${x.provider.id}:${x.id}`,
|
||||
filterKeys: ["provider.name", "name", "id"],
|
||||
sortBy: (a, b) => a.name.localeCompare(b.name),
|
||||
sortBy: sortModels,
|
||||
groupBy: (x) => x.provider.id,
|
||||
sortGroupsBy: (a, b) => {
|
||||
const aIndex = popularProviders.indexOf(a.category)
|
||||
|
|
|
|||
25
packages/app/src/utils/model-sort.test.ts
Normal file
25
packages/app/src/utils/model-sort.test.ts
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
import { describe, expect, test } from "bun:test"
|
||||
import { sortModels } from "./model-sort"
|
||||
|
||||
function model(input: { id: string; name: string; release_date: string; cost?: number }) {
|
||||
return {
|
||||
id: input.id,
|
||||
name: input.name,
|
||||
release_date: input.release_date,
|
||||
provider: { id: "opencode" },
|
||||
cost: { input: input.cost ?? 0 },
|
||||
}
|
||||
}
|
||||
|
||||
describe("sortModels", () => {
|
||||
test("pins Big Pickle before free models sorted by release date", () => {
|
||||
expect(
|
||||
[
|
||||
model({ id: "older-free", name: "Older Free", release_date: "2026-01-01" }),
|
||||
model({ id: "paid", name: "Paid", release_date: "2026-05-01", cost: 1 }),
|
||||
model({ id: "newer-free", name: "Newer Free", release_date: "2026-05-01" }),
|
||||
model({ id: "big-pickle", name: "Big Pickle", release_date: "2025-10-17" }),
|
||||
].sort(sortModels).map((item) => item.id),
|
||||
).toEqual(["big-pickle", "newer-free", "older-free", "paid"])
|
||||
})
|
||||
})
|
||||
26
packages/app/src/utils/model-sort.ts
Normal file
26
packages/app/src/utils/model-sort.ts
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
type SortableModel = {
|
||||
id: string
|
||||
name: string
|
||||
release_date: string
|
||||
provider: { id: string }
|
||||
cost?: { input: number }
|
||||
}
|
||||
|
||||
export function isFreeModel(model: { provider: { id: string }; cost?: { input: number } }) {
|
||||
return model.provider.id === "opencode" && (!model.cost || model.cost.input === 0)
|
||||
}
|
||||
|
||||
export function sortModels(a: SortableModel, b: SortableModel) {
|
||||
const aFree = isFreeModel(a)
|
||||
const bFree = isFreeModel(b)
|
||||
if (aFree && !bFree) return -1
|
||||
if (!aFree && bFree) return 1
|
||||
if (aFree && bFree) {
|
||||
if (a.id !== b.id) {
|
||||
if (a.id === "big-pickle") return -1
|
||||
if (b.id === "big-pickle") return 1
|
||||
}
|
||||
return b.release_date.localeCompare(a.release_date) || a.name.localeCompare(b.name)
|
||||
}
|
||||
return a.name.localeCompare(b.name)
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue