| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163 |
- import { createMemo } from "solid-js"
- import { createStore } from "solid-js/store"
- import { DateTime } from "luxon"
- import { filter, firstBy, flat, groupBy, mapValues, pipe, uniqueBy, values } from "remeda"
- import { createSimpleContext } from "@opencode-ai/ui/context"
- import { useProviders } from "@/hooks/use-providers"
- import { Persist, persisted } from "@/utils/persist"
- export type ModelKey = { providerID: string; modelID: string }
- type Visibility = "show" | "hide"
- type User = ModelKey & { visibility: Visibility; favorite?: boolean }
- type Store = {
- user: User[]
- recent: ModelKey[]
- variant?: Record<string, string | undefined>
- }
- const RECENT_LIMIT = 5
- function modelKey(model: ModelKey) {
- return `${model.providerID}:${model.modelID}`
- }
- export const { use: useModels, provider: ModelsProvider } = createSimpleContext({
- name: "Models",
- init: () => {
- const providers = useProviders()
- const [store, setStore, _, ready] = persisted(
- Persist.global("model", ["model.v1"]),
- createStore<Store>({
- user: [],
- recent: [],
- variant: {},
- }),
- )
- const available = createMemo(() =>
- providers.connected().flatMap((p) =>
- Object.values(p.models).map((m) => ({
- ...m,
- provider: p,
- })),
- ),
- )
- const release = createMemo(
- () =>
- new Map(
- available().map((model) => {
- const parsed = DateTime.fromISO(model.release_date)
- return [modelKey({ providerID: model.provider.id, modelID: model.id }), parsed] as const
- }),
- ),
- )
- const latest = createMemo(() =>
- pipe(
- available(),
- filter(
- (x) =>
- Math.abs(
- (release().get(modelKey({ providerID: x.provider.id, modelID: x.id })) ?? DateTime.invalid("invalid"))
- .diffNow()
- .as("months"),
- ) < 6,
- ),
- groupBy((x) => x.provider.id),
- mapValues((models) =>
- pipe(
- models,
- groupBy((x) => x.family),
- values(),
- (groups) =>
- groups.flatMap((g) => {
- const first = firstBy(g, [(x) => x.release_date, "desc"])
- return first ? [{ modelID: first.id, providerID: first.provider.id }] : []
- }),
- ),
- ),
- values(),
- flat(),
- ),
- )
- const latestSet = createMemo(() => new Set(latest().map((x) => modelKey(x))))
- const visibility = createMemo(() => {
- const map = new Map<string, Visibility>()
- for (const item of store.user) map.set(`${item.providerID}:${item.modelID}`, item.visibility)
- return map
- })
- const list = createMemo(() =>
- available().map((m) => ({
- ...m,
- name: m.name.replace("(latest)", "").trim(),
- latest: m.name.includes("(latest)"),
- })),
- )
- const find = (key: ModelKey) => list().find((m) => m.id === key.modelID && m.provider.id === key.providerID)
- function update(model: ModelKey, state: Visibility) {
- const index = store.user.findIndex((x) => x.modelID === model.modelID && x.providerID === model.providerID)
- if (index >= 0) {
- setStore("user", index, (current) => ({ ...current, visibility: state }))
- return
- }
- setStore("user", store.user.length, { ...model, visibility: state })
- }
- const visible = (model: ModelKey) => {
- const key = modelKey(model)
- const state = visibility().get(key)
- if (state === "hide") return false
- if (state === "show") return true
- if (latestSet().has(key)) return true
- const date = release().get(key)
- if (!date?.isValid) return true
- return false
- }
- const setVisibility = (model: ModelKey, state: boolean) => {
- update(model, state ? "show" : "hide")
- }
- const push = (model: ModelKey) => {
- const uniq = uniqueBy([model, ...store.recent], (x) => `${x.providerID}:${x.modelID}`)
- if (uniq.length > RECENT_LIMIT) uniq.pop()
- setStore("recent", uniq)
- }
- const variantKey = (model: ModelKey) => `${model.providerID}/${model.modelID}`
- const getVariant = (model: ModelKey) => store.variant?.[variantKey(model)]
- const setVariant = (model: ModelKey, value: string | undefined) => {
- const key = variantKey(model)
- if (!store.variant) {
- setStore("variant", { [key]: value })
- return
- }
- setStore("variant", key, value)
- }
- return {
- ready,
- list,
- find,
- visible,
- setVisibility,
- recent: {
- list: createMemo(() => store.recent),
- push,
- },
- variant: {
- get: getVariant,
- set: setVariant,
- },
- }
- },
- })
|