fix(opencode): a context overflow that OpenCode compacts no longer fails the turn#26743
Problem
When an OpenCode 1.x provider request exceeds the model's context window, OpenCode publishes session.error with ContextOverflowError, stays busy, auto-compacts and keeps working. T3 ended the turn as failed on that first error, so a delegated task reported a failure to its parent while the OpenCode session went on editing the worktree with nobody watching it.
Reproduced against a real opencode serve 1.18.18 and a fake OpenAI-compatible model that answers one request with the reporter's context_length_exceeded error: OpenCode emits session.error ContextOverflowError → compaction summary → session.compacted → another agent step → idle. T3's adapter finalized the turn at the first event.
Change
In the OpenCode 1.x adapter, a ContextOverflowError for a session with an active turn no longer finalizes that turn. The adapter keeps the failure on the turn, and session.compacted clears it. When the session goes idle, the turn completes normally if compaction succeeded. If compaction is off or itself overflowed, the turn fails with the same provider failure as before. Interrupts and broken event streams keep their existing outcomes. Every other session.error is unchanged. The OpenCode 2 adapter is not touched.
Scope and approval
Fixes pingdotgg/t3code#26674
Triaged via the automated issue flow; GitCafe issue #26674.
Verification
vp test run packages/provider-opencode/src/server/adapter.test.ts: 36 passed on the head.keeps a turn running through a context overflow that OpenCode auto-compacts: fails on main (expected 'failed' to equal 'completed'), passes with the fix.fails a turn on a context overflow that OpenCode does not compact: guard for auto-compaction off; passes on both.
vp run typecheckinpackages/provider-opencode: clean.vp formatandvp linton the changed files: pass.- Not finished locally: the knip, cross-package typecheck and test stages of
vp run check:changed. They did not finish within 30 minutes on a heavily loaded host and were stopped. CI runs them.
Before (main 9826dbb990) | After (dd3b029f53) | |
|---|---|---|
| Overflow, then compaction, then idle | turn failed at the overflow; later output orphaned | turn completed after idle, post-compaction output in the turn |
| Overflow, then idle (no compaction) | turn failed | turn failed, same failure |
This only changes how the server ends a turn, so there are no screenshots. Runtime evidence, synthetic data only:
- opencode-1.18.18-overflow-transcript.txt: OpenCode's event timeline for the overflow.
- Driver: drive-26674.sh, fake_model-26674.py, timeline-26674.py, opencode-26674.json.
Not checked: a full delegated task end to end in the T3 app with this model. The dev server's model picker did not list the fake provider.
Claude Opus 5.5 (Claude Code, run from T3 Code); reviews by Codex gpt-6.1-sol and Claude Opus 5.5.
Takeover
Taken over from @juliusmarminge (evidence-only round). No code changes; evidence and verification added below. The earlier evidence showed only OpenCode's own event timeline; the captures below record T3's turn outcome before and after, against a real opencode serve.
Evidence
Beyond root recovery, overflow settlement timing, failure precedence and native-child outcomes change as listed in what-else-changed-v2.md. Not covered by the title: with an overflow pending, an explicit /compact whose summary also overflows now emits a completed "Context compacted" item and then fails the turn with the pending overflow (R11). Before, the turn failed at the overflow with no compaction item. OpenCode 1.18.18 returns summarize success without session.compacted in that case; the proof audit reproduced it against real OpenCode with controlled event delivery (audit2-report.md).
Fixture matrix: proof-matrix-26743-pass1.md. Server-only change: captures are ordered NDJSON runtime transcripts and normalized outcome diffs; viewport and theme are N/A.
15/15 matrix rows captured; 10 selected live runs and 26 synthetic fixtures per SHA (31 paired fixtures). No missing matrix rows.
OpenCode 1.18.18, Node v26.12.1, Linux fs-14; pinned before e34067edef, after dd3b029f53. LIVE = production adapter/real SDK/external real opencode serve + fake fake/fake HTTP model. UNIT = synthetic native-event harness.
Original adapter tests: before 34 passed, after 36 passed. Head's two new tests against before source: 1 failed (recovery: failed ≠ completed), 1 passed (uncompacted overflow). Guard capture cases complete 26/26 per SHA; separate transcript audit 202/202.
LIVE logs include native SSE through idle, model request logs, full emitted T3 outcomes, and adapter snapshots at native error/compaction/idle boundaries. Queued event-observer timing alone is not used to infer emission timing.
Limits: no orchestration persistence, parent delegate notification, client rendering, external-server ownership cleanup, or OpenCode 2 claim. Viewport/theme N/A; synthetic data only.
Drivers, every generated per-run config, raw SSE/model logs and preliminary runs: raw-evidence-and-drivers.tar.gz. environment-and-limits.md.
Unverified required rows: none. Guard rows use labelled UNIT recordings; live native-child and EOF routes are outside this evidence.
Verification log
- Mode: evidence-only, round 1. No code changes, no review rounds this round.
- Proof audit pass 1: 15-row matrix (R1–R4, R9 live and paired; the rest labelled unit guards).
- Capture: 15/15 rows at both SHAs; 10 live runs, 26 synthetic guard fixtures per SHA.
- Proof audit pass 2: all 30 transcripts and 15 diffs read; SHA headers match; diffs recompute exactly; independent R1 rebuild at
dd3b029f53gives zero normalized delta (21/21 outcome records). R1–R13 and R15 sufficient; the R14 inventory omitted the retained provider-assigned assistant item and failureItemOrdinal 101→102, corrected in what-else-changed-v2.md. R11 reproduced live: supplemental proof. - Tests:
adapter.test.ts34 passed ate34067edef, 36 passed atdd3b029f53; the recovery regression test fails one34067edef. - CI on
dd3b029f53: 40/40 checks green, mergeable. - Unverified surfaces: none (server only).
- Proof audit and capture: Codex gpt-6.1-sol (high) via T3 Code; lead: Claude Opus 5.5 (Claude Code, run from T3 Code).
🤖 Generated with Claude Code
Checks
Added 3 commits
Approvability
Verdict: Approved at dd3b029
Macroscope's review found this PR approvable — OpenCode turns now remain active through recoverable context overflows, while overflows that are not compacted still fail. The change is limited to turn lifecycle reporting and does not enable new provider actions or change product defaults.
You can add or adjust custom eligibility rules. Learn more.
Thread transfer impact
✅ Thread transfer remains within every enforced ceiling.
| Provider | Metric | Main baseline | This PR | Impact | PR ceiling | |
|---|---|---|---|---|---|---|
| Codex | Total thread wire | 5.0 KiB | 5.0 KiB | −6 B (−0.1%) | 6.8 KiB | ✅ |
| Codex | Thread snapshot wire | 3.8 KiB | 3.8 KiB | 0 B (0.0%) | 4.9 KiB | ✅ |
| Codex | Live turn WebSocket wire | 1.3 KiB | 1.2 KiB | −6 B (−0.5%) | 2.0 KiB | ✅ |
| Codex | Live turn WebSocket decoded | 21.6 KiB | 21.6 KiB | 0 B (0.0%) | 24.4 KiB | ✅ |
| Codex | Live turn messages | 2 | 2 | 0 (0.0%) | 8 | ✅ |
| Claude | Total thread wire | 5.0 KiB | 5.0 KiB | 0 B (0.0%) | 6.8 KiB | ✅ |
| Claude | Thread snapshot wire | 3.8 KiB | 3.8 KiB | 0 B (0.0%) | 4.9 KiB | ✅ |
| Claude | Live turn WebSocket wire | 1.3 KiB | 1.3 KiB | 0 B (0.0%) | 2.0 KiB | ✅ |
| Claude | Live turn WebSocket decoded | 21.9 KiB | 21.9 KiB | 0 B (0.0%) | 24.4 KiB | ✅ |
| Claude | Live turn messages | 2 | 2 | 0 (0.0%) | 8 | ✅ |
Baseline: 29f33af · PR result: dd3b029 · Source CI: success
Scenario and decoded snapshot size
10 historical turns, 5 command tools per turn, 878.9 KiB retained MCP result per historical turn, and a 1.05 MiB retained result in the measured turn.
- Codex decoded thread snapshot: 108.5 KiB
- Claude decoded thread snapshot: 108.8 KiB
Updated in place by a trusted workflow. PR artifacts are strictly validated and never executed.
No actionable comments were generated in the recent review.
External image Recent review info
-
External image Run configuration
- Source mode: Auto
- Repository: pingdotgg/t3code
- Branch: fix/issue-26674
- File: .coderabbit.config.ts
- Commit: dd3b029
- Layers: Repository TS config
- Review profile: CHILL
- Plan: Team
- Run ID:
3c33cc5d-8230-450e-a328-239a2224cfbd
External image Commits
Reviewing files that changed from the base of the PR and between 29f33af7d7e81ced8d0c3098ea0fe0ff1895d6a7 and dd3b029f5325ae8e67ca89f37c426bdbe92449e6.
External image Files selected for processing: 2
packages/provider-opencode/src/server/adapter.test.tspackages/provider-opencode/src/server/adapter.ts
Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 3 remain after this review.
Walkthrough
The OpenCode adapter now defers a context-overflow failure while the session may compact. Compaction clears the pending failure; if the turn reaches idle without compaction, finalization marks it failed. Tests cover both outcomes.
Changes: Context-overflow turn handling
Layer / File(s) Summary Record and clear overflow state
packages/provider-opencode/src/server/adapter.tsActive turns track a context-overflow failure. The adapter records the error without immediately finalizing the turn, then clears it on session.compacted.Finalize turns and verify outcomes
packages/provider-opencode/src/server/adapter.ts,packages/provider-opencode/src/server/adapter.test.tsIf overflow remains recorded when a turn completes, finalization marks it failed and updates the session’s lastError. Tests cover completion after compaction and failure without compaction.Priority: External image Normal
Estimated code review effort: 2 (Simple) | ~12 minutes
Change: Bug fix · Severity of issue fixed: Medium
Sequence Diagram(s)
mermaid1 sequenceDiagram 2 participant OpenCodeSession 3 participant Adapter 4 participant ActiveOpenCodeTurn 5 participant finalizeTurn 6 OpenCodeSession->>Adapter: Send ContextOverflowError 7 Adapter->>ActiveOpenCodeTurn: Record overflow failure 8 alt Session compacts 9 OpenCodeSession->>Adapter: Send session.compacted 10 Adapter->>ActiveOpenCodeTurn: Clear overflow failure 11 OpenCodeSession->>Adapter: Send idle status 12 Adapter->>finalizeTurn: Finalize turn as completed 13 else Session does not compact 14 OpenCodeSession->>Adapter: Send idle status 15 Adapter->>finalizeTurn: Finalize turn as failed with overflow failure 16 end Possibly related issues
pingdotgg/t3code#26674— The change defers a context-overflow failure during compaction and allows the session to continue. It does not implement the issue’s alternative of aborting the session.
Possibly related PRs
- pingdotgg/t3code#24734 — This PR uses the OpenCode error-message formatting for a recorded context-overflow failure.
Suggested reviewers:
t3dotgg
Merge Risk: External image Minimal · up to dd3b0
The adapter waits through overflow recovery and reports failure if the session idles without compaction. No merge-blocking risk was established.
Pre-merge checks: Passed 4
Check name Status Explanation Title check Passed The title clearly and concisely describes the primary fix: preventing a context overflow from failing an OpenCode turn when OpenCode compacts and continues. Linked Issues check Passed The changes address the coding objective in #26674. The OpenCode 1.x adapter records an active turn'sContextOverflowErrorwithout finalizing the turn, clears that failure onsession.compacted, an…Out of Scope Changes check Passed The whole-PR diff changes only packages/provider-opencode/src/server/adapter.tsand its test file. The adapter logic and tests directly support#26674. No unrelated adapter, OpenCode 2, or process-m…Description check Passed The description covers the problem, implementation, scope, approval reference, focused verification, observed results, limitations, and agent attribution. It also documents additional evidence and unv… Full details: Linked Issues check
Explanation
The changes address the coding objective in
#26674. The OpenCode 1.x adapter records an active turn'sContextOverflowErrorwithout finalizing the turn, clears that failure onsession.compacted, and fails the turn with the recorded provider failure only when the turn reaches completion without compaction. The new tests cover both auto-compaction followed by completion and overflow followed by idle without compaction. The issue's abort-and-stop alternative is not required because the PR implements the first expected outcome.
Full details: Out of Scope Changes check
Explanation
The whole-PR diff changes only
packages/provider-opencode/src/server/adapter.tsand its test file. The adapter logic and tests directly support#26674. No unrelated adapter, OpenCode 2, or process-management changes are present.
Full details: Description check
Explanation
The description covers the problem, implementation, scope, approval reference, focused verification, observed results, limitations, and agent attribution. It also documents additional evidence and unverified checks. An explicit maintainer approval comment is not included, but the description is otherwise complete and sufficiently detailed.
Finishing Touches
📝 Generate docstrings
- Commit to this branch
- Create a new PR
🧪 Generate unit tests (beta)
- Commit to this branch
- Create a new PR
- Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts
Comment @coderabbitai help to get the list of available commands.
Taking over this one