import type { AgentListOutput, ModelDefaultOutput, ModelListOutput, PermissionV2Request, ProviderListOutput, } from "@opencode-ai/client/promise" import type { Agent, PermissionRequest, Project, Provider, ProviderListResponse } from "@opencode-ai/sdk/v2/client" import type { Project as CurrentProject } from "@opencode-ai/client/promise" import { NormalizedProviderListResponse } from "@opencode-ai/session-ui/context" export { pathKey as directoryKey, type PathKey as DirectoryKey } from "@/utils/path-key" export const cmp = (a: string, b: string) => (a < b ? -1 : a > b ? 1 : 0) 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 normalizePermissionRequest(input: PermissionV2Request | PermissionRequest): PermissionRequest { if ("permission" in input) return input return { id: input.id, sessionID: input.sessionID, permission: input.action, patterns: input.resources, always: input.save ?? [], metadata: input.metadata ?? {}, tool: input.source?.type === "tool" ? { messageID: input.source.messageID, callID: input.source.callID } : undefined, } } export function normalizeProviderList( providers: ProviderListOutput["data"] | ProviderListResponse, models?: ModelListOutput["data"], defaultModel?: ModelDefaultOutput["data"], ): NormalizedProviderListResponse { if (!Array.isArray(providers)) { return { ...providers, all: new Map( providers.all.map((provider) => [ provider.id, { ...provider, models: Object.fromEntries( Object.entries(provider.models).filter(([, model]) => model.status !== "deprecated"), ), }, ]), ), } } const all = new Map() for (const provider of providers) { all.set(provider.id, { id: provider.id, 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 ?? {}])), } } return { all, connected: providers.map((provider) => provider.id), defaultModel: defaultModel ? { providerID: defaultModel.providerID, modelID: defaultModel.id } : null, default: Object.fromEntries( providers.flatMap((provider) => { const model = defaultModel?.providerID === provider.id ? defaultModel : models?.find((item) => item.providerID === provider.id && item.status !== "deprecated") return model ? [[provider.id, model.id]] : [] }), ), } } export function sanitizeProject(project: Project) { if (!project.icon?.url && !project.icon?.override) return project return { ...project, icon: { ...project.icon, url: undefined, override: undefined, }, } } export function normalizeProjectInfo(project: Project | CurrentProject): Project { return { ...project, vcs: project.vcs === "git" ? "git" : undefined, } }