Skip to content

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

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

abdfattahz wants to merge 7 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 https://git.cafe/pingdotgg/t3code/pulls/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 https://git.cafe/pingdotgg/t3code/pulls/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 https://git.cafe/pingdotgg/t3code/issues/26265.

Follow-up to https://git.cafe/pingdotgg/t3code/issues/16366, which was closed by https://git.cafe/pingdotgg/t3code/pulls/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 https://git.cafe/pingdotgg/t3code/pulls/18721 / https://git.cafe/pingdotgg/t3code/issues/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

Fixes #26265

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 <[email protected]>
@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 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

Explain Change →

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • Resume reviews
  • Trigger review

No actionable comments were generated in the recent review.

Walkthrough

The OpenCode 2 adapter parses a reset timestamp from a usage-limit response body and uses it when no Claude-specific reset time is available. A test covers a ChatGPT quota error and checks 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

Suggested reviewers: juliusmarminge, fixfon

Merge Risk: Minimal · previous review 7500e

OpenCode ChatGPT usage-limit failures now keep their reset time, so the reset UI and auto-resume can use it. Other failures behave as before. No merge-blocking risk was found.

Pre-merge checks: Passed 4

Check name Status Explanation
Title check Passed The title names the main change: OpenCode ChatGPT usage-limit failures now keep their reset time, which matches the adapter change that reads error.resets_at from the response body and passes it as re…
Description check Passed The description follows the template's sections (Problem, Change, Scope, Verification) and fills each one with specific content. It explains the failure, the 429 payload shape, the adapter fix, and th…
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 reviewed head 7500e4b) in `packages/provider-opencode/src/ser…
Out of Scope Changes check Passed The whole-PR diff changes two files: packages/provider-opencode/src/server/v2/adapter.ts (the usageLimitResetAt helper and the resetAt fallback in the usage-limit branch) and `apps/server/src/or…
Full details: Title check

Explanation

The title names the main change: OpenCode ChatGPT usage-limit failures now keep their reset time, which matches the adapter change that reads error.resets_at from the response body and passes it as resetAt. It follows conventional commit format and is specific.

Full details: Description check

Explanation

The description follows the template's sections (Problem, Change, Scope, Verification) and fills each one with specific content. It explains the failure, the 429 payload shape, the adapter fix, and the precedence with the Claude reset path. It links the issue and the prior work. It gives focused test results and states what was not checked. The template's agent attribution line is present, and the description notes that the change is server-only, so no screenshots are needed. The description is mostly complete and clear.

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 reviewed head 7500e4b) in packages/provider-opencode/src/server/v2/adapter.ts adds decodeUsageLimitBody, which decodes error.resets_at (Finite, Unix seconds) from response.body with Schema.decodeUnknownOption. usageLimitResetAt converts it to ISO with DateTime.make and DateTime.formatIso, and returns null when the body or field is absent or invalid. The usage-limit failure now sets resetAt: claudeLimit?.resetAt ?? usageLimitResetAt(response?.body), so the Claude message-based reset keeps precedence. The previous review also confirmed a ChatGPT provider.quota 429 row in OpenCode2AdapterV2.test.ts expecting resetAt: "2026-10-27T15:25:41.000Z", which matches 1793114741 Unix seconds. The head changed through a merge of main. The current adapter diff matches the earlier reviewed logic. The test diff was not re-read at this head. The UI and auto-resume paths were not re-verified in this review; the PR states they are unchanged and read the field.

Full details: Out of Scope Changes check

Explanation

The whole-PR diff changes two files: packages/provider-opencode/src/server/v2/adapter.ts (the usageLimitResetAt helper and the resetAt fallback in the usage-limit branch) and apps/server/src/orchestration-v2/Adapters/OpenCode2AdapterV2.test.ts (one ChatGPT row, and a runner that passes resetAt only when a row defines it). All changes serve issue #26265. No contract, client, orchestration, or unrelated provider changes appear in the reviewed evidence. The adapter diff at this head shows no import change, so the Option and DateTime references rely on imports already present at the merge base.

Finishing Touches

Generate unit tests (beta)

  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts
Recent review info

Run configuration

Commits

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

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
…usage-limit-reset

# Conflicts:
#	packages/provider-opencode/src/server/v2/adapter.ts
AI-assisted; verified with the tests and tools listed above.
@juliusmarminge

Copy link
Copy Markdown
Member

The automated pipeline stopped on this pull request and will not merge it:

the fix is written and reviewed, but proving it needs something no worker has:

  • Permanent blocker: verification requires OpenCode 2.x connected through first-party OpenAI OAuth to a ChatGPT subscription with an exhausted usage window; first-party ChatGPT OAuth usage, limit, and renewal flows are unavailable on every VM. This prevents observing reset-time retention, Resume at reset, Snooze until reset, and automatic recovery on both commits. Replay cannot substitute because the scenario runner excludes provider-specific behavior and usage-limit stops.

It stays open for a person to finish or close.

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 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