refactor(core): simplify provider helpers

This commit is contained in:
Shoubhit Dash 2026-06-29 22:47:08 +05:30
commit 9ad7612ff4
3 changed files with 66 additions and 50 deletions

View file

@ -15,11 +15,12 @@ export const Plugin = define({
const generated = generate(draft, record.provider) const generated = generate(draft, record.provider)
if (generated.length === 0) return if (generated.length === 0) return
const explicit = new Map((draft.variants ?? []).map((variant) => [variant.id, variant])) const variants = draft.variants ?? []
const explicit = new Map(variants.map((variant) => [variant.id, variant]))
const generatedIDs = new Set<string>(generated.map((variant) => variant.id)) const generatedIDs = new Set<string>(generated.map((variant) => variant.id))
draft.variants = [ draft.variants = [
...generated.map((variant) => explicit.get(variant.id) ?? variant), ...generated.map((variant) => explicit.get(variant.id) ?? variant),
...(draft.variants ?? []).filter((variant) => !generatedIDs.has(variant.id)), ...variants.filter((variant) => !generatedIDs.has(variant.id)),
] ]
}) })
} }

View file

@ -11,10 +11,12 @@ export const ID = Provider.ID
export type ID = typeof ID.Type export type ID = typeof ID.Type
export const AISDK_PREFIX = "aisdk:" export const AISDK_PREFIX = "aisdk:"
export const isAISDK = (packageName: string | undefined) => packageName?.startsWith(AISDK_PREFIX) ?? false export const isAISDK = (value: string | undefined) => value?.startsWith(AISDK_PREFIX) ?? false
export const aisdk = (packageName: string) => (isAISDK(packageName) ? packageName : `${AISDK_PREFIX}${packageName}`) export const aisdk = (value: string) => (isAISDK(value) ? value : `${AISDK_PREFIX}${value}`)
export const packageName = (packageName: string | undefined) => export const packageName = (value: string | undefined) => {
isAISDK(packageName) ? packageName!.slice(AISDK_PREFIX.length) : packageName if (value === undefined || !isAISDK(value)) return value
return value.slice(AISDK_PREFIX.length)
}
export class LoadError extends Schema.TaggedErrorClass<LoadError>()("ProviderV2.LoadError", { export class LoadError extends Schema.TaggedErrorClass<LoadError>()("ProviderV2.LoadError", {
package: Schema.String, package: Schema.String,
@ -25,7 +27,14 @@ export type ProviderPackage = ProviderPackageDefinition
const packages = new Map<string, Promise<unknown>>() const packages = new Map<string, Promise<unknown>>()
export const loadPackage = Effect.fn("ProviderV2.loadPackage")(function* (specifier: string, npm?: Npm.Interface) { export const loadPackage = Effect.fn("ProviderV2.loadPackage")(function* (specifier: string, npm?: Npm.Interface) {
const resolved = yield* resolvePackage(specifier) const resolved = yield* Effect.sync(() => {
if (specifier.startsWith("file://") || specifier.startsWith("@opencode-ai/llm/")) return specifier
try {
return import.meta.resolve(specifier)
} catch {
return undefined
}
})
if (resolved) return yield* importPackage(specifier, resolved) if (resolved) return yield* importPackage(specifier, resolved)
if (!npm) { if (!npm) {
return yield* new LoadError({ return yield* new LoadError({
@ -33,8 +42,10 @@ export const loadPackage = Effect.fn("ProviderV2.loadPackage")(function* (specif
cause: new Error(`Provider package ${specifier} is not installed`), cause: new Error(`Provider package ${specifier} is not installed`),
}) })
} }
const parts = specifier.split("/")
const root = specifier.startsWith("@") ? parts.slice(0, 2).join("/") : (parts[0] ?? specifier)
const installed = yield* npm const installed = yield* npm
.add(rootPackage(specifier)) .add(root)
.pipe(Effect.mapError((cause) => new LoadError({ package: specifier, cause }))) .pipe(Effect.mapError((cause) => new LoadError({ package: specifier, cause })))
const entrypoint = yield* Effect.try({ const entrypoint = yield* Effect.try({
try: () => import.meta.resolve(specifier, pathToFileURL(`${installed.directory}/`).href), try: () => import.meta.resolve(specifier, pathToFileURL(`${installed.directory}/`).href),
@ -95,16 +106,6 @@ export type Info = Provider.Info
export type MutableInfo = DeepMutable<Info> export type MutableInfo = DeepMutable<Info>
const resolvePackage = (specifier: string) =>
Effect.sync(() => {
if (specifier.startsWith("file://") || specifier.startsWith("@opencode-ai/llm/")) return specifier
try {
return import.meta.resolve(specifier)
} catch {
return undefined
}
})
const importPackage = Effect.fn("ProviderV2.importPackage")(function* (specifier: string, entrypoint: string) { const importPackage = Effect.fn("ProviderV2.importPackage")(function* (specifier: string, entrypoint: string) {
const module = yield* Effect.tryPromise({ const module = yield* Effect.tryPromise({
try: () => { try: () => {
@ -116,21 +117,11 @@ const importPackage = Effect.fn("ProviderV2.importPackage")(function* (specifier
}, },
catch: (cause) => new LoadError({ package: specifier, cause }), catch: (cause) => new LoadError({ package: specifier, cause }),
}) })
if (!isProviderPackage(module)) { if (typeof module !== "object" || module === null || typeof (module as { model?: unknown }).model !== "function") {
return yield* new LoadError({ return yield* new LoadError({
package: specifier, package: specifier,
cause: new Error(`Provider package ${specifier} does not export model(modelID, settings)`), cause: new Error(`Provider package ${specifier} does not export model(modelID, settings)`),
}) })
} }
return module return module as ProviderPackageDefinition
}) })
function isProviderPackage(input: unknown): input is ProviderPackageDefinition {
return typeof input === "object" && input !== null && "model" in input && typeof input.model === "function"
}
function rootPackage(specifier: string) {
const parts = specifier.split("/")
if (specifier.startsWith("@")) return parts.slice(0, 2).join("/")
return parts[0]
}

View file

@ -108,19 +108,6 @@ export interface Dependencies {
readonly loadAISDK?: (model: ModelV2.Info) => Effect.Effect<Model, AISDK.InitError> readonly loadAISDK?: (model: ModelV2.Info) => Effect.Effect<Model, AISDK.InitError>
} }
const unsupported = (model: ModelV2.Info, packageName = model.package ?? "unknown") =>
new UnsupportedPackageError({
providerID: model.providerID,
modelID: model.id,
package: packageName,
})
const credentialSettings = (credential: Credential.Value | undefined) => ({
...(credential?.type === "key" ? { apiKey: credential.key } : {}),
...(credential?.type === "oauth" ? { apiKey: credential.access } : {}),
...credential?.metadata,
})
export const fromCatalogModel = ( export const fromCatalogModel = (
model: ModelV2.Info, model: ModelV2.Info,
credential?: Credential.Value, credential?: Credential.Value,
@ -134,35 +121,72 @@ export const fromCatalogModel = (
}) })
if (ProviderV2.isAISDK(resolved.package)) { if (ProviderV2.isAISDK(resolved.package)) {
if (!dependencies.loadAISDK) { if (!dependencies.loadAISDK) {
return Effect.fail(unsupported(resolved)) return Effect.fail(
new UnsupportedPackageError({
providerID: resolved.providerID,
modelID: resolved.id,
package: resolved.package ?? "unknown",
}),
)
} }
const runtime = produce(resolved, (draft) => { const runtime = produce(resolved, (draft) => {
draft.settings = ProviderV2.mergeOverlay(draft.settings, credentialSettings(credential)) draft.settings = ProviderV2.mergeOverlay(draft.settings, {
...(credential?.type === "key" ? { apiKey: credential.key } : {}),
...(credential?.type === "oauth" ? { apiKey: credential.access } : {}),
...credential?.metadata,
})
}) })
return dependencies.loadAISDK(runtime).pipe( return dependencies.loadAISDK(runtime).pipe(
Effect.mapError(() => unsupported(resolved)), Effect.mapError(
() =>
new UnsupportedPackageError({
providerID: resolved.providerID,
modelID: resolved.id,
package: resolved.package ?? "unknown",
}),
),
) )
} }
if (resolved.package) { if (resolved.package) {
const specifier = resolved.package const specifier = resolved.package
return Effect.gen(function* () { return Effect.gen(function* () {
const module = yield* (dependencies.loadPackage ?? ProviderV2.loadPackage)(specifier).pipe( const module = yield* (dependencies.loadPackage ?? ProviderV2.loadPackage)(specifier).pipe(
Effect.mapError(() => unsupported(resolved, specifier)), Effect.mapError(
() =>
new UnsupportedPackageError({
providerID: resolved.providerID,
modelID: resolved.id,
package: specifier,
}),
),
) )
const settings = { const settings = {
...resolved.settings, ...resolved.settings,
...credentialSettings(credential), ...(credential?.type === "key" ? { apiKey: credential.key } : {}),
...(credential?.type === "oauth" ? { apiKey: credential.access } : {}),
...credential?.metadata,
headers: resolved.headers, headers: resolved.headers,
body: resolved.body, body: resolved.body,
limits: { context: resolved.limit.context, output: resolved.limit.output }, limits: { context: resolved.limit.context, output: resolved.limit.output },
} }
return yield* Effect.try({ return yield* Effect.try({
try: () => Model.update(module.model(resolved.modelID ?? resolved.id, settings), { provider: resolved.providerID }), try: () => Model.update(module.model(resolved.modelID ?? resolved.id, settings), { provider: resolved.providerID }),
catch: () => unsupported(resolved, specifier), catch: () =>
new UnsupportedPackageError({
providerID: resolved.providerID,
modelID: resolved.id,
package: specifier,
}),
}) })
}) })
} }
return Effect.fail(unsupported(resolved)) return Effect.fail(
new UnsupportedPackageError({
providerID: resolved.providerID,
modelID: resolved.id,
package: resolved.package ?? "unknown",
}),
)
} }
export const resolve = ( export const resolve = (