summaryrefslogtreecommitdiffhomepage
path: root/packages/desktop/src/context
diff options
context:
space:
mode:
authorAdam <[email protected]>2025-12-14 05:40:43 -0600
committerAdam <[email protected]>2025-12-14 21:38:58 -0600
commit4a8e8f537ca688cca52674a619065f577cbd3f9b (patch)
tree2255aa8ab0a9bb9d90519a1ac6d35e60b1e3e6f0 /packages/desktop/src/context
parenta68bee7878d78ac7d480d6fbbd3225759e695c61 (diff)
downloadopencode-4a8e8f537ca688cca52674a619065f577cbd3f9b.tar.gz
opencode-4a8e8f537ca688cca52674a619065f577cbd3f9b.zip
wip(desktop): progress
Diffstat (limited to 'packages/desktop/src/context')
-rw-r--r--packages/desktop/src/context/layout.tsx9
-rw-r--r--packages/desktop/src/context/local.tsx93
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")
+ },
}
})()