refactor(core): move database schema ownership (#29068)
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
This commit is contained in:
co-authored by
copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
parent
6bcb9cb9bb
commit
7f571d36ea
@@ -4,7 +4,7 @@ import { Auth } from "@/auth"
|
||||
import { InstanceState } from "@/effect/instance-state"
|
||||
import { optionalOmitUndefined } from "@opencode-ai/core/schema"
|
||||
import { Plugin } from "../plugin"
|
||||
import { ProviderID } from "./schema"
|
||||
import { ProviderV2 } from "@opencode-ai/core/provider"
|
||||
import { Array as Arr, Effect, Layer, Record, Result, Context, Schema } from "effect"
|
||||
|
||||
const When = Schema.Struct({
|
||||
@@ -65,11 +65,11 @@ export const CallbackInput = Schema.Struct({
|
||||
export type CallbackInput = Schema.Schema.Type<typeof CallbackInput>
|
||||
|
||||
export class OauthMissing extends Schema.TaggedErrorClass<OauthMissing>()("ProviderAuthOauthMissing", {
|
||||
providerID: ProviderID,
|
||||
providerID: ProviderV2.ID,
|
||||
}) {}
|
||||
|
||||
export class OauthCodeMissing extends Schema.TaggedErrorClass<OauthCodeMissing>()("ProviderAuthOauthCodeMissing", {
|
||||
providerID: ProviderID,
|
||||
providerID: ProviderV2.ID,
|
||||
}) {}
|
||||
|
||||
export class OauthCallbackFailed extends Schema.TaggedErrorClass<OauthCallbackFailed>()(
|
||||
@@ -90,15 +90,15 @@ export interface Interface {
|
||||
readonly methods: () => Effect.Effect<Methods>
|
||||
readonly authorize: (
|
||||
input: {
|
||||
providerID: ProviderID
|
||||
providerID: ProviderV2.ID
|
||||
} & AuthorizeInput,
|
||||
) => Effect.Effect<Authorization | undefined, Error>
|
||||
readonly callback: (input: { providerID: ProviderID } & CallbackInput) => Effect.Effect<void, Error>
|
||||
readonly callback: (input: { providerID: ProviderV2.ID } & CallbackInput) => Effect.Effect<void, Error>
|
||||
}
|
||||
|
||||
interface State {
|
||||
hooks: Record<ProviderID, Hook>
|
||||
pending: Map<ProviderID, AuthOAuthResult>
|
||||
hooks: Record<ProviderV2.ID, Hook>
|
||||
pending: Map<ProviderV2.ID, AuthOAuthResult>
|
||||
}
|
||||
|
||||
export class Service extends Context.Service<Service, Interface>()("@opencode/ProviderAuth") {}
|
||||
@@ -117,11 +117,11 @@ export const layer: Layer.Layer<Service, never, Auth.Service | Plugin.Service> =
|
||||
hooks: Record.fromEntries(
|
||||
Arr.filterMap(plugins, (x) =>
|
||||
x.auth?.provider !== undefined
|
||||
? Result.succeed([ProviderID.make(x.auth.provider), x.auth] as const)
|
||||
? Result.succeed([ProviderV2.ID.make(x.auth.provider), x.auth] as const)
|
||||
: Result.failVoid,
|
||||
),
|
||||
),
|
||||
pending: new Map<ProviderID, AuthOAuthResult>(),
|
||||
pending: new Map<ProviderV2.ID, AuthOAuthResult>(),
|
||||
}
|
||||
}),
|
||||
)
|
||||
@@ -160,7 +160,7 @@ export const layer: Layer.Layer<Service, never, Auth.Service | Plugin.Service> =
|
||||
})
|
||||
|
||||
const authorize = Effect.fn("ProviderAuth.authorize")(function* (
|
||||
input: { providerID: ProviderID } & AuthorizeInput,
|
||||
input: { providerID: ProviderV2.ID } & AuthorizeInput,
|
||||
) {
|
||||
const { hooks, pending } = yield* InstanceState.get(state)
|
||||
const method = hooks[input.providerID].methods[input.method]
|
||||
@@ -184,7 +184,7 @@ export const layer: Layer.Layer<Service, never, Auth.Service | Plugin.Service> =
|
||||
}
|
||||
})
|
||||
|
||||
const callback = Effect.fn("ProviderAuth.callback")(function* (input: { providerID: ProviderID } & CallbackInput) {
|
||||
const callback = Effect.fn("ProviderAuth.callback")(function* (input: { providerID: ProviderV2.ID } & CallbackInput) {
|
||||
const pending = (yield* InstanceState.get(state)).pending
|
||||
const match = pending.get(input.providerID)
|
||||
if (!match) return yield* new OauthMissing({ providerID: input.providerID })
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { APICallError } from "ai"
|
||||
import { STATUS_CODES } from "http"
|
||||
import { iife } from "@/util/iife"
|
||||
import type { ProviderID } from "./schema"
|
||||
import type { ProviderV2 } from "@opencode-ai/core/provider"
|
||||
|
||||
export class HeaderTimeoutError extends Error {
|
||||
public override readonly name = "ProviderHeaderTimeoutError"
|
||||
@@ -61,7 +61,7 @@ function isOverflow(message: string) {
|
||||
return /^4(00|13)\s*(status code)?\s*\(no body\)/i.test(message)
|
||||
}
|
||||
|
||||
function message(providerID: ProviderID, e: APICallError) {
|
||||
function message(providerID: ProviderV2.ID, e: APICallError) {
|
||||
return iife(() => {
|
||||
const msg = e.message
|
||||
if (msg === "") {
|
||||
@@ -194,7 +194,7 @@ export type ParsedAPICallError =
|
||||
metadata?: Record<string, string>
|
||||
}
|
||||
|
||||
export function parseAPICallError(input: { providerID: ProviderID; error: APICallError }): ParsedAPICallError {
|
||||
export function parseAPICallError(input: { providerID: ProviderV2.ID; error: APICallError }): ParsedAPICallError {
|
||||
const m = message(input.providerID, input.error)
|
||||
const body = json(input.error.responseBody)
|
||||
if (isOverflow(m) || input.error.statusCode === 413 || body?.error?.code === "context_length_exceeded") {
|
||||
|
||||
@@ -25,7 +25,7 @@ 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 { ModelID, ProviderID } from "./schema"
|
||||
import { ProviderV2 } from "@opencode-ai/core/provider"
|
||||
import { ModelStatus } from "./model-status"
|
||||
import { RuntimeFlags } from "@/effect/runtime-flags"
|
||||
import { ProviderError } from "./error"
|
||||
@@ -663,8 +663,8 @@ function custom(dep: CustomDep): Record<string, CustomLoader> {
|
||||
for (const m of result.models) {
|
||||
if (!input.models[m.id]) {
|
||||
models[m.id] = {
|
||||
id: ModelID.make(m.id),
|
||||
providerID: ProviderID.make("gitlab"),
|
||||
id: ProviderV2.ModelID.make(m.id),
|
||||
providerID: ProviderV2.ID.make("gitlab"),
|
||||
name: `Agent Platform (${m.name})`,
|
||||
family: "",
|
||||
api: {
|
||||
@@ -928,8 +928,8 @@ const ProviderLimit = Schema.Struct({
|
||||
})
|
||||
|
||||
export const Model = Schema.Struct({
|
||||
id: ModelID,
|
||||
providerID: ProviderID,
|
||||
id: ProviderV2.ModelID,
|
||||
providerID: ProviderV2.ID,
|
||||
api: ProviderApiInfo,
|
||||
name: Schema.String,
|
||||
family: optionalOmitUndefined(Schema.String),
|
||||
@@ -945,7 +945,7 @@ export const Model = Schema.Struct({
|
||||
export type Model = Types.DeepMutable<Schema.Schema.Type<typeof Model>>
|
||||
|
||||
export const Info = Schema.Struct({
|
||||
id: ProviderID,
|
||||
id: ProviderV2.ID,
|
||||
name: Schema.String,
|
||||
source: Schema.Literals(["env", "config", "custom", "api"]),
|
||||
env: Schema.Array(Schema.String),
|
||||
@@ -985,8 +985,8 @@ export function defaultModelIDs<T extends { models: Record<string, { id: string
|
||||
}
|
||||
|
||||
export class ModelNotFoundError extends Schema.TaggedErrorClass<ModelNotFoundError>()("ProviderModelNotFoundError", {
|
||||
providerID: ProviderID,
|
||||
modelID: ModelID,
|
||||
providerID: ProviderV2.ID,
|
||||
modelID: ProviderV2.ModelID,
|
||||
suggestions: Schema.optional(Schema.Array(Schema.String)),
|
||||
cause: Schema.optional(Schema.Defect),
|
||||
}) {
|
||||
@@ -996,7 +996,7 @@ export class ModelNotFoundError extends Schema.TaggedErrorClass<ModelNotFoundErr
|
||||
}
|
||||
|
||||
export class InitError extends Schema.TaggedErrorClass<InitError>()("ProviderInitError", {
|
||||
providerID: ProviderID,
|
||||
providerID: ProviderV2.ID,
|
||||
cause: Schema.optional(Schema.Defect),
|
||||
}) {
|
||||
static isInstance(input: unknown): input is InitError {
|
||||
@@ -1011,7 +1011,7 @@ export class NoProvidersError extends Schema.TaggedErrorClass<NoProvidersError>(
|
||||
}
|
||||
|
||||
export class NoModelsError extends Schema.TaggedErrorClass<NoModelsError>()("ProviderNoModelsError", {
|
||||
providerID: ProviderID,
|
||||
providerID: ProviderV2.ID,
|
||||
}) {
|
||||
static isInstance(input: unknown): input is NoModelsError {
|
||||
return input instanceof NoModelsError
|
||||
@@ -1022,22 +1022,22 @@ export type DefaultModelError = ModelNotFoundError | NoProvidersError | NoModels
|
||||
export type Error = ModelNotFoundError | InitError | NoProvidersError | NoModelsError
|
||||
|
||||
export interface Interface {
|
||||
readonly list: () => Effect.Effect<Record<ProviderID, Info>>
|
||||
readonly getProvider: (providerID: ProviderID) => Effect.Effect<Info>
|
||||
readonly getModel: (providerID: ProviderID, modelID: ModelID) => Effect.Effect<Model, ModelNotFoundError>
|
||||
readonly list: () => Effect.Effect<Record<ProviderV2.ID, Info>>
|
||||
readonly getProvider: (providerID: ProviderV2.ID) => Effect.Effect<Info>
|
||||
readonly getModel: (providerID: ProviderV2.ID, modelID: ProviderV2.ModelID) => Effect.Effect<Model, ModelNotFoundError>
|
||||
readonly getLanguage: (model: Model) => Effect.Effect<LanguageModelV3, ModelNotFoundError>
|
||||
readonly closest: (
|
||||
providerID: ProviderID,
|
||||
providerID: ProviderV2.ID,
|
||||
query: string[],
|
||||
) => Effect.Effect<{ providerID: ProviderID; modelID: string } | undefined>
|
||||
readonly getSmallModel: (providerID: ProviderID) => Effect.Effect<Model | undefined>
|
||||
readonly defaultModel: () => Effect.Effect<{ providerID: ProviderID; modelID: ModelID }, DefaultModelError>
|
||||
) => Effect.Effect<{ providerID: ProviderV2.ID; modelID: string } | undefined>
|
||||
readonly getSmallModel: (providerID: ProviderV2.ID) => Effect.Effect<Model | undefined>
|
||||
readonly defaultModel: () => Effect.Effect<{ providerID: ProviderV2.ID; modelID: ProviderV2.ModelID }, DefaultModelError>
|
||||
}
|
||||
|
||||
interface State {
|
||||
models: Map<string, LanguageModelV3>
|
||||
providers: Record<ProviderID, Info>
|
||||
catalog: Record<ProviderID, Info>
|
||||
providers: Record<ProviderV2.ID, Info>
|
||||
catalog: Record<ProviderV2.ID, Info>
|
||||
sdk: Map<string, BundledSDK>
|
||||
modelLoaders: Record<string, CustomModelLoader>
|
||||
varsLoaders: Record<string, CustomVarsLoader>
|
||||
@@ -1082,8 +1082,8 @@ function cost(c: ModelsDev.Model["cost"]): Model["cost"] {
|
||||
|
||||
function fromModelsDevModel(provider: ModelsDev.Provider, model: ModelsDev.Model): Model {
|
||||
const base: Model = {
|
||||
id: ModelID.make(model.id),
|
||||
providerID: ProviderID.make(provider.id),
|
||||
id: ProviderV2.ModelID.make(model.id),
|
||||
providerID: ProviderV2.ID.make(provider.id),
|
||||
name: model.name,
|
||||
family: model.family,
|
||||
api: {
|
||||
@@ -1140,7 +1140,7 @@ export function fromModelsDevProvider(provider: ModelsDev.Provider): Info {
|
||||
const base = fromModelsDevModel(provider, model)
|
||||
models[id] = {
|
||||
...base,
|
||||
id: ModelID.make(id),
|
||||
id: ProviderV2.ModelID.make(id),
|
||||
name: `${model.name} ${mode[0].toUpperCase()}${mode.slice(1)}`,
|
||||
cost: opts.cost ? mergeDeep(base.cost, cost(opts.cost)) : base.cost,
|
||||
options: opts.provider?.body
|
||||
@@ -1156,7 +1156,7 @@ export function fromModelsDevProvider(provider: ModelsDev.Provider): Info {
|
||||
}
|
||||
}
|
||||
return {
|
||||
id: ProviderID.make(provider.id),
|
||||
id: ProviderV2.ID.make(provider.id),
|
||||
source: "custom",
|
||||
name: provider.name,
|
||||
env: [...(provider.env ?? [])],
|
||||
@@ -1175,7 +1175,7 @@ function suggestionModelIDs(provider: Info | undefined, enableExperimentalModels
|
||||
})
|
||||
}
|
||||
|
||||
function modelSuggestions(provider: Info | undefined, modelID: ModelID, enableExperimentalModels: boolean) {
|
||||
function modelSuggestions(provider: Info | undefined, modelID: ProviderV2.ModelID, enableExperimentalModels: boolean) {
|
||||
const available = suggestionModelIDs(provider, enableExperimentalModels)
|
||||
const fuzzy = fuzzysort.go(modelID, available, { limit: 3, threshold: -10000 }).map((m) => m.target)
|
||||
if (fuzzy.length) return fuzzy
|
||||
@@ -1217,7 +1217,7 @@ export const layer = Layer.effect(
|
||||
const catalog = mapValues(modelsDev, fromModelsDevProvider)
|
||||
const database = mapValues(catalog, toPublicInfo)
|
||||
|
||||
const providers: Record<ProviderID, Info> = {} as Record<ProviderID, Info>
|
||||
const providers: Record<ProviderV2.ID, Info> = {} as Record<ProviderV2.ID, Info>
|
||||
const languages = new Map<string, LanguageModelV3>()
|
||||
const modelLoaders: {
|
||||
[providerID: string]: CustomModelLoader
|
||||
@@ -1238,7 +1238,7 @@ export const layer = Layer.effect(
|
||||
|
||||
log.info("init")
|
||||
|
||||
function mergeProvider(providerID: ProviderID, provider: Partial<Info>) {
|
||||
function mergeProvider(providerID: ProviderV2.ID, provider: Partial<Info>) {
|
||||
const existing = providers[providerID]
|
||||
if (existing) {
|
||||
// @ts-expect-error
|
||||
@@ -1259,7 +1259,7 @@ export const layer = Layer.effect(
|
||||
const disabled = new Set(cfg.disabled_providers ?? [])
|
||||
const enabled = cfg.enabled_providers ? new Set(cfg.enabled_providers) : null
|
||||
|
||||
function isProviderAllowed(providerID: ProviderID): boolean {
|
||||
function isProviderAllowed(providerID: ProviderV2.ID): boolean {
|
||||
if (enabled && !enabled.has(providerID)) return false
|
||||
if (disabled.has(providerID)) return false
|
||||
return true
|
||||
@@ -1270,7 +1270,7 @@ export const layer = Layer.effect(
|
||||
const models = p?.models
|
||||
if (!p || !models) continue
|
||||
|
||||
const providerID = ProviderID.make(p.id)
|
||||
const providerID = ProviderV2.ID.make(p.id)
|
||||
if (disabled.has(providerID)) continue
|
||||
|
||||
const provider = database[providerID]
|
||||
@@ -1284,7 +1284,7 @@ export const layer = Layer.effect(
|
||||
id,
|
||||
{
|
||||
...model,
|
||||
id: ModelID.make(id),
|
||||
id: ProviderV2.ModelID.make(id),
|
||||
providerID,
|
||||
},
|
||||
]),
|
||||
@@ -1296,7 +1296,7 @@ export const layer = Layer.effect(
|
||||
for (const [providerID, provider] of configProviders) {
|
||||
const existing = database[providerID]
|
||||
const parsed: Info = {
|
||||
id: ProviderID.make(providerID),
|
||||
id: ProviderV2.ID.make(providerID),
|
||||
name: provider.name ?? existing?.name ?? providerID,
|
||||
env: provider.env ?? existing?.env ?? [],
|
||||
options: mergeDeep(existing?.options ?? {}, provider.options ?? {}),
|
||||
@@ -1319,7 +1319,7 @@ export const layer = Layer.effect(
|
||||
return existingModel?.name ?? modelID
|
||||
})
|
||||
const parsedModel: Model = {
|
||||
id: ModelID.make(modelID),
|
||||
id: ProviderV2.ModelID.make(modelID),
|
||||
api: {
|
||||
id: apiID,
|
||||
npm: apiNpm,
|
||||
@@ -1327,7 +1327,7 @@ export const layer = Layer.effect(
|
||||
},
|
||||
status: model.status ?? existingModel?.status ?? "active",
|
||||
name,
|
||||
providerID: ProviderID.make(providerID),
|
||||
providerID: ProviderV2.ID.make(providerID),
|
||||
capabilities: {
|
||||
temperature: model.temperature ?? existingModel?.capabilities.temperature ?? false,
|
||||
reasoning: model.reasoning ?? existingModel?.capabilities.reasoning ?? false,
|
||||
@@ -1389,7 +1389,7 @@ export const layer = Layer.effect(
|
||||
// load env
|
||||
const envs = yield* env.all()
|
||||
for (const [id, provider] of Object.entries(database)) {
|
||||
const providerID = ProviderID.make(id)
|
||||
const providerID = ProviderV2.ID.make(id)
|
||||
if (disabled.has(providerID)) continue
|
||||
const apiKey = provider.env.map((item) => envs[item]).find(Boolean)
|
||||
if (!apiKey) continue
|
||||
@@ -1402,7 +1402,7 @@ export const layer = Layer.effect(
|
||||
// load apikeys
|
||||
const auths = yield* auth.all().pipe(Effect.orDie)
|
||||
for (const [id, provider] of Object.entries(auths)) {
|
||||
const providerID = ProviderID.make(id)
|
||||
const providerID = ProviderV2.ID.make(id)
|
||||
if (disabled.has(providerID)) continue
|
||||
if (provider.type === "api") {
|
||||
mergeProvider(providerID, {
|
||||
@@ -1415,7 +1415,7 @@ export const layer = Layer.effect(
|
||||
// plugin auth loader - database now has entries for config providers
|
||||
for (const plugin of plugins) {
|
||||
if (!plugin.auth) continue
|
||||
const providerID = ProviderID.make(plugin.auth.provider)
|
||||
const providerID = ProviderV2.ID.make(plugin.auth.provider)
|
||||
if (disabled.has(providerID)) continue
|
||||
|
||||
const stored = yield* auth.get(providerID).pipe(Effect.orDie)
|
||||
@@ -1434,7 +1434,7 @@ export const layer = Layer.effect(
|
||||
}
|
||||
|
||||
for (const [id, fn] of Object.entries(custom(dep))) {
|
||||
const providerID = ProviderID.make(id)
|
||||
const providerID = ProviderV2.ID.make(id)
|
||||
if (disabled.has(providerID)) continue
|
||||
const data = database[providerID]
|
||||
if (!data) {
|
||||
@@ -1454,7 +1454,7 @@ export const layer = Layer.effect(
|
||||
|
||||
// load config - re-apply with updated data
|
||||
for (const [id, provider] of configProviders) {
|
||||
const providerID = ProviderID.make(id)
|
||||
const providerID = ProviderV2.ID.make(id)
|
||||
const partial: Partial<Info> = { source: "config" }
|
||||
if (provider.env) partial.env = provider.env
|
||||
if (provider.name) partial.name = provider.name
|
||||
@@ -1462,7 +1462,7 @@ export const layer = Layer.effect(
|
||||
mergeProvider(providerID, partial)
|
||||
}
|
||||
|
||||
const gitlab = ProviderID.make("gitlab")
|
||||
const gitlab = ProviderV2.ID.make("gitlab")
|
||||
if (discoveryLoaders[gitlab] && providers[gitlab] && isProviderAllowed(gitlab)) {
|
||||
yield* Effect.promise(async () => {
|
||||
try {
|
||||
@@ -1479,7 +1479,7 @@ export const layer = Layer.effect(
|
||||
}
|
||||
|
||||
for (const [id, provider] of Object.entries(providers)) {
|
||||
const providerID = ProviderID.make(id)
|
||||
const providerID = ProviderV2.ID.make(id)
|
||||
if (!isProviderAllowed(providerID)) {
|
||||
delete providers[providerID]
|
||||
continue
|
||||
@@ -1493,10 +1493,10 @@ export const layer = Layer.effect(
|
||||
// These chat aliases are invalid for the special handling in the
|
||||
// built-in providers below, but custom providers may support them.
|
||||
(modelID === "gpt-5-chat-latest" &&
|
||||
(providerID === ProviderID.openai ||
|
||||
providerID === ProviderID.githubCopilot ||
|
||||
providerID === ProviderID.openrouter)) ||
|
||||
(providerID === ProviderID.openrouter && modelID === "openai/gpt-5-chat")
|
||||
(providerID === ProviderV2.ID.openai ||
|
||||
providerID === ProviderV2.ID.githubCopilot ||
|
||||
providerID === ProviderV2.ID.openrouter)) ||
|
||||
(providerID === ProviderV2.ID.openrouter && modelID === "openai/gpt-5-chat")
|
||||
)
|
||||
delete provider.models[modelID]
|
||||
if (model.status === "alpha" && !runtimeFlags.enableExperimentalModels) delete provider.models[modelID]
|
||||
@@ -1702,11 +1702,11 @@ export const layer = Layer.effect(
|
||||
}
|
||||
}
|
||||
|
||||
const getProvider = Effect.fn("Provider.getProvider")((providerID: ProviderID) =>
|
||||
const getProvider = Effect.fn("Provider.getProvider")((providerID: ProviderV2.ID) =>
|
||||
InstanceState.use(state, (s) => s.providers[providerID]),
|
||||
)
|
||||
|
||||
const getModel = Effect.fn("Provider.getModel")(function* (providerID: ProviderID, modelID: ModelID) {
|
||||
const getModel = Effect.fn("Provider.getModel")(function* (providerID: ProviderV2.ID, modelID: ProviderV2.ModelID) {
|
||||
const s = yield* InstanceState.get(state)
|
||||
const provider = s.providers[providerID]
|
||||
if (!provider) {
|
||||
@@ -1756,7 +1756,7 @@ export const layer = Layer.effect(
|
||||
)
|
||||
})
|
||||
|
||||
const closest = Effect.fn("Provider.closest")(function* (providerID: ProviderID, query: string[]) {
|
||||
const closest = Effect.fn("Provider.closest")(function* (providerID: ProviderV2.ID, query: string[]) {
|
||||
const s = yield* InstanceState.get(state)
|
||||
const provider = s.providers[providerID]
|
||||
if (!provider) return undefined
|
||||
@@ -1768,7 +1768,7 @@ export const layer = Layer.effect(
|
||||
return undefined
|
||||
})
|
||||
|
||||
const getSmallModel = Effect.fn("Provider.getSmallModel")(function* (providerID: ProviderID) {
|
||||
const getSmallModel = Effect.fn("Provider.getSmallModel")(function* (providerID: ProviderV2.ID) {
|
||||
const cfg = yield* config.get()
|
||||
|
||||
if (cfg.small_model) {
|
||||
@@ -1798,7 +1798,7 @@ export const layer = Layer.effect(
|
||||
priority = ["gpt-5-mini", "claude-haiku-4.5", ...priority]
|
||||
}
|
||||
for (const item of priority) {
|
||||
if (providerID === ProviderID.amazonBedrock) {
|
||||
if (providerID === ProviderV2.ID.amazonBedrock) {
|
||||
const crossRegionPrefixes = ["global.", "us.", "eu."]
|
||||
const candidates = Object.keys(provider.models).filter((m) => m.includes(item))
|
||||
|
||||
@@ -1832,16 +1832,16 @@ export const layer = Layer.effect(
|
||||
|
||||
const s = yield* InstanceState.get(state)
|
||||
const recent = yield* fs.readJson(path.join(Global.Path.state, "model.json")).pipe(
|
||||
Effect.map((x): { providerID: ProviderID; modelID: ModelID }[] => {
|
||||
Effect.map((x): { providerID: ProviderV2.ID; modelID: ProviderV2.ModelID }[] => {
|
||||
if (!isRecord(x) || !Array.isArray(x.recent)) return []
|
||||
return x.recent.flatMap((item) => {
|
||||
if (!isRecord(item)) return []
|
||||
if (typeof item.providerID !== "string") return []
|
||||
if (typeof item.modelID !== "string") return []
|
||||
return [{ providerID: ProviderID.make(item.providerID), modelID: ModelID.make(item.modelID) }]
|
||||
return [{ providerID: ProviderV2.ID.make(item.providerID), modelID: ProviderV2.ModelID.make(item.modelID) }]
|
||||
})
|
||||
}),
|
||||
Effect.catch(() => Effect.succeed([] as { providerID: ProviderID; modelID: ModelID }[])),
|
||||
Effect.catch(() => Effect.succeed([] as { providerID: ProviderV2.ID; modelID: ProviderV2.ModelID }[])),
|
||||
)
|
||||
for (const entry of recent) {
|
||||
const provider = s.providers[entry.providerID]
|
||||
@@ -1889,8 +1889,8 @@ export function sort<T extends { id: string }>(models: T[]) {
|
||||
export function parseModel(model: string) {
|
||||
const [providerID, ...rest] = model.split("/")
|
||||
return {
|
||||
providerID: ProviderID.make(providerID),
|
||||
modelID: ModelID.make(rest.join("/")),
|
||||
providerID: ProviderV2.ID.make(providerID),
|
||||
modelID: ProviderV2.ModelID.make(rest.join("/")),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
import { Schema } from "effect"
|
||||
|
||||
import { withStatics } from "@opencode-ai/core/schema"
|
||||
|
||||
const providerIdSchema = Schema.String.pipe(Schema.brand("ProviderID"))
|
||||
|
||||
export type ProviderID = typeof providerIdSchema.Type
|
||||
|
||||
export const ProviderID = providerIdSchema.pipe(
|
||||
withStatics((schema: typeof providerIdSchema) => ({
|
||||
// Well-known providers
|
||||
opencode: schema.make("opencode"),
|
||||
anthropic: schema.make("anthropic"),
|
||||
openai: schema.make("openai"),
|
||||
google: schema.make("google"),
|
||||
googleVertex: schema.make("google-vertex"),
|
||||
githubCopilot: schema.make("github-copilot"),
|
||||
amazonBedrock: schema.make("amazon-bedrock"),
|
||||
azure: schema.make("azure"),
|
||||
openrouter: schema.make("openrouter"),
|
||||
mistral: schema.make("mistral"),
|
||||
gitlab: schema.make("gitlab"),
|
||||
})),
|
||||
)
|
||||
|
||||
const modelIdSchema = Schema.String.pipe(Schema.brand("ModelID"))
|
||||
|
||||
export type ModelID = typeof modelIdSchema.Type
|
||||
|
||||
export const ModelID = modelIdSchema
|
||||
Reference in New Issue
Block a user