From 80bcc8d4781888f107ae1473cc995def44496bec Mon Sep 17 00:00:00 2001 From: Kit Langton Date: Tue, 28 Apr 2026 22:10:41 -0400 Subject: [PATCH] fix(httpapi): restore CI schema parity --- .../server/routes/instance/httpapi/public.ts | 36 +++++++++++++++++++ packages/opencode/src/session/message-v2.ts | 2 +- .../__snapshots__/parameters.test.ts.snap | 15 +++++--- 3 files changed, 47 insertions(+), 6 deletions(-) diff --git a/packages/opencode/src/server/routes/instance/httpapi/public.ts b/packages/opencode/src/server/routes/instance/httpapi/public.ts index 2b5b6a4378..69599febe1 100644 --- a/packages/opencode/src/server/routes/instance/httpapi/public.ts +++ b/packages/opencode/src/server/routes/instance/httpapi/public.ts @@ -68,6 +68,34 @@ const QueryParameterSchemas = { "GET /session/{sessionID}/message limit": { type: "integer", minimum: 0, maximum: Number.MAX_SAFE_INTEGER }, } satisfies Record +const LegacyRequestBodySchemas: Record = { + "POST /global/upgrade": { type: "object" }, + "POST /log": { type: "object" }, + "POST /experimental/workspace": { type: "object" }, + "POST /experimental/workspace/{id}/session-restore": { type: "object" }, + "PATCH /project/{projectID}": { type: "object" }, + "POST /experimental/console/switch": { type: "object" }, + "POST /experimental/worktree": { $ref: "#/components/schemas/WorktreeCreateInput" }, + "POST /session": { type: "object" }, + "PATCH /session/{sessionID}": { type: "object" }, + "POST /session/{sessionID}/init": { type: "object" }, + "POST /session/{sessionID}/fork": { type: "object" }, + "POST /session/{sessionID}/summarize": { type: "object" }, + "POST /session/{sessionID}/message": { type: "object" }, + "POST /session/{sessionID}/prompt_async": { type: "object" }, + "POST /session/{sessionID}/command": { type: "object" }, + "POST /session/{sessionID}/shell": { type: "object" }, + "POST /session/{sessionID}/revert": { type: "object" }, + "POST /session/{sessionID}/permissions/{permissionID}": { type: "object" }, + "POST /permission/{requestID}/reply": { type: "object" }, + "POST /question/{requestID}/reply": { type: "object" }, + "POST /sync/replay": { type: "object" }, + "POST /mcp": { type: "object" }, + "POST /mcp/{name}/auth/callback": { type: "object" }, + "POST /tui/execute-command": { type: "object" }, + "POST /tui/publish": {}, +} + // Mapping of "METHOD /path" to the correct 200 response description from Hono spec const ResponseDescriptions = { "GET /global/health": "Health information", @@ -210,6 +238,7 @@ function matchLegacyOpenApi(input: Record) { // Hono's generated OpenAPI never marked request bodies as required. Keep // that SDK surface stable during the HttpApi migration. delete operation.requestBody.required + normalizeRequestBody(operation, `${method.toUpperCase()} ${path}`) if (path === "/experimental/workspace" && method === "post") { // Workspace creation fields `branch` and `extra` are Schema.NullOr — // genuinely nullable, not just optional. Re-add the null that the @@ -252,6 +281,13 @@ function matchLegacyOpenApi(input: Record) { return input } +function normalizeRequestBody(operation: OpenApiOperation, route: string) { + const schema = LegacyRequestBodySchemas[route] + const body = operation.requestBody?.content?.["application/json"] + if (!schema || !body) return + body.schema = structuredClone(schema) +} + /** * Fix component schemas that are self-referencing `$ref`s — an Effect OpenAPI * generation bug where annotated union arms that share AST nodes with other diff --git a/packages/opencode/src/session/message-v2.ts b/packages/opencode/src/session/message-v2.ts index 550ab17c16..b1a6ff4036 100644 --- a/packages/opencode/src/session/message-v2.ts +++ b/packages/opencode/src/session/message-v2.ts @@ -659,7 +659,7 @@ export type WithParts = { const Cursor = Schema.Struct({ id: MessageID, - time: NonNegativeInt, + time: Schema.Finite.check(Schema.isGreaterThanOrEqualTo(0)), }) type Cursor = typeof Cursor.Type diff --git a/packages/opencode/test/tool/__snapshots__/parameters.test.ts.snap b/packages/opencode/test/tool/__snapshots__/parameters.test.ts.snap index b20665b34d..02de54406a 100644 --- a/packages/opencode/test/tool/__snapshots__/parameters.test.ts.snap +++ b/packages/opencode/test/tool/__snapshots__/parameters.test.ts.snap @@ -43,7 +43,9 @@ Output: Creates directory 'foo'" }, "timeout": { "description": "Optional timeout in milliseconds", - "type": "number", + "exclusiveMinimum": 0, + "maximum": 9007199254740991, + "type": "integer", }, "workdir": { "description": "The working directory to run the command in. Defaults to the current directory. Use this instead of 'cd' commands.", @@ -71,7 +73,7 @@ exports[`tool parameters JSON Schema (wire shape) codesearch 1`] = ` "description": "Number of tokens to return (1000-50000). Default is 5000 tokens. Adjust this value based on how much context you need - use lower values for focused queries and higher values for comprehensive documentation.", "maximum": 50000, "minimum": 1000, - "type": "number", + "type": "integer", }, }, "required": [ @@ -224,7 +226,6 @@ exports[`tool parameters JSON Schema (wire shape) lsp 1`] = ` } `; - exports[`tool parameters JSON Schema (wire shape) plan 1`] = ` { "$schema": "https://json-schema.org/draft/2020-12/schema", @@ -304,11 +305,15 @@ exports[`tool parameters JSON Schema (wire shape) read 1`] = ` }, "limit": { "description": "The maximum number of lines to read (defaults to 2000)", - "type": "number", + "maximum": 9007199254740991, + "minimum": 0, + "type": "integer", }, "offset": { "description": "The line number to start reading from (1-indexed)", - "type": "number", + "maximum": 9007199254740991, + "minimum": 0, + "type": "integer", }, }, "required": [