Files
Kilo-Org_kilocode/packages/opencode/test/kilocode/server/httpapi-public.test.ts
T
2026-06-11 12:29:01 -03:00

192 lines
8.4 KiB
TypeScript

import { describe, expect, test } from "bun:test"
import { Result, Schema as EffectSchema } from "effect"
import { OpenApi } from "effect/unstable/httpapi"
import { AgentBuilderPaths } from "../../../src/kilocode/server/httpapi/groups/agent-builder"
import { BackgroundProcessPaths } from "../../../src/kilocode/server/httpapi/groups/background-process"
import { ConfigConsolePaths } from "../../../src/kilocode/server/httpapi/groups/config-console"
import { IndexingPaths, KiloEmbeddingModel } from "../../../src/kilocode/server/httpapi/groups/indexing"
import { KiloGatewayPaths } from "../../../src/kilocode/server/httpapi/groups/kilo-gateway"
import { NetworkPaths } from "../../../src/kilocode/server/httpapi/groups/network"
import { TelemetryPaths } from "../../../src/kilocode/server/httpapi/groups/telemetry"
import { ExperimentalPaths } from "../../../src/server/routes/instance/httpapi/groups/experimental"
import { SessionPaths } from "../../../src/server/routes/instance/httpapi/groups/session"
import { PublicApi } from "../../../src/server/routes/instance/httpapi/public"
type Schema = {
anyOf?: Schema[]
items?: Schema
properties?: Record<string, Schema>
type?: string
minLength?: number
maxLength?: number
pattern?: string
}
type Parameter = {
in?: string
name?: string
schema?: Schema
}
type Method = "get" | "post" | "patch" | "put"
type Body = {
content?: Record<string, { schema?: Schema }>
}
describe("Kilo PublicApi OpenAPI contract", () => {
test("uses Kilo branding", () => {
const spec = OpenApi.fromApi(PublicApi)
expect(spec.info.title).toBe("kilo")
expect(spec.info.description).toBe("kilo api")
})
test("constrains embedding model metadata", () => {
const accepts = (dimension: number, scoreThreshold: number) =>
Result.isSuccess(
EffectSchema.decodeUnknownResult(KiloEmbeddingModel)({
id: "provider/model",
name: "Model",
dimension,
scoreThreshold,
}),
)
expect(accepts(1, 0)).toBe(true)
expect(accepts(1024, 1)).toBe(true)
expect(accepts(0, 0.5)).toBe(false)
expect(accepts(1.5, 0.5)).toBe(false)
expect(accepts(1024, -0.1)).toBe(false)
expect(accepts(1024, 1.1)).toBe(false)
})
test("constrains agent builder route ids", () => {
const spec = OpenApi.fromApi(PublicApi)
const save = AgentBuilderPaths.save.replace(":id", "{id}")
const params = spec.paths[save]?.put?.parameters as Parameter[] | undefined
const schema = params?.find((param) => param.name === "id")?.schema
expect(schema).toEqual({
type: "string",
minLength: 1,
maxLength: 64,
pattern: "^[a-zA-Z0-9][a-zA-Z0-9._-]*$",
})
})
test("keeps workspace routing queries on background process routes", () => {
const spec = OpenApi.fromApi(PublicApi)
const routes = [
{ method: "get", path: BackgroundProcessPaths.list },
{ method: "get", path: BackgroundProcessPaths.get },
{ method: "get", path: BackgroundProcessPaths.logs },
{ method: "post", path: BackgroundProcessPaths.stop },
{ method: "post", path: BackgroundProcessPaths.restart },
{ method: "post", path: BackgroundProcessPaths.stopSession },
] satisfies Array<{ method: Method; path: string }>
for (const route of routes) {
const path = route.path.replace(/:([A-Za-z0-9_]+)/g, "{$1}")
const params = spec.paths[path]?.[route.method]?.parameters as Parameter[] | undefined
const query = params?.filter((param) => param.in === "query").map((param) => param.name)
expect(query, `${route.method.toUpperCase()} ${route.path}`).toEqual(["directory", "workspace"])
}
})
test("keeps directory routing queries on Kilo Console routes", () => {
const spec = OpenApi.fromApi(PublicApi)
const routes = [
{ method: "get", path: ExperimentalPaths.worktreeDiff },
{ method: "get", path: ExperimentalPaths.worktreeDiffSummary },
{ method: "get", path: ExperimentalPaths.worktreeDiffFile },
{ method: "post", path: SessionPaths.viewed },
{ method: "get", path: ConfigConsolePaths.overlay },
{ method: "patch", path: ConfigConsolePaths.overlay },
{ method: "get", path: IndexingPaths.status },
{ method: "get", path: IndexingPaths.models },
] satisfies Array<{ method: Method; path: string }>
for (const route of routes) {
const params = spec.paths[route.path]?.[route.method]?.parameters as Parameter[] | undefined
const query = params?.filter((param) => param.in === "query").map((param) => param.name)
expect(query, `${route.method.toUpperCase()} ${route.path}`).toContain("directory")
expect(query, `${route.method.toUpperCase()} ${route.path}`).toContain("workspace")
}
})
test("keeps workspace routing queries on all Kilo-owned routed endpoints", () => {
const spec = OpenApi.fromApi(PublicApi)
const routes = [
{ method: "post", path: AgentBuilderPaths.preview },
{ method: "put", path: AgentBuilderPaths.save },
{ method: "post", path: "/commit-message" },
{ method: "post", path: "/enhance-prompt" },
{ method: "get", path: NetworkPaths.list },
{ method: "post", path: NetworkPaths.reply },
{ method: "post", path: NetworkPaths.reject },
{ method: "post", path: TelemetryPaths.capture },
{ method: "post", path: TelemetryPaths.setEnabled },
{ method: "get", path: ConfigConsolePaths.sources },
{ method: "get", path: ConfigConsolePaths.effective },
{ method: "get", path: ConfigConsolePaths.rules },
{ method: "put", path: ConfigConsolePaths.rules },
{ method: "get", path: ConfigConsolePaths.modelState },
{ method: "patch", path: ConfigConsolePaths.modelState },
{ method: "get", path: ConfigConsolePaths.tuiConfig },
{ method: "get", path: ConfigConsolePaths.tuiKeybinds },
{ method: "patch", path: ConfigConsolePaths.tuiConfig },
] satisfies Array<{ method: Method; path: string }>
for (const route of routes) {
const path = route.path.replace(/:([A-Za-z0-9_]+)/g, "{$1}")
const params = spec.paths[path]?.[route.method]?.parameters as Parameter[] | undefined
const query = params?.filter((param) => param.in === "query").map((param) => param.name)
expect(query, `${route.method.toUpperCase()} ${route.path}`).toContain("directory")
expect(query, `${route.method.toUpperCase()} ${route.path}`).toContain("workspace")
}
})
test("keeps personal organization resets nullable", () => {
const spec = OpenApi.fromApi(PublicApi)
const body = spec.paths[KiloGatewayPaths.organization]?.post?.requestBody as Body | undefined
const schema = body?.content?.["application/json"]?.schema
const props = schema?.properties
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
const schema = body?.content?.["application/json"]?.schema
expect(schema?.properties?.prompt).toEqual({ type: "string" })
})
})