Something went wrong. Try again.
opencode v2 mirror
Something went wrong. Try again.
TypeScript
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150import type { AgentListOutput, ModelListOutput, ProviderListOutput } from "@opencode/client/promise"import type { Agent, Project, Provider, ProviderListResponse } from "@/runtime/server/types"import type { Project as CurrentProject } from "@opencode/client/promise"import { unwrap } from "solid-js/store"export { pathKey as directoryKey, type PathKey as DirectoryKey } from "@/workspaces/path-key"
export const cmp = (a: string, b: string) => (a < b ? -1 : a > b ? 1 : 0)
const providerCatalogs = new WeakMap< ProviderListOutput["data"], WeakMap<ModelListOutput["data"], ProviderListResponse>>()
export function normalizeAgentList(input: AgentListOutput["data"] | Agent[]): Agent[] { if (input.every((agent) => !("request" in agent))) return input as Agent[] return (input as AgentListOutput["data"]).map((agent) => ({ name: agent.id, description: agent.description, mode: agent.mode, hidden: agent.hidden, temperature: typeof agent.request.settings.temperature === "number" ? agent.request.settings.temperature : undefined, topP: typeof agent.request.settings.topP === "number" ? agent.request.settings.topP : undefined, color: agent.color, permission: agent.permissions.map((rule) => ({ permission: rule.action, pattern: rule.resource, action: rule.effect, })), model: agent.model && { providerID: agent.model.providerID, modelID: agent.model.id }, variant: agent.model?.variant, prompt: agent.system, options: agent.request.settings, steps: agent.steps, }))}
export function normalizeProviderList( input: ProviderListOutput["data"] | ProviderListResponse, catalog?: ModelListOutput["data"],): ProviderListResponse { if (!Array.isArray(input)) return input // Client sync replaces whole catalog lists. Track those reads at the caller, // not every model field, and share conversions without retaining old lists. const providers = unwrap(input) const models = unwrap(catalog) const cached = models && providerCatalogs.get(providers)?.get(models) if (cached) return cached const all = new Map<string, Provider>()
for (const provider of providers) { all.set(provider.id, { id: provider.id, integrationID: provider.integrationID, name: provider.name, source: "custom", env: [], options: provider.settings ?? {}, models: {}, }) }
for (const model of models ?? []) { const provider = all.get(model.providerID) if (!provider || model.status === "deprecated") continue const cost = model.cost.find((item) => item.tier === undefined) ?? model.cost[0] provider.models[model.id] = { id: model.id, providerID: model.providerID, api: { id: model.modelID, url: "", npm: model.package ?? provider.id, }, name: model.name, family: model.family, capabilities: { temperature: false, reasoning: false, attachment: model.capabilities.input.some((item) => item !== "text"), toolcall: model.capabilities.tools, input: { text: model.capabilities.input.includes("text"), audio: model.capabilities.input.includes("audio"), image: model.capabilities.input.includes("image"), video: model.capabilities.input.includes("video"), pdf: model.capabilities.input.includes("pdf"), }, output: { text: model.capabilities.output.includes("text"), audio: model.capabilities.output.includes("audio"), image: model.capabilities.output.includes("image"), video: model.capabilities.output.includes("video"), pdf: model.capabilities.output.includes("pdf"), }, interleaved: false, }, cost: { input: cost?.input ?? 0, output: cost?.output ?? 0, cache: { read: cost?.cache.read ?? 0, write: cost?.cache.write ?? 0, }, }, limit: model.limit, status: model.status, options: model.settings ?? {}, headers: model.headers ?? {}, release_date: new Date(model.time.released).toISOString().slice(0, 10), variants: Object.fromEntries(model.variants.map((variant) => [variant.id, variant.settings ?? {}])), } }
const result = { all, connected: providers.map((provider) => provider.id), default: Object.fromEntries( providers.flatMap((provider) => { const model = models?.find((item) => item.providerID === provider.id && item.status !== "deprecated") return model ? [[provider.id, model.id]] : [] }), ), } if (models) { const cache = providerCatalogs.get(providers) ?? new WeakMap<ModelListOutput["data"], ProviderListResponse>() cache.set(models, result) providerCatalogs.set(providers, cache) } return result}
export function normalizeProjectInfo(project: Project | CurrentProject): Project { const worktree = "canonical" in project ? project.canonical : project.worktree return { ...project, worktree, worktrees: "worktrees" in project ? project.worktrees : [{ directory: worktree }], }}
export function updateProjectInfo(project: Project, update: CurrentProject): Project { return { ...project, ...update, worktree: update.canonical, worktrees: project.worktrees, }}