refactor(opencode): simplify provider setup flow (#30173)

This commit is contained in:
Aiden Cline
2026-05-31 23:17:57 -05:00
committed by GitHub
parent 917a36abc3
commit a9c115c220
+20 -34
View File
@@ -3,13 +3,13 @@ import fuzzysort from "fuzzysort"
import { Config } from "@/config/config" import { Config } from "@/config/config"
import { mapValues, mergeDeep, omit, pickBy, sortBy } from "remeda" import { mapValues, mergeDeep, omit, pickBy, sortBy } from "remeda"
import { NoSuchModelError, type Provider as SDK } from "ai" import { NoSuchModelError, type Provider as SDK } from "ai"
import * as Log from "@opencode-ai/core/util/log" import { Log } from "@opencode-ai/core/util/log"
import { Npm } from "@opencode-ai/core/npm" import { Npm } from "@opencode-ai/core/npm"
import { Hash } from "@opencode-ai/core/util/hash" import { Hash } from "@opencode-ai/core/util/hash"
import { Plugin } from "../plugin" import { Plugin } from "../plugin"
import { serviceUse } from "@opencode-ai/core/effect/service-use" import { serviceUse } from "@opencode-ai/core/effect/service-use"
import { type LanguageModelV3 } from "@ai-sdk/provider" import { type LanguageModelV3 } from "@ai-sdk/provider"
import * as ModelsDev from "@opencode-ai/core/models-dev" import { ModelsDev } from "@opencode-ai/core/models-dev"
import { Auth } from "../auth" import { Auth } from "../auth"
import { Env } from "../env" import { Env } from "../env"
import { InstallationVersion } from "@opencode-ai/core/installation/version" import { InstallationVersion } from "@opencode-ai/core/installation/version"
@@ -24,7 +24,7 @@ import { EffectPromise } from "@/effect/promise"
import { AppFileSystem } from "@opencode-ai/core/filesystem" import { AppFileSystem } from "@opencode-ai/core/filesystem"
import { isRecord } from "@/util/record" import { isRecord } from "@/util/record"
import { optionalOmitUndefined } from "@opencode-ai/core/schema" import { optionalOmitUndefined } from "@opencode-ai/core/schema"
import * as ProviderTransform from "./transform" import { ProviderTransform } from "./transform"
import { ProviderV2 } from "@opencode-ai/core/provider" import { ProviderV2 } from "@opencode-ai/core/provider"
import { ModelStatus } from "./model-status" import { ModelStatus } from "./model-status"
import { RuntimeFlags } from "@/effect/runtime-flags" import { RuntimeFlags } from "@/effect/runtime-flags"
@@ -575,11 +575,7 @@ function custom(dep: CustomDep): Record<string, CustomLoader> {
const instanceUrl = (yield* dep.get("GITLAB_INSTANCE_URL")) || "https://gitlab.com" const instanceUrl = (yield* dep.get("GITLAB_INSTANCE_URL")) || "https://gitlab.com"
const auth = yield* dep.auth(input.id) const auth = yield* dep.auth(input.id)
const apiKey = yield* Effect.sync(() => { const apiKey = auth?.type === "oauth" ? auth.access : auth?.type === "api" ? auth.key : undefined
if (auth?.type === "oauth") return auth.access
if (auth?.type === "api") return auth.key
return undefined
})
const token = apiKey ?? (yield* dep.get("GITLAB_TOKEN")) const token = apiKey ?? (yield* dep.get("GITLAB_TOKEN"))
const providerConfig = (yield* dep.config()).provider?.["gitlab"] const providerConfig = (yield* dep.config()).provider?.["gitlab"]
@@ -727,12 +723,7 @@ function custom(dep: CustomDep): Record<string, CustomLoader> {
}, },
} }
const apiKey = yield* Effect.gen(function* () { const apiKey = env["CLOUDFLARE_API_KEY"] || (auth?.type === "api" ? auth.key : undefined)
const envToken = env["CLOUDFLARE_API_KEY"]
if (envToken) return envToken
if (auth?.type === "api") return auth.key
return undefined
})
return { return {
autoload: !!apiKey, autoload: !!apiKey,
@@ -778,12 +769,8 @@ function custom(dep: CustomDep): Record<string, CustomLoader> {
} }
// Get API token from env or auth - required for authenticated gateways // Get API token from env or auth - required for authenticated gateways
const apiToken = yield* Effect.gen(function* () { const apiToken =
const envToken = env["CLOUDFLARE_API_TOKEN"] || env["CF_AIG_TOKEN"] env["CLOUDFLARE_API_TOKEN"] || env["CF_AIG_TOKEN"] || (auth?.type === "api" ? auth.key : undefined)
if (envToken) return envToken
if (auth?.type === "api") return auth.key
return undefined
})
if (!apiToken) { if (!apiToken) {
throw new Error( throw new Error(
@@ -1671,15 +1658,15 @@ export const layer = Layer.effect(
return loaded as SDK return loaded as SDK
} }
let installedPath: string const installedPath = await (async () => {
if (!model.api.npm.startsWith("file://")) { if (model.api.npm.startsWith("file://")) {
log.info("loading local provider", { pkg: model.api.npm })
return model.api.npm
}
const item = await Npm.add(model.api.npm) const item = await Npm.add(model.api.npm)
if (!item.entrypoint) throw new Error(`Package ${model.api.npm} has no import entrypoint`) if (!item.entrypoint) throw new Error(`Package ${model.api.npm} has no import entrypoint`)
installedPath = item.entrypoint return item.entrypoint
} else { })()
log.info("loading local provider", { pkg: model.api.npm })
installedPath = model.api.npm
}
// `installedPath` is a local entry path or an existing `file://` URL. Normalize // `installedPath` is a local entry path or an existing `file://` URL. Normalize
// only path inputs so Node on Windows accepts the dynamic import. // only path inputs so Node on Windows accepts the dynamic import.
@@ -1778,7 +1765,7 @@ export const layer = Layer.effect(
const provider = s.providers[providerID] const provider = s.providers[providerID]
if (!provider) return undefined if (!provider) return undefined
let priority = [ const defaultPriority = [
"claude-haiku-4-5", "claude-haiku-4-5",
"claude-haiku-4.5", "claude-haiku-4.5",
"3-5-haiku", "3-5-haiku",
@@ -1787,12 +1774,11 @@ export const layer = Layer.effect(
"gemini-2.5-flash", "gemini-2.5-flash",
"gpt-5-nano", "gpt-5-nano",
] ]
if (providerID.startsWith("opencode")) { const priority = providerID.startsWith("opencode")
priority = ["gpt-5-nano"] ? ["gpt-5-nano"]
} : providerID.startsWith("github-copilot")
if (providerID.startsWith("github-copilot")) { ? ["gpt-5-mini", "claude-haiku-4.5", ...defaultPriority]
priority = ["gpt-5-mini", "claude-haiku-4.5", ...priority] : defaultPriority
}
for (const item of priority) { for (const item of priority) {
if (providerID === ProviderV2.ID.amazonBedrock) { if (providerID === ProviderV2.ID.amazonBedrock) {
const crossRegionPrefixes = ["global.", "us.", "eu."] const crossRegionPrefixes = ["global.", "us.", "eu."]