diff --git a/packages/opencode/src/server/routes/instance/httpapi/groups/question.ts b/packages/opencode/src/server/routes/instance/httpapi/groups/question.ts index e9e63429db20..09fbe94088f3 100644 --- a/packages/opencode/src/server/routes/instance/httpapi/groups/question.ts +++ b/packages/opencode/src/server/routes/instance/httpapi/groups/question.ts @@ -1,5 +1,6 @@ import { Question } from "@/question" import { QuestionID } from "@/question/schema" +import { SessionID } from "@/session/schema" import { Schema } from "effect" import { HttpApi, HttpApiEndpoint, HttpApiError, HttpApiGroup, OpenApi } from "effect/unstable/httpapi" import { QuestionNotFoundError } from "../errors" @@ -15,6 +16,11 @@ const ReplyPayload = Schema.Struct({ }), }) +const AskPayload = Schema.Struct({ + sessionID: SessionID, + questions: Schema.Array(Question.Info).annotate({ description: "Questions to ask" }), +}) + export const QuestionApi = HttpApi.make("question") .add( HttpApiGroup.make("question") @@ -29,6 +35,19 @@ export const QuestionApi = HttpApi.make("question") description: "Get all pending question requests across all sessions.", }), ), + HttpApiEndpoint.post("ask", `${root}/ask`, { + query: WorkspaceRoutingQuery, + payload: AskPayload, + success: described(Schema.Array(Question.Answer), "User answers in order of questions"), + error: [HttpApiError.BadRequest], + }).annotateMerge( + OpenApi.annotations({ + identifier: "question.ask", + summary: "Ask question request", + description: + "Create a pending question, publish question.asked for the TUI wizard, and block until the user replies or rejects.", + }), + ), HttpApiEndpoint.post("reply", `${root}/:requestID/reply`, { params: { requestID: QuestionID }, query: WorkspaceRoutingQuery, diff --git a/packages/opencode/src/server/routes/instance/httpapi/handlers/question.ts b/packages/opencode/src/server/routes/instance/httpapi/handlers/question.ts index e9ed8cc89154..1949f7a13f5f 100644 --- a/packages/opencode/src/server/routes/instance/httpapi/handlers/question.ts +++ b/packages/opencode/src/server/routes/instance/httpapi/handlers/question.ts @@ -1,7 +1,8 @@ import { Question } from "@/question" import { QuestionID } from "@/question/schema" +import { SessionID } from "@/session/schema" import { Effect } from "effect" -import { HttpApiBuilder } from "effect/unstable/httpapi" +import { HttpApiBuilder, HttpApiError } from "effect/unstable/httpapi" import { InstanceHttpApi } from "../api" import { QuestionNotFoundError } from "../errors" @@ -13,6 +14,20 @@ export const questionHandlers = HttpApiBuilder.group(InstanceHttpApi, "question" return yield* svc.list() }) + const ask = Effect.fn("QuestionHttpApi.ask")(function* (ctx: { + payload: { + sessionID: SessionID + questions: ReadonlyArray + } + }) { + return yield* svc + .ask({ + sessionID: ctx.payload.sessionID, + questions: ctx.payload.questions, + }) + .pipe(Effect.mapError(() => new HttpApiError.BadRequest({}))) + }) + const reply = Effect.fn("QuestionHttpApi.reply")(function* (ctx: { params: { requestID: QuestionID } payload: Question.Reply @@ -49,6 +64,6 @@ export const questionHandlers = HttpApiBuilder.group(InstanceHttpApi, "question" return true }) - return handlers.handle("list", list).handle("reply", reply).handle("reject", reject) + return handlers.handle("list", list).handle("ask", ask).handle("reply", reply).handle("reject", reject) }), )