| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140 |
- 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>
- }
- 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 latest = createMemo(() =>
- pipe(
- available(),
- filter((x) => Math.abs(DateTime.fromISO(x.release_date).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) => `${x.providerID}:${x.modelID}`)))
- 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, { visibility: state })
- return
- }
- setStore("user", store.user.length, { ...model, visibility: state })
- }
- const visible = (model: ModelKey) => {
- const key = `${model.providerID}:${model.modelID}`
- const state = visibility().get(key)
- if (state === "hide") return false
- if (state === "show") return true
- if (latestSet().has(key)) return true
- const m = find(model)
- if (!m?.release_date || !DateTime.fromISO(m.release_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 > 5) 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,
- },
- }
- },
- })
|