import { AppLayer } from "@/effect/app-runtime" import { memoMap } from "@/effect/run-service" import { Question } from "@/question" import { QuestionID } from "@/question/schema" import { lazy } from "@/util/lazy" import { Effect, Layer, Schema } from "effect" import { HttpRouter, HttpServer } from "effect/unstable/http" import { HttpApi, HttpApiBuilder, HttpApiEndpoint, HttpApiGroup, OpenApi } from "effect/unstable/httpapi" import type { Handler } from "hono" const root = "/experimental/httpapi/question" const Api = HttpApi.make("question") .add( HttpApiGroup.make("question") .add( HttpApiEndpoint.get("list", root, { success: Schema.Array(Question.Request), }).annotateMerge( OpenApi.annotations({ identifier: "question.list", summary: "List pending questions", description: "Get all pending question requests across all sessions.", }), ), HttpApiEndpoint.post("reply", `${root}/:requestID/reply`, { params: { requestID: QuestionID }, payload: Question.Reply, success: Schema.Boolean, }).annotateMerge( OpenApi.annotations({ identifier: "question.reply", summary: "Reply to question request", description: "Provide answers to a question request from the AI assistant.", }), ), ) .annotateMerge( OpenApi.annotations({ title: "question", description: "Experimental HttpApi question routes.", }), ), ) .annotateMerge( OpenApi.annotations({ title: "opencode experimental HttpApi", version: "0.0.1", description: "Experimental HttpApi surface for selected instance routes.", }), ) const QuestionLive = HttpApiBuilder.group( Api, "question", Effect.fn("QuestionHttpApi.handlers")(function* (handlers) { const svc = yield* Question.Service const list = Effect.fn("QuestionHttpApi.list")(function* () { return yield* svc.list() }) const reply = Effect.fn("QuestionHttpApi.reply")(function* (ctx: { params: { requestID: QuestionID } payload: Question.Reply }) { yield* svc.reply({ requestID: ctx.params.requestID, answers: ctx.payload.answers, }) return true }) return handlers.handle("list", list).handle("reply", reply) }), ).pipe(Layer.provide(Question.defaultLayer)) const web = lazy(() => HttpRouter.toWebHandler( Layer.mergeAll( AppLayer, HttpApiBuilder.layer(Api, { openapiPath: `${root}/doc` }).pipe( Layer.provide(QuestionLive), Layer.provide(HttpServer.layerServices), ), ), { disableLogger: true, memoMap, }, ), ) export const QuestionHttpApiHandler: Handler = (c, _next) => web().handler(c.req.raw)