summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorAiden Cline <[email protected]>2025-12-01 12:46:28 -0600
committerAiden Cline <[email protected]>2025-12-01 13:02:33 -0600
commit027d43b5ea49a132caa3b18169cac9a0286f1e44 (patch)
treee9da9009ff41299f340604e46084b32eaf2d4a17
parent729a6eda23a431a287aed28307e248ec3561cb1b (diff)
downloadopencode-027d43b5ea49a132caa3b18169cac9a0286f1e44.tar.gz
opencode-027d43b5ea49a132caa3b18169cac9a0286f1e44.zip
fix case where opencode wasn't retrying
-rw-r--r--packages/opencode/src/provider/transform.ts16
-rw-r--r--packages/opencode/src/session/message-v2.ts25
-rw-r--r--packages/opencode/src/session/processor.ts5
-rw-r--r--packages/opencode/src/session/retry.ts19
4 files changed, 47 insertions, 18 deletions
diff --git a/packages/opencode/src/provider/transform.ts b/packages/opencode/src/provider/transform.ts
index dc640ef6b..5ea3e0c31 100644
--- a/packages/opencode/src/provider/transform.ts
+++ b/packages/opencode/src/provider/transform.ts
@@ -1,5 +1,4 @@
import type { APICallError, ModelMessage } from "ai"
-import { STATUS_CODES } from "http"
import { unique } from "remeda"
import type { JSONSchema } from "zod/v4/core"
@@ -318,19 +317,6 @@ export namespace ProviderTransform {
)
}
- if (!error.responseBody || (error.statusCode && message !== STATUS_CODES[error.statusCode])) {
- return message
- }
-
- try {
- const body = JSON.parse(error.responseBody)
- // try to extract common error message fields
- const errMsg = body.message || body.error
- if (errMsg && typeof errMsg === "string") {
- return `${message}: ${errMsg}`
- }
- } catch {}
-
- return `${message}: ${error.responseBody}`
+ return message
}
}
diff --git a/packages/opencode/src/session/message-v2.ts b/packages/opencode/src/session/message-v2.ts
index f7b3ed479..b0dc12549 100644
--- a/packages/opencode/src/session/message-v2.ts
+++ b/packages/opencode/src/session/message-v2.ts
@@ -9,6 +9,8 @@ import { Snapshot } from "@/snapshot"
import { fn } from "@/util/fn"
import { Storage } from "@/storage/storage"
import { ProviderTransform } from "@/provider/transform"
+import { STATUS_CODES } from "http"
+import { iife } from "@/util/iife"
export namespace MessageV2 {
export const OutputLengthError = NamedError.create("MessageOutputLengthError", z.object({}))
@@ -739,7 +741,28 @@ export namespace MessageV2 {
{ cause: e },
).toObject()
case APICallError.isInstance(e):
- const message = ProviderTransform.error(ctx.providerID, e)
+ const message = iife(() => {
+ let msg = e.message
+ const transformed = ProviderTransform.error(ctx.providerID, e)
+ if (transformed !== msg) {
+ return transformed
+ }
+ if (!e.responseBody || (e.statusCode && msg !== STATUS_CODES[e.statusCode])) {
+ return msg
+ }
+
+ try {
+ const body = JSON.parse(e.responseBody)
+ // try to extract common error message fields
+ const errMsg = body.message || body.error
+ if (errMsg && typeof errMsg === "string") {
+ return `${msg}: ${errMsg}`
+ }
+ } catch {}
+
+ return `${msg}: ${e.responseBody}`
+ })
+
return new MessageV2.APIError(
{
message,
diff --git a/packages/opencode/src/session/processor.ts b/packages/opencode/src/session/processor.ts
index 2f2ba4e94..8655781d5 100644
--- a/packages/opencode/src/session/processor.ts
+++ b/packages/opencode/src/session/processor.ts
@@ -333,13 +333,14 @@ export namespace SessionProcessor {
error: e,
})
const error = MessageV2.fromError(e, { providerID: input.providerID })
- if (error?.name === "APIError" && error.data.isRetryable) {
+ const retry = SessionRetry.retryable(error)
+ if (retry !== undefined) {
attempt++
const delay = SessionRetry.delay(attempt, error.name === "APIError" ? error : undefined)
SessionStatus.set(input.sessionID, {
type: "retry",
attempt,
- message: error.data.message.includes("Overloaded") ? "Provider is overloaded" : error.data.message,
+ message: retry,
next: Date.now() + delay,
})
await SessionRetry.sleep(delay, input.abort).catch(() => {})
diff --git a/packages/opencode/src/session/retry.ts b/packages/opencode/src/session/retry.ts
index 4ad81ea08..ace7350b2 100644
--- a/packages/opencode/src/session/retry.ts
+++ b/packages/opencode/src/session/retry.ts
@@ -1,3 +1,4 @@
+import type { NamedError } from "@opencode-ai/util/error"
import { MessageV2 } from "./message-v2"
export namespace SessionRetry {
@@ -51,4 +52,22 @@ export namespace SessionRetry {
return Math.min(RETRY_INITIAL_DELAY * Math.pow(RETRY_BACKOFF_FACTOR, attempt - 1), RETRY_MAX_DELAY_NO_HEADERS)
}
+
+ export function retryable(error: ReturnType<NamedError["toObject"]>) {
+ if (MessageV2.APIError.isInstance(error)) {
+ if (!error.data.isRetryable) return undefined
+ return error.data.message.includes("Overloaded") ? "Provider is overloaded" : error.data.message
+ }
+
+ if (typeof error.data?.message === "string") {
+ try {
+ const json = JSON.parse(error.data.message)
+ if (json.type === "error" && json.error?.type === "too_many_requests") {
+ return "Too Many Requests"
+ }
+ } catch {}
+ }
+
+ return undefined
+ }
}