Skip to content

Commit ce69bd9

Browse files
authored
refactor(config): migrate model-id and command to Effect Schema (#23175)
1 parent 999d865 commit ce69bd9

4 files changed

Lines changed: 30 additions & 15 deletions

File tree

packages/opencode/src/config/agent.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ const log = Log.create({ service: "config" })
1515

1616
export const Info = z
1717
.object({
18-
model: ConfigModelID.optional(),
18+
model: ConfigModelID.zod.optional(),
1919
variant: z
2020
.string()
2121
.optional()

packages/opencode/src/config/command.ts

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,28 @@
11
export * as ConfigCommand from "./command"
22

33
import { Log } from "../util"
4-
import z from "zod"
4+
import { Schema } from "effect"
55
import { NamedError } from "@opencode-ai/shared/util/error"
66
import { Glob } from "@opencode-ai/shared/util/glob"
77
import { Bus } from "@/bus"
8+
import { zod } from "@/util/effect-zod"
9+
import { withStatics } from "@/util/schema"
810
import { configEntryNameFromPath } from "./entry-name"
911
import { InvalidError } from "./error"
1012
import * as ConfigMarkdown from "./markdown"
1113
import { ConfigModelID } from "./model-id"
1214

1315
const log = Log.create({ service: "config" })
1416

15-
export const Info = z.object({
16-
template: z.string(),
17-
description: z.string().optional(),
18-
agent: z.string().optional(),
19-
model: ConfigModelID.optional(),
20-
subtask: z.boolean().optional(),
21-
})
17+
export const Info = Schema.Struct({
18+
template: Schema.String,
19+
description: Schema.optional(Schema.String),
20+
agent: Schema.optional(Schema.String),
21+
model: Schema.optional(ConfigModelID),
22+
subtask: Schema.optional(Schema.Boolean),
23+
}).pipe(withStatics((s) => ({ zod: zod(s) })))
2224

23-
export type Info = z.infer<typeof Info>
25+
export type Info = Schema.Schema.Type<typeof Info>
2426

2527
export async function load(dir: string) {
2628
const result: Record<string, Info> = {}
@@ -49,7 +51,7 @@ export async function load(dir: string) {
4951
...md.data,
5052
template: md.content.trim(),
5153
}
52-
const parsed = Info.safeParse(config)
54+
const parsed = Info.zod.safeParse(config)
5355
if (parsed.success) {
5456
result[config.name] = parsed.data
5557
continue

packages/opencode/src/config/config.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ export const Info = z
9797
logLevel: Log.Level.optional().describe("Log level"),
9898
server: Server.optional().describe("Server configuration for opencode serve and web commands"),
9999
command: z
100-
.record(z.string(), ConfigCommand.Info)
100+
.record(z.string(), ConfigCommand.Info.zod)
101101
.optional()
102102
.describe("Command configuration, see https://opencode.ai/docs/commands"),
103103
skills: ConfigSkills.Info.zod.optional().describe("Additional skill folder paths"),
@@ -135,8 +135,10 @@ export const Info = z
135135
.array(z.string())
136136
.optional()
137137
.describe("When set, ONLY these providers will be enabled. All other providers will be ignored"),
138-
model: ConfigModelID.describe("Model to use in the format of provider/model, eg anthropic/claude-2").optional(),
139-
small_model: ConfigModelID.describe(
138+
model: ConfigModelID.zod
139+
.describe("Model to use in the format of provider/model, eg anthropic/claude-2")
140+
.optional(),
141+
small_model: ConfigModelID.zod.describe(
140142
"Small model to use for tasks like title generation in the format of provider/model",
141143
).optional(),
142144
default_agent: z
Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,14 @@
1+
import { Schema } from "effect"
12
import z from "zod"
3+
import { zod, ZodOverride } from "@/util/effect-zod"
4+
import { withStatics } from "@/util/schema"
25

3-
export const ConfigModelID = z.string().meta({ $ref: "https://models.dev/model-schema.json#/$defs/Model" })
6+
// The original Zod schema carried an external $ref pointing at the models.dev
7+
// JSON schema. That external reference is not a named SDK component — it is a
8+
// literal pointer to an outside schema — so the walker cannot re-derive it
9+
// from AST metadata. Preserve the exact original Zod via ZodOverride.
10+
export const ConfigModelID = Schema.String.annotate({
11+
[ZodOverride]: z.string().meta({ $ref: "https://models.dev/model-schema.json#/$defs/Model" }),
12+
}).pipe(withStatics((s) => ({ zod: zod(s) })))
13+
14+
export type ConfigModelID = Schema.Schema.Type<typeof ConfigModelID>

0 commit comments

Comments
 (0)