diff options
| author | Adam <[email protected]> | 2025-12-14 05:40:43 -0600 |
|---|---|---|
| committer | Adam <[email protected]> | 2025-12-14 21:38:58 -0600 |
| commit | 4a8e8f537ca688cca52674a619065f577cbd3f9b (patch) | |
| tree | 2255aa8ab0a9bb9d90519a1ac6d35e60b1e3e6f0 /packages/desktop/src/context | |
| parent | a68bee7878d78ac7d480d6fbbd3225759e695c61 (diff) | |
| download | opencode-4a8e8f537ca688cca52674a619065f577cbd3f9b.tar.gz opencode-4a8e8f537ca688cca52674a619065f577cbd3f9b.zip | |
wip(desktop): progress
Diffstat (limited to 'packages/desktop/src/context')
| -rw-r--r-- | packages/desktop/src/context/layout.tsx | 9 | ||||
| -rw-r--r-- | packages/desktop/src/context/local.tsx | 93 |
2 files changed, 75 insertions, 27 deletions
diff --git a/packages/desktop/src/context/layout.tsx b/packages/desktop/src/context/layout.tsx index 3d5cad761..587276c53 100644 --- a/packages/desktop/src/context/layout.tsx +++ b/packages/desktop/src/context/layout.tsx @@ -22,7 +22,7 @@ export function getAvatarColors(key?: string) { } } -type Dialog = "provider" | "model" | "connect" +type Dialog = "provider" | "model" | "connect" | "manage-models" export const { use: useLayout, provider: LayoutProvider } = createSimpleContext({ name: "Layout", @@ -172,12 +172,7 @@ export const { use: useLayout, provider: LayoutProvider } = createSimpleContext( dialog: { opened: createMemo(() => ephemeral.dialog?.open), open(dialog: Dialog) { - batch(() => { - // if (dialog !== "connect") { - // setEphemeral("connect", {}) - // } - setEphemeral("dialog", "open", dialog) - }) + setEphemeral("dialog", "open", dialog) }, close(dialog: Dialog) { if (ephemeral.dialog.open === dialog) { diff --git a/packages/desktop/src/context/local.tsx b/packages/desktop/src/context/local.tsx index 181a4d247..f841da1cc 100644 --- a/packages/desktop/src/context/local.tsx +++ b/packages/desktop/src/context/local.tsx @@ -1,12 +1,14 @@ import { createStore, produce, reconcile } from "solid-js/store" import { batch, createEffect, createMemo } from "solid-js" -import { uniqueBy } from "remeda" +import { filter, firstBy, flat, groupBy, mapValues, pipe, uniqueBy, values } from "remeda" import type { FileContent, FileNode, Model, Provider, File as FileStatus } from "@opencode-ai/sdk/v2" import { createSimpleContext } from "@opencode-ai/ui/context" import { useSDK } from "./sdk" import { useSync } from "./sync" import { base64Encode } from "@opencode-ai/util/encode" import { useProviders } from "@/hooks/use-providers" +import { makePersisted } from "@solid-primitives/storage" +import { DateTime } from "luxon" export type LocalFile = FileNode & Partial<{ @@ -108,30 +110,66 @@ export const { use: useLocal, provider: LocalProvider } = createSimpleContext({ })() const model = (() => { - const [store, setStore] = createStore<{ + const [store, setStore] = makePersisted( + createStore<{ + user: (ModelKey & { visibility: "show" | "hide"; favorite?: boolean })[] + recent: ModelKey[] + }>({ + user: [], + recent: [], + }), + { name: "model.v1" }, + ) + + const [ephemeral, setEphemeral] = createStore<{ model: Record<string, ModelKey> - recent: ModelKey[] }>({ model: {}, - recent: [], - }) - - const value = localStorage.getItem("model") - setStore("recent", JSON.parse(value ?? "[]")) - createEffect(() => { - localStorage.setItem("model", JSON.stringify(store.recent)) }) - const list = createMemo(() => + const available = createMemo(() => providers.connected().flatMap((p) => Object.values(p.models).map((m) => ({ ...m, - name: m.name.replace("(latest)", "").trim(), provider: p, - latest: m.name.includes("(latest)"), + user: store.user.find((x) => x.modelID === m.id && x.providerID === p.id), })), ), ) + 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 list = createMemo(() => + available().map((m) => ({ + ...m, + name: m.name.replace("(latest)", "").trim(), + latest: m.name.includes("(latest)"), + visible: + m.user?.visibility !== "hide" && + (latest().find((x) => x.modelID === m.id && x.providerID === m.provider.id) || + store.user.find((x) => x.modelID === m.id && x.providerID === m.provider.id)?.visibility === "show"), + })), + ) + const find = (key: ModelKey) => list().find((m) => m.id === key?.modelID && m.provider.id === key.providerID) const fallbackModel = createMemo(() => { @@ -163,10 +201,10 @@ export const { use: useLocal, provider: LocalProvider } = createSimpleContext({ throw new Error("No default model found") }) - const currentModel = createMemo(() => { + const current = createMemo(() => { const a = agent.current() const key = getFirstValidModel( - () => store.model[a.name], + () => ephemeral.model[a.name], () => a.model, fallbackModel, )! @@ -177,10 +215,12 @@ export const { use: useLocal, provider: LocalProvider } = createSimpleContext({ const cycle = (direction: 1 | -1) => { const recentList = recent() - const current = currentModel() - if (!current) return + const currentModel = current() + if (!currentModel) return - const index = recentList.findIndex((x) => x?.provider.id === current.provider.id && x?.id === current.id) + const index = recentList.findIndex( + (x) => x?.provider.id === currentModel.provider.id && x?.id === currentModel.id, + ) if (index === -1) return let next = index + direction @@ -196,14 +236,21 @@ export const { use: useLocal, provider: LocalProvider } = createSimpleContext({ }) } + function updateVisibility(model: ModelKey, visibility: "show" | "hide") { + const index = store.user.findIndex((x) => x.modelID === model.modelID && x.providerID === model.providerID) + if (index >= 0) { + setStore("user", index, { visibility: visibility }) + } + } + return { - current: currentModel, + current, recent, list, cycle, set(model: ModelKey | undefined, options?: { recent?: boolean }) { batch(() => { - setStore("model", agent.current().name, model ?? fallbackModel()) + setEphemeral("model", agent.current().name, model ?? fallbackModel()) if (options?.recent && model) { const uniq = uniqueBy([model, ...store.recent], (x) => x.providerID + x.modelID) if (uniq.length > 5) uniq.pop() @@ -211,6 +258,12 @@ export const { use: useLocal, provider: LocalProvider } = createSimpleContext({ } }) }, + show(model: ModelKey) { + updateVisibility(model, "show") + }, + hide(model: ModelKey) { + updateVisibility(model, "hide") + }, } })() |
