mirror of
https://github.com/anomalyco/opencode.git
synced 2026-07-25 04:35:37 -04:00
refactor(core): simplify provider helpers
This commit is contained in:
@@ -15,11 +15,12 @@ export const Plugin = define({
|
||||
const generated = generate(draft, record.provider)
|
||||
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))
|
||||
draft.variants = [
|
||||
...generated.map((variant) => explicit.get(variant.id) ?? variant),
|
||||
...(draft.variants ?? []).filter((variant) => !generatedIDs.has(variant.id)),
|
||||
...variants.filter((variant) => !generatedIDs.has(variant.id)),
|
||||
]
|
||||
})
|
||||
}
|
||||
|
||||
@@ -11,10 +11,12 @@ export const ID = Provider.ID
|
||||
export type ID = typeof ID.Type
|
||||
|
||||
export const AISDK_PREFIX = "aisdk:"
|
||||
export const isAISDK = (packageName: string | undefined) => packageName?.startsWith(AISDK_PREFIX) ?? false
|
||||
export const aisdk = (packageName: string) => (isAISDK(packageName) ? packageName : `${AISDK_PREFIX}${packageName}`)
|
||||
export const packageName = (packageName: string | undefined) =>
|
||||
isAISDK(packageName) ? packageName!.slice(AISDK_PREFIX.length) : packageName
|
||||
export const isAISDK = (value: string | undefined) => value?.startsWith(AISDK_PREFIX) ?? false
|
||||
export const aisdk = (value: string) => (isAISDK(value) ? value : `${AISDK_PREFIX}${value}`)
|
||||
export const packageName = (value: string | undefined) => {
|
||||
if (value === undefined || !isAISDK(value)) return value
|
||||
return value.slice(AISDK_PREFIX.length)
|
||||
}
|
||||
|
||||
export class LoadError extends Schema.TaggedErrorClass<LoadError>()("ProviderV2.LoadError", {
|
||||
package: Schema.String,
|
||||
@@ -25,7 +27,14 @@ export type ProviderPackage = ProviderPackageDefinition
|
||||
const packages = new Map<string, Promise<unknown>>()
|
||||
|
||||
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 (!npm) {
|
||||
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`),
|
||||
})
|
||||
}
|
||||
const parts = specifier.split("/")
|
||||
const root = specifier.startsWith("@") ? parts.slice(0, 2).join("/") : (parts[0] ?? specifier)
|
||||
const installed = yield* npm
|
||||
.add(rootPackage(specifier))
|
||||
.add(root)
|
||||
.pipe(Effect.mapError((cause) => new LoadError({ package: specifier, cause })))
|
||||
const entrypoint = yield* Effect.try({
|
||||
try: () => import.meta.resolve(specifier, pathToFileURL(`${installed.directory}/`).href),
|
||||
@@ -95,16 +106,6 @@ export type Info = Provider.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 module = yield* Effect.tryPromise({
|
||||
try: () => {
|
||||
@@ -116,21 +117,11 @@ const importPackage = Effect.fn("ProviderV2.importPackage")(function* (specifier
|
||||
},
|
||||
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({
|
||||
package: specifier,
|
||||
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]
|
||||
}
|
||||
|
||||
@@ -108,19 +108,6 @@ export interface Dependencies {
|
||||
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 = (
|
||||
model: ModelV2.Info,
|
||||
credential?: Credential.Value,
|
||||
@@ -134,35 +121,72 @@ export const fromCatalogModel = (
|
||||
})
|
||||
if (ProviderV2.isAISDK(resolved.package)) {
|
||||
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) => {
|
||||
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(
|
||||
Effect.mapError(() => unsupported(resolved)),
|
||||
Effect.mapError(
|
||||
() =>
|
||||
new UnsupportedPackageError({
|
||||
providerID: resolved.providerID,
|
||||
modelID: resolved.id,
|
||||
package: resolved.package ?? "unknown",
|
||||
}),
|
||||
),
|
||||
)
|
||||
}
|
||||
if (resolved.package) {
|
||||
const specifier = resolved.package
|
||||
return Effect.gen(function* () {
|
||||
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 = {
|
||||
...resolved.settings,
|
||||
...credentialSettings(credential),
|
||||
...(credential?.type === "key" ? { apiKey: credential.key } : {}),
|
||||
...(credential?.type === "oauth" ? { apiKey: credential.access } : {}),
|
||||
...credential?.metadata,
|
||||
headers: resolved.headers,
|
||||
body: resolved.body,
|
||||
limits: { context: resolved.limit.context, output: resolved.limit.output },
|
||||
}
|
||||
return yield* Effect.try({
|
||||
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 = (
|
||||
|
||||
Reference in New Issue
Block a user