fix(opencode): a context overflow that OpenCode compacts no longer fails the turn#26743

open3
main
fix/issue-26674
opened6d agobyJJulius Marminge
View on GitHubTwo-way sync enabledPR last imported 5d ago

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 typecheck in packages/provider-opencode: clean. vp format and vp lint on 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 idleturn failed at the overflow; later output orphanedturn completed after idle, post-compaction output in the turn
Overflow, then idle (no compaction)turn failedturn failed, same failure

This only changes how the server ends a turn, so there are no screenshots. Runtime evidence, synthetic data only:

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.

Matrix row / harnessBefore e34067edefAfter dd3b029f53Normalized diff
R1 LIVE root recoveryR1-before.ndjsonR1-after.ndjsonR1-outcome.diff
R2 LIVE compaction disabledR2-before.ndjsonR2-after.ndjsonR2-outcome.diff
R3 LIVE summary overflowR3-before.ndjsonR3-after.ndjsonR3-outcome.diff
R4 LIVE stop during recoveryR4-before.ndjsonR4-after.ndjsonR4-outcome.diff
R5 UNIT EOF after overflowR5-before.ndjsonR5-after.ndjsonR5-outcome.diff
R6 UNIT known inactive sessionR6-before.ndjsonR6-after.ndjsonR6-outcome.diff
R7 UNIT foreign/related isolationR7-before.ndjsonR7-after.ndjsonR7-outcome.diff
R8 UNIT missing session IDR8-before.ndjsonR8-after.ndjsonR8-outcome.diff
R9 LIVE APIError + UNIT error guardsR9-before.ndjsonR9-after.ndjsonR9-outcome.diff
R10 UNIT native child recovery/failureR10-before.ndjsonR10-after.ndjsonR10-outcome.diff
R11 UNIT explicit compactR11-before.ndjsonR11-after.ndjsonR11-outcome.diff
R12 UNIT healthy/next-turn controlsR12-before.ndjsonR12-after.ndjsonR12-outcome.diff
R13 UNIT replace/clear orderingsR13-before.ndjsonR13-after.ndjsonR13-outcome.diff
R14 UNIT admission/legacy idleR14-before.ndjsonR14-after.ndjsonR14-outcome.diff
R15 UNIT finalizer precedence/raceR15-before.ndjsonR15-after.ndjsonR15-outcome.diff

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 dd3b029f53 gives 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.ts 34 passed at e34067edef, 36 passed at dd3b029f53; the recovery regression test fails on e34067edef.
  • 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

23 successful · 17 skipped
All checks passed
dd3b029

Added 3 commits

  • test(opencode): turns survive context overflows that OpenCode auto-compacts (red)6370fdc
  • Merge remote-tracking branch 'origin/main' into fix/issue-26674dd3b029
  • fix(opencode): a context overflow that OpenCode compacts no longer fails the turnf7c3dc1
Synced from GitHub

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.

Synced from GitHub

Thread transfer impact

✅ Thread transfer remains within every enforced ceiling.

ProviderMetricMain baselineThis PRImpactPR ceiling
CodexTotal thread wire5.0 KiB5.0 KiB−6 B (−0.1%)6.8 KiB✅
CodexThread snapshot wire3.8 KiB3.8 KiB0 B (0.0%)4.9 KiB✅
CodexLive turn WebSocket wire1.3 KiB1.2 KiB−6 B (−0.5%)2.0 KiB✅
CodexLive turn WebSocket decoded21.6 KiB21.6 KiB0 B (0.0%)24.4 KiB✅
CodexLive turn messages220 (0.0%)8✅
ClaudeTotal thread wire5.0 KiB5.0 KiB0 B (0.0%)6.8 KiB✅
ClaudeThread snapshot wire3.8 KiB3.8 KiB0 B (0.0%)4.9 KiB✅
ClaudeLive turn WebSocket wire1.3 KiB1.3 KiB0 B (0.0%)2.0 KiB✅
ClaudeLive turn WebSocket decoded21.9 KiB21.9 KiB0 B (0.0%)24.4 KiB✅
ClaudeLive turn messages220 (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.

Synced from GitHub

Review in Change Stack →

No actionable comments were generated in the recent review.

External image Recent review info
External image Run configuration
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.ts
  • packages/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.ts
Active 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.ts
If 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)

mermaid
1sequenceDiagram
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 nameStatusExplanation
Title checkPassedThe title clearly and concisely describes the primary fix: preventing a context overflow from failing an OpenCode turn when OpenCode compacts and continues.
Linked Issues checkPassedThe changes address the coding objective in #26674. The OpenCode 1.x adapter records an active turn's ContextOverflowError without finalizing the turn, clears that failure on session.compacted, an…
Out of Scope Changes checkPassedThe whole-PR diff changes only packages/provider-opencode/src/server/adapter.ts and its test file. The adapter logic and tests directly support #26674. No unrelated adapter, OpenCode 2, or process-m…
Description checkPassedThe 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's ContextOverflowError without finalizing the turn, clears that failure on session.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.ts and 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.