refactor(core): inject models options

This commit is contained in:
Dax Raad 2026-07-20 15:18:03 -04:00
commit 0aa4031dd0
8 changed files with 370 additions and 417 deletions

View file

@ -58,6 +58,6 @@ export function layer(options?: Options) {
export const node = makeGlobalNode({
service: Service,
layer: layer(),
layer: layer({ path: ":memory:" }),
deps: [],
})

View file

@ -530,9 +530,15 @@ export interface Interface {
readonly refresh: (force?: boolean) => Effect.Effect<void>
}
export interface Options {
readonly url?: string
readonly file?: string
readonly fetch?: boolean
}
export class Service extends Context.Service<Service, Interface>()("@opencode/ModelsDev") {}
const layer = Layer.effect(
export const layer = (options?: Options) => Layer.effect(
Service,
Effect.gen(function* () {
const fs = yield* FSUtil.Service
@ -547,7 +553,8 @@ const layer = Layer.effect(
),
)
const source = Flag.OPENCODE_MODELS_URL || "https://models.dev"
const source = options?.url ?? "https://models.dev"
const fetch = options?.fetch ?? true
const filepath = path.join(
Global.Path.cache,
source === "https://models.dev" ? "models.json" : `models-${Hash.fast(source)}.json`,
@ -571,11 +578,11 @@ const layer = Layer.effect(
)
})
const loadFromDisk = fs.readJson(Flag.OPENCODE_MODELS_PATH ?? filepath).pipe(
const loadFromDisk = fs.readJson(options?.file ?? filepath).pipe(
Effect.map((input) => input as Record<string, SourceProvider>),
Effect.catch((error) => {
if (
Flag.OPENCODE_MODELS_PATH === undefined &&
options?.file === undefined &&
error._tag === "FileSystemError" &&
error.method === "readJson"
) {
@ -609,7 +616,7 @@ const layer = Layer.effect(
if (fromDisk) return normalize(fromDisk)
const bundled = yield* loadSnapshot
if (bundled) return normalize(bundled)
if (Flag.OPENCODE_DISABLE_MODELS_FETCH) return []
if (!fetch) return []
// Flock is cross-process: concurrent opencode CLIs can race on this cache file.
const text = yield* Effect.scoped(
Effect.gen(function* () {
@ -642,7 +649,7 @@ const layer = Layer.effect(
)
})
if (!Flag.OPENCODE_DISABLE_MODELS_FETCH && !process.argv.includes("--get-yargs-completions")) {
if (fetch && !process.argv.includes("--get-yargs-completions")) {
// Schedule.spaced runs the effect once, then waits between completions.
yield* Effect.forkScoped(refresh().pipe(Effect.repeat(Schedule.spaced("60 minutes")), Effect.ignore))
}
@ -651,6 +658,10 @@ const layer = Layer.effect(
}),
)
export const node = makeGlobalNode({ service: Service, layer: layer, deps: [FSUtil.node, EventV2.node, httpClient] })
export function nodeWith(options?: Options) {
return makeGlobalNode({ service: Service, layer: layer(options), deps: [FSUtil.node, EventV2.node, httpClient] })
}
export const node = nodeWith()
export * as ModelsDev from "./models-dev"