Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 20 additions & 34 deletions packages/opencode/src/provider/provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@ import fuzzysort from "fuzzysort"
import { Config } from "@/config/config"
import { mapValues, mergeDeep, omit, pickBy, sortBy } from "remeda"
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 { Hash } from "@opencode-ai/core/util/hash"
import { Plugin } from "../plugin"
import { serviceUse } from "@opencode-ai/core/effect/service-use"
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 { Env } from "../env"
import { InstallationVersion } from "@opencode-ai/core/installation/version"
Expand All @@ -24,7 +24,7 @@ import { EffectPromise } from "@/effect/promise"
import { AppFileSystem } from "@opencode-ai/core/filesystem"
import { isRecord } from "@/util/record"
import { optionalOmitUndefined } from "@opencode-ai/core/schema"
import * as ProviderTransform from "./transform"
import { ProviderTransform } from "./transform"
import { ProviderV2 } from "@opencode-ai/core/provider"
import { ModelStatus } from "./model-status"
import { RuntimeFlags } from "@/effect/runtime-flags"
Expand Down Expand Up @@ -575,11 +575,7 @@ function custom(dep: CustomDep): Record<string, CustomLoader> {
const instanceUrl = (yield* dep.get("GITLAB_INSTANCE_URL")) || "https://gitlab.com"

const auth = yield* dep.auth(input.id)
const apiKey = yield* Effect.sync(() => {
if (auth?.type === "oauth") return auth.access
if (auth?.type === "api") return auth.key
return undefined
})
const apiKey = auth?.type === "oauth" ? auth.access : auth?.type === "api" ? auth.key : undefined
const token = apiKey ?? (yield* dep.get("GITLAB_TOKEN"))

const providerConfig = (yield* dep.config()).provider?.["gitlab"]
Expand Down Expand Up @@ -727,12 +723,7 @@ function custom(dep: CustomDep): Record<string, CustomLoader> {
},
}

const apiKey = yield* Effect.gen(function* () {
const envToken = env["CLOUDFLARE_API_KEY"]
if (envToken) return envToken
if (auth?.type === "api") return auth.key
return undefined
})
const apiKey = env["CLOUDFLARE_API_KEY"] || (auth?.type === "api" ? auth.key : undefined)

return {
autoload: !!apiKey,
Expand Down Expand Up @@ -778,12 +769,8 @@ function custom(dep: CustomDep): Record<string, CustomLoader> {
}

// Get API token from env or auth - required for authenticated gateways
const apiToken = yield* Effect.gen(function* () {
const envToken = env["CLOUDFLARE_API_TOKEN"] || env["CF_AIG_TOKEN"]
if (envToken) return envToken
if (auth?.type === "api") return auth.key
return undefined
})
const apiToken =
env["CLOUDFLARE_API_TOKEN"] || env["CF_AIG_TOKEN"] || (auth?.type === "api" ? auth.key : undefined)

if (!apiToken) {
throw new Error(
Expand Down Expand Up @@ -1671,15 +1658,15 @@ export const layer = Layer.effect(
return loaded as SDK
}

let installedPath: string
if (!model.api.npm.startsWith("file://")) {
const installedPath = await (async () => {
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)
if (!item.entrypoint) throw new Error(`Package ${model.api.npm} has no import entrypoint`)
installedPath = item.entrypoint
} else {
log.info("loading local provider", { pkg: model.api.npm })
installedPath = model.api.npm
}
return item.entrypoint
})()

// `installedPath` is a local entry path or an existing `file://` URL. Normalize
// only path inputs so Node on Windows accepts the dynamic import.
Expand Down Expand Up @@ -1778,7 +1765,7 @@ export const layer = Layer.effect(
const provider = s.providers[providerID]
if (!provider) return undefined

let priority = [
const defaultPriority = [
"claude-haiku-4-5",
"claude-haiku-4.5",
"3-5-haiku",
Expand All @@ -1787,12 +1774,11 @@ export const layer = Layer.effect(
"gemini-2.5-flash",
"gpt-5-nano",
]
if (providerID.startsWith("opencode")) {
priority = ["gpt-5-nano"]
}
if (providerID.startsWith("github-copilot")) {
priority = ["gpt-5-mini", "claude-haiku-4.5", ...priority]
}
const priority = providerID.startsWith("opencode")
? ["gpt-5-nano"]
: providerID.startsWith("github-copilot")
? ["gpt-5-mini", "claude-haiku-4.5", ...defaultPriority]
: defaultPriority
for (const item of priority) {
if (providerID === ProviderV2.ID.amazonBedrock) {
const crossRegionPrefixes = ["global.", "us.", "eu."]
Expand Down
Loading