diff options
| author | Shoubhit Dash <[email protected]> | 2026-04-15 04:45:25 +0530 |
|---|---|---|
| committer | Dax Raad <[email protected]> | 2026-04-14 20:55:39 -0400 |
| commit | fba752a5016a93ad7ea54890cf444de02a89a0f8 (patch) | |
| tree | f56a7f7705574fb418c7773e915dceafdcc51a1f /packages/server/src/definition | |
| parent | 87b2a9d749ac39f47ea2d9d6806e32f224fe8ba9 (diff) | |
| download | opencode-fba752a5016a93ad7ea54890cf444de02a89a0f8.tar.gz opencode-fba752a5016a93ad7ea54890cf444de02a89a0f8.zip | |
feat(server): extract question httpapi contract
Diffstat (limited to 'packages/server/src/definition')
| -rw-r--r-- | packages/server/src/definition/api.ts | 16 | ||||
| -rw-r--r-- | packages/server/src/definition/index.ts | 1 | ||||
| -rw-r--r-- | packages/server/src/definition/question.ts | 94 |
3 files changed, 106 insertions, 5 deletions
diff --git a/packages/server/src/definition/api.ts b/packages/server/src/definition/api.ts index 6eda4090e..e2f70196d 100644 --- a/packages/server/src/definition/api.ts +++ b/packages/server/src/definition/api.ts @@ -1,6 +1,12 @@ -import type { ServerApi } from "../types.js" +import { HttpApi, OpenApi } from "effect/unstable/httpapi" +import { questionApi } from "./question.js" -export const api: ServerApi = { - name: "opencode", - groups: [], -} +export const api = HttpApi.make("opencode") + .addHttpApi(questionApi) + .annotateMerge( + OpenApi.annotations({ + title: "opencode experimental HttpApi", + version: "0.0.1", + description: "Experimental HttpApi surface for selected instance routes.", + }), + ) diff --git a/packages/server/src/definition/index.ts b/packages/server/src/definition/index.ts index 39cab2446..e9a52dc93 100644 --- a/packages/server/src/definition/index.ts +++ b/packages/server/src/definition/index.ts @@ -1 +1,2 @@ export { api } from "./api.js" +export { questionApi, QuestionReply, QuestionRequest } from "./question.js" diff --git a/packages/server/src/definition/question.ts b/packages/server/src/definition/question.ts new file mode 100644 index 000000000..0d161e013 --- /dev/null +++ b/packages/server/src/definition/question.ts @@ -0,0 +1,94 @@ +import { Schema } from "effect" +import { HttpApi, HttpApiEndpoint, HttpApiGroup, OpenApi } from "effect/unstable/httpapi" + +const root = "/experimental/httpapi/question" + +// Temporary transport-local schemas until canonical question schemas move into packages/core. +export const QuestionID = Schema.String.annotate({ identifier: "QuestionID" }) +export const SessionID = Schema.String.annotate({ identifier: "SessionID" }) +export const MessageID = Schema.String.annotate({ identifier: "MessageID" }) + +export class QuestionOption extends Schema.Class<QuestionOption>("QuestionOption")({ + label: Schema.String.annotate({ + description: "Display text (1-5 words, concise)", + }), + description: Schema.String.annotate({ + description: "Explanation of choice", + }), +}) {} + +const base = { + question: Schema.String.annotate({ + description: "Complete question", + }), + header: Schema.String.annotate({ + description: "Very short label (max 30 chars)", + }), + options: Schema.Array(QuestionOption).annotate({ + description: "Available choices", + }), + multiple: Schema.optional(Schema.Boolean).annotate({ + description: "Allow selecting multiple choices", + }), +} + +export class QuestionInfo extends Schema.Class<QuestionInfo>("QuestionInfo")({ + ...base, + custom: Schema.optional(Schema.Boolean).annotate({ + description: "Allow typing a custom answer (default: true)", + }), +}) {} + +export class QuestionTool extends Schema.Class<QuestionTool>("QuestionTool")({ + messageID: MessageID, + callID: Schema.String, +}) {} + +export class QuestionRequest extends Schema.Class<QuestionRequest>("QuestionRequest")({ + id: QuestionID, + sessionID: SessionID, + questions: Schema.Array(QuestionInfo).annotate({ + description: "Questions to ask", + }), + tool: Schema.optional(QuestionTool), +}) {} + +export const QuestionAnswer = Schema.Array(Schema.String).annotate({ identifier: "QuestionAnswer" }) + +export class QuestionReply extends Schema.Class<QuestionReply>("QuestionReply")({ + answers: Schema.Array(QuestionAnswer).annotate({ + description: "User answers in order of questions (each answer is an array of selected labels)", + }), +}) {} + +export const questionApi = HttpApi.make("question").add( + HttpApiGroup.make("question") + .add( + HttpApiEndpoint.get("list", root, { + success: Schema.Array(QuestionRequest), + }).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: QuestionReply, + 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.", + }), + ), +) |
