feat(server): add form routes (#35099)

Co-authored-by: Luke Parker <10430890+Hona@users.noreply.github.com>
This commit is contained in:
Aiden Cline 2026-07-03 02:40:44 -05:00 committed by GitHub
commit d9bf30fc22
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
16 changed files with 3080 additions and 436 deletions

View file

@ -6,6 +6,7 @@ import { ProviderHandler } from "./handlers/provider"
import { SessionHandler } from "./handlers/session"
import { PermissionHandler } from "./handlers/permission"
import { FileSystemHandler } from "./handlers/fs"
import { FormHandler } from "./handlers/form"
import { CommandHandler } from "./handlers/command"
import { SkillHandler } from "./handlers/skill"
import { EventHandler } from "./handlers/event"
@ -37,6 +38,7 @@ export const handlers = Layer.mergeAll(
McpHandler,
CredentialHandler,
ProjectHandler,
FormHandler,
PermissionHandler,
FileSystemHandler,
CommandHandler,

View file

@ -0,0 +1,123 @@
import { Form } from "@opencode-ai/core/form"
import {
ConflictError,
FormAlreadySettledError,
FormInvalidAnswerError,
FormNotFoundError,
InvalidRequestError,
} from "@opencode-ai/protocol/errors"
import { Effect } from "effect"
import { HttpApiBuilder, HttpApiSchema } from "effect/unstable/httpapi"
import { Api } from "../api"
import { response } from "../location"
function missingForm(id: Form.ID) {
return new FormNotFoundError({ id, message: `Form not found: ${id}` })
}
export const FormHandler = HttpApiBuilder.group(Api, "server.form", (handlers) =>
Effect.gen(function* () {
const requireOwnedForm = Effect.fnUntraced(function* (sessionID: Form.Info["sessionID"], formID: Form.ID) {
const form = yield* Form.Service
const info = yield* form.get(formID).pipe(Effect.catchTag("Form.NotFoundError", () => missingForm(formID)))
if (info.sessionID !== sessionID) return yield* missingForm(formID)
return { form, info }
})
return handlers
.handle(
"form.request.list",
Effect.fn(function* () {
const form = yield* Form.Service
return yield* response(form.list())
}),
)
.handle(
"session.form.list",
Effect.fn(function* (ctx) {
const form = yield* Form.Service
const forms = yield* form.list({ sessionID: ctx.params.sessionID })
return { data: forms }
}),
)
.handle(
"session.form.create",
Effect.fn(function* (ctx) {
const form = yield* Form.Service
const common = {
id: ctx.payload.id,
sessionID: ctx.params.sessionID,
title: ctx.payload.title,
metadata: ctx.payload.metadata,
}
const input = yield* (() => {
if (ctx.payload.mode === "form") {
if (!ctx.payload.fields) {
return new InvalidRequestError({ message: "Form fields are required", field: "fields" })
}
return Effect.succeed({ ...common, mode: "form" as const, fields: ctx.payload.fields })
}
if (!ctx.payload.url) return new InvalidRequestError({ message: "Form URL is required", field: "url" })
return Effect.succeed({ ...common, mode: "url" as const, url: ctx.payload.url })
})()
const created = yield* form
.create(input)
.pipe(
Effect.catchTag(
"Form.AlreadyExistsError",
(error) => new ConflictError({ resource: error.id, message: error.message }),
),
)
return { data: created }
}),
)
.handle(
"session.form.get",
Effect.fn(function* (ctx) {
const owned = yield* requireOwnedForm(ctx.params.sessionID, ctx.params.formID)
return { data: owned.info }
}),
)
.handle(
"session.form.state",
Effect.fn(function* (ctx) {
const owned = yield* requireOwnedForm(ctx.params.sessionID, ctx.params.formID)
const data = yield* owned.form
.state(ctx.params.formID)
.pipe(Effect.catchTag("Form.NotFoundError", () => missingForm(ctx.params.formID)))
return { data }
}),
)
.handle(
"session.form.reply",
Effect.fn(function* (ctx) {
const owned = yield* requireOwnedForm(ctx.params.sessionID, ctx.params.formID)
yield* owned.form.reply({ id: ctx.params.formID, answer: ctx.payload.answer }).pipe(
Effect.catchTags({
"Form.AlreadySettledError": (error) =>
new FormAlreadySettledError({ id: error.id, message: error.message }),
"Form.InvalidAnswerError": (error) =>
new FormInvalidAnswerError({ id: error.id, message: error.message }),
"Form.NotFoundError": () => missingForm(ctx.params.formID),
}),
)
return HttpApiSchema.NoContent.make()
}),
)
.handle(
"session.form.cancel",
Effect.fn(function* (ctx) {
const owned = yield* requireOwnedForm(ctx.params.sessionID, ctx.params.formID)
yield* owned.form.cancel(ctx.params.formID).pipe(
Effect.catchTags({
"Form.AlreadySettledError": (error) =>
new FormAlreadySettledError({ id: error.id, message: error.message }),
"Form.NotFoundError": () => missingForm(ctx.params.formID),
}),
)
return HttpApiSchema.NoContent.make()
}),
)
}),
)