Repository navigation
fix(opencode): show compaction progress with OpenCode 2.1+ - #26206
juliusmarminge wants to merge 3 commits into
Conversation
OpenCode 2.1 stopped sending data.recent on session.compaction.started and session.compaction.ended. The bundled 2.0.28 protocol schema still requires it, so both frames were rejected and silently dropped, and the thread never showed compaction. When an event fails to decode and is one of those two types without a recent key, decode it again with recent filled as an empty string. T3 never reads recent. Frames that decode today take the same path as before. Fixes #26193 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
ApprovabilityVerdict: Approved at Macroscope's review found this PR approvable — Restores compaction progress reporting for OpenCode 2.1+ events while retaining existing schema validation. The change is limited to interpreting progress events and does not alter compaction operations or product defaults. You can add or adjust custom eligibility rules. Learn more. |
Thread transfer impact✅ Thread transfer remains within every enforced ceiling.
Baseline: Scenario and decoded snapshot size10 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.
Updated in place by a trusted workflow. PR artifacts are strictly validated and never executed. |
|
No actionable comments were generated in the recent review.
|
| Layer / File(s) | Summary |
|---|---|
Compaction event fallback decoding packages/provider-opencode/src/server/v2/OpenCode2Client.ts |
When normal decoding fails, the client checks for compaction-started or compaction-ended events with object-valued data and no recent. It inserts an empty string and returns the event only if the existing schema accepts it. |
Event-stream handling and test packages/provider-opencode/src/server/v2/OpenCode2Client.ts, packages/provider-opencode/src/server/v2/OpenCode2Client.test.ts |
The event stream tries the fallback before marking an event undecodable. The test checks that both compaction event types are emitted in order. |
Priority:
Estimated code review effort: 2 (Simple) | ~10 minutes
Change: Bug fix · Severity of issue fixed: Medium
Possibly related PRs
- pingdotgg/t3code#25404: Its
/compactturns produce the live compaction events handled by this change. - pingdotgg/t3code#21597: It covers compaction lifecycle outcomes and timeline progress presentation.
- pingdotgg/t3code#24334: It defines shared compaction presentation for provider-started compaction rows.
Suggested labels: size:M
Suggested reviewers: maria-rcks
Merge Risk: 
Minimal · up to b996e
-
The change supports live compaction events from OpenCode 2.1+ without an identified regression. It is mergeable after normal checks.
Pre-merge checks: 
4
-
Check name Status Explanation Title check The title is concise, conventional, and accurately describes the main change: restoring compaction progress for OpenCode 2.1 and newer versions. Description check The description is complete and relevant. It explains the problem, the compatibility fix, scope and linked issue, focused tests, broader verification, runtime results, and limitations. Linked Issues check Linked issue #26193is the only active direct target. Its coding requirement is that T3 decodes live OpenCode 2.1 compaction frames, so the adapter can create the native compaction item. The PR meets …Out of Scope Changes check The whole-PR diff against merge base 735cc3c changes two files. (1) packages/provider-opencode/src/server/v2/OpenCode2Client.ts adds a Predicate import, decodeJson, decodeEventValue, and decodeCompac… Full details: Linked Issues check
-
Explanation
Linked issue
#26193is the only active direct target. Its coding requirement is that T3 decodes live OpenCode 2.1 compaction frames, so the adapter can create the native compaction item. The PR meets this in OpenCode2Client.ts. When the normal decodeEvent fails, decodeCompactionWithoutRecent parses the frame. If the frame is session.compaction.started or session.compaction.ended and has no data.recent key, it adds recent: "" and decodes again. Frames that fail for any other reason still reach the existing undecodable(frame.data) path. The new test 'delivers compaction events from OpenCode 2.1' in OpenCode2Client.test.ts feeds two 2.1.4 frames without recent through OpenCode2Client.layer and asserts both event types are delivered. The PR also reports runtime evidence against real OpenCode 2.1.4 and 2.2.0 servers: both events were delivered after the change. The issue states that the adapter branches for these events already exist. The UI result ('Compacting context' in a running thread) was not exercised by a test or a runtime check in this PR. The PR states this, so the UI outcome rests on the existing adapter code that the issue describes. Message-history decoding is not changed.#22656and PR#22661are history-record work and are not a requirement here.
Full details: Out of Scope Changes check
-
Explanation
The whole-PR diff against merge base 735cc3c changes two files. (1) packages/provider-opencode/src/server/v2/OpenCode2Client.ts adds a Predicate import, decodeJson, decodeEventValue, and decodeCompactionWithoutRecent. It also changes the filterMapEffect branch in readEvents to try the compaction fallback before undecodable handling. All of these changes serve the
#26193decode fix. (2) OpenCode2Client.test.ts adds the Stream import, a COMPACTION_FRAMES fixture taken from real 2.1.4 frames, a layerEventStream helper, and one test. The fixture, helper, and test all support the same fix. No dependency, schema, adapter, or history-decoding file changed. The ignored_files list is empty, so no excluded file affects this verdict.
-
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.
Problem
OpenCode 2.1+ no longer sends
data.recentonsession.compaction.startedandsession.compaction.ended. T3 bundles the 2.0.28 OpenCode protocol, which still requires it, so both live/api/eventframes fail decoding and are silently skipped. The adapter never sees them, and an OpenCode thread never shows "Compacting context" or "Context compacted". Reproduced by driving realopencode serve2.1.4 and 2.2.0 through T3'sOpenCode2Clientand running/compact(client.session.compact): both events appear on the wire, and T3 delivers neither. On 2.0.28 it delivers both.Change
When a frame fails the normal decode, and it is a compaction start or end event with no
recentkey,OpenCode2Clientdecodes it again withrecent: "". T3 never reads that field. Frames that decode today, including 2.0.x frames carryingrecent, keep the original path. Any other failure still falls through to the existing undecodable handling. No dependency bump. Message-history decoding is untouched.Scope and approval
Fixes #26193
Triaged via the automated issue flow.
Verification
vp test run src/server/v2/OpenCode2Client.test.tsinpackages/provider-opencode:delivers compaction events from OpenCode 2.1feeds the two frames captured from a real 2.1.4 server throughOpenCode2Client.layer.expected [] to deeply equal [ 'session.compaction.started', 'session.compaction.ended' ]. With this change, 2/2 pass.vp run check:changed: format, lint, knip, typecheck (10 packages) and tests all pass.OpenCode2Client.layer+FetchHttpClientagainst real@opencode/cliservers. It creates a session, sends one prompt, then runsclient.session.compact, whilecurlcaptures the raw SSE stream.recentpresent?)b88da913976aae4aa4f4There is no visible surface beyond the existing compaction item, so this PR has no captures. Not checked: the adapter rendering of the compaction item in a running T3 thread. That adapter branch is unchanged and is reached once the event decodes.
Runtime transcript
Scratch driver (not committed)
Implemented and verified by Claude Opus 5.5 (lead, red test, fix, reviewer B) and GPT-6.1 Sol (reviewer A), in T3 Code through Claude Code and Codex.
🤖 Generated with Claude Code