Repository navigation
fix(chat): say why a run is waiting when the provider keeps failing - #399
Merged
Merged
Conversation
When a model call fails with a retryable error (rate limit, overloaded model,
dropped connection), OpenCode keeps the turn open and waits out a backoff,
announcing it only as `session.status` of type `retry` with the attempt number
and the provider's message. The parser read the type and dropped the rest, the
chat treated it like `busy`, and the screen stayed on "Thinking..." for as long
as the retries lasted - which has no upper bound. After 2.5 minutes the stall
card then called the run dead ("producing nothing") although the runtime was
alive and had said exactly why it was waiting.
Keep the retry details (attempt, message) on the status event, hold them in
the chat state until the run produces output or ends, and show a card with the
provider's reason in place of the "Thinking"/"Processing" labels. The stall
diagnosis gets a PROVIDER_RETRYING verdict that outranks "no output" but not a
finished turn or a dead event stream, and is not painted as a stopped run.
Refs #397
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…the retry Applies the non-blocking suggestions from the pre-PR review: the stall card now shows a retrying run's provider message too, which can be a whole JSON error body, so the supporting detail gets the same four-line cap as the retry card; and a test pins that stopping a retrying run drops the retry. Refs #397 Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Refs #397 ("In chat sometimes it does not respond, stuck on processing/thinking, too slow").
The issue has no logs or backend details, so this fixes the cause that could be confirmed from the code and OpenCode's published SDK types, and it was not reproduced on a device.
Cause. When a model call fails with a retryable error (rate limit, overloaded model, dropped connection), OpenCode keeps the turn open and waits out a backoff, announcing it only as
session.statusof typeretrywithattemptand the provider'smessage. The parser kept thetypeand dropped the rest, the chat treated it likebusy, and the screen stayed on "Thinking…" for as long as the retries lasted (there is no upper bound). After 150 s the stall card then said the run produced nothing and had probably stopped, although the runtime was alive and had said exactly why it was waiting.Fix.
OpenCodeEvent.SessionStatusChangedgainsretry: RunRetry?(attempt, message); the V1 parser fills it. Existing two-argument constructions are unchanged.ChatUiState.retryholds it until the run produces output or ends (it is deliberately kept across thebusythat starts each attempt, so the card does not flicker back to "Thinking"). A new prompt starts without it.PROVIDER_RETRYING: it outranks "no output" but not a finished turn, a recorded provider failure, an unanswered approval/question or a dead event stream, and is not painted as a stopped run.chat_retry_*,chat_stall_reason_provider_retrying).Not changed (found while investigating, separate causes, left for follow-ups):
RuntimeActivityRepositorydoes not know about retries, so with the chat closed a retrying run is still announced as "probably stopped" and eventually settled. Not made worse by this PR.readTimeout(0)and has no heartbeat check, so a silently dead connection is never reconnected.ServerConnected) the chat reloads the transcript but does not settle a turn that finished while it was disconnected; only the stall watchdog (about 3 minutes) does.PROVIDER_RETRYINGrather thanNO_OUTPUT; keepingnextand ignoring an overdue retry would tighten this.If the reporter or you can say which backend the freezes were seen on (OpenCode vs Codex / Claude Code / Antigravity), that tells us whether the items above are needed. This change only affects OpenCode.
Test plan
./gradlew detekt spotlessCheckpasses./gradlew :app:testGithubDebugUnitTest(1404 tests, 0 failures, 8 skipped) and:app:assembleGithubDebugpassChatViewModel(retry kept, cleared on output / run end / stop / replacement prompt, stall explained as a retry).github/workflows/i18n-check.ymlPre-PR review
The named
repo-reviewersubagent (.opencode/agents/repo-reviewer.md) is not registered in Claude Code, so the review was run by a read-only general-purpose subagent given that definition verbatim. It reviewed commit30411535; commitc462f07aafterwards applied two of its non-blocking suggestions (a 4-line cap on the stall card's detail text, and a test that stopping clears the retry) and nothing else.🤖 Generated with Claude Code