Skip to content

fix(server): OpenCode ChatGPT usage limits keep their reset time - #26264

Open
abdfattahz wants to merge 4 commits into
pingdotgg:mainfrom
abdfattahz:fix/opencode-chatgpt-usage-limit-reset
Open

abdfattahz wants to merge 4 commits into
pingdotgg:mainfrom
abdfattahz:fix/opencode-chatgpt-usage-limit-reset

Conversation

@abdfattahz

@abdfattahz abdfattahz commented Oct 28, 2026 •

Copy link
Copy Markdown

Problem

When OpenCode runs an OpenAI model through a ChatGPT subscription and the Codex usage window is exhausted, the turn now fails as usage_limit (since #18315) but without resetAt. The thread shows "Reset time unavailable; retry manually", the resume-at-reset and snooze actions are hidden, and auto-resume never arms.

ChatGPT already says when the limit lifts. Its 429 body is:

{"error":{"type":"usage_limit_reached","message":"The usage limit has been reached","plan_type":"plus","resets_at":1788753614,"resets_in_seconds":57361}}

OpenCode 2 forwards that body on session.execution.failed as error.response.body, but the adapter ignored it.

Change

When the OpenCode 2 adapter classifies a failure as a usage limit, it decodes error.resets_at (Unix seconds) from response.body and passes it as resetAt to makeProviderFailure, which already validates it and keeps it only for usage_limit. Claude limits keep the message-based reset from #29301, which takes precedence. Other bodies without that field (OpenCode Go, Zen, other providers) still produce no reset time, as before. No contract, client, or orchestration changes; the existing reset UI and auto-resume worker pick it up.

Scope and approval

Fixes #26265.

Follow-up to #16366, which was closed by #18315 with the note that "OpenCode doesn't send a reset time in these events, so none is shown yet". For ChatGPT-backed models it does send one, in the response body. This is a small, focused fix in one adapter branch: it fills a field the failure contract already has, for the one provider shape that reports it. Separate from the Codex-provider fix in #18721 / #14169.

Verification

  • Added a ChatGPT 429 row to the existing classifies $name as $failureClass table in OpenCode2AdapterV2.test.ts, expecting resetAt: "2026-10-27T15:25:41.000Z". With the adapter change stashed it fails on exactly that row (missing resetAt); the other rows pass. With the change, the file passes (89/89 after merging current main).
  • vp run check:changed: format, lint, knip, typecheck (36 packages), and the changed test file all pass.
  • Payload shape: taken from a real ChatGPT Plus usage-limit 429 recorded in my local OpenCode store (responseBody on an OpenCode 1.x message). I confirmed that OpenCode 2.1.3's execution-failure mapper includes response: { body } when the HTTP error has a body, and the @opencode/schema 2.0.28 Session.StructuredError used here declares response.body.
  • Not checked: a live end-to-end ChatGPT quota refusal through T3. My quota had already reset when I wrote this, and I couldn't get OpenCode 2 to route to a local mock 429 endpoint. Server-only change, so there are no screenshots.

Implementation, tests, and PR: Claude Opus 5.5 via Claude Code in T3 Code.

🤖 Generated with Claude Code

ChatGPT-backed OpenAI models answer usage limits with a 429 whose body
carries error.resets_at. Read it from the failure's response body so the
usage-limit failure gets a resetAt, enabling resume and snooze at reset.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 28, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ⚠️ Failed 2026-10-28T03:03:34.169508Z
We couldn’t complete this review. Comment @codex review to try again.
b5e2a29 PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@github-actions github-actions Bot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:S 10-29 changed lines (additions + deletions). labels Oct 28, 2026
@macroscopeapp

macroscopeapp Bot commented Oct 28, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Approved at b5e2a29

Macroscope's review found this PR approvable — Preserves provider-reported usage-limit reset times for existing display and recovery flows. Invalid timestamps are ignored, and automatic recovery remains controlled by existing preferences, disabled by default.

You can add or adjust custom eligibility rules. Learn more.

@coderabbitai

coderabbitai Bot commented Oct 28, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

No actionable comments were generated in the recent review.

Walkthrough

The OpenCode 2 adapter parses a valid resets_at timestamp from an error response and uses it when no Claude-specific reset time is available. A test covers a ChatGPT quota error with HTTP 429 and verifies the expected reset time.

Changes: OpenCode 2 reset-time handling

Layer / File(s) Summary
Parse and attach reset time
packages/provider-opencode/src/server/v2/adapter.ts, apps/server/src/orchestration-v2/Adapters/OpenCode2AdapterV2.test.ts
The adapter converts a finite Unix-seconds resets_at value to an ISO timestamp. It returns null if decoding or date conversion fails, and uses the parsed timestamp when a Claude-specific reset time is unavailable. The test checks the ChatGPT quota-error case and conditionally expects resetAt.

Estimated code review effort: 2 (Simple) | ~10 minutes

Change: Bug fix · Severity of issue fixed: Medium

Possibly related issues

Possibly related PRs

  • pingdotgg/t3code#28375: Both changes affect usage-limit handling in the OpenCode 2 adapter. This PR preserves the reset time for a ChatGPT quota failure.
  • pingdotgg/t3code#29301: Both changes affect OpenCode 2 failure handling and resetAt. This PR adds ChatGPT reset extraction while retaining the Claude reset time as a fallback.

Suggested reviewers: juliusmarminge, fixfon

Merge Risk: Minimal · up to 51345

The change is mergeable; it preserves existing failure behavior while attaching the quota reset time for supported usage-limit responses.

Pre-merge checks: Passed 4
Check name Status Explanation
Title check Passed The title clearly and concisely describes the main change: preserving the reset time for ChatGPT usage limits in the OpenCode adapter.
Description check Passed The description includes complete Problem, Change, Scope and approval, and Verification sections. It explains the affected behavior, implementation, scope rationale, issue reference, tests, validation…
Linked Issues check Passed Issue #26265 requires OpenCode 2 ChatGPT usage-limit failures to carry the reset time from the 429 body. The whole-PR diff (merge base to head) changes `packages/provider-opencode/src/server/v2/adapte…
Out of Scope Changes check Passed The whole-PR diff touches two files: packages/provider-opencode/src/server/v2/adapter.ts and apps/server/src/orchestration-v2/Adapters/OpenCode2AdapterV2.test.ts. The adapter change adds the `rese…
Full details: Description check

Explanation

The description includes complete Problem, Change, Scope and approval, and Verification sections. It explains the affected behavior, implementation, scope rationale, issue reference, tests, validation results, and untested live scenario.

Full details: Linked Issues check

Explanation

Issue #26265 requires OpenCode 2 ChatGPT usage-limit failures to carry the reset time from the 429 body. The whole-PR diff (merge base to head) changes packages/provider-opencode/src/server/v2/adapter.ts. A new usageLimitResetAt helper decodes error.resets_at (Unix seconds) from response.body with Schema.decodeUnknownOption. It converts the value to ISO with DateTime.make and DateTime.formatIso, and returns null when the body or field is absent or invalid. The failure record now sets resetAt: claudeLimit?.resetAt ?? usageLimitResetAt(response?.body), so the Claude message-based reset keeps precedence, as the PR describes. The test diff adds a ChatGPT provider.quota 429 row with usage_limit_reached body to the existing classifies $name as $failureClass table, expecting resetAt: "2026-10-27T15:25:41.000Z". I checked the fixture value: 1793114741 Unix seconds equals 2026-10-27T15:25:41Z. The test harness asserts resetAt only when the row defines it. The UI and auto-resume behavior named in the issue rely on existing code, which the PR states is unchanged. The adapter now supplies the field those paths read. The reviewed diff does not show the UI or worker code, so the end-to-end display and auto-resume behavior is not re-verified here. The coding requirement at the adapter level is met.

Full details: Out of Scope Changes check

Explanation

The whole-PR diff touches two files: packages/provider-opencode/src/server/v2/adapter.ts and apps/server/src/orchestration-v2/Adapters/OpenCode2AdapterV2.test.ts. The adapter change adds the resets_at extraction helper, the effect/Option import it uses, and the resetAt fallback in the usage-limit failure branch. The test change adds one ChatGPT row, and adjusts the table runner to pass resetAt only when a row defines it. All changes serve issue #26265. No contract, client, orchestration, or unrelated provider changes appear in the reviewed diff. The Option import and helper are needed by the new decode path.

Finishing Touches
Generate unit tests (beta)
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Warning

Some tools did not complete. Review the errors below.

ast-grep (0.51.1)

ast-grep could not parse rule config: /ast-grep-rules/ast-grep-essentials/rules/csharp/security/jwt-hardcoded-secret-csharp.yml

Tip

🎯 Customize your risk assessments

Guide how CodeRabbit assesses merge risk and security architecture risk. Highlight sensitive changes and explain your security boundaries using Merge Risk Instructions and Security Risk Instructions in your review settings. Security architecture risk assessments require the Advanced plan or above.

✅ Automatic approvals, with your rules

Let CodeRabbit approve pull requests once required threads are resolved, pre-merge checks pass, and your risk limits are met. Enable Automatic approvals in review settings, with overrides for teams or file paths.

CodeRabbit Verify

  • Run CodeRabbit Verify to test the changes in this pull request.
Recent review info
Run configuration
Commits

Reviewing files that changed from the base of the PR and between d4c9def and 513453f.

Files selected for processing: 2
  • apps/server/src/orchestration-v2/Adapters/OpenCode2AdapterV2.test.ts
  • packages/provider-opencode/src/server/v2/adapter.ts

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 9 remain after this review.

@juliusmarminge juliusmarminge added bugfix Fix PR opened by an issue lead; enters the PR loop pr:gate-failed A land gate failed labels Oct 28, 2026
@abdfattahz

Copy link
Copy Markdown
Author

Note

Claude Code (Claude Opus 5.5) is posting this comment for the PR author.

I merged current main into the branch (29c81724). The diff against main is still the same two files, +31/−2.

The earlier Agent context budget failure (claudeSystemAppendBytes: 5135 -> 5258) came from the PR being 254 commits behind. main had shrunk agentContextBudget.json since this branch was created, and this PR doesn't touch agent context. On the new head, Agent Context Budget, CI, Mobile Fingerprint, PR Vouch and PR Size all pass, and the branch merges cleanly.

The pr:gate-failed label seems to be left over from that run. Could a maintainer clear it? The bug report is #26265.

…usage-limit-reset

# Conflicts:
#	apps/server/src/orchestration-v2/Adapters/OpenCode2AdapterV2.test.ts
#	packages/provider-opencode/src/server/v2/adapter.ts

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bugfix Fix PR opened by an issue lead; enters the PR loop pr:gate-failed A land gate failed size:S 10-29 changed lines (additions + deletions). vouch:unvouched PR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: OpenCode ChatGPT usage-limit failures drop the reset time, so auto-resume never arms

2 participants