mirror of
https://github.com/Kilo-Org/kilocode.git
synced 2026-09-01 15:32:11 +08:00
fix: accept null error fields and narrow message retry heuristics
This commit is contained in:
@@ -9,8 +9,8 @@ export type Frame = {
|
||||
} & Record<string, unknown>
|
||||
|
||||
const payload = z.looseObject({
|
||||
code: z.union([z.string(), z.number()]).optional(),
|
||||
message: z.string().optional(),
|
||||
code: z.union([z.string(), z.number()]).nullish(),
|
||||
message: z.string().nullish(),
|
||||
})
|
||||
|
||||
// OpenAI Responses API terminal frame forwarded by @ai-sdk/openai >= 3.0.82
|
||||
@@ -29,7 +29,7 @@ const wrapper = z.looseObject({
|
||||
// fields so gateway wrappers keep the specific inner code
|
||||
const bare = z.looseObject({
|
||||
type: z.undefined().optional(),
|
||||
code: z.union([z.string(), z.number()]),
|
||||
code: z.union([z.string(), z.number(), z.null()]),
|
||||
message: z.string(),
|
||||
})
|
||||
|
||||
@@ -49,6 +49,9 @@ export function frame(body: unknown): Frame {
|
||||
}
|
||||
|
||||
const RETRYABLE = /rate.?limit|too.?many.?requests|rate increased too quickly|exhausted|overload|server|unavailable|timeout/i
|
||||
// Session.retryable only matched these phrases against free-form message
|
||||
// text; the wider pattern above is for structured code/type fields only
|
||||
const RETRYABLE_TEXT = /rate increased too quickly|rate limit|too many requests/i
|
||||
|
||||
// Must stay at least as permissive as the Session.retryable heuristics that
|
||||
// applied when these frames still surfaced as NamedError.Unknown, or
|
||||
@@ -63,7 +66,7 @@ function retryable(error: Frame["error"], message: string) {
|
||||
}
|
||||
const type = error?.type
|
||||
if (typeof type === "string" && RETRYABLE.test(type)) return true
|
||||
return RETRYABLE.test(message)
|
||||
return RETRYABLE_TEXT.test(message)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -187,6 +187,45 @@ describe("responses api terminal frames", () => {
|
||||
expect(result.data.isRetryable).toBe(true)
|
||||
})
|
||||
|
||||
test("normalizes error objects with explicit null fields", () => {
|
||||
const payload = {
|
||||
error: {
|
||||
message: "The server had an error while processing your request",
|
||||
type: "server_error",
|
||||
param: null,
|
||||
code: null,
|
||||
},
|
||||
}
|
||||
const result = MessageV2.fromError(payload, { providerID: ProviderV2.ID.make("openai") })
|
||||
|
||||
expect(MessageV2.APIError.isInstance(result)).toBe(true)
|
||||
if (!MessageV2.APIError.isInstance(result)) throw new Error("expected APIError")
|
||||
expect(result.data.message).toBe(payload.error.message)
|
||||
expect(result.data.isRetryable).toBe(true)
|
||||
})
|
||||
|
||||
test("normalizes response.failed frames with a null error code", () => {
|
||||
const payload = {
|
||||
type: "response.failed",
|
||||
response: { error: { code: null, message: "mid-stream failure" }, incomplete_details: null },
|
||||
}
|
||||
const result = MessageV2.fromError(payload, { providerID: ProviderV2.ID.make("openai") })
|
||||
|
||||
expect(MessageV2.APIError.isInstance(result)).toBe(true)
|
||||
if (!MessageV2.APIError.isInstance(result)) throw new Error("expected APIError")
|
||||
expect(result.data.message).toBe("mid-stream failure")
|
||||
expect(result.data.isRetryable).toBe(false)
|
||||
})
|
||||
|
||||
test("does not retry terminal errors that merely mention availability", () => {
|
||||
const payload = { code: "invalid_request", message: "The model is unavailable in your region" }
|
||||
const result = MessageV2.fromError(payload, { providerID: ProviderV2.ID.make("openai") })
|
||||
|
||||
expect(MessageV2.APIError.isInstance(result)).toBe(true)
|
||||
if (!MessageV2.APIError.isInstance(result)) throw new Error("expected APIError")
|
||||
expect(result.data.isRetryable).toBe(false)
|
||||
})
|
||||
|
||||
test("ignores response.failed frames without an error payload", () => {
|
||||
const payload = { type: "response.failed", response: { error: null, incomplete_details: null } }
|
||||
const result = MessageV2.fromError(payload, { providerID: ProviderV2.ID.make("openai") })
|
||||
|
||||
Reference in New Issue
Block a user