diff --git a/.changeset/nullable-kilo-gateway-sdk.md b/.changeset/nullable-kilo-gateway-sdk.md new file mode 100644 index 0000000000..3b9c4b0b8c --- /dev/null +++ b/.changeset/nullable-kilo-gateway-sdk.md @@ -0,0 +1,5 @@ +--- +"@kilocode/sdk": patch +--- + +Preserve nullable Kilo gateway response fields in the generated TypeScript SDK. diff --git a/packages/opencode/src/kilocode/server/httpapi/public.ts b/packages/opencode/src/kilocode/server/httpapi/public.ts index 5de2211d03..78deb6d62b 100644 --- a/packages/opencode/src/kilocode/server/httpapi/public.ts +++ b/packages/opencode/src/kilocode/server/httpapi/public.ts @@ -49,6 +49,26 @@ export function matchLegacyKiloOpenApi(input: Record) { const props = ref ? spec.components?.schemas?.[ref]?.properties : body?.properties if (props?.organizationId) props.organizationId = nullable(props.organizationId) + const json = (path: string) => spec.paths?.[path]?.get?.responses?.["200"]?.content?.["application/json"] + const profile = json("/kilo/profile")?.schema?.properties + if (profile?.balance) profile.balance = nullable(profile.balance) + if (profile?.currentOrgId) profile.currentOrgId = nullable(profile.currentOrgId) + + const sessions = json("/kilo/cloud-sessions")?.schema?.properties + const session = sessions?.cliSessions?.items?.properties + if (session?.title) session.title = nullable(session.title) + if (sessions?.nextCursor) sessions.nextCursor = nullable(sessions.nextCursor) + + const claw = json("/kilo/claw/status")?.schema?.properties + if (claw?.status) claw.status = nullable(claw.status) + if (claw?.openclawVersion) claw.openclawVersion = nullable(claw.openclawVersion) + if (claw?.lastStartedAt) claw.lastStartedAt = nullable(claw.lastStartedAt) + if (claw?.lastStoppedAt) claw.lastStoppedAt = nullable(claw.lastStoppedAt) + if (claw?.botName) claw.botName = nullable(claw.botName) + + const credentials = json("/kilo/claw/chat-credentials") + if (credentials?.schema) credentials.schema = nullable(credentials.schema) + const provider = spec.components?.schemas?.Config?.properties?.provider if (provider?.additionalProperties && typeof provider.additionalProperties === "object") provider.additionalProperties = nullable(provider.additionalProperties) diff --git a/packages/opencode/test/kilocode/server/httpapi-public.test.ts b/packages/opencode/test/kilocode/server/httpapi-public.test.ts index 979ed653bc..1dc4ee7ffb 100644 --- a/packages/opencode/test/kilocode/server/httpapi-public.test.ts +++ b/packages/opencode/test/kilocode/server/httpapi-public.test.ts @@ -6,6 +6,7 @@ import { PublicApi } from "../../../src/server/routes/instance/httpapi/public" type Schema = { anyOf?: Schema[] + items?: Schema properties?: Record type?: string minLength?: number @@ -51,6 +52,34 @@ describe("Kilo PublicApi OpenAPI contract", () => { expect(props?.organizationId).toEqual({ anyOf: [{ type: "string" }, { type: "null" }] }) }) + test("keeps Kilo gateway responses nullable", () => { + const spec = OpenApi.fromApi(PublicApi) + const response = (path: string) => { + const body = spec.paths[path]?.get?.responses?.["200"] as Body | undefined + return body?.content?.["application/json"]?.schema + } + + const profile = response(KiloGatewayPaths.profile)?.properties + expect(profile?.balance).toEqual({ anyOf: [expect.objectContaining({ type: "object" }), { type: "null" }] }) + expect(profile?.currentOrgId).toEqual({ anyOf: [{ type: "string" }, { type: "null" }] }) + + const sessions = response(KiloGatewayPaths.cloudSessions)?.properties + expect(sessions?.cliSessions?.items?.properties?.title).toEqual({ + anyOf: [{ type: "string" }, { type: "null" }], + }) + expect(sessions?.nextCursor).toEqual({ anyOf: [{ type: "string" }, { type: "null" }] }) + + const claw = response(KiloGatewayPaths.clawStatus)?.properties + expect(claw?.status).toEqual({ anyOf: [expect.objectContaining({ type: "string" }), { type: "null" }] }) + for (const field of ["openclawVersion", "lastStartedAt", "lastStoppedAt", "botName"]) { + expect(claw?.[field]).toEqual({ anyOf: [{ type: "string" }, { type: "null" }] }) + } + + expect(response(KiloGatewayPaths.clawChatCredentials)).toEqual({ + anyOf: [expect.objectContaining({ type: "object" }), { type: "null" }], + }) + }) + test("keeps transcription prompts in the public contract", () => { const spec = OpenApi.fromApi(PublicApi) const body = spec.paths[KiloGatewayPaths.audioTranscriptions]?.post?.requestBody as Body | undefined diff --git a/packages/sdk/js/src/v2/gen/types.gen.ts b/packages/sdk/js/src/v2/gen/types.gen.ts index a0fb916a27..f5bc92b87c 100644 --- a/packages/sdk/js/src/v2/gen/types.gen.ts +++ b/packages/sdk/js/src/v2/gen/types.gen.ts @@ -8268,8 +8268,8 @@ export type KiloProfileResponses = { } balance: { balance: number - } - currentOrgId: string + } | null + currentOrgId: string | null } } @@ -8557,19 +8557,20 @@ export type KiloClawStatusResponses = { | "stopped" | "destroying" | "restoring" + | null sandboxId?: string flyRegion?: string machineSize?: { cpus: number memory_mb: number } - openclawVersion?: string - lastStartedAt?: string - lastStoppedAt?: string + openclawVersion?: string | null + lastStartedAt?: string | null + lastStoppedAt?: string | null channelCount?: number secretCount?: number userId?: string - botName?: string + botName?: string | null } } @@ -8594,7 +8595,7 @@ export type KiloClawChatCredentialsResponses = { expiresAt: string kiloChatUrl: string eventServiceUrl: string - } + } | null } export type KiloClawChatCredentialsResponse = KiloClawChatCredentialsResponses[keyof KiloClawChatCredentialsResponses] @@ -8628,12 +8629,12 @@ export type KiloCloudSessionsResponses = { 200: { cliSessions: Array<{ session_id: string - title: string + title: string | null created_at: string updated_at: string version: number }> - nextCursor: string + nextCursor: string | null } } diff --git a/packages/sdk/openapi.json b/packages/sdk/openapi.json index 66750773bf..294c6526d4 100644 --- a/packages/sdk/openapi.json +++ b/packages/sdk/openapi.json @@ -10950,17 +10950,31 @@ "additionalProperties": false }, "balance": { - "type": "object", - "properties": { - "balance": { - "type": "number" + "anyOf": [ + { + "type": "object", + "properties": { + "balance": { + "type": "number" + } + }, + "required": ["balance"], + "additionalProperties": false + }, + { + "type": "null" } - }, - "required": ["balance"], - "additionalProperties": false + ] }, "currentOrgId": { - "type": "string" + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ] } }, "required": ["profile", "balance", "currentOrgId"], @@ -11712,16 +11726,23 @@ "type": "object", "properties": { "status": { - "type": "string", - "enum": [ - "provisioned", - "starting", - "restarting", - "recovering", - "running", - "stopped", - "destroying", - "restoring" + "anyOf": [ + { + "type": "string", + "enum": [ + "provisioned", + "starting", + "restarting", + "recovering", + "running", + "stopped", + "destroying", + "restoring" + ] + }, + { + "type": "null" + } ] }, "sandboxId": { @@ -11744,13 +11765,34 @@ "additionalProperties": false }, "openclawVersion": { - "type": "string" + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ] }, "lastStartedAt": { - "type": "string" + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ] }, "lastStoppedAt": { - "type": "string" + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ] }, "channelCount": { "type": "number" @@ -11762,7 +11804,14 @@ "type": "string" }, "botName": { - "type": "string" + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ] } }, "required": ["status"], @@ -11821,23 +11870,30 @@ "content": { "application/json": { "schema": { - "type": "object", - "properties": { - "token": { - "type": "string" + "anyOf": [ + { + "type": "object", + "properties": { + "token": { + "type": "string" + }, + "expiresAt": { + "type": "string" + }, + "kiloChatUrl": { + "type": "string" + }, + "eventServiceUrl": { + "type": "string" + } + }, + "required": ["token", "expiresAt", "kiloChatUrl", "eventServiceUrl"], + "additionalProperties": false }, - "expiresAt": { - "type": "string" - }, - "kiloChatUrl": { - "type": "string" - }, - "eventServiceUrl": { - "type": "string" + { + "type": "null" } - }, - "required": ["token", "expiresAt", "kiloChatUrl", "eventServiceUrl"], - "additionalProperties": false + ] } } } @@ -11916,7 +11972,14 @@ "type": "string" }, "title": { - "type": "string" + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ] }, "created_at": { "type": "string" @@ -11933,7 +11996,14 @@ } }, "nextCursor": { - "type": "string" + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ] } }, "required": ["cliSessions", "nextCursor"],