Skip to content

Commit cf45a8d

Browse files
authored
refactor(schema): decode effect schemas directly (#24169)
1 parent 435becb commit cf45a8d

4 files changed

Lines changed: 24 additions & 19 deletions

File tree

packages/opencode/src/acp/agent.ts

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -46,14 +46,15 @@ import { MessageV2 } from "@/session/message-v2"
4646
import { Config } from "@/config"
4747
import { ConfigMCP } from "@/config/mcp"
4848
import { Todo } from "@/session/todo"
49-
import { z } from "zod"
49+
import { Result, Schema } from "effect"
5050
import { LoadAPIKeyError } from "ai"
5151
import type { AssistantMessage, Event, OpencodeClient, SessionMessageResponse, ToolPart } from "@opencode-ai/sdk/v2"
5252
import { applyPatch } from "diff"
5353
import { InstallationVersion } from "@/installation/version"
5454

5555
type ModeOption = { id: string; name: string; description?: string }
5656
type ModelOption = { modelId: string; name: string }
57+
const decodeTodos = Schema.decodeUnknownResult(Schema.fromJsonString(Schema.Array(Todo.Info)))
5758

5859
const DEFAULT_VARIANT_VALUE = "default"
5960

@@ -372,14 +373,14 @@ export class Agent implements ACPAgent {
372373
}
373374

374375
if (part.tool === "todowrite") {
375-
const parsedTodos = z.array(Todo.Info.zod).safeParse(JSON.parse(part.state.output))
376-
if (parsedTodos.success) {
376+
const parsedTodos = decodeTodos(part.state.output)
377+
if (Result.isSuccess(parsedTodos)) {
377378
await this.connection
378379
.sessionUpdate({
379380
sessionId,
380381
update: {
381382
sessionUpdate: "plan",
382-
entries: parsedTodos.data.map((todo) => {
383+
entries: parsedTodos.success.map((todo) => {
383384
const status: PlanEntry["status"] =
384385
todo.status === "cancelled" ? "completed" : (todo.status as PlanEntry["status"])
385386
return {
@@ -394,7 +395,7 @@ export class Agent implements ACPAgent {
394395
log.error("failed to send session update for todo", { error })
395396
})
396397
} else {
397-
log.error("failed to parse todo output", { error: parsedTodos.error })
398+
log.error("failed to parse todo output", { error: parsedTodos.failure })
398399
}
399400
}
400401

@@ -901,14 +902,14 @@ export class Agent implements ACPAgent {
901902
}
902903

903904
if (part.tool === "todowrite") {
904-
const parsedTodos = z.array(Todo.Info.zod).safeParse(JSON.parse(part.state.output))
905-
if (parsedTodos.success) {
905+
const parsedTodos = decodeTodos(part.state.output)
906+
if (Result.isSuccess(parsedTodos)) {
906907
await this.connection
907908
.sessionUpdate({
908909
sessionId,
909910
update: {
910911
sessionUpdate: "plan",
911-
entries: parsedTodos.data.map((todo) => {
912+
entries: parsedTodos.success.map((todo) => {
912913
const status: PlanEntry["status"] =
913914
todo.status === "cancelled" ? "completed" : (todo.status as PlanEntry["status"])
914915
return {
@@ -923,7 +924,7 @@ export class Agent implements ACPAgent {
923924
log.error("failed to send session update for todo", { error: err })
924925
})
925926
} else {
926-
log.error("failed to parse todo output", { error: parsedTodos.error })
927+
log.error("failed to parse todo output", { error: parsedTodos.failure })
927928
}
928929
}
929930

packages/opencode/src/cli/cmd/import.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@ import { Filesystem } from "../../util"
1313
import { AppRuntime } from "@/effect/app-runtime"
1414
import { Schema } from "effect"
1515

16+
const decodeMessageInfo = Schema.decodeUnknownSync(MessageV2.Info)
17+
const decodePart = Schema.decodeUnknownSync(MessageV2.Part)
18+
1619
/** Discriminated union returned by the ShareNext API (GET /api/shares/:id/data) */
1720
export type ShareData =
1821
| { type: "session"; data: SDKSession }
@@ -169,7 +172,7 @@ export const ImportCommand = cmd({
169172
)
170173

171174
for (const msg of exportData.messages) {
172-
const msgInfo = MessageV2.Info.zod.parse(msg.info)
175+
const msgInfo = decodeMessageInfo(msg.info) as MessageV2.Info
173176
const { id, sessionID: _, ...msgData } = msgInfo
174177
Database.use((db) =>
175178
db
@@ -185,7 +188,7 @@ export const ImportCommand = cmd({
185188
)
186189

187190
for (const part of msg.parts) {
188-
const partInfo = MessageV2.Part.zod.parse(part)
191+
const partInfo = decodePart(part) as MessageV2.Part
189192
const { id: partId, sessionID: _s, messageID, ...partData } = partInfo
190193
Database.use((db) =>
191194
db

packages/opencode/src/control-plane/adaptors/worktree.ts

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,13 @@ import { Schema } from "effect"
22
import { AppRuntime } from "@/effect/app-runtime"
33
import { Worktree } from "@/worktree"
44
import { type WorkspaceAdaptor, WorkspaceInfo } from "../types"
5-
import { zod } from "@/util/effect-zod"
6-
import { withStatics } from "@/util/schema"
75

86
const WorktreeConfig = Schema.Struct({
97
name: WorkspaceInfo.fields.name,
108
branch: Schema.String,
119
directory: Schema.String,
12-
}).pipe(withStatics((s) => ({ zod: zod(s) })))
10+
})
11+
const decodeWorktreeConfig = Schema.decodeUnknownSync(WorktreeConfig)
1312

1413
export const WorktreeAdaptor: WorkspaceAdaptor = {
1514
name: "Worktree",
@@ -24,7 +23,7 @@ export const WorktreeAdaptor: WorkspaceAdaptor = {
2423
}
2524
},
2625
async create(info) {
27-
const config = WorktreeConfig.zod.parse(info)
26+
const config = decodeWorktreeConfig(info)
2827
await AppRuntime.runPromise(
2928
Worktree.Service.use((svc) =>
3029
svc.createFromInfo({
@@ -36,11 +35,11 @@ export const WorktreeAdaptor: WorkspaceAdaptor = {
3635
)
3736
},
3837
async remove(info) {
39-
const config = WorktreeConfig.zod.parse(info)
38+
const config = decodeWorktreeConfig(info)
4039
await AppRuntime.runPromise(Worktree.Service.use((svc) => svc.remove({ directory: config.directory })))
4140
},
4241
target(info) {
43-
const config = WorktreeConfig.zod.parse(info)
42+
const config = decodeWorktreeConfig(info)
4443
return {
4544
type: "local",
4645
directory: config.directory,

packages/opencode/src/server/routes/instance/pty.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { Hono } from "hono"
22
import { describeRoute, validator, resolver } from "hono-openapi"
33
import type { UpgradeWebSocket } from "hono/ws"
4-
import { Effect } from "effect"
4+
import { Effect, Schema } from "effect"
55
import z from "zod"
66
import { AppRuntime } from "@/effect/app-runtime"
77
import { Pty } from "@/pty"
@@ -10,6 +10,8 @@ import { NotFoundError } from "@/storage"
1010
import { errors } from "../../error"
1111
import { jsonRequest, runRequest } from "./trace"
1212

13+
const decodePtyID = Schema.decodeUnknownSync(PtyID)
14+
1315
export function PtyRoutes(upgradeWebSocket: UpgradeWebSocket) {
1416
return new Hono()
1517
.get(
@@ -171,7 +173,7 @@ export function PtyRoutes(upgradeWebSocket: UpgradeWebSocket) {
171173
onClose: () => void
172174
}
173175

174-
const id = PtyID.zod.parse(c.req.param("ptyID"))
176+
const id = decodePtyID(c.req.param("ptyID"))
175177
const cursor = (() => {
176178
const value = c.req.query("cursor")
177179
if (!value) return

0 commit comments

Comments
 (0)