Skip to content

Commit fe1a7b2

Browse files
authored
Merge pull request #142 from browser-use/nested-server-error
fix(opencode): retry nested OpenAI errors
2 parents 6b3408f + 05f9985 commit fe1a7b2

2 files changed

Lines changed: 61 additions & 5 deletions

File tree

‎packages/opencode/src/provider/error.ts‎

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -105,9 +105,16 @@ export function parseStreamError(input: unknown): ParsedStreamError | undefined
105105
if (!body) return
106106

107107
const responseBody = JSON.stringify(body)
108-
if (body.type !== "error") return
109-
110-
switch (body?.error?.code) {
108+
const error =
109+
body.type === "error"
110+
? body.error
111+
: body.type === "response.failed" &&
112+
(body.response?.error?.code === "server_is_overloaded" || body.response?.error?.code === "server_error")
113+
? body.response.error
114+
: undefined
115+
if (!error) return
116+
117+
switch (error.code) {
111118
case "context_length_exceeded":
112119
return {
113120
type: "context_overflow",
@@ -131,15 +138,15 @@ export function parseStreamError(input: unknown): ParsedStreamError | undefined
131138
case "invalid_prompt":
132139
return {
133140
type: "api_error",
134-
message: typeof body?.error?.message === "string" ? body?.error?.message : "Invalid prompt.",
141+
message: typeof error.message === "string" ? error.message : "Invalid prompt.",
135142
isRetryable: false,
136143
responseBody,
137144
}
138145
case "server_is_overloaded":
139146
case "server_error":
140147
return {
141148
type: "api_error",
142-
message: typeof body?.error?.message === "string" ? body?.error?.message : "Server error.",
149+
message: typeof error.message === "string" ? error.message : "Server error.",
143150
isRetryable: true,
144151
responseBody,
145152
}

‎packages/opencode/test/session/retry.test.ts‎

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -485,4 +485,53 @@ describe("session.message-v2.fromError", () => {
485485
message: "An error occurred while processing your request.",
486486
})
487487
})
488+
489+
test("converts nested OpenAI response.failed server errors to retryable APIError", () => {
490+
const cases = ["server_error", "server_is_overloaded"]
491+
492+
cases.forEach((code) => {
493+
const body = {
494+
type: "response.failed",
495+
sequence_number: 2,
496+
response: {
497+
status: "failed",
498+
error: {
499+
code,
500+
message: `OpenAI ${code}`,
501+
},
502+
},
503+
}
504+
const result = MessageV2.fromError(
505+
{ message: JSON.stringify(body) },
506+
{ providerID: ProviderV2.ID.make("openai") },
507+
)
508+
509+
expect(SessionV1.APIError.isInstance(result)).toBe(true)
510+
if (!SessionV1.APIError.isInstance(result)) throw new Error("expected APIError")
511+
expect(result.data.isRetryable).toBe(true)
512+
expect(result.data.responseBody).toBe(JSON.stringify(body))
513+
expect(SessionRetry.retryable(result, retryProvider)).toEqual({ message: `OpenAI ${code}` })
514+
})
515+
})
516+
517+
test("leaves other nested OpenAI response.failed errors terminal", () => {
518+
const result = MessageV2.fromError(
519+
{
520+
message: JSON.stringify({
521+
type: "response.failed",
522+
response: {
523+
status: "failed",
524+
error: {
525+
code: "invalid_prompt",
526+
message: "Invalid prompt from test",
527+
},
528+
},
529+
}),
530+
},
531+
{ providerID: ProviderV2.ID.make("openai") },
532+
)
533+
534+
expect(SessionV1.APIError.isInstance(result)).toBe(false)
535+
expect(SessionRetry.retryable(result, retryProvider)).toBeUndefined()
536+
})
488537
})

0 commit comments

Comments
 (0)