Files
Kilo-Org_kilocode/packages/opencode/test/kilocode/kilo-errors.test.ts
T
2026-06-01 15:20:54 +02:00

143 lines
4.5 KiB
TypeScript

import { describe, it, expect } from "bun:test"
import { MessageV2 } from "../../src/session/message-v2"
import { KILO_ERROR_CODES, isKiloError, parseKiloErrorCode } from "../../src/kilocode/kilo-errors"
import { SessionRetry } from "../../src/session/retry"
import { NamedError } from "@opencode-ai/core/util/error"
/**
* Helper to create a mock APIError object (as returned by .toObject())
*/
function makeAPIError(opts: {
statusCode?: number
isRetryable?: boolean
responseBody?: string
message?: string
}): ReturnType<NamedError["toObject"]> {
return new MessageV2.APIError({
message: opts.message ?? "Error",
statusCode: opts.statusCode,
isRetryable: opts.isRetryable ?? false,
responseBody: opts.responseBody,
}).toObject()
}
describe("parseKiloErrorCode", () => {
it("extracts PAID_MODEL_AUTH_REQUIRED from { error: { code } }", () => {
const error = makeAPIError({
statusCode: 401,
responseBody: JSON.stringify({ error: { code: "PAID_MODEL_AUTH_REQUIRED" } }),
})
expect(parseKiloErrorCode(error)).toBe("PAID_MODEL_AUTH_REQUIRED")
})
it("extracts PROMOTION_MODEL_LIMIT_REACHED from { code } (top-level)", () => {
const error = makeAPIError({
statusCode: 429,
responseBody: JSON.stringify({ code: "PROMOTION_MODEL_LIMIT_REACHED" }),
})
expect(parseKiloErrorCode(error)).toBe("PROMOTION_MODEL_LIMIT_REACHED")
})
it("extracts PROMOTION_MODEL_LIMIT_REACHED from { error: { code } }", () => {
const error = makeAPIError({
statusCode: 401,
responseBody: JSON.stringify({
error: {
code: "PROMOTION_MODEL_LIMIT_REACHED",
message: "Sign up for free to continue",
},
}),
})
expect(parseKiloErrorCode(error)).toBe("PROMOTION_MODEL_LIMIT_REACHED")
})
it("returns undefined for non-Kilo error codes", () => {
const error = makeAPIError({
statusCode: 429,
responseBody: JSON.stringify({ error: { code: "SOME_OTHER_ERROR" } }),
})
expect(parseKiloErrorCode(error)).toBeUndefined()
})
it("returns undefined for non-APIError types", () => {
const error = new MessageV2.AbortedError({ message: "aborted" }).toObject()
expect(parseKiloErrorCode(error)).toBeUndefined()
})
it("returns undefined for malformed responseBody", () => {
const error = makeAPIError({
statusCode: 401,
responseBody: "not valid json",
})
expect(parseKiloErrorCode(error)).toBeUndefined()
})
it("returns undefined when responseBody is missing", () => {
const error = makeAPIError({
statusCode: 401,
})
expect(parseKiloErrorCode(error)).toBeUndefined()
})
})
describe("isKiloError", () => {
it("returns true for PAID_MODEL_AUTH_REQUIRED", () => {
const error = makeAPIError({
statusCode: 401,
responseBody: JSON.stringify({ error: { code: "PAID_MODEL_AUTH_REQUIRED" } }),
})
expect(isKiloError(error)).toBe(true)
})
it("returns true for PROMOTION_MODEL_LIMIT_REACHED", () => {
const error = makeAPIError({
statusCode: 429,
responseBody: JSON.stringify({ code: "PROMOTION_MODEL_LIMIT_REACHED" }),
})
expect(isKiloError(error)).toBe(true)
})
it("returns false for regular 429 errors without Kilo code", () => {
const error = makeAPIError({
statusCode: 429,
isRetryable: true,
message: "Too Many Requests",
})
expect(isKiloError(error)).toBe(false)
})
it("returns false for non-APIError types", () => {
const error = new MessageV2.AbortedError({ message: "aborted" }).toObject()
expect(isKiloError(error)).toBe(false)
})
})
describe("SessionRetry.retryable with Kilo errors", () => {
it("returns undefined for PAID_MODEL_AUTH_REQUIRED (not retryable)", () => {
const error = makeAPIError({
statusCode: 401,
isRetryable: false,
responseBody: JSON.stringify({ error: { code: "PAID_MODEL_AUTH_REQUIRED" } }),
})
expect(SessionRetry.retryable(error)).toBeUndefined()
})
it("returns undefined for PROMOTION_MODEL_LIMIT_REACHED even when isRetryable is true", () => {
const error = makeAPIError({
statusCode: 429,
isRetryable: true,
responseBody: JSON.stringify({ code: "PROMOTION_MODEL_LIMIT_REACHED" }),
})
expect(SessionRetry.retryable(error)).toBeUndefined()
})
it("still returns retry details for regular 429 errors", () => {
const error = makeAPIError({
statusCode: 429,
isRetryable: true,
message: "Too Many Requests",
})
expect(SessionRetry.retryable(error)).toEqual({ message: "Too Many Requests" })
})
})