refactor(config): migrate provider (Model + Info) to Effect Schema (#23197)

This commit is contained in:
Kit Langton
2026-04-18 00:29:26 +00:00
committed by opencode
parent eafbe5c57c
commit 2899984819
2 changed files with 109 additions and 113 deletions
+1 -1
View File
@@ -171,7 +171,7 @@ export const Info = z
.optional() .optional()
.describe("Agent configuration, see https://opencode.ai/docs/agents"), .describe("Agent configuration, see https://opencode.ai/docs/agents"),
provider: z provider: z
.record(z.string(), ConfigProvider.Info) .record(z.string(), ConfigProvider.Info.zod)
.optional() .optional()
.describe("Custom provider configurations and model overrides"), .describe("Custom provider configurations and model overrides"),
mcp: z mcp: z
+108 -112
View File
@@ -1,120 +1,116 @@
import { Schema } from "effect"
import z from "zod" import z from "zod"
import { zod, ZodOverride } from "@/util/effect-zod"
import { withStatics } from "@/util/schema"
export const Model = z // Positive integer preserving exact Zod JSON Schema (type: integer, exclusiveMinimum: 0).
.object({ const PositiveInt = Schema.Number.annotate({
id: z.string(), [ZodOverride]: z.number().int().positive(),
name: z.string(), })
family: z.string().optional(),
release_date: z.string(), export const Model = Schema.Struct({
attachment: z.boolean(), id: Schema.optional(Schema.String),
reasoning: z.boolean(), name: Schema.optional(Schema.String),
temperature: z.boolean(), family: Schema.optional(Schema.String),
tool_call: z.boolean(), release_date: Schema.optional(Schema.String),
interleaved: z attachment: Schema.optional(Schema.Boolean),
.union([ reasoning: Schema.optional(Schema.Boolean),
z.literal(true), temperature: Schema.optional(Schema.Boolean),
z tool_call: Schema.optional(Schema.Boolean),
.object({ interleaved: Schema.optional(
field: z.enum(["reasoning_content", "reasoning_details"]), Schema.Union([
}) Schema.Literal(true),
.strict(), Schema.Struct({
]) field: Schema.Literals(["reasoning_content", "reasoning_details"]),
.optional(), }),
cost: z ]),
.object({ ),
input: z.number(), cost: Schema.optional(
output: z.number(), Schema.Struct({
cache_read: z.number().optional(), input: Schema.Number,
cache_write: z.number().optional(), output: Schema.Number,
context_over_200k: z cache_read: Schema.optional(Schema.Number),
.object({ cache_write: Schema.optional(Schema.Number),
input: z.number(), context_over_200k: Schema.optional(
output: z.number(), Schema.Struct({
cache_read: z.number().optional(), input: Schema.Number,
cache_write: z.number().optional(), output: Schema.Number,
}) cache_read: Schema.optional(Schema.Number),
.optional(), cache_write: Schema.optional(Schema.Number),
}) }),
.optional(), ),
limit: z.object({
context: z.number(),
input: z.number().optional(),
output: z.number(),
}), }),
modalities: z ),
.object({ limit: Schema.optional(
input: z.array(z.enum(["text", "audio", "image", "video", "pdf"])), Schema.Struct({
output: z.array(z.enum(["text", "audio", "image", "video", "pdf"])), context: Schema.Number,
}) input: Schema.optional(Schema.Number),
.optional(), output: Schema.Number,
experimental: z.boolean().optional(), }),
status: z.enum(["alpha", "beta", "deprecated"]).optional(), ),
provider: z.object({ npm: z.string().optional(), api: z.string().optional() }).optional(), modalities: Schema.optional(
options: z.record(z.string(), z.any()), Schema.Struct({
headers: z.record(z.string(), z.string()).optional(), input: Schema.mutable(Schema.Array(Schema.Literals(["text", "audio", "image", "video", "pdf"]))),
variants: z output: Schema.mutable(Schema.Array(Schema.Literals(["text", "audio", "image", "video", "pdf"]))),
.record( }),
z.string(), ),
z experimental: Schema.optional(Schema.Boolean),
.object({ status: Schema.optional(Schema.Literals(["alpha", "beta", "deprecated"])),
disabled: z.boolean().optional().describe("Disable this variant for the model"), provider: Schema.optional(Schema.Struct({ npm: Schema.optional(Schema.String), api: Schema.optional(Schema.String) })),
}) options: Schema.optional(Schema.Record(Schema.String, Schema.Any)),
.catchall(z.any()), headers: Schema.optional(Schema.Record(Schema.String, Schema.String)),
) variants: Schema.optional(
.optional() Schema.Record(
.describe("Variant-specific configuration"), Schema.String,
}) Schema.StructWithRest(
.partial() Schema.Struct({
disabled: Schema.optional(Schema.Boolean).annotate({ description: "Disable this variant for the model" }),
}),
[Schema.Record(Schema.String, Schema.Any)],
),
).annotate({ description: "Variant-specific configuration" }),
),
}).pipe(withStatics((s) => ({ zod: zod(s) })))
export const Info = z export class Info extends Schema.Class<Info>("ProviderConfig")({
.object({ api: Schema.optional(Schema.String),
api: z.string().optional(), name: Schema.optional(Schema.String),
name: z.string(), env: Schema.optional(Schema.mutable(Schema.Array(Schema.String))),
env: z.array(z.string()), id: Schema.optional(Schema.String),
id: z.string(), npm: Schema.optional(Schema.String),
npm: z.string().optional(), whitelist: Schema.optional(Schema.mutable(Schema.Array(Schema.String))),
whitelist: z.array(z.string()).optional(), blacklist: Schema.optional(Schema.mutable(Schema.Array(Schema.String))),
blacklist: z.array(z.string()).optional(), options: Schema.optional(
options: z Schema.StructWithRest(
.object({ Schema.Struct({
apiKey: z.string().optional(), apiKey: Schema.optional(Schema.String),
baseURL: z.string().optional(), baseURL: Schema.optional(Schema.String),
enterpriseUrl: z.string().optional().describe("GitHub Enterprise URL for copilot authentication"), enterpriseUrl: Schema.optional(Schema.String).annotate({
setCacheKey: z.boolean().optional().describe("Enable promptCacheKey for this provider (default false)"), description: "GitHub Enterprise URL for copilot authentication",
timeout: z }),
.union([ setCacheKey: Schema.optional(Schema.Boolean).annotate({
z description: "Enable promptCacheKey for this provider (default false)",
.number() }),
.int() timeout: Schema.optional(
.positive() Schema.Union([PositiveInt, Schema.Literal(false)]).annotate({
.describe( description:
"Timeout in milliseconds for requests to this provider. Default is 300000 (5 minutes). Set to false to disable timeout.", "Timeout in milliseconds for requests to this provider. Default is 300000 (5 minutes). Set to false to disable timeout.",
), }),
z.literal(false).describe("Disable timeout for this provider entirely."), ).annotate({
]) description:
.optional()
.describe(
"Timeout in milliseconds for requests to this provider. Default is 300000 (5 minutes). Set to false to disable timeout.", "Timeout in milliseconds for requests to this provider. Default is 300000 (5 minutes). Set to false to disable timeout.",
), }),
chunkTimeout: z chunkTimeout: Schema.optional(PositiveInt).annotate({
.number() description:
.int()
.positive()
.optional()
.describe(
"Timeout in milliseconds between streamed SSE chunks for this provider. If no chunk arrives within this window, the request is aborted.", "Timeout in milliseconds between streamed SSE chunks for this provider. If no chunk arrives within this window, the request is aborted.",
), }),
}) }),
.catchall(z.any()) [Schema.Record(Schema.String, Schema.Any)],
.optional(), ),
models: z.record(z.string(), Model).optional(), ),
}) models: Schema.optional(Schema.Record(Schema.String, Model)),
.partial() }) {
.strict() static readonly zod = zod(this)
.meta({ }
ref: "ProviderConfig",
})
export type Info = z.infer<typeof Info>
export * as ConfigProvider from "./provider" export * as ConfigProvider from "./provider"