fix: fail bare rate limits and show retry waits - #3115

Merged
M4n5ter merged 3 commits into
mainfrom
fix/runtime-rate-limit-requires-retry-after
Aug 16, 2026
Merged

fix: fail bare rate limits and show retry waits#3115
M4n5ter merged 3 commits into
mainfrom
fix/runtime-rate-limit-requires-retry-after

Conversation

@Astro-Han

@Astro-HanAstro-Han commented Aug 16, 2026

Copy link
Copy Markdown
Contributor

Summary

A bare 429, including OpenCode FreeUsageLimitError, was retried ten times and looked like a hang. Rate limits now fail immediately unless the provider names Retry-After. A real wait still is not a conversation fact: Host keeps the current overlay on the in-memory Turn snapshot, publishes it when it appears, and drops it on the next content event so remount cannot resurrect a finished wait. The chat shows that overlay as an Astryx warning Banner.

Before — a muted status row with no reason:

image

After — an Astryx warning Banner with the retry reason:

image

Verification

  • packages/runtime/src/__tests__/provider-error-classification.test.ts (retries a rate limit only when the provider names a retry delay)
  • packages/runtime/src/__tests__/session-manager.test.ts (provider retry progress reaches observers...)
  • packages/runtime-host/src/__tests__/session-continuity-coordinator.test.ts (keeps the current provider retry on the live Turn until the next content event)
  • packages/runtime-host/src/__tests__/session-projector.test.ts
  • packages/runtime-host/src/__tests__/protocol.test.ts
  • packages/runtime-host/src/__tests__/canonical-session-projection.test.ts
  • npm run format:check

Did not run repository-wide tests or a live Electron remount of a Retry-After wait.

AI use

  • Generative tooling made a substantive contribution

Tool(s) and scope:

Cursor Grok 4.5 diagnosed the hung session, shaped the change, and authored the commits.

Checklist

  • Tests cover the change and fail without it
  • Lint, format, typecheck and the affected suites pass locally

Does this PR entail a change in behavior?

  • Yes — described under Summary above

@coderabbitai

coderabbitaiBot commented Aug 16, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Problem solved

Bare 429 errors now fail immediately unless the provider supplies a valid Retry-After value. Provider retry waits remain visible in chat with a localized reason and countdown. Retry state survives session projection and remounts, then clears after the next content event.

Design

The PR extends the existing live Turn snapshot and session-continuity path. It does not create a separate retry-state path. The provider_retry event updates canonical turn state, projects it to subscribers, and preserves it during session reopening.

The added protocol validation, event handling, projection logic, and UI presentation form the smallest coherent solution for persistence, remount behavior, and user feedback. The added complexity is required to distinguish scheduled retries from completed content and to prevent stale retry state from returning.

No safe deletion or simplification is evident from the current diff. The new tests cover protocol decoding, projection, continuity, error classification, telemetry, and UI-facing behavior.

Validation and risks

Coverage was added or updated for runtime, runtime-host, session projection, session continuity, protocol compatibility, retry classification, telemetry, and formatting. The runtime-host compatibility epoch increased from 20 to 21.

Repository-wide tests were not run. A live Electron remount was not verified. Required checks therefore remain unverified without direct check results.

Review-relevant risks

  • User-visible behavior changes because retry errors, reasons, countdowns, and warning banners now appear differently. Material UI behavior changes require independent human review under repository policy.
  • Provider retry classification changes because bare 429 errors are no longer retryable. Material runtime behavior changes require independent human review under repository policy.
  • The runtime-host protocol changes through new TurnProviderRetry and LiveTurnSnapshot types, validation rules, and compatibility epoch 21. Material public-contract and release-compatibility changes require independent human review under repository policy.
  • No security, licensing, or governance effect was identified in the current diff.
  • The person performing the merge must review the final diff. A maintainer makes the final determination.

Walkthrough

The PR makes rate-limit retries conditional on valid Retry-After data. It adds validated provider-retry state to runtime-host snapshots, persists retry events across session continuity, and renders localized retry banners in the UI.

Changes

Provider retry flow

Layer / File(s)Summary
Rate-limit retry classification
packages/runtime/src/provider-error-classification.ts, packages/runtime/src/__tests__/*
Rate-limit errors retry only when a valid delay exists. Tests update retryability and diagnostic expectations.
Retry snapshot protocol
packages/runtime-host/src/protocol/turn.ts, packages/runtime-host/src/protocol/operations.ts, packages/runtime-host/src/protocol/index.ts, packages/runtime-host/src/__tests__/protocol.test.ts
Turn snapshots support validated provider retry metadata. The compatibility epoch changes to 21.
Provider retry projection persistence
packages/runtime-host/src/adapter/session-projector.ts, packages/runtime-host/src/server/*, packages/runtime-host/src/__tests__/session-projector.test.ts, packages/runtime-host/src/__tests__/session-continuity-coordinator.test.ts
Projectors emit retry events. Session continuity stores, republishes, preserves, and clears retry metadata.
Localized retry presentation
packages/ui/src/chat-turn.tsx, packages/ui/src/conversation-copy.ts, packages/ui/src/styles.css
The UI renders retry information with localized reason labels and a warning banner.

Estimated code review effort: 4 (Complex) | ~45 minutes

Merge Risk:🟡 Moderate · up to d2666

Remounting during a provider retry can show a countdown longer than the actual remaining wait because the scheduled retry time is not preserved. This is a concrete user-visible correctness issue that should be fixed before merge.

Sequence Diagram(s)

sequenceDiagram
participant Provider
participant Runtime
participant RuntimeHost
participant UI
Provider->>Runtime: return rate-limit error
Runtime->>Runtime: parse Retry-After
Runtime->>RuntimeHost: provide retry metadata
RuntimeHost->>RuntimeHost: publish provider_retry event
RuntimeHost->>UI: project retry snapshot
UI->>UI: render localized warning banner
Loading

Possibly related PRs

Suggested reviewers:m4n5ter

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check nameStatusExplanation
Linked Issues check✅ PassedCheck skipped because no linked issues were found for this pull request.
Out of Scope Changes check✅ PassedCheck skipped because no linked issues were found for this pull request.
Ai Use Disclosure✅ PassedThe PR selects generative tooling and names Cursor Grok 4.5 with scope; all three introduced commits contain matching standalone Generated-by trailers.
Title check✅ PassedThe title clearly summarizes the two main changes: immediate failure for bare rate limits and visible retry waits.
Description check✅ PassedThe description includes the required summary, verification, AI-use selection, checklist, behavior change, evidence, and unrun checks.
✨ Finishing Touches 💡 1
🛠️ Fix failing CI checks 💡
  • Create stacked PR
  • Commit on current branch
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/runtime-rate-limit-requires-retry-after

Comment @coderabbitai help to get the list of available commands.

@Astro-Han
Astro-Han marked this pull request as ready for review August 16, 2026 10:28

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1


ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: af9b5f4d-87df-471c-86b7-6d7a4f3ac623

📥 Commits

Reviewing files that changed from the base of the PR and between 8b79a6d and 968aae0.

📒 Files selected for processing (21)
  • packages/core/src/agent-run.ts
  • packages/runtime-host/src/__tests__/canonical-session-projection.test.ts
  • packages/runtime-host/src/__tests__/protocol.test.ts
  • packages/runtime-host/src/__tests__/session-projector.test.ts
  • packages/runtime-host/src/adapter/session-projector.ts
  • packages/runtime-host/src/protocol/operations.ts
  • packages/runtime-host/src/protocol/turn.ts
  • packages/runtime-host/src/server/canonical-turn-snapshot.ts
  • packages/runtime/src/__tests__/model-adapter.test.ts
  • packages/runtime/src/__tests__/provider-error-classification.test.ts
  • packages/runtime/src/__tests__/provider-request-telemetry.test.ts
  • packages/runtime/src/__tests__/session-manager.test.ts
  • packages/runtime/src/agent-run.ts
  • packages/runtime/src/provider-error-classification.ts
  • packages/storage/src/agent-run-store.ts
  • packages/ui/src/__tests__/provider-retry-presentation.test.ts
  • packages/ui/src/chat-turn.tsx
  • packages/ui/src/conversation-copy.ts
  • packages/ui/src/index.ts
  • packages/ui/src/provider-retry-presentation.ts
  • packages/ui/src/styles.css

Included review availability: Your plan includes up to 3 reviews per rolling hour; 1 remains after this review.

Comment threadpackages/runtime/src/agent-run.ts Outdated
@Astro-Han
Astro-Hanforce-pushed the fix/runtime-rate-limit-requires-retry-after branch from 968aae0 to d2666f5CompareAugust 16, 2026 11:29

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1


ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 1c38e715-0bfe-4131-b811-131d2fbb9cd9

📥 Commits

Reviewing files that changed from the base of the PR and between 968aae0 and d2666f5.

📒 Files selected for processing (10)
  • packages/runtime-host/src/__tests__/protocol.test.ts
  • packages/runtime-host/src/__tests__/session-continuity-coordinator.test.ts
  • packages/runtime-host/src/__tests__/session-projector.test.ts
  • packages/runtime-host/src/adapter/session-projector.ts
  • packages/runtime-host/src/protocol/index.ts
  • packages/runtime-host/src/protocol/operations.ts
  • packages/runtime-host/src/protocol/turn.ts
  • packages/runtime-host/src/server/root-turn-coordinator.ts
  • packages/runtime-host/src/server/session-continuity-coordinator.ts
  • packages/ui/src/chat-turn.tsx
🚧 Files skipped from review as they are similar to previous changes (3)
  • packages/runtime-host/src/tests/protocol.test.ts
  • packages/ui/src/chat-turn.tsx
  • packages/runtime-host/src/protocol/turn.ts

Included review availability: Your plan includes up to 3 reviews per rolling hour; 2 remain after this review.

@Astro-Han
Astro-Hanforce-pushed the fix/runtime-rate-limit-requires-retry-after branch from d2666f5 to 3cc3de4CompareAugust 16, 2026 11:35
A bare 429, including OpenCode FreeUsageLimitError, is a quota or
throttle without a recovery time. Retrying it ten times only hid the
failure behind a three-minute empty wait. Keep automatic retries for
rate limits that name Retry-After, and leave network or 5xx retries
unchanged.
Generated-by: Cursor Grok 4.5
The live retry line used the same muted working-status treatment as
"thinking", so a 40-second rate-limit wait looked like a hang. Keep
the existing live providerRetry object, and render its reason plus
countdown through the shared Astryx Banner.
Generated-by: Cursor Grok 4.5
A provider retry is still not a conversation fact. Hold the current wait
on the in-memory Turn snapshot, publish it when it appears, and drop it
on the next content event so remount cannot resurrect a finished wait.
Generated-by: Cursor Grok 4.5
@Astro-Han
Astro-Hanforce-pushed the fix/runtime-rate-limit-requires-retry-after branch from 3cc3de4 to f8eb564CompareAugust 16, 2026 11:49
@Astro-Han
Astro-Han requested a review from M4n5terAugust 16, 2026 12:27

@M4n5terM4n5ter left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. The rate-limit classification, transient retry overlay lifecycle, protocol boundary, and UI presentation are coherent and well covered by tests.

@M4n5ter
M4n5ter merged commit c92d0a2 into mainAug 16, 2026
12 checks passed
@M4n5ter
M4n5ter deleted the fix/runtime-rate-limit-requires-retry-after branch August 16, 2026 12:51
Sign up for freeto 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.

2 participants

@Astro-Han@M4n5ter
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

fix: fail bare rate limits and show retry waits - #3115

Merged
M4n5ter merged 3 commits into
mainfrom
fix/runtime-rate-limit-requires-retry-after
Aug 16, 2026
Merged

fix: fail bare rate limits and show retry waits#3115
M4n5ter merged 3 commits into
mainfrom
fix/runtime-rate-limit-requires-retry-after

Conversation

@Astro-Han

@Astro-HanAstro-Han commented Aug 16, 2026

Copy link
Copy Markdown
Contributor

Summary

A bare 429, including OpenCode FreeUsageLimitError, was retried ten times and looked like a hang. Rate limits now fail immediately unless the provider names Retry-After. A real wait still is not a conversation fact: Host keeps the current overlay on the in-memory Turn snapshot, publishes it when it appears, and drops it on the next content event so remount cannot resurrect a finished wait. The chat shows that overlay as an Astryx warning Banner.

Before — a muted status row with no reason:

image

After — an Astryx warning Banner with the retry reason:

image

Verification

  • packages/runtime/src/__tests__/provider-error-classification.test.ts (retries a rate limit only when the provider names a retry delay)
  • packages/runtime/src/__tests__/session-manager.test.ts (provider retry progress reaches observers...)
  • packages/runtime-host/src/__tests__/session-continuity-coordinator.test.ts (keeps the current provider retry on the live Turn until the next content event)
  • packages/runtime-host/src/__tests__/session-projector.test.ts
  • packages/runtime-host/src/__tests__/protocol.test.ts
  • packages/runtime-host/src/__tests__/canonical-session-projection.test.ts
  • npm run format:check

Did not run repository-wide tests or a live Electron remount of a Retry-After wait.

AI use

  • Generative tooling made a substantive contribution

Tool(s) and scope:

Cursor Grok 4.5 diagnosed the hung session, shaped the change, and authored the commits.

Checklist

  • Tests cover the change and fail without it
  • Lint, format, typecheck and the affected suites pass locally

Does this PR entail a change in behavior?

  • Yes — described under Summary above

@coderabbitai

coderabbitaiBot commented Aug 16, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Problem solved

Bare 429 errors now fail immediately unless the provider supplies a valid Retry-After value. Provider retry waits remain visible in chat with a localized reason and countdown. Retry state survives session projection and remounts, then clears after the next content event.

Design

The PR extends the existing live Turn snapshot and session-continuity path. It does not create a separate retry-state path. The provider_retry event updates canonical turn state, projects it to subscribers, and preserves it during session reopening.

The added protocol validation, event handling, projection logic, and UI presentation form the smallest coherent solution for persistence, remount behavior, and user feedback. The added complexity is required to distinguish scheduled retries from completed content and to prevent stale retry state from returning.

No safe deletion or simplification is evident from the current diff. The new tests cover protocol decoding, projection, continuity, error classification, telemetry, and UI-facing behavior.

Validation and risks

Coverage was added or updated for runtime, runtime-host, session projection, session continuity, protocol compatibility, retry classification, telemetry, and formatting. The runtime-host compatibility epoch increased from 20 to 21.

Repository-wide tests were not run. A live Electron remount was not verified. Required checks therefore remain unverified without direct check results.

Review-relevant risks

  • User-visible behavior changes because retry errors, reasons, countdowns, and warning banners now appear differently. Material UI behavior changes require independent human review under repository policy.
  • Provider retry classification changes because bare 429 errors are no longer retryable. Material runtime behavior changes require independent human review under repository policy.
  • The runtime-host protocol changes through new TurnProviderRetry and LiveTurnSnapshot types, validation rules, and compatibility epoch 21. Material public-contract and release-compatibility changes require independent human review under repository policy.
  • No security, licensing, or governance effect was identified in the current diff.
  • The person performing the merge must review the final diff. A maintainer makes the final determination.

Walkthrough

The PR makes rate-limit retries conditional on valid Retry-After data. It adds validated provider-retry state to runtime-host snapshots, persists retry events across session continuity, and renders localized retry banners in the UI.

Changes

Provider retry flow

Layer / File(s)Summary
Rate-limit retry classification
packages/runtime/src/provider-error-classification.ts, packages/runtime/src/__tests__/*
Rate-limit errors retry only when a valid delay exists. Tests update retryability and diagnostic expectations.
Retry snapshot protocol
packages/runtime-host/src/protocol/turn.ts, packages/runtime-host/src/protocol/operations.ts, packages/runtime-host/src/protocol/index.ts, packages/runtime-host/src/__tests__/protocol.test.ts
Turn snapshots support validated provider retry metadata. The compatibility epoch changes to 21.
Provider retry projection persistence
packages/runtime-host/src/adapter/session-projector.ts, packages/runtime-host/src/server/*, packages/runtime-host/src/__tests__/session-projector.test.ts, packages/runtime-host/src/__tests__/session-continuity-coordinator.test.ts
Projectors emit retry events. Session continuity stores, republishes, preserves, and clears retry metadata.
Localized retry presentation
packages/ui/src/chat-turn.tsx, packages/ui/src/conversation-copy.ts, packages/ui/src/styles.css
The UI renders retry information with localized reason labels and a warning banner.

Estimated code review effort: 4 (Complex) | ~45 minutes

Merge Risk:🟡 Moderate · up to d2666

Remounting during a provider retry can show a countdown longer than the actual remaining wait because the scheduled retry time is not preserved. This is a concrete user-visible correctness issue that should be fixed before merge.

Sequence Diagram(s)

sequenceDiagram
participant Provider
participant Runtime
participant RuntimeHost
participant UI
Provider->>Runtime: return rate-limit error
Runtime->>Runtime: parse Retry-After
Runtime->>RuntimeHost: provide retry metadata
RuntimeHost->>RuntimeHost: publish provider_retry event
RuntimeHost->>UI: project retry snapshot
UI->>UI: render localized warning banner
Loading

Possibly related PRs

Suggested reviewers:m4n5ter

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check nameStatusExplanation
Linked Issues check✅ PassedCheck skipped because no linked issues were found for this pull request.
Out of Scope Changes check✅ PassedCheck skipped because no linked issues were found for this pull request.
Ai Use Disclosure✅ PassedThe PR selects generative tooling and names Cursor Grok 4.5 with scope; all three introduced commits contain matching standalone Generated-by trailers.
Title check✅ PassedThe title clearly summarizes the two main changes: immediate failure for bare rate limits and visible retry waits.
Description check✅ PassedThe description includes the required summary, verification, AI-use selection, checklist, behavior change, evidence, and unrun checks.
✨ Finishing Touches 💡 1
🛠️ Fix failing CI checks 💡
  • Create stacked PR
  • Commit on current branch
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/runtime-rate-limit-requires-retry-after

Comment @coderabbitai help to get the list of available commands.

@Astro-Han
Astro-Han marked this pull request as ready for review August 16, 2026 10:28

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1


ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: af9b5f4d-87df-471c-86b7-6d7a4f3ac623

📥 Commits

Reviewing files that changed from the base of the PR and between 8b79a6d and 968aae0.

📒 Files selected for processing (21)
  • packages/core/src/agent-run.ts
  • packages/runtime-host/src/__tests__/canonical-session-projection.test.ts
  • packages/runtime-host/src/__tests__/protocol.test.ts
  • packages/runtime-host/src/__tests__/session-projector.test.ts
  • packages/runtime-host/src/adapter/session-projector.ts
  • packages/runtime-host/src/protocol/operations.ts
  • packages/runtime-host/src/protocol/turn.ts
  • packages/runtime-host/src/server/canonical-turn-snapshot.ts
  • packages/runtime/src/__tests__/model-adapter.test.ts
  • packages/runtime/src/__tests__/provider-error-classification.test.ts
  • packages/runtime/src/__tests__/provider-request-telemetry.test.ts
  • packages/runtime/src/__tests__/session-manager.test.ts
  • packages/runtime/src/agent-run.ts
  • packages/runtime/src/provider-error-classification.ts
  • packages/storage/src/agent-run-store.ts
  • packages/ui/src/__tests__/provider-retry-presentation.test.ts
  • packages/ui/src/chat-turn.tsx
  • packages/ui/src/conversation-copy.ts
  • packages/ui/src/index.ts
  • packages/ui/src/provider-retry-presentation.ts
  • packages/ui/src/styles.css

Included review availability: Your plan includes up to 3 reviews per rolling hour; 1 remains after this review.

Comment threadpackages/runtime/src/agent-run.ts Outdated
@Astro-Han
Astro-Hanforce-pushed the fix/runtime-rate-limit-requires-retry-after branch from 968aae0 to d2666f5CompareAugust 16, 2026 11:29

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1


ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 1c38e715-0bfe-4131-b811-131d2fbb9cd9

📥 Commits

Reviewing files that changed from the base of the PR and between 968aae0 and d2666f5.

📒 Files selected for processing (10)
  • packages/runtime-host/src/__tests__/protocol.test.ts
  • packages/runtime-host/src/__tests__/session-continuity-coordinator.test.ts
  • packages/runtime-host/src/__tests__/session-projector.test.ts
  • packages/runtime-host/src/adapter/session-projector.ts
  • packages/runtime-host/src/protocol/index.ts
  • packages/runtime-host/src/protocol/operations.ts
  • packages/runtime-host/src/protocol/turn.ts
  • packages/runtime-host/src/server/root-turn-coordinator.ts
  • packages/runtime-host/src/server/session-continuity-coordinator.ts
  • packages/ui/src/chat-turn.tsx
🚧 Files skipped from review as they are similar to previous changes (3)
  • packages/runtime-host/src/tests/protocol.test.ts
  • packages/ui/src/chat-turn.tsx
  • packages/runtime-host/src/protocol/turn.ts

Included review availability: Your plan includes up to 3 reviews per rolling hour; 2 remain after this review.

@Astro-Han
Astro-Hanforce-pushed the fix/runtime-rate-limit-requires-retry-after branch from d2666f5 to 3cc3de4CompareAugust 16, 2026 11:35
A bare 429, including OpenCode FreeUsageLimitError, is a quota or
throttle without a recovery time. Retrying it ten times only hid the
failure behind a three-minute empty wait. Keep automatic retries for
rate limits that name Retry-After, and leave network or 5xx retries
unchanged.
Generated-by: Cursor Grok 4.5
The live retry line used the same muted working-status treatment as
"thinking", so a 40-second rate-limit wait looked like a hang. Keep
the existing live providerRetry object, and render its reason plus
countdown through the shared Astryx Banner.
Generated-by: Cursor Grok 4.5
A provider retry is still not a conversation fact. Hold the current wait
on the in-memory Turn snapshot, publish it when it appears, and drop it
on the next content event so remount cannot resurrect a finished wait.
Generated-by: Cursor Grok 4.5
@Astro-Han
Astro-Hanforce-pushed the fix/runtime-rate-limit-requires-retry-after branch from 3cc3de4 to f8eb564CompareAugust 16, 2026 11:49
@Astro-Han
Astro-Han requested a review from M4n5terAugust 16, 2026 12:27

@M4n5terM4n5ter left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. The rate-limit classification, transient retry overlay lifecycle, protocol boundary, and UI presentation are coherent and well covered by tests.

@M4n5ter
M4n5ter merged commit c92d0a2 into mainAug 16, 2026
12 checks passed
@M4n5ter
M4n5ter deleted the fix/runtime-rate-limit-requires-retry-after branch August 16, 2026 12:51
Sign up for freeto 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.

2 participants

@Astro-Han@M4n5ter
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix: fail bare rate limits and show retry waits - #3115

Merged
M4n5ter merged 3 commits into
mainfrom
fix/runtime-rate-limit-requires-retry-after
Aug 16, 2026
Merged

fix: fail bare rate limits and show retry waits#3115
M4n5ter merged 3 commits into
mainfrom
fix/runtime-rate-limit-requires-retry-after

Conversation

@Astro-Han

@Astro-HanAstro-Han commented Aug 16, 2026

Copy link
Copy Markdown
Contributor

Summary

A bare 429, including OpenCode FreeUsageLimitError, was retried ten times and looked like a hang. Rate limits now fail immediately unless the provider names Retry-After. A real wait still is not a conversation fact: Host keeps the current overlay on the in-memory Turn snapshot, publishes it when it appears, and drops it on the next content event so remount cannot resurrect a finished wait. The chat shows that overlay as an Astryx warning Banner.

Before — a muted status row with no reason:

image

After — an Astryx warning Banner with the retry reason:

image

Verification

  • packages/runtime/src/__tests__/provider-error-classification.test.ts (retries a rate limit only when the provider names a retry delay)
  • packages/runtime/src/__tests__/session-manager.test.ts (provider retry progress reaches observers...)
  • packages/runtime-host/src/__tests__/session-continuity-coordinator.test.ts (keeps the current provider retry on the live Turn until the next content event)
  • packages/runtime-host/src/__tests__/session-projector.test.ts
  • packages/runtime-host/src/__tests__/protocol.test.ts
  • packages/runtime-host/src/__tests__/canonical-session-projection.test.ts
  • npm run format:check

Did not run repository-wide tests or a live Electron remount of a Retry-After wait.

AI use

  • Generative tooling made a substantive contribution

Tool(s) and scope:

Cursor Grok 4.5 diagnosed the hung session, shaped the change, and authored the commits.

Checklist

  • Tests cover the change and fail without it
  • Lint, format, typecheck and the affected suites pass locally

Does this PR entail a change in behavior?

  • Yes — described under Summary above

@coderabbitai

coderabbitaiBot commented Aug 16, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Problem solved

Bare 429 errors now fail immediately unless the provider supplies a valid Retry-After value. Provider retry waits remain visible in chat with a localized reason and countdown. Retry state survives session projection and remounts, then clears after the next content event.

Design

The PR extends the existing live Turn snapshot and session-continuity path. It does not create a separate retry-state path. The provider_retry event updates canonical turn state, projects it to subscribers, and preserves it during session reopening.

The added protocol validation, event handling, projection logic, and UI presentation form the smallest coherent solution for persistence, remount behavior, and user feedback. The added complexity is required to distinguish scheduled retries from completed content and to prevent stale retry state from returning.

No safe deletion or simplification is evident from the current diff. The new tests cover protocol decoding, projection, continuity, error classification, telemetry, and UI-facing behavior.

Validation and risks

Coverage was added or updated for runtime, runtime-host, session projection, session continuity, protocol compatibility, retry classification, telemetry, and formatting. The runtime-host compatibility epoch increased from 20 to 21.

Repository-wide tests were not run. A live Electron remount was not verified. Required checks therefore remain unverified without direct check results.

Review-relevant risks

  • User-visible behavior changes because retry errors, reasons, countdowns, and warning banners now appear differently. Material UI behavior changes require independent human review under repository policy.
  • Provider retry classification changes because bare 429 errors are no longer retryable. Material runtime behavior changes require independent human review under repository policy.
  • The runtime-host protocol changes through new TurnProviderRetry and LiveTurnSnapshot types, validation rules, and compatibility epoch 21. Material public-contract and release-compatibility changes require independent human review under repository policy.
  • No security, licensing, or governance effect was identified in the current diff.
  • The person performing the merge must review the final diff. A maintainer makes the final determination.

Walkthrough

The PR makes rate-limit retries conditional on valid Retry-After data. It adds validated provider-retry state to runtime-host snapshots, persists retry events across session continuity, and renders localized retry banners in the UI.

Changes

Provider retry flow

Layer / File(s)Summary
Rate-limit retry classification
packages/runtime/src/provider-error-classification.ts, packages/runtime/src/__tests__/*
Rate-limit errors retry only when a valid delay exists. Tests update retryability and diagnostic expectations.
Retry snapshot protocol
packages/runtime-host/src/protocol/turn.ts, packages/runtime-host/src/protocol/operations.ts, packages/runtime-host/src/protocol/index.ts, packages/runtime-host/src/__tests__/protocol.test.ts
Turn snapshots support validated provider retry metadata. The compatibility epoch changes to 21.
Provider retry projection persistence
packages/runtime-host/src/adapter/session-projector.ts, packages/runtime-host/src/server/*, packages/runtime-host/src/__tests__/session-projector.test.ts, packages/runtime-host/src/__tests__/session-continuity-coordinator.test.ts
Projectors emit retry events. Session continuity stores, republishes, preserves, and clears retry metadata.
Localized retry presentation
packages/ui/src/chat-turn.tsx, packages/ui/src/conversation-copy.ts, packages/ui/src/styles.css
The UI renders retry information with localized reason labels and a warning banner.

Estimated code review effort: 4 (Complex) | ~45 minutes

Merge Risk:🟡 Moderate · up to d2666

Remounting during a provider retry can show a countdown longer than the actual remaining wait because the scheduled retry time is not preserved. This is a concrete user-visible correctness issue that should be fixed before merge.

Sequence Diagram(s)

sequenceDiagram
participant Provider
participant Runtime
participant RuntimeHost
participant UI
Provider->>Runtime: return rate-limit error
Runtime->>Runtime: parse Retry-After
Runtime->>RuntimeHost: provide retry metadata
RuntimeHost->>RuntimeHost: publish provider_retry event
RuntimeHost->>UI: project retry snapshot
UI->>UI: render localized warning banner
Loading

Possibly related PRs

Suggested reviewers:m4n5ter

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check nameStatusExplanation
Linked Issues check✅ PassedCheck skipped because no linked issues were found for this pull request.
Out of Scope Changes check✅ PassedCheck skipped because no linked issues were found for this pull request.
Ai Use Disclosure✅ PassedThe PR selects generative tooling and names Cursor Grok 4.5 with scope; all three introduced commits contain matching standalone Generated-by trailers.
Title check✅ PassedThe title clearly summarizes the two main changes: immediate failure for bare rate limits and visible retry waits.
Description check✅ PassedThe description includes the required summary, verification, AI-use selection, checklist, behavior change, evidence, and unrun checks.
✨ Finishing Touches 💡 1
🛠️ Fix failing CI checks 💡
  • Create stacked PR
  • Commit on current branch
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/runtime-rate-limit-requires-retry-after

Comment @coderabbitai help to get the list of available commands.

@Astro-Han
Astro-Han marked this pull request as ready for review August 16, 2026 10:28

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1


ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: af9b5f4d-87df-471c-86b7-6d7a4f3ac623

📥 Commits

Reviewing files that changed from the base of the PR and between 8b79a6d and 968aae0.

📒 Files selected for processing (21)
  • packages/core/src/agent-run.ts
  • packages/runtime-host/src/__tests__/canonical-session-projection.test.ts
  • packages/runtime-host/src/__tests__/protocol.test.ts
  • packages/runtime-host/src/__tests__/session-projector.test.ts
  • packages/runtime-host/src/adapter/session-projector.ts
  • packages/runtime-host/src/protocol/operations.ts
  • packages/runtime-host/src/protocol/turn.ts
  • packages/runtime-host/src/server/canonical-turn-snapshot.ts
  • packages/runtime/src/__tests__/model-adapter.test.ts
  • packages/runtime/src/__tests__/provider-error-classification.test.ts
  • packages/runtime/src/__tests__/provider-request-telemetry.test.ts
  • packages/runtime/src/__tests__/session-manager.test.ts
  • packages/runtime/src/agent-run.ts
  • packages/runtime/src/provider-error-classification.ts
  • packages/storage/src/agent-run-store.ts
  • packages/ui/src/__tests__/provider-retry-presentation.test.ts
  • packages/ui/src/chat-turn.tsx
  • packages/ui/src/conversation-copy.ts
  • packages/ui/src/index.ts
  • packages/ui/src/provider-retry-presentation.ts
  • packages/ui/src/styles.css

Included review availability: Your plan includes up to 3 reviews per rolling hour; 1 remains after this review.

Comment threadpackages/runtime/src/agent-run.ts Outdated
@Astro-Han
Astro-Hanforce-pushed the fix/runtime-rate-limit-requires-retry-after branch from 968aae0 to d2666f5CompareAugust 16, 2026 11:29

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1


ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 1c38e715-0bfe-4131-b811-131d2fbb9cd9

📥 Commits

Reviewing files that changed from the base of the PR and between 968aae0 and d2666f5.

📒 Files selected for processing (10)
  • packages/runtime-host/src/__tests__/protocol.test.ts
  • packages/runtime-host/src/__tests__/session-continuity-coordinator.test.ts
  • packages/runtime-host/src/__tests__/session-projector.test.ts
  • packages/runtime-host/src/adapter/session-projector.ts
  • packages/runtime-host/src/protocol/index.ts
  • packages/runtime-host/src/protocol/operations.ts
  • packages/runtime-host/src/protocol/turn.ts
  • packages/runtime-host/src/server/root-turn-coordinator.ts
  • packages/runtime-host/src/server/session-continuity-coordinator.ts
  • packages/ui/src/chat-turn.tsx
🚧 Files skipped from review as they are similar to previous changes (3)
  • packages/runtime-host/src/tests/protocol.test.ts
  • packages/ui/src/chat-turn.tsx
  • packages/runtime-host/src/protocol/turn.ts

Included review availability: Your plan includes up to 3 reviews per rolling hour; 2 remain after this review.

@Astro-Han
Astro-Hanforce-pushed the fix/runtime-rate-limit-requires-retry-after branch from d2666f5 to 3cc3de4CompareAugust 16, 2026 11:35
A bare 429, including OpenCode FreeUsageLimitError, is a quota or
throttle without a recovery time. Retrying it ten times only hid the
failure behind a three-minute empty wait. Keep automatic retries for
rate limits that name Retry-After, and leave network or 5xx retries
unchanged.
Generated-by: Cursor Grok 4.5
The live retry line used the same muted working-status treatment as
"thinking", so a 40-second rate-limit wait looked like a hang. Keep
the existing live providerRetry object, and render its reason plus
countdown through the shared Astryx Banner.
Generated-by: Cursor Grok 4.5
A provider retry is still not a conversation fact. Hold the current wait
on the in-memory Turn snapshot, publish it when it appears, and drop it
on the next content event so remount cannot resurrect a finished wait.
Generated-by: Cursor Grok 4.5
@Astro-Han
Astro-Hanforce-pushed the fix/runtime-rate-limit-requires-retry-after branch from 3cc3de4 to f8eb564CompareAugust 16, 2026 11:49
@Astro-Han
Astro-Han requested a review from M4n5terAugust 16, 2026 12:27

@M4n5terM4n5ter left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. The rate-limit classification, transient retry overlay lifecycle, protocol boundary, and UI presentation are coherent and well covered by tests.

@M4n5ter
M4n5ter merged commit c92d0a2 into mainAug 16, 2026
12 checks passed
@M4n5ter
M4n5ter deleted the fix/runtime-rate-limit-requires-retry-after branch August 16, 2026 12:51
Sign up for freeto 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.

2 participants

@Astro-Han@M4n5ter
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix: fail bare rate limits and show retry waits - #3115

Merged
M4n5ter merged 3 commits into
mainfrom
fix/runtime-rate-limit-requires-retry-after
Aug 16, 2026
Merged

fix: fail bare rate limits and show retry waits#3115
M4n5ter merged 3 commits into
mainfrom
fix/runtime-rate-limit-requires-retry-after

Conversation

@Astro-Han

@Astro-HanAstro-Han commented Aug 16, 2026

Copy link
Copy Markdown
Contributor

Summary

A bare 429, including OpenCode FreeUsageLimitError, was retried ten times and looked like a hang. Rate limits now fail immediately unless the provider names Retry-After. A real wait still is not a conversation fact: Host keeps the current overlay on the in-memory Turn snapshot, publishes it when it appears, and drops it on the next content event so remount cannot resurrect a finished wait. The chat shows that overlay as an Astryx warning Banner.

Before — a muted status row with no reason:

image

After — an Astryx warning Banner with the retry reason:

image

Verification

  • packages/runtime/src/__tests__/provider-error-classification.test.ts (retries a rate limit only when the provider names a retry delay)
  • packages/runtime/src/__tests__/session-manager.test.ts (provider retry progress reaches observers...)
  • packages/runtime-host/src/__tests__/session-continuity-coordinator.test.ts (keeps the current provider retry on the live Turn until the next content event)
  • packages/runtime-host/src/__tests__/session-projector.test.ts
  • packages/runtime-host/src/__tests__/protocol.test.ts
  • packages/runtime-host/src/__tests__/canonical-session-projection.test.ts
  • npm run format:check

Did not run repository-wide tests or a live Electron remount of a Retry-After wait.

AI use

  • Generative tooling made a substantive contribution

Tool(s) and scope:

Cursor Grok 4.5 diagnosed the hung session, shaped the change, and authored the commits.

Checklist

  • Tests cover the change and fail without it
  • Lint, format, typecheck and the affected suites pass locally

Does this PR entail a change in behavior?

  • Yes — described under Summary above

@coderabbitai

coderabbitaiBot commented Aug 16, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Problem solved

Bare 429 errors now fail immediately unless the provider supplies a valid Retry-After value. Provider retry waits remain visible in chat with a localized reason and countdown. Retry state survives session projection and remounts, then clears after the next content event.

Design

The PR extends the existing live Turn snapshot and session-continuity path. It does not create a separate retry-state path. The provider_retry event updates canonical turn state, projects it to subscribers, and preserves it during session reopening.

The added protocol validation, event handling, projection logic, and UI presentation form the smallest coherent solution for persistence, remount behavior, and user feedback. The added complexity is required to distinguish scheduled retries from completed content and to prevent stale retry state from returning.

No safe deletion or simplification is evident from the current diff. The new tests cover protocol decoding, projection, continuity, error classification, telemetry, and UI-facing behavior.

Validation and risks

Coverage was added or updated for runtime, runtime-host, session projection, session continuity, protocol compatibility, retry classification, telemetry, and formatting. The runtime-host compatibility epoch increased from 20 to 21.

Repository-wide tests were not run. A live Electron remount was not verified. Required checks therefore remain unverified without direct check results.

Review-relevant risks

  • User-visible behavior changes because retry errors, reasons, countdowns, and warning banners now appear differently. Material UI behavior changes require independent human review under repository policy.
  • Provider retry classification changes because bare 429 errors are no longer retryable. Material runtime behavior changes require independent human review under repository policy.
  • The runtime-host protocol changes through new TurnProviderRetry and LiveTurnSnapshot types, validation rules, and compatibility epoch 21. Material public-contract and release-compatibility changes require independent human review under repository policy.
  • No security, licensing, or governance effect was identified in the current diff.
  • The person performing the merge must review the final diff. A maintainer makes the final determination.

Walkthrough

The PR makes rate-limit retries conditional on valid Retry-After data. It adds validated provider-retry state to runtime-host snapshots, persists retry events across session continuity, and renders localized retry banners in the UI.

Changes

Provider retry flow

Layer / File(s)Summary
Rate-limit retry classification
packages/runtime/src/provider-error-classification.ts, packages/runtime/src/__tests__/*
Rate-limit errors retry only when a valid delay exists. Tests update retryability and diagnostic expectations.
Retry snapshot protocol
packages/runtime-host/src/protocol/turn.ts, packages/runtime-host/src/protocol/operations.ts, packages/runtime-host/src/protocol/index.ts, packages/runtime-host/src/__tests__/protocol.test.ts
Turn snapshots support validated provider retry metadata. The compatibility epoch changes to 21.
Provider retry projection persistence
packages/runtime-host/src/adapter/session-projector.ts, packages/runtime-host/src/server/*, packages/runtime-host/src/__tests__/session-projector.test.ts, packages/runtime-host/src/__tests__/session-continuity-coordinator.test.ts
Projectors emit retry events. Session continuity stores, republishes, preserves, and clears retry metadata.
Localized retry presentation
packages/ui/src/chat-turn.tsx, packages/ui/src/conversation-copy.ts, packages/ui/src/styles.css
The UI renders retry information with localized reason labels and a warning banner.

Estimated code review effort: 4 (Complex) | ~45 minutes

Merge Risk:🟡 Moderate · up to d2666

Remounting during a provider retry can show a countdown longer than the actual remaining wait because the scheduled retry time is not preserved. This is a concrete user-visible correctness issue that should be fixed before merge.

Sequence Diagram(s)

sequenceDiagram
participant Provider
participant Runtime
participant RuntimeHost
participant UI
Provider->>Runtime: return rate-limit error
Runtime->>Runtime: parse Retry-After
Runtime->>RuntimeHost: provide retry metadata
RuntimeHost->>RuntimeHost: publish provider_retry event
RuntimeHost->>UI: project retry snapshot
UI->>UI: render localized warning banner
Loading

Possibly related PRs

Suggested reviewers:m4n5ter

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check nameStatusExplanation
Linked Issues check✅ PassedCheck skipped because no linked issues were found for this pull request.
Out of Scope Changes check✅ PassedCheck skipped because no linked issues were found for this pull request.
Ai Use Disclosure✅ PassedThe PR selects generative tooling and names Cursor Grok 4.5 with scope; all three introduced commits contain matching standalone Generated-by trailers.
Title check✅ PassedThe title clearly summarizes the two main changes: immediate failure for bare rate limits and visible retry waits.
Description check✅ PassedThe description includes the required summary, verification, AI-use selection, checklist, behavior change, evidence, and unrun checks.
✨ Finishing Touches 💡 1
🛠️ Fix failing CI checks 💡
  • Create stacked PR
  • Commit on current branch
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/runtime-rate-limit-requires-retry-after

Comment @coderabbitai help to get the list of available commands.

@Astro-Han
Astro-Han marked this pull request as ready for review August 16, 2026 10:28

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1


ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: af9b5f4d-87df-471c-86b7-6d7a4f3ac623

📥 Commits

Reviewing files that changed from the base of the PR and between 8b79a6d and 968aae0.

📒 Files selected for processing (21)
  • packages/core/src/agent-run.ts
  • packages/runtime-host/src/__tests__/canonical-session-projection.test.ts
  • packages/runtime-host/src/__tests__/protocol.test.ts
  • packages/runtime-host/src/__tests__/session-projector.test.ts
  • packages/runtime-host/src/adapter/session-projector.ts
  • packages/runtime-host/src/protocol/operations.ts
  • packages/runtime-host/src/protocol/turn.ts
  • packages/runtime-host/src/server/canonical-turn-snapshot.ts
  • packages/runtime/src/__tests__/model-adapter.test.ts
  • packages/runtime/src/__tests__/provider-error-classification.test.ts
  • packages/runtime/src/__tests__/provider-request-telemetry.test.ts
  • packages/runtime/src/__tests__/session-manager.test.ts
  • packages/runtime/src/agent-run.ts
  • packages/runtime/src/provider-error-classification.ts
  • packages/storage/src/agent-run-store.ts
  • packages/ui/src/__tests__/provider-retry-presentation.test.ts
  • packages/ui/src/chat-turn.tsx
  • packages/ui/src/conversation-copy.ts
  • packages/ui/src/index.ts
  • packages/ui/src/provider-retry-presentation.ts
  • packages/ui/src/styles.css

Included review availability: Your plan includes up to 3 reviews per rolling hour; 1 remains after this review.

Comment threadpackages/runtime/src/agent-run.ts Outdated
@Astro-Han
Astro-Hanforce-pushed the fix/runtime-rate-limit-requires-retry-after branch from 968aae0 to d2666f5CompareAugust 16, 2026 11:29

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1


ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 1c38e715-0bfe-4131-b811-131d2fbb9cd9

📥 Commits

Reviewing files that changed from the base of the PR and between 968aae0 and d2666f5.

📒 Files selected for processing (10)
  • packages/runtime-host/src/__tests__/protocol.test.ts
  • packages/runtime-host/src/__tests__/session-continuity-coordinator.test.ts
  • packages/runtime-host/src/__tests__/session-projector.test.ts
  • packages/runtime-host/src/adapter/session-projector.ts
  • packages/runtime-host/src/protocol/index.ts
  • packages/runtime-host/src/protocol/operations.ts
  • packages/runtime-host/src/protocol/turn.ts
  • packages/runtime-host/src/server/root-turn-coordinator.ts
  • packages/runtime-host/src/server/session-continuity-coordinator.ts
  • packages/ui/src/chat-turn.tsx
🚧 Files skipped from review as they are similar to previous changes (3)
  • packages/runtime-host/src/tests/protocol.test.ts
  • packages/ui/src/chat-turn.tsx
  • packages/runtime-host/src/protocol/turn.ts

Included review availability: Your plan includes up to 3 reviews per rolling hour; 2 remain after this review.

@Astro-Han
Astro-Hanforce-pushed the fix/runtime-rate-limit-requires-retry-after branch from d2666f5 to 3cc3de4CompareAugust 16, 2026 11:35
A bare 429, including OpenCode FreeUsageLimitError, is a quota or
throttle without a recovery time. Retrying it ten times only hid the
failure behind a three-minute empty wait. Keep automatic retries for
rate limits that name Retry-After, and leave network or 5xx retries
unchanged.
Generated-by: Cursor Grok 4.5
The live retry line used the same muted working-status treatment as
"thinking", so a 40-second rate-limit wait looked like a hang. Keep
the existing live providerRetry object, and render its reason plus
countdown through the shared Astryx Banner.
Generated-by: Cursor Grok 4.5
A provider retry is still not a conversation fact. Hold the current wait
on the in-memory Turn snapshot, publish it when it appears, and drop it
on the next content event so remount cannot resurrect a finished wait.
Generated-by: Cursor Grok 4.5
@Astro-Han
Astro-Hanforce-pushed the fix/runtime-rate-limit-requires-retry-after branch from 3cc3de4 to f8eb564CompareAugust 16, 2026 11:49
@Astro-Han
Astro-Han requested a review from M4n5terAugust 16, 2026 12:27

@M4n5terM4n5ter left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. The rate-limit classification, transient retry overlay lifecycle, protocol boundary, and UI presentation are coherent and well covered by tests.

@M4n5ter
M4n5ter merged commit c92d0a2 into mainAug 16, 2026
12 checks passed
@M4n5ter
M4n5ter deleted the fix/runtime-rate-limit-requires-retry-after branch August 16, 2026 12:51
Sign up for freeto 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.

2 participants

@Astro-Han@M4n5ter
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

fix: fail bare rate limits and show retry waits - #3115

Merged
M4n5ter merged 3 commits into
mainfrom
fix/runtime-rate-limit-requires-retry-after
Aug 16, 2026
Merged

fix: fail bare rate limits and show retry waits#3115
M4n5ter merged 3 commits into
mainfrom
fix/runtime-rate-limit-requires-retry-after

Conversation

@Astro-Han

@Astro-HanAstro-Han commented Aug 16, 2026

Copy link
Copy Markdown
Contributor

Summary

A bare 429, including OpenCode FreeUsageLimitError, was retried ten times and looked like a hang. Rate limits now fail immediately unless the provider names Retry-After. A real wait still is not a conversation fact: Host keeps the current overlay on the in-memory Turn snapshot, publishes it when it appears, and drops it on the next content event so remount cannot resurrect a finished wait. The chat shows that overlay as an Astryx warning Banner.

Before — a muted status row with no reason:

image

After — an Astryx warning Banner with the retry reason:

image

Verification

  • packages/runtime/src/__tests__/provider-error-classification.test.ts (retries a rate limit only when the provider names a retry delay)
  • packages/runtime/src/__tests__/session-manager.test.ts (provider retry progress reaches observers...)
  • packages/runtime-host/src/__tests__/session-continuity-coordinator.test.ts (keeps the current provider retry on the live Turn until the next content event)
  • packages/runtime-host/src/__tests__/session-projector.test.ts
  • packages/runtime-host/src/__tests__/protocol.test.ts
  • packages/runtime-host/src/__tests__/canonical-session-projection.test.ts
  • npm run format:check

Did not run repository-wide tests or a live Electron remount of a Retry-After wait.

AI use

  • Generative tooling made a substantive contribution

Tool(s) and scope:

Cursor Grok 4.5 diagnosed the hung session, shaped the change, and authored the commits.

Checklist

  • Tests cover the change and fail without it
  • Lint, format, typecheck and the affected suites pass locally

Does this PR entail a change in behavior?

  • Yes — described under Summary above

@coderabbitai

coderabbitaiBot commented Aug 16, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Problem solved

Bare 429 errors now fail immediately unless the provider supplies a valid Retry-After value. Provider retry waits remain visible in chat with a localized reason and countdown. Retry state survives session projection and remounts, then clears after the next content event.

Design

The PR extends the existing live Turn snapshot and session-continuity path. It does not create a separate retry-state path. The provider_retry event updates canonical turn state, projects it to subscribers, and preserves it during session reopening.

The added protocol validation, event handling, projection logic, and UI presentation form the smallest coherent solution for persistence, remount behavior, and user feedback. The added complexity is required to distinguish scheduled retries from completed content and to prevent stale retry state from returning.

No safe deletion or simplification is evident from the current diff. The new tests cover protocol decoding, projection, continuity, error classification, telemetry, and UI-facing behavior.

Validation and risks

Coverage was added or updated for runtime, runtime-host, session projection, session continuity, protocol compatibility, retry classification, telemetry, and formatting. The runtime-host compatibility epoch increased from 20 to 21.

Repository-wide tests were not run. A live Electron remount was not verified. Required checks therefore remain unverified without direct check results.

Review-relevant risks

  • User-visible behavior changes because retry errors, reasons, countdowns, and warning banners now appear differently. Material UI behavior changes require independent human review under repository policy.
  • Provider retry classification changes because bare 429 errors are no longer retryable. Material runtime behavior changes require independent human review under repository policy.
  • The runtime-host protocol changes through new TurnProviderRetry and LiveTurnSnapshot types, validation rules, and compatibility epoch 21. Material public-contract and release-compatibility changes require independent human review under repository policy.
  • No security, licensing, or governance effect was identified in the current diff.
  • The person performing the merge must review the final diff. A maintainer makes the final determination.

Walkthrough

The PR makes rate-limit retries conditional on valid Retry-After data. It adds validated provider-retry state to runtime-host snapshots, persists retry events across session continuity, and renders localized retry banners in the UI.

Changes

Provider retry flow

Layer / File(s)Summary
Rate-limit retry classification
packages/runtime/src/provider-error-classification.ts, packages/runtime/src/__tests__/*
Rate-limit errors retry only when a valid delay exists. Tests update retryability and diagnostic expectations.
Retry snapshot protocol
packages/runtime-host/src/protocol/turn.ts, packages/runtime-host/src/protocol/operations.ts, packages/runtime-host/src/protocol/index.ts, packages/runtime-host/src/__tests__/protocol.test.ts
Turn snapshots support validated provider retry metadata. The compatibility epoch changes to 21.
Provider retry projection persistence
packages/runtime-host/src/adapter/session-projector.ts, packages/runtime-host/src/server/*, packages/runtime-host/src/__tests__/session-projector.test.ts, packages/runtime-host/src/__tests__/session-continuity-coordinator.test.ts
Projectors emit retry events. Session continuity stores, republishes, preserves, and clears retry metadata.
Localized retry presentation
packages/ui/src/chat-turn.tsx, packages/ui/src/conversation-copy.ts, packages/ui/src/styles.css
The UI renders retry information with localized reason labels and a warning banner.

Estimated code review effort: 4 (Complex) | ~45 minutes

Merge Risk:🟡 Moderate · up to d2666

Remounting during a provider retry can show a countdown longer than the actual remaining wait because the scheduled retry time is not preserved. This is a concrete user-visible correctness issue that should be fixed before merge.

Sequence Diagram(s)

sequenceDiagram
participant Provider
participant Runtime
participant RuntimeHost
participant UI
Provider->>Runtime: return rate-limit error
Runtime->>Runtime: parse Retry-After
Runtime->>RuntimeHost: provide retry metadata
RuntimeHost->>RuntimeHost: publish provider_retry event
RuntimeHost->>UI: project retry snapshot
UI->>UI: render localized warning banner
Loading

Possibly related PRs

Suggested reviewers:m4n5ter

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check nameStatusExplanation
Linked Issues check✅ PassedCheck skipped because no linked issues were found for this pull request.
Out of Scope Changes check✅ PassedCheck skipped because no linked issues were found for this pull request.
Ai Use Disclosure✅ PassedThe PR selects generative tooling and names Cursor Grok 4.5 with scope; all three introduced commits contain matching standalone Generated-by trailers.
Title check✅ PassedThe title clearly summarizes the two main changes: immediate failure for bare rate limits and visible retry waits.
Description check✅ PassedThe description includes the required summary, verification, AI-use selection, checklist, behavior change, evidence, and unrun checks.
✨ Finishing Touches 💡 1
🛠️ Fix failing CI checks 💡
  • Create stacked PR
  • Commit on current branch
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/runtime-rate-limit-requires-retry-after

Comment @coderabbitai help to get the list of available commands.

@Astro-Han
Astro-Han marked this pull request as ready for review August 16, 2026 10:28

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1


ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: af9b5f4d-87df-471c-86b7-6d7a4f3ac623

📥 Commits

Reviewing files that changed from the base of the PR and between 8b79a6d and 968aae0.

📒 Files selected for processing (21)
  • packages/core/src/agent-run.ts
  • packages/runtime-host/src/__tests__/canonical-session-projection.test.ts
  • packages/runtime-host/src/__tests__/protocol.test.ts
  • packages/runtime-host/src/__tests__/session-projector.test.ts
  • packages/runtime-host/src/adapter/session-projector.ts
  • packages/runtime-host/src/protocol/operations.ts
  • packages/runtime-host/src/protocol/turn.ts
  • packages/runtime-host/src/server/canonical-turn-snapshot.ts
  • packages/runtime/src/__tests__/model-adapter.test.ts
  • packages/runtime/src/__tests__/provider-error-classification.test.ts
  • packages/runtime/src/__tests__/provider-request-telemetry.test.ts
  • packages/runtime/src/__tests__/session-manager.test.ts
  • packages/runtime/src/agent-run.ts
  • packages/runtime/src/provider-error-classification.ts
  • packages/storage/src/agent-run-store.ts
  • packages/ui/src/__tests__/provider-retry-presentation.test.ts
  • packages/ui/src/chat-turn.tsx
  • packages/ui/src/conversation-copy.ts
  • packages/ui/src/index.ts
  • packages/ui/src/provider-retry-presentation.ts
  • packages/ui/src/styles.css

Included review availability: Your plan includes up to 3 reviews per rolling hour; 1 remains after this review.

Comment threadpackages/runtime/src/agent-run.ts Outdated
@Astro-Han
Astro-Hanforce-pushed the fix/runtime-rate-limit-requires-retry-after branch from 968aae0 to d2666f5CompareAugust 16, 2026 11:29

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1


ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 1c38e715-0bfe-4131-b811-131d2fbb9cd9

📥 Commits

Reviewing files that changed from the base of the PR and between 968aae0 and d2666f5.

📒 Files selected for processing (10)
  • packages/runtime-host/src/__tests__/protocol.test.ts
  • packages/runtime-host/src/__tests__/session-continuity-coordinator.test.ts
  • packages/runtime-host/src/__tests__/session-projector.test.ts
  • packages/runtime-host/src/adapter/session-projector.ts
  • packages/runtime-host/src/protocol/index.ts
  • packages/runtime-host/src/protocol/operations.ts
  • packages/runtime-host/src/protocol/turn.ts
  • packages/runtime-host/src/server/root-turn-coordinator.ts
  • packages/runtime-host/src/server/session-continuity-coordinator.ts
  • packages/ui/src/chat-turn.tsx
🚧 Files skipped from review as they are similar to previous changes (3)
  • packages/runtime-host/src/tests/protocol.test.ts
  • packages/ui/src/chat-turn.tsx
  • packages/runtime-host/src/protocol/turn.ts

Included review availability: Your plan includes up to 3 reviews per rolling hour; 2 remain after this review.

@Astro-Han
Astro-Hanforce-pushed the fix/runtime-rate-limit-requires-retry-after branch from d2666f5 to 3cc3de4CompareAugust 16, 2026 11:35
A bare 429, including OpenCode FreeUsageLimitError, is a quota or
throttle without a recovery time. Retrying it ten times only hid the
failure behind a three-minute empty wait. Keep automatic retries for
rate limits that name Retry-After, and leave network or 5xx retries
unchanged.
Generated-by: Cursor Grok 4.5
The live retry line used the same muted working-status treatment as
"thinking", so a 40-second rate-limit wait looked like a hang. Keep
the existing live providerRetry object, and render its reason plus
countdown through the shared Astryx Banner.
Generated-by: Cursor Grok 4.5
A provider retry is still not a conversation fact. Hold the current wait
on the in-memory Turn snapshot, publish it when it appears, and drop it
on the next content event so remount cannot resurrect a finished wait.
Generated-by: Cursor Grok 4.5
@Astro-Han
Astro-Hanforce-pushed the fix/runtime-rate-limit-requires-retry-after branch from 3cc3de4 to f8eb564CompareAugust 16, 2026 11:49
@Astro-Han
Astro-Han requested a review from M4n5terAugust 16, 2026 12:27

@M4n5terM4n5ter left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. The rate-limit classification, transient retry overlay lifecycle, protocol boundary, and UI presentation are coherent and well covered by tests.

@M4n5ter
M4n5ter merged commit c92d0a2 into mainAug 16, 2026
12 checks passed
@M4n5ter
M4n5ter deleted the fix/runtime-rate-limit-requires-retry-after branch August 16, 2026 12:51
Sign up for freeto 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.

2 participants

@Astro-Han@M4n5ter
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix: fail bare rate limits and show retry waits - #3115

Merged
M4n5ter merged 3 commits into
mainfrom
fix/runtime-rate-limit-requires-retry-after
Aug 16, 2026
Merged

fix: fail bare rate limits and show retry waits#3115
M4n5ter merged 3 commits into
mainfrom
fix/runtime-rate-limit-requires-retry-after

Conversation

@Astro-Han

@Astro-HanAstro-Han commented Aug 16, 2026

Copy link
Copy Markdown
Contributor

Summary

A bare 429, including OpenCode FreeUsageLimitError, was retried ten times and looked like a hang. Rate limits now fail immediately unless the provider names Retry-After. A real wait still is not a conversation fact: Host keeps the current overlay on the in-memory Turn snapshot, publishes it when it appears, and drops it on the next content event so remount cannot resurrect a finished wait. The chat shows that overlay as an Astryx warning Banner.

Before — a muted status row with no reason:

image

After — an Astryx warning Banner with the retry reason:

image

Verification

  • packages/runtime/src/__tests__/provider-error-classification.test.ts (retries a rate limit only when the provider names a retry delay)
  • packages/runtime/src/__tests__/session-manager.test.ts (provider retry progress reaches observers...)
  • packages/runtime-host/src/__tests__/session-continuity-coordinator.test.ts (keeps the current provider retry on the live Turn until the next content event)
  • packages/runtime-host/src/__tests__/session-projector.test.ts
  • packages/runtime-host/src/__tests__/protocol.test.ts
  • packages/runtime-host/src/__tests__/canonical-session-projection.test.ts
  • npm run format:check

Did not run repository-wide tests or a live Electron remount of a Retry-After wait.

AI use

  • Generative tooling made a substantive contribution

Tool(s) and scope:

Cursor Grok 4.5 diagnosed the hung session, shaped the change, and authored the commits.

Checklist

  • Tests cover the change and fail without it
  • Lint, format, typecheck and the affected suites pass locally

Does this PR entail a change in behavior?

  • Yes — described under Summary above

@coderabbitai

coderabbitaiBot commented Aug 16, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Problem solved

Bare 429 errors now fail immediately unless the provider supplies a valid Retry-After value. Provider retry waits remain visible in chat with a localized reason and countdown. Retry state survives session projection and remounts, then clears after the next content event.

Design

The PR extends the existing live Turn snapshot and session-continuity path. It does not create a separate retry-state path. The provider_retry event updates canonical turn state, projects it to subscribers, and preserves it during session reopening.

The added protocol validation, event handling, projection logic, and UI presentation form the smallest coherent solution for persistence, remount behavior, and user feedback. The added complexity is required to distinguish scheduled retries from completed content and to prevent stale retry state from returning.

No safe deletion or simplification is evident from the current diff. The new tests cover protocol decoding, projection, continuity, error classification, telemetry, and UI-facing behavior.

Validation and risks

Coverage was added or updated for runtime, runtime-host, session projection, session continuity, protocol compatibility, retry classification, telemetry, and formatting. The runtime-host compatibility epoch increased from 20 to 21.

Repository-wide tests were not run. A live Electron remount was not verified. Required checks therefore remain unverified without direct check results.

Review-relevant risks

  • User-visible behavior changes because retry errors, reasons, countdowns, and warning banners now appear differently. Material UI behavior changes require independent human review under repository policy.
  • Provider retry classification changes because bare 429 errors are no longer retryable. Material runtime behavior changes require independent human review under repository policy.
  • The runtime-host protocol changes through new TurnProviderRetry and LiveTurnSnapshot types, validation rules, and compatibility epoch 21. Material public-contract and release-compatibility changes require independent human review under repository policy.
  • No security, licensing, or governance effect was identified in the current diff.
  • The person performing the merge must review the final diff. A maintainer makes the final determination.

Walkthrough

The PR makes rate-limit retries conditional on valid Retry-After data. It adds validated provider-retry state to runtime-host snapshots, persists retry events across session continuity, and renders localized retry banners in the UI.

Changes

Provider retry flow

Layer / File(s)Summary
Rate-limit retry classification
packages/runtime/src/provider-error-classification.ts, packages/runtime/src/__tests__/*
Rate-limit errors retry only when a valid delay exists. Tests update retryability and diagnostic expectations.
Retry snapshot protocol
packages/runtime-host/src/protocol/turn.ts, packages/runtime-host/src/protocol/operations.ts, packages/runtime-host/src/protocol/index.ts, packages/runtime-host/src/__tests__/protocol.test.ts
Turn snapshots support validated provider retry metadata. The compatibility epoch changes to 21.
Provider retry projection persistence
packages/runtime-host/src/adapter/session-projector.ts, packages/runtime-host/src/server/*, packages/runtime-host/src/__tests__/session-projector.test.ts, packages/runtime-host/src/__tests__/session-continuity-coordinator.test.ts
Projectors emit retry events. Session continuity stores, republishes, preserves, and clears retry metadata.
Localized retry presentation
packages/ui/src/chat-turn.tsx, packages/ui/src/conversation-copy.ts, packages/ui/src/styles.css
The UI renders retry information with localized reason labels and a warning banner.

Estimated code review effort: 4 (Complex) | ~45 minutes

Merge Risk:🟡 Moderate · up to d2666

Remounting during a provider retry can show a countdown longer than the actual remaining wait because the scheduled retry time is not preserved. This is a concrete user-visible correctness issue that should be fixed before merge.

Sequence Diagram(s)

sequenceDiagram
participant Provider
participant Runtime
participant RuntimeHost
participant UI
Provider->>Runtime: return rate-limit error
Runtime->>Runtime: parse Retry-After
Runtime->>RuntimeHost: provide retry metadata
RuntimeHost->>RuntimeHost: publish provider_retry event
RuntimeHost->>UI: project retry snapshot
UI->>UI: render localized warning banner
Loading

Possibly related PRs

Suggested reviewers:m4n5ter

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check nameStatusExplanation
Linked Issues check✅ PassedCheck skipped because no linked issues were found for this pull request.
Out of Scope Changes check✅ PassedCheck skipped because no linked issues were found for this pull request.
Ai Use Disclosure✅ PassedThe PR selects generative tooling and names Cursor Grok 4.5 with scope; all three introduced commits contain matching standalone Generated-by trailers.
Title check✅ PassedThe title clearly summarizes the two main changes: immediate failure for bare rate limits and visible retry waits.
Description check✅ PassedThe description includes the required summary, verification, AI-use selection, checklist, behavior change, evidence, and unrun checks.
✨ Finishing Touches 💡 1
🛠️ Fix failing CI checks 💡
  • Create stacked PR
  • Commit on current branch
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/runtime-rate-limit-requires-retry-after

Comment @coderabbitai help to get the list of available commands.

@Astro-Han
Astro-Han marked this pull request as ready for review August 16, 2026 10:28

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1


ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: af9b5f4d-87df-471c-86b7-6d7a4f3ac623

📥 Commits

Reviewing files that changed from the base of the PR and between 8b79a6d and 968aae0.

📒 Files selected for processing (21)
  • packages/core/src/agent-run.ts
  • packages/runtime-host/src/__tests__/canonical-session-projection.test.ts
  • packages/runtime-host/src/__tests__/protocol.test.ts
  • packages/runtime-host/src/__tests__/session-projector.test.ts
  • packages/runtime-host/src/adapter/session-projector.ts
  • packages/runtime-host/src/protocol/operations.ts
  • packages/runtime-host/src/protocol/turn.ts
  • packages/runtime-host/src/server/canonical-turn-snapshot.ts
  • packages/runtime/src/__tests__/model-adapter.test.ts
  • packages/runtime/src/__tests__/provider-error-classification.test.ts
  • packages/runtime/src/__tests__/provider-request-telemetry.test.ts
  • packages/runtime/src/__tests__/session-manager.test.ts
  • packages/runtime/src/agent-run.ts
  • packages/runtime/src/provider-error-classification.ts
  • packages/storage/src/agent-run-store.ts
  • packages/ui/src/__tests__/provider-retry-presentation.test.ts
  • packages/ui/src/chat-turn.tsx
  • packages/ui/src/conversation-copy.ts
  • packages/ui/src/index.ts
  • packages/ui/src/provider-retry-presentation.ts
  • packages/ui/src/styles.css

Included review availability: Your plan includes up to 3 reviews per rolling hour; 1 remains after this review.

Comment threadpackages/runtime/src/agent-run.ts Outdated
@Astro-Han
Astro-Hanforce-pushed the fix/runtime-rate-limit-requires-retry-after branch from 968aae0 to d2666f5CompareAugust 16, 2026 11:29

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1


ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 1c38e715-0bfe-4131-b811-131d2fbb9cd9

📥 Commits

Reviewing files that changed from the base of the PR and between 968aae0 and d2666f5.

📒 Files selected for processing (10)
  • packages/runtime-host/src/__tests__/protocol.test.ts
  • packages/runtime-host/src/__tests__/session-continuity-coordinator.test.ts
  • packages/runtime-host/src/__tests__/session-projector.test.ts
  • packages/runtime-host/src/adapter/session-projector.ts
  • packages/runtime-host/src/protocol/index.ts
  • packages/runtime-host/src/protocol/operations.ts
  • packages/runtime-host/src/protocol/turn.ts
  • packages/runtime-host/src/server/root-turn-coordinator.ts
  • packages/runtime-host/src/server/session-continuity-coordinator.ts
  • packages/ui/src/chat-turn.tsx
🚧 Files skipped from review as they are similar to previous changes (3)
  • packages/runtime-host/src/tests/protocol.test.ts
  • packages/ui/src/chat-turn.tsx
  • packages/runtime-host/src/protocol/turn.ts

Included review availability: Your plan includes up to 3 reviews per rolling hour; 2 remain after this review.

@Astro-Han
Astro-Hanforce-pushed the fix/runtime-rate-limit-requires-retry-after branch from d2666f5 to 3cc3de4CompareAugust 16, 2026 11:35
A bare 429, including OpenCode FreeUsageLimitError, is a quota or
throttle without a recovery time. Retrying it ten times only hid the
failure behind a three-minute empty wait. Keep automatic retries for
rate limits that name Retry-After, and leave network or 5xx retries
unchanged.
Generated-by: Cursor Grok 4.5
The live retry line used the same muted working-status treatment as
"thinking", so a 40-second rate-limit wait looked like a hang. Keep
the existing live providerRetry object, and render its reason plus
countdown through the shared Astryx Banner.
Generated-by: Cursor Grok 4.5
A provider retry is still not a conversation fact. Hold the current wait
on the in-memory Turn snapshot, publish it when it appears, and drop it
on the next content event so remount cannot resurrect a finished wait.
Generated-by: Cursor Grok 4.5
@Astro-Han
Astro-Hanforce-pushed the fix/runtime-rate-limit-requires-retry-after branch from 3cc3de4 to f8eb564CompareAugust 16, 2026 11:49
@Astro-Han
Astro-Han requested a review from M4n5terAugust 16, 2026 12:27

@M4n5terM4n5ter left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. The rate-limit classification, transient retry overlay lifecycle, protocol boundary, and UI presentation are coherent and well covered by tests.

@M4n5ter
M4n5ter merged commit c92d0a2 into mainAug 16, 2026
12 checks passed
@M4n5ter
M4n5ter deleted the fix/runtime-rate-limit-requires-retry-after branch August 16, 2026 12:51
Sign up for freeto 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.

2 participants

@Astro-Han@M4n5ter
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix: fail bare rate limits and show retry waits - #3115

Merged
M4n5ter merged 3 commits into
mainfrom
fix/runtime-rate-limit-requires-retry-after
Aug 16, 2026
Merged

fix: fail bare rate limits and show retry waits#3115
M4n5ter merged 3 commits into
mainfrom
fix/runtime-rate-limit-requires-retry-after

Conversation

@Astro-Han

@Astro-HanAstro-Han commented Aug 16, 2026

Copy link
Copy Markdown
Contributor

Summary

A bare 429, including OpenCode FreeUsageLimitError, was retried ten times and looked like a hang. Rate limits now fail immediately unless the provider names Retry-After. A real wait still is not a conversation fact: Host keeps the current overlay on the in-memory Turn snapshot, publishes it when it appears, and drops it on the next content event so remount cannot resurrect a finished wait. The chat shows that overlay as an Astryx warning Banner.

Before — a muted status row with no reason:

image

After — an Astryx warning Banner with the retry reason:

image

Verification

  • packages/runtime/src/__tests__/provider-error-classification.test.ts (retries a rate limit only when the provider names a retry delay)
  • packages/runtime/src/__tests__/session-manager.test.ts (provider retry progress reaches observers...)
  • packages/runtime-host/src/__tests__/session-continuity-coordinator.test.ts (keeps the current provider retry on the live Turn until the next content event)
  • packages/runtime-host/src/__tests__/session-projector.test.ts
  • packages/runtime-host/src/__tests__/protocol.test.ts
  • packages/runtime-host/src/__tests__/canonical-session-projection.test.ts
  • npm run format:check

Did not run repository-wide tests or a live Electron remount of a Retry-After wait.

AI use

  • Generative tooling made a substantive contribution

Tool(s) and scope:

Cursor Grok 4.5 diagnosed the hung session, shaped the change, and authored the commits.

Checklist

  • Tests cover the change and fail without it
  • Lint, format, typecheck and the affected suites pass locally

Does this PR entail a change in behavior?

  • Yes — described under Summary above

@coderabbitai

coderabbitaiBot commented Aug 16, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Problem solved

Bare 429 errors now fail immediately unless the provider supplies a valid Retry-After value. Provider retry waits remain visible in chat with a localized reason and countdown. Retry state survives session projection and remounts, then clears after the next content event.

Design

The PR extends the existing live Turn snapshot and session-continuity path. It does not create a separate retry-state path. The provider_retry event updates canonical turn state, projects it to subscribers, and preserves it during session reopening.

The added protocol validation, event handling, projection logic, and UI presentation form the smallest coherent solution for persistence, remount behavior, and user feedback. The added complexity is required to distinguish scheduled retries from completed content and to prevent stale retry state from returning.

No safe deletion or simplification is evident from the current diff. The new tests cover protocol decoding, projection, continuity, error classification, telemetry, and UI-facing behavior.

Validation and risks

Coverage was added or updated for runtime, runtime-host, session projection, session continuity, protocol compatibility, retry classification, telemetry, and formatting. The runtime-host compatibility epoch increased from 20 to 21.

Repository-wide tests were not run. A live Electron remount was not verified. Required checks therefore remain unverified without direct check results.

Review-relevant risks

  • User-visible behavior changes because retry errors, reasons, countdowns, and warning banners now appear differently. Material UI behavior changes require independent human review under repository policy.
  • Provider retry classification changes because bare 429 errors are no longer retryable. Material runtime behavior changes require independent human review under repository policy.
  • The runtime-host protocol changes through new TurnProviderRetry and LiveTurnSnapshot types, validation rules, and compatibility epoch 21. Material public-contract and release-compatibility changes require independent human review under repository policy.
  • No security, licensing, or governance effect was identified in the current diff.
  • The person performing the merge must review the final diff. A maintainer makes the final determination.

Walkthrough

The PR makes rate-limit retries conditional on valid Retry-After data. It adds validated provider-retry state to runtime-host snapshots, persists retry events across session continuity, and renders localized retry banners in the UI.

Changes

Provider retry flow

Layer / File(s)Summary
Rate-limit retry classification
packages/runtime/src/provider-error-classification.ts, packages/runtime/src/__tests__/*
Rate-limit errors retry only when a valid delay exists. Tests update retryability and diagnostic expectations.
Retry snapshot protocol
packages/runtime-host/src/protocol/turn.ts, packages/runtime-host/src/protocol/operations.ts, packages/runtime-host/src/protocol/index.ts, packages/runtime-host/src/__tests__/protocol.test.ts
Turn snapshots support validated provider retry metadata. The compatibility epoch changes to 21.
Provider retry projection persistence
packages/runtime-host/src/adapter/session-projector.ts, packages/runtime-host/src/server/*, packages/runtime-host/src/__tests__/session-projector.test.ts, packages/runtime-host/src/__tests__/session-continuity-coordinator.test.ts
Projectors emit retry events. Session continuity stores, republishes, preserves, and clears retry metadata.
Localized retry presentation
packages/ui/src/chat-turn.tsx, packages/ui/src/conversation-copy.ts, packages/ui/src/styles.css
The UI renders retry information with localized reason labels and a warning banner.

Estimated code review effort: 4 (Complex) | ~45 minutes

Merge Risk:🟡 Moderate · up to d2666

Remounting during a provider retry can show a countdown longer than the actual remaining wait because the scheduled retry time is not preserved. This is a concrete user-visible correctness issue that should be fixed before merge.

Sequence Diagram(s)

sequenceDiagram
participant Provider
participant Runtime
participant RuntimeHost
participant UI
Provider->>Runtime: return rate-limit error
Runtime->>Runtime: parse Retry-After
Runtime->>RuntimeHost: provide retry metadata
RuntimeHost->>RuntimeHost: publish provider_retry event
RuntimeHost->>UI: project retry snapshot
UI->>UI: render localized warning banner
Loading

Possibly related PRs

Suggested reviewers:m4n5ter

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check nameStatusExplanation
Linked Issues check✅ PassedCheck skipped because no linked issues were found for this pull request.
Out of Scope Changes check✅ PassedCheck skipped because no linked issues were found for this pull request.
Ai Use Disclosure✅ PassedThe PR selects generative tooling and names Cursor Grok 4.5 with scope; all three introduced commits contain matching standalone Generated-by trailers.
Title check✅ PassedThe title clearly summarizes the two main changes: immediate failure for bare rate limits and visible retry waits.
Description check✅ PassedThe description includes the required summary, verification, AI-use selection, checklist, behavior change, evidence, and unrun checks.
✨ Finishing Touches 💡 1
🛠️ Fix failing CI checks 💡
  • Create stacked PR
  • Commit on current branch
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/runtime-rate-limit-requires-retry-after

Comment @coderabbitai help to get the list of available commands.

@Astro-Han
Astro-Han marked this pull request as ready for review August 16, 2026 10:28

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1


ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: af9b5f4d-87df-471c-86b7-6d7a4f3ac623

📥 Commits

Reviewing files that changed from the base of the PR and between 8b79a6d and 968aae0.

📒 Files selected for processing (21)
  • packages/core/src/agent-run.ts
  • packages/runtime-host/src/__tests__/canonical-session-projection.test.ts
  • packages/runtime-host/src/__tests__/protocol.test.ts
  • packages/runtime-host/src/__tests__/session-projector.test.ts
  • packages/runtime-host/src/adapter/session-projector.ts
  • packages/runtime-host/src/protocol/operations.ts
  • packages/runtime-host/src/protocol/turn.ts
  • packages/runtime-host/src/server/canonical-turn-snapshot.ts
  • packages/runtime/src/__tests__/model-adapter.test.ts
  • packages/runtime/src/__tests__/provider-error-classification.test.ts
  • packages/runtime/src/__tests__/provider-request-telemetry.test.ts
  • packages/runtime/src/__tests__/session-manager.test.ts
  • packages/runtime/src/agent-run.ts
  • packages/runtime/src/provider-error-classification.ts
  • packages/storage/src/agent-run-store.ts
  • packages/ui/src/__tests__/provider-retry-presentation.test.ts
  • packages/ui/src/chat-turn.tsx
  • packages/ui/src/conversation-copy.ts
  • packages/ui/src/index.ts
  • packages/ui/src/provider-retry-presentation.ts
  • packages/ui/src/styles.css

Included review availability: Your plan includes up to 3 reviews per rolling hour; 1 remains after this review.

Comment threadpackages/runtime/src/agent-run.ts Outdated
@Astro-Han
Astro-Hanforce-pushed the fix/runtime-rate-limit-requires-retry-after branch from 968aae0 to d2666f5CompareAugust 16, 2026 11:29

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1


ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 1c38e715-0bfe-4131-b811-131d2fbb9cd9

📥 Commits

Reviewing files that changed from the base of the PR and between 968aae0 and d2666f5.

📒 Files selected for processing (10)
  • packages/runtime-host/src/__tests__/protocol.test.ts
  • packages/runtime-host/src/__tests__/session-continuity-coordinator.test.ts
  • packages/runtime-host/src/__tests__/session-projector.test.ts
  • packages/runtime-host/src/adapter/session-projector.ts
  • packages/runtime-host/src/protocol/index.ts
  • packages/runtime-host/src/protocol/operations.ts
  • packages/runtime-host/src/protocol/turn.ts
  • packages/runtime-host/src/server/root-turn-coordinator.ts
  • packages/runtime-host/src/server/session-continuity-coordinator.ts
  • packages/ui/src/chat-turn.tsx
🚧 Files skipped from review as they are similar to previous changes (3)
  • packages/runtime-host/src/tests/protocol.test.ts
  • packages/ui/src/chat-turn.tsx
  • packages/runtime-host/src/protocol/turn.ts

Included review availability: Your plan includes up to 3 reviews per rolling hour; 2 remain after this review.

@Astro-Han
Astro-Hanforce-pushed the fix/runtime-rate-limit-requires-retry-after branch from d2666f5 to 3cc3de4CompareAugust 16, 2026 11:35
A bare 429, including OpenCode FreeUsageLimitError, is a quota or
throttle without a recovery time. Retrying it ten times only hid the
failure behind a three-minute empty wait. Keep automatic retries for
rate limits that name Retry-After, and leave network or 5xx retries
unchanged.
Generated-by: Cursor Grok 4.5
The live retry line used the same muted working-status treatment as
"thinking", so a 40-second rate-limit wait looked like a hang. Keep
the existing live providerRetry object, and render its reason plus
countdown through the shared Astryx Banner.
Generated-by: Cursor Grok 4.5
A provider retry is still not a conversation fact. Hold the current wait
on the in-memory Turn snapshot, publish it when it appears, and drop it
on the next content event so remount cannot resurrect a finished wait.
Generated-by: Cursor Grok 4.5
@Astro-Han
Astro-Hanforce-pushed the fix/runtime-rate-limit-requires-retry-after branch from 3cc3de4 to f8eb564CompareAugust 16, 2026 11:49
@Astro-Han
Astro-Han requested a review from M4n5terAugust 16, 2026 12:27

@M4n5terM4n5ter left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. The rate-limit classification, transient retry overlay lifecycle, protocol boundary, and UI presentation are coherent and well covered by tests.

@M4n5ter
M4n5ter merged commit c92d0a2 into mainAug 16, 2026
12 checks passed
@M4n5ter
M4n5ter deleted the fix/runtime-rate-limit-requires-retry-after branch August 16, 2026 12:51
Sign up for freeto 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.

2 participants

@Astro-Han@M4n5ter
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

fix: fail bare rate limits and show retry waits - #3115

Merged
M4n5ter merged 3 commits into
mainfrom
fix/runtime-rate-limit-requires-retry-after
Aug 16, 2026
Merged

fix: fail bare rate limits and show retry waits#3115
M4n5ter merged 3 commits into
mainfrom
fix/runtime-rate-limit-requires-retry-after

Conversation

@Astro-Han

@Astro-HanAstro-Han commented Aug 16, 2026

Copy link
Copy Markdown
Contributor

Summary

A bare 429, including OpenCode FreeUsageLimitError, was retried ten times and looked like a hang. Rate limits now fail immediately unless the provider names Retry-After. A real wait still is not a conversation fact: Host keeps the current overlay on the in-memory Turn snapshot, publishes it when it appears, and drops it on the next content event so remount cannot resurrect a finished wait. The chat shows that overlay as an Astryx warning Banner.

Before — a muted status row with no reason:

image

After — an Astryx warning Banner with the retry reason:

image

Verification

  • packages/runtime/src/__tests__/provider-error-classification.test.ts (retries a rate limit only when the provider names a retry delay)
  • packages/runtime/src/__tests__/session-manager.test.ts (provider retry progress reaches observers...)
  • packages/runtime-host/src/__tests__/session-continuity-coordinator.test.ts (keeps the current provider retry on the live Turn until the next content event)
  • packages/runtime-host/src/__tests__/session-projector.test.ts
  • packages/runtime-host/src/__tests__/protocol.test.ts
  • packages/runtime-host/src/__tests__/canonical-session-projection.test.ts
  • npm run format:check

Did not run repository-wide tests or a live Electron remount of a Retry-After wait.

AI use

  • Generative tooling made a substantive contribution

Tool(s) and scope:

Cursor Grok 4.5 diagnosed the hung session, shaped the change, and authored the commits.

Checklist

  • Tests cover the change and fail without it
  • Lint, format, typecheck and the affected suites pass locally

Does this PR entail a change in behavior?

  • Yes — described under Summary above

@coderabbitai

coderabbitaiBot commented Aug 16, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Problem solved

Bare 429 errors now fail immediately unless the provider supplies a valid Retry-After value. Provider retry waits remain visible in chat with a localized reason and countdown. Retry state survives session projection and remounts, then clears after the next content event.

Design

The PR extends the existing live Turn snapshot and session-continuity path. It does not create a separate retry-state path. The provider_retry event updates canonical turn state, projects it to subscribers, and preserves it during session reopening.

The added protocol validation, event handling, projection logic, and UI presentation form the smallest coherent solution for persistence, remount behavior, and user feedback. The added complexity is required to distinguish scheduled retries from completed content and to prevent stale retry state from returning.

No safe deletion or simplification is evident from the current diff. The new tests cover protocol decoding, projection, continuity, error classification, telemetry, and UI-facing behavior.

Validation and risks

Coverage was added or updated for runtime, runtime-host, session projection, session continuity, protocol compatibility, retry classification, telemetry, and formatting. The runtime-host compatibility epoch increased from 20 to 21.

Repository-wide tests were not run. A live Electron remount was not verified. Required checks therefore remain unverified without direct check results.

Review-relevant risks

  • User-visible behavior changes because retry errors, reasons, countdowns, and warning banners now appear differently. Material UI behavior changes require independent human review under repository policy.
  • Provider retry classification changes because bare 429 errors are no longer retryable. Material runtime behavior changes require independent human review under repository policy.
  • The runtime-host protocol changes through new TurnProviderRetry and LiveTurnSnapshot types, validation rules, and compatibility epoch 21. Material public-contract and release-compatibility changes require independent human review under repository policy.
  • No security, licensing, or governance effect was identified in the current diff.
  • The person performing the merge must review the final diff. A maintainer makes the final determination.

Walkthrough

The PR makes rate-limit retries conditional on valid Retry-After data. It adds validated provider-retry state to runtime-host snapshots, persists retry events across session continuity, and renders localized retry banners in the UI.

Changes

Provider retry flow

Layer / File(s)Summary
Rate-limit retry classification
packages/runtime/src/provider-error-classification.ts, packages/runtime/src/__tests__/*
Rate-limit errors retry only when a valid delay exists. Tests update retryability and diagnostic expectations.
Retry snapshot protocol
packages/runtime-host/src/protocol/turn.ts, packages/runtime-host/src/protocol/operations.ts, packages/runtime-host/src/protocol/index.ts, packages/runtime-host/src/__tests__/protocol.test.ts
Turn snapshots support validated provider retry metadata. The compatibility epoch changes to 21.
Provider retry projection persistence
packages/runtime-host/src/adapter/session-projector.ts, packages/runtime-host/src/server/*, packages/runtime-host/src/__tests__/session-projector.test.ts, packages/runtime-host/src/__tests__/session-continuity-coordinator.test.ts
Projectors emit retry events. Session continuity stores, republishes, preserves, and clears retry metadata.
Localized retry presentation
packages/ui/src/chat-turn.tsx, packages/ui/src/conversation-copy.ts, packages/ui/src/styles.css
The UI renders retry information with localized reason labels and a warning banner.

Estimated code review effort: 4 (Complex) | ~45 minutes

Merge Risk:🟡 Moderate · up to d2666

Remounting during a provider retry can show a countdown longer than the actual remaining wait because the scheduled retry time is not preserved. This is a concrete user-visible correctness issue that should be fixed before merge.

Sequence Diagram(s)

sequenceDiagram
participant Provider
participant Runtime
participant RuntimeHost
participant UI
Provider->>Runtime: return rate-limit error
Runtime->>Runtime: parse Retry-After
Runtime->>RuntimeHost: provide retry metadata
RuntimeHost->>RuntimeHost: publish provider_retry event
RuntimeHost->>UI: project retry snapshot
UI->>UI: render localized warning banner
Loading

Possibly related PRs

Suggested reviewers:m4n5ter

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check nameStatusExplanation
Linked Issues check✅ PassedCheck skipped because no linked issues were found for this pull request.
Out of Scope Changes check✅ PassedCheck skipped because no linked issues were found for this pull request.
Ai Use Disclosure✅ PassedThe PR selects generative tooling and names Cursor Grok 4.5 with scope; all three introduced commits contain matching standalone Generated-by trailers.
Title check✅ PassedThe title clearly summarizes the two main changes: immediate failure for bare rate limits and visible retry waits.
Description check✅ PassedThe description includes the required summary, verification, AI-use selection, checklist, behavior change, evidence, and unrun checks.
✨ Finishing Touches 💡 1
🛠️ Fix failing CI checks 💡
  • Create stacked PR
  • Commit on current branch
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/runtime-rate-limit-requires-retry-after

Comment @coderabbitai help to get the list of available commands.

@Astro-Han
Astro-Han marked this pull request as ready for review August 16, 2026 10:28

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1


ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: af9b5f4d-87df-471c-86b7-6d7a4f3ac623

📥 Commits

Reviewing files that changed from the base of the PR and between 8b79a6d and 968aae0.

📒 Files selected for processing (21)
  • packages/core/src/agent-run.ts
  • packages/runtime-host/src/__tests__/canonical-session-projection.test.ts
  • packages/runtime-host/src/__tests__/protocol.test.ts
  • packages/runtime-host/src/__tests__/session-projector.test.ts
  • packages/runtime-host/src/adapter/session-projector.ts
  • packages/runtime-host/src/protocol/operations.ts
  • packages/runtime-host/src/protocol/turn.ts
  • packages/runtime-host/src/server/canonical-turn-snapshot.ts
  • packages/runtime/src/__tests__/model-adapter.test.ts
  • packages/runtime/src/__tests__/provider-error-classification.test.ts
  • packages/runtime/src/__tests__/provider-request-telemetry.test.ts
  • packages/runtime/src/__tests__/session-manager.test.ts
  • packages/runtime/src/agent-run.ts
  • packages/runtime/src/provider-error-classification.ts
  • packages/storage/src/agent-run-store.ts
  • packages/ui/src/__tests__/provider-retry-presentation.test.ts
  • packages/ui/src/chat-turn.tsx
  • packages/ui/src/conversation-copy.ts
  • packages/ui/src/index.ts
  • packages/ui/src/provider-retry-presentation.ts
  • packages/ui/src/styles.css

Included review availability: Your plan includes up to 3 reviews per rolling hour; 1 remains after this review.

Comment threadpackages/runtime/src/agent-run.ts Outdated
@Astro-Han
Astro-Hanforce-pushed the fix/runtime-rate-limit-requires-retry-after branch from 968aae0 to d2666f5CompareAugust 16, 2026 11:29

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1


ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 1c38e715-0bfe-4131-b811-131d2fbb9cd9

📥 Commits

Reviewing files that changed from the base of the PR and between 968aae0 and d2666f5.

📒 Files selected for processing (10)
  • packages/runtime-host/src/__tests__/protocol.test.ts
  • packages/runtime-host/src/__tests__/session-continuity-coordinator.test.ts
  • packages/runtime-host/src/__tests__/session-projector.test.ts
  • packages/runtime-host/src/adapter/session-projector.ts
  • packages/runtime-host/src/protocol/index.ts
  • packages/runtime-host/src/protocol/operations.ts
  • packages/runtime-host/src/protocol/turn.ts
  • packages/runtime-host/src/server/root-turn-coordinator.ts
  • packages/runtime-host/src/server/session-continuity-coordinator.ts
  • packages/ui/src/chat-turn.tsx
🚧 Files skipped from review as they are similar to previous changes (3)
  • packages/runtime-host/src/tests/protocol.test.ts
  • packages/ui/src/chat-turn.tsx
  • packages/runtime-host/src/protocol/turn.ts

Included review availability: Your plan includes up to 3 reviews per rolling hour; 2 remain after this review.

@Astro-Han
Astro-Hanforce-pushed the fix/runtime-rate-limit-requires-retry-after branch from d2666f5 to 3cc3de4CompareAugust 16, 2026 11:35
A bare 429, including OpenCode FreeUsageLimitError, is a quota or
throttle without a recovery time. Retrying it ten times only hid the
failure behind a three-minute empty wait. Keep automatic retries for
rate limits that name Retry-After, and leave network or 5xx retries
unchanged.
Generated-by: Cursor Grok 4.5
The live retry line used the same muted working-status treatment as
"thinking", so a 40-second rate-limit wait looked like a hang. Keep
the existing live providerRetry object, and render its reason plus
countdown through the shared Astryx Banner.
Generated-by: Cursor Grok 4.5
A provider retry is still not a conversation fact. Hold the current wait
on the in-memory Turn snapshot, publish it when it appears, and drop it
on the next content event so remount cannot resurrect a finished wait.
Generated-by: Cursor Grok 4.5
@Astro-Han
Astro-Hanforce-pushed the fix/runtime-rate-limit-requires-retry-after branch from 3cc3de4 to f8eb564CompareAugust 16, 2026 11:49
@Astro-Han
Astro-Han requested a review from M4n5terAugust 16, 2026 12:27

@M4n5terM4n5ter left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. The rate-limit classification, transient retry overlay lifecycle, protocol boundary, and UI presentation are coherent and well covered by tests.

@M4n5ter
M4n5ter merged commit c92d0a2 into mainAug 16, 2026
12 checks passed
@M4n5ter
M4n5ter deleted the fix/runtime-rate-limit-requires-retry-after branch August 16, 2026 12:51
Sign up for freeto 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.

2 participants

@Astro-Han@M4n5ter