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 { 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" }) }) })