mirror of
https://github.com/anomalyco/opencode.git
synced 2026-04-28 04:29:42 +00:00
refactor(schema): decode effect schemas directly (#24169)
This commit is contained in:
parent
435becbea0
commit
cf45a8d807
4 changed files with 24 additions and 19 deletions
|
|
@ -46,7 +46,7 @@ import { MessageV2 } from "@/session/message-v2"
|
|||
import { Config } from "@/config"
|
||||
import { ConfigMCP } from "@/config/mcp"
|
||||
import { Todo } from "@/session/todo"
|
||||
import { z } from "zod"
|
||||
import { Result, Schema } from "effect"
|
||||
import { LoadAPIKeyError } from "ai"
|
||||
import type { AssistantMessage, Event, OpencodeClient, SessionMessageResponse, ToolPart } from "@opencode-ai/sdk/v2"
|
||||
import { applyPatch } from "diff"
|
||||
|
|
@ -54,6 +54,7 @@ import { InstallationVersion } from "@/installation/version"
|
|||
|
||||
type ModeOption = { id: string; name: string; description?: string }
|
||||
type ModelOption = { modelId: string; name: string }
|
||||
const decodeTodos = Schema.decodeUnknownResult(Schema.fromJsonString(Schema.Array(Todo.Info)))
|
||||
|
||||
const DEFAULT_VARIANT_VALUE = "default"
|
||||
|
||||
|
|
@ -372,14 +373,14 @@ export class Agent implements ACPAgent {
|
|||
}
|
||||
|
||||
if (part.tool === "todowrite") {
|
||||
const parsedTodos = z.array(Todo.Info.zod).safeParse(JSON.parse(part.state.output))
|
||||
if (parsedTodos.success) {
|
||||
const parsedTodos = decodeTodos(part.state.output)
|
||||
if (Result.isSuccess(parsedTodos)) {
|
||||
await this.connection
|
||||
.sessionUpdate({
|
||||
sessionId,
|
||||
update: {
|
||||
sessionUpdate: "plan",
|
||||
entries: parsedTodos.data.map((todo) => {
|
||||
entries: parsedTodos.success.map((todo) => {
|
||||
const status: PlanEntry["status"] =
|
||||
todo.status === "cancelled" ? "completed" : (todo.status as PlanEntry["status"])
|
||||
return {
|
||||
|
|
@ -394,7 +395,7 @@ export class Agent implements ACPAgent {
|
|||
log.error("failed to send session update for todo", { error })
|
||||
})
|
||||
} else {
|
||||
log.error("failed to parse todo output", { error: parsedTodos.error })
|
||||
log.error("failed to parse todo output", { error: parsedTodos.failure })
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -901,14 +902,14 @@ export class Agent implements ACPAgent {
|
|||
}
|
||||
|
||||
if (part.tool === "todowrite") {
|
||||
const parsedTodos = z.array(Todo.Info.zod).safeParse(JSON.parse(part.state.output))
|
||||
if (parsedTodos.success) {
|
||||
const parsedTodos = decodeTodos(part.state.output)
|
||||
if (Result.isSuccess(parsedTodos)) {
|
||||
await this.connection
|
||||
.sessionUpdate({
|
||||
sessionId,
|
||||
update: {
|
||||
sessionUpdate: "plan",
|
||||
entries: parsedTodos.data.map((todo) => {
|
||||
entries: parsedTodos.success.map((todo) => {
|
||||
const status: PlanEntry["status"] =
|
||||
todo.status === "cancelled" ? "completed" : (todo.status as PlanEntry["status"])
|
||||
return {
|
||||
|
|
@ -923,7 +924,7 @@ export class Agent implements ACPAgent {
|
|||
log.error("failed to send session update for todo", { error: err })
|
||||
})
|
||||
} else {
|
||||
log.error("failed to parse todo output", { error: parsedTodos.error })
|
||||
log.error("failed to parse todo output", { error: parsedTodos.failure })
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -13,6 +13,9 @@ import { Filesystem } from "../../util"
|
|||
import { AppRuntime } from "@/effect/app-runtime"
|
||||
import { Schema } from "effect"
|
||||
|
||||
const decodeMessageInfo = Schema.decodeUnknownSync(MessageV2.Info)
|
||||
const decodePart = Schema.decodeUnknownSync(MessageV2.Part)
|
||||
|
||||
/** Discriminated union returned by the ShareNext API (GET /api/shares/:id/data) */
|
||||
export type ShareData =
|
||||
| { type: "session"; data: SDKSession }
|
||||
|
|
@ -169,7 +172,7 @@ export const ImportCommand = cmd({
|
|||
)
|
||||
|
||||
for (const msg of exportData.messages) {
|
||||
const msgInfo = MessageV2.Info.zod.parse(msg.info)
|
||||
const msgInfo = decodeMessageInfo(msg.info) as MessageV2.Info
|
||||
const { id, sessionID: _, ...msgData } = msgInfo
|
||||
Database.use((db) =>
|
||||
db
|
||||
|
|
@ -185,7 +188,7 @@ export const ImportCommand = cmd({
|
|||
)
|
||||
|
||||
for (const part of msg.parts) {
|
||||
const partInfo = MessageV2.Part.zod.parse(part)
|
||||
const partInfo = decodePart(part) as MessageV2.Part
|
||||
const { id: partId, sessionID: _s, messageID, ...partData } = partInfo
|
||||
Database.use((db) =>
|
||||
db
|
||||
|
|
|
|||
|
|
@ -2,14 +2,13 @@ import { Schema } from "effect"
|
|||
import { AppRuntime } from "@/effect/app-runtime"
|
||||
import { Worktree } from "@/worktree"
|
||||
import { type WorkspaceAdaptor, WorkspaceInfo } from "../types"
|
||||
import { zod } from "@/util/effect-zod"
|
||||
import { withStatics } from "@/util/schema"
|
||||
|
||||
const WorktreeConfig = Schema.Struct({
|
||||
name: WorkspaceInfo.fields.name,
|
||||
branch: Schema.String,
|
||||
directory: Schema.String,
|
||||
}).pipe(withStatics((s) => ({ zod: zod(s) })))
|
||||
})
|
||||
const decodeWorktreeConfig = Schema.decodeUnknownSync(WorktreeConfig)
|
||||
|
||||
export const WorktreeAdaptor: WorkspaceAdaptor = {
|
||||
name: "Worktree",
|
||||
|
|
@ -24,7 +23,7 @@ export const WorktreeAdaptor: WorkspaceAdaptor = {
|
|||
}
|
||||
},
|
||||
async create(info) {
|
||||
const config = WorktreeConfig.zod.parse(info)
|
||||
const config = decodeWorktreeConfig(info)
|
||||
await AppRuntime.runPromise(
|
||||
Worktree.Service.use((svc) =>
|
||||
svc.createFromInfo({
|
||||
|
|
@ -36,11 +35,11 @@ export const WorktreeAdaptor: WorkspaceAdaptor = {
|
|||
)
|
||||
},
|
||||
async remove(info) {
|
||||
const config = WorktreeConfig.zod.parse(info)
|
||||
const config = decodeWorktreeConfig(info)
|
||||
await AppRuntime.runPromise(Worktree.Service.use((svc) => svc.remove({ directory: config.directory })))
|
||||
},
|
||||
target(info) {
|
||||
const config = WorktreeConfig.zod.parse(info)
|
||||
const config = decodeWorktreeConfig(info)
|
||||
return {
|
||||
type: "local",
|
||||
directory: config.directory,
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { Hono } from "hono"
|
||||
import { describeRoute, validator, resolver } from "hono-openapi"
|
||||
import type { UpgradeWebSocket } from "hono/ws"
|
||||
import { Effect } from "effect"
|
||||
import { Effect, Schema } from "effect"
|
||||
import z from "zod"
|
||||
import { AppRuntime } from "@/effect/app-runtime"
|
||||
import { Pty } from "@/pty"
|
||||
|
|
@ -10,6 +10,8 @@ import { NotFoundError } from "@/storage"
|
|||
import { errors } from "../../error"
|
||||
import { jsonRequest, runRequest } from "./trace"
|
||||
|
||||
const decodePtyID = Schema.decodeUnknownSync(PtyID)
|
||||
|
||||
export function PtyRoutes(upgradeWebSocket: UpgradeWebSocket) {
|
||||
return new Hono()
|
||||
.get(
|
||||
|
|
@ -171,7 +173,7 @@ export function PtyRoutes(upgradeWebSocket: UpgradeWebSocket) {
|
|||
onClose: () => void
|
||||
}
|
||||
|
||||
const id = PtyID.zod.parse(c.req.param("ptyID"))
|
||||
const id = decodePtyID(c.req.param("ptyID"))
|
||||
const cursor = (() => {
|
||||
const value = c.req.query("cursor")
|
||||
if (!value) return
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue