Skip to content

Retry overloaded responses, honour Retry-After, and log API errors - #36

Open
olosegres wants to merge 5 commits into
dotCipher:mainfrom
olosegres:fix/retries-and-error-log
Open

olosegres wants to merge 5 commits into
dotCipher:mainfrom
olosegres:fix/retries-and-error-log

Conversation

@olosegres

Copy link
Copy Markdown
Contributor

Summary

  • Retry 429 and 529 responses up to twice, waiting as long as Retry-After asks (exponential backoff when it is absent). Before, only 429 was retried, after a fixed 1s/2s pause, and a 529 went straight back to opencode. A requested wait longer than 10s is not absorbed inside the request: the response is returned at once so opencode's own retry loop — which shows the wait and can be cancelled — takes over, instead of a usage-limit 429 that resets in hours being retried twice for nothing. The wait ends early when the request is aborted, and 429 keeps its token refresh.
  • Retry the OAuth token endpoint on 529 as well, honouring retry_after from its body, and return the endpoint's real last answer instead of a made-up "Rate limited" 429.
  • Accept a plain-string system prompt. The request rewrite assumed text blocks; a string threw before the billing header was added, the error was swallowed, and the request went out unrewritten.
  • Log failed responses. opencode only shows a one-line summary of a failed request; each failed response handed back to it (after retries) is now written to stderr and appended, with its request id, to ~/.local/share/opencode/log/claude-bridge-api-errors.log ($XDG_DATA_HOME is respected).

Test plan

  • npm test — retry policy units; the plugin's fetch wrapper driven against a stubbed network (529 recovery, retries running out, long Retry-After, abort during the wait, string system prompt, error log); the token endpoint retry loop driven through a stand-in curl
  • npm run typecheck
  • With the plugin loaded in OpenCode, prompts go through as before, and a request for a nonexistent model leaves the expected 404 entry, with its request id, in the error log.

Only 429 was retried, after a fixed 1s/2s pause. An overloaded (529)
response went straight back to the caller, and a 429's Retry-After was
ignored: a short one was retried too early, and a usage-limit one that
resets in hours was retried twice for nothing.

Retry 429 and 529 up to twice, waiting as long as Retry-After asks
(exponential backoff when it is absent). A wait longer than 10s is not
absorbed inside the request: the response is returned at once, so
opencode's own retry loop - which shows the wait and can be cancelled -
takes over. The wait ends early when the request is aborted, and the
failed response body is released before the retry. 429 keeps its token
refresh.
The token request retried only 429. An overloaded (529) answer failed the
refresh at once, and when 429 retries ran out the caller got a made-up
"Rate limited" response instead of what the endpoint actually said.

Retry 529 as well, wait as long as the body's retry_after asks, and
return the endpoint's real last answer. The request blocks the process
while it sleeps, so a requested wait over 10s is not absorbed: the
answer is returned straight away.
The Messages API takes `system` either as a string or as text blocks,
but the request rewrite assumed blocks. A string made it throw before
the billing header was added; the error was swallowed and the request
went out unrewritten, so the subscription endpoint rejected it.

Wrap a string prompt in a single text block before rewriting.
When a request fails, opencode shows a one-line summary and the error
body and request id are gone, which is exactly what is needed to tell a
rejected request shape from a rate limit or an outage.

Write each failed response that is handed back to opencode (after any
retries) to stderr and append it, with its request id, to
opencode/log/claude-bridge-api-errors.log under XDG_DATA_HOME
(~/.local/share by default), next to opencode's own logs.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant