Skip to content

Commit aad7116

Browse files
feat(opencode): auto-discover models from OpenAI-compatible providers (anomalyco#32731)
Merge PR anomalyco#32731 by sethjones into dev branch. Auto-discovers available models from OpenAI-compatible providers that have a baseURL configured. opencode now calls GET /v1/models at startup and populates the model list from the provider API. Features: - discoverModels: false opt-out per-provider - Parses context_length and max_output_tokens from API - Warning logs for discovery failures and config limits exceeding discovered limits
2 parents dfeb1b5 + 450ac37 commit aad7116

8 files changed

Lines changed: 708 additions & 23 deletions

File tree

‎packages/core/src/v1/config/provider.ts‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,5 +117,8 @@ export const Info = Schema.Struct({
117117
),
118118
),
119119
models: Schema.optional(Schema.Record(Schema.String, Model)),
120+
discoverModels: Schema.optional(Schema.Boolean).annotate({
121+
description: "Whether to discover models from the provider's /v1/models endpoint (default true)",
122+
}),
120123
}).annotate({ identifier: "ProviderConfig" })
121124
export type Info = Schema.Schema.Type<typeof Info>

‎packages/opencode/src/project/bootstrap.ts‎

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { LayerNode } from "@opencode-ai/core/effect/layer-node"
22
import { Plugin } from "../plugin"
33
import { Format } from "../format"
44
import { LSP } from "@/lsp/lsp"
5+
import { Provider } from "@/provider/provider"
56
import { Snapshot } from "../snapshot"
67
import * as Project from "./project"
78
import * as Vcs from "./vcs"
@@ -24,6 +25,7 @@ export const layer = Layer.effect(
2425
const format = yield* Format.Service
2526
const lsp = yield* LSP.Service
2627
const plugin = yield* Plugin.Service
28+
const provider = yield* Provider.Service
2729
const project = yield* Project.Service
2830
const shareNext = yield* ShareNext.Service
2931
const snapshot = yield* Snapshot.Service
@@ -39,7 +41,7 @@ export const layer = Layer.effect(
3941
// Each service self-manages its own slow work via Effect.forkScoped against
4042
// its per-instance state scope. We just await materialization here.
4143
yield* Effect.forEach(
42-
[lsp, shareNext, format, vcs, snapshot, project],
44+
[lsp, shareNext, format, vcs, snapshot, project, provider],
4345
(s) => s.init().pipe(Effect.catchCause((cause) => Effect.logWarning("init failed", { cause }))),
4446
{ concurrency: "unbounded", discard: true },
4547
).pipe(Effect.withSpan("InstanceBootstrap.init"))
@@ -55,6 +57,7 @@ export const defaultLayer: Layer.Layer<Service> = layer.pipe(
5557
Format.defaultLayer,
5658
LSP.defaultLayer,
5759
Plugin.defaultLayer,
60+
Provider.defaultLayer,
5861
Project.defaultLayer,
5962
ShareNext.defaultLayer,
6063
Snapshot.defaultLayer,
@@ -65,7 +68,7 @@ export const defaultLayer: Layer.Layer<Service> = layer.pipe(
6568
export const node = LayerNode.make({
6669
service: Service,
6770
layer: layer,
68-
deps: [Config.node, Format.node, LSP.node, Plugin.node, Project.node, ShareNext.node, Snapshot.node, Vcs.node],
71+
deps: [Config.node, Format.node, LSP.node, Plugin.node, Provider.node, Project.node, ShareNext.node, Snapshot.node, Vcs.node],
6972
})
7073

7174
export * as InstanceBootstrap from "./bootstrap"

0 commit comments

Comments
 (0)