fix: parse mid stream openai responses style errors to prevent infinite retries for errors that should STOP execution (#12768)
This commit is contained in:
@@ -796,7 +796,76 @@ export namespace MessageV2 {
|
|||||||
case e instanceof Error:
|
case e instanceof Error:
|
||||||
return new NamedError.Unknown({ message: e.toString() }, { cause: e }).toObject()
|
return new NamedError.Unknown({ message: e.toString() }, { cause: e }).toObject()
|
||||||
default:
|
default:
|
||||||
return new NamedError.Unknown({ message: JSON.stringify(e) }, { cause: e })
|
try {
|
||||||
|
const json = iife(() => {
|
||||||
|
if (typeof e === "string") {
|
||||||
|
try {
|
||||||
|
return JSON.parse(e)
|
||||||
|
} catch {
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof e === "object" && e !== null) {
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
return undefined
|
||||||
|
})
|
||||||
|
if (json) {
|
||||||
|
const responseBody = JSON.stringify(json)
|
||||||
|
// Handle Responses API mid stream style errors
|
||||||
|
if (json?.type === "error") {
|
||||||
|
switch (json?.error?.code) {
|
||||||
|
case "context_length_exceeded":
|
||||||
|
return new MessageV2.APIError(
|
||||||
|
{
|
||||||
|
message: "Input exceeds context window of this model",
|
||||||
|
isRetryable: false,
|
||||||
|
responseBody,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
cause: e,
|
||||||
|
},
|
||||||
|
).toObject()
|
||||||
|
case "insufficient_quota":
|
||||||
|
return new MessageV2.APIError(
|
||||||
|
{
|
||||||
|
message: "Quota exceeded. Check your plan and billing details.",
|
||||||
|
isRetryable: false,
|
||||||
|
responseBody,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
cause: e,
|
||||||
|
},
|
||||||
|
).toObject()
|
||||||
|
case "usage_not_included":
|
||||||
|
return new MessageV2.APIError(
|
||||||
|
{
|
||||||
|
message:
|
||||||
|
"To use Codex with your ChatGPT plan, upgrade to Plus: https://chatgpt.com/explore/plus.",
|
||||||
|
isRetryable: false,
|
||||||
|
responseBody,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
cause: e,
|
||||||
|
},
|
||||||
|
).toObject()
|
||||||
|
case "invalid_prompt":
|
||||||
|
return new MessageV2.APIError(
|
||||||
|
{
|
||||||
|
message: json?.error?.message || "Invalid prompt.",
|
||||||
|
isRetryable: false,
|
||||||
|
responseBody,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
cause: e,
|
||||||
|
},
|
||||||
|
).toObject()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch {}
|
||||||
|
return new NamedError.Unknown({ message: JSON.stringify(e) }, { cause: e }).toObject()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -784,3 +784,57 @@ describe("session.message-v2.toModelMessage", () => {
|
|||||||
])
|
])
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe("session.message-v2.fromError", () => {
|
||||||
|
test("serializes response error codes", () => {
|
||||||
|
const cases = [
|
||||||
|
{
|
||||||
|
code: "context_length_exceeded",
|
||||||
|
message: "Input exceeds context window of this model",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
code: "insufficient_quota",
|
||||||
|
message: "Quota exceeded. Check your plan and billing details.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
code: "usage_not_included",
|
||||||
|
message: "To use Codex with your ChatGPT plan, upgrade to Plus: https://chatgpt.com/explore/plus.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
code: "invalid_prompt",
|
||||||
|
message: "Invalid prompt from test",
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
cases.forEach((item) => {
|
||||||
|
const input = {
|
||||||
|
type: "error",
|
||||||
|
error: {
|
||||||
|
code: item.code,
|
||||||
|
message: item.code === "invalid_prompt" ? item.message : undefined,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
const result = MessageV2.fromError(input, { providerID: "test" })
|
||||||
|
|
||||||
|
expect(result).toStrictEqual({
|
||||||
|
name: "APIError",
|
||||||
|
data: {
|
||||||
|
message: item.message,
|
||||||
|
isRetryable: false,
|
||||||
|
responseBody: JSON.stringify(input),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
test("serializes unknown inputs", () => {
|
||||||
|
const result = MessageV2.fromError(123, { providerID: "test" })
|
||||||
|
|
||||||
|
expect(result).toStrictEqual({
|
||||||
|
name: "UnknownError",
|
||||||
|
data: {
|
||||||
|
message: "123",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user