Repository navigation
fix(opencode): read v2 session usage - #1668
Conversation
Read assistant usage from OpenCode v2 session_message rows while preserving legacy message loading. Support historical session_v2 and current session aggregates, and avoid counting aggregate rows when message-level usage exists. Co-authored-by: amirh-amini <[email protected]>
Deploying with
|
| Status | Name | Latest Commit | Preview URL | Updated (UTC) |
|---|---|---|---|---|
| ✅ Deployment successful! View logs |
ccusage-guide | 5592b88 | Commit Preview URL Branch Preview URL |
Aug 30 2026, 10:56 AM |
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (3)
Included review availability: Your plan provides up to 10 included reviews per hour; 8 remain after this review. 📝 WalkthroughWalkthroughThe OpenCode adapter now converts legacy and v2 usage data, including session aggregates. Aggregate fallback runs only for unfiltered ChangesOpenCode report loading
Estimated code review effort: 4 (Complex) | ~45 minutes Merge Risk: ⚪ Minimal · up to This PR adds OpenCode v2 usage loading while preserving legacy data handling and preventing duplicate or inapplicable aggregate counts. No actionable merge-blocking risk remains after normal checks and review. Sequence Diagram(s)sequenceDiagram
participant ReportRunner
participant OpenCodeLoader
participant OpenCodeDatabase
participant OpenCodeParser
participant LoadedEntries
ReportRunner->>OpenCodeLoader: request entries with report kind
OpenCodeLoader->>OpenCodeDatabase: read message and aggregate rows
OpenCodeDatabase-->>OpenCodeLoader: return source rows
OpenCodeLoader->>OpenCodeParser: convert v2 messages and aggregates
OpenCodeParser-->>OpenCodeLoader: return LoadedEntry values
OpenCodeLoader->>LoadedEntries: deduplicate and append eligible entries
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
Full details: Linked Issues checkExplanation The changes satisfy issue
✨ Finishing Touches 💡 1📝 Generate docstrings 💡
🧪 Generate unit tests (beta)
Warning Some tools did not complete. Review the errors below. 🔧 Clippy (1.97.1)Clippy execution failed Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Important
The aggregate fallback is currently emitted as a normal usage entry, which misattributes cumulative usage in daily, weekly, and monthly reports for sessions that cross reporting-period boundaries.
Reviewed changes
- OpenCode v2 message loading — reviewed the new
session_messagequery, assistant filtering, nested payload normalization, and ID deduplication alongside legacy SQLite and JSON sources. - Session aggregate fallback — reviewed the
session_v2and v2sessionaggregate readers, model/cost parsing, date filtering, and conversion into report entries. - Compatibility coverage — reviewed the added fixtures for mixed schemas, missing
time_created, duplicate IDs, date windows, and source detection. The focused adapter test suite passes with 50 tests.
@v0 or keep the SHA fresh with Dependabot | Fix all ➔ | Fix 👍s ➔ | View workflow run | Using GPT Luna (free via Pullfrog for OSS) | 𝕏
ccusage
@ccusage/ccusage-darwin-arm64
@ccusage/ccusage-darwin-x64
@ccusage/ccusage-linux-arm64
@ccusage/ccusage-linux-x64
@ccusage/ccusage-win32-x64
commit: |
ccusage performance comparisonPR SHA: This compares the PR package against the configured base package on the same CI runner. Package runtime diagnosticsCompares the PR package wrapper, the installed native optional dependency binary, and the workspace release binary on the same large fixture. This identifies whether slow package results come from JavaScript wrapper overhead, the published native binary build, or the Rust core itself. Fixtures: Claude
Committed fixture performanceCommitted small fixtures for stable PR-to-PR feedback and explicit Claude/Codex command coverage. Fixtures: Claude
Large real-world-shaped fixture performanceGenerated fixtures shaped from aggregate local log statistics: thousands of JSONL files, many small sessions, and a long tail of larger sessions. No real prompts, paths, or outputs are stored in the fixtures. Fixtures: Claude
Artifact size
Lower medians and smaller artifacts are better. CI runner noise still applies; use same-run ratios as directional PR feedback, not release guarantees. |
ccusage performance comparisonPR SHA: This compares the Rust PR release binary against the configured base package on the same CI runner. Package runtime diagnosticsCompares the PR package wrapper, the installed native optional dependency binary, and the workspace release binary on the same large fixture. This identifies whether slow package results come from JavaScript wrapper overhead, the published native binary build, or the Rust core itself. Fixtures: Claude
Committed fixture performanceCommitted small fixtures for stable PR-to-PR feedback and explicit Claude/Codex command coverage. Fixtures: Claude
Large real-world-shaped fixture performanceGenerated fixtures shaped from aggregate local log statistics: thousands of JSONL files, many small sessions, and a long tail of larger sessions. No real prompts, paths, or outputs are stored in the fixtures. Fixtures: Claude
Artifact size
Lower medians and smaller artifacts are better. CI runner noise still applies; use same-run ratios as directional PR feedback, not release guarantees. |
There was a problem hiding this comment.
All reported issues were addressed across 2 files
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
Avoid adding cumulative session aggregates until all message sources are loaded, so legacy JSON messages suppress matching aggregate rows. Skip aggregate-only fallback rows for bounded reports because cumulative totals cannot be sliced accurately. Preserve message-level legacy and v2 loading. Co-authored-by: amirh-amini <[email protected]>
There was a problem hiding this comment.
Important
The new aggregate gate still allows cumulative fallback rows into the default period reports, so the original cross-period misattribution remains.
Reviewed changes
- Separated message and aggregate results — reviewed the new result type and the handoff between message entries and aggregate fallback entries.
- Restricted aggregate fallback to bounded loads — checked the new date-window gate and its interaction with the adapter's report pipeline.
- Added fallback coverage — reviewed the tests for bounded windows, JSON-backed messages, and current session schemas.
@v0 or keep the SHA fresh with Dependabot | Fix all ➔ | Fix 👍s ➔ | View workflow run | Using GPT Luna (free via Pullfrog for OSS) | 𝕏
ccusage performance comparisonPR SHA: This compares the PR package against the configured base package on the same CI runner. Package runtime diagnosticsCompares the PR package wrapper, the installed native optional dependency binary, and the workspace release binary on the same large fixture. This identifies whether slow package results come from JavaScript wrapper overhead, the published native binary build, or the Rust core itself. Fixtures: Claude
Committed fixture performanceCommitted small fixtures for stable PR-to-PR feedback and explicit Claude/Codex command coverage. Fixtures: Claude
Large real-world-shaped fixture performanceGenerated fixtures shaped from aggregate local log statistics: thousands of JSONL files, many small sessions, and a long tail of larger sessions. No real prompts, paths, or outputs are stored in the fixtures. Fixtures: Claude
Artifact size
Lower medians and smaller artifacts are better. CI runner noise still applies; use same-run ratios as directional PR feedback, not release guarantees. |
ccusage performance comparisonPR SHA: This compares the Rust PR release binary against the configured base package on the same CI runner. Package runtime diagnosticsCompares the PR package wrapper, the installed native optional dependency binary, and the workspace release binary on the same large fixture. This identifies whether slow package results come from JavaScript wrapper overhead, the published native binary build, or the Rust core itself. Fixtures: Claude
Committed fixture performanceCommitted small fixtures for stable PR-to-PR feedback and explicit Claude/Codex command coverage. Fixtures: Claude
Large real-world-shaped fixture performanceGenerated fixtures shaped from aggregate local log statistics: thousands of JSONL files, many small sessions, and a long tail of larger sessions. No real prompts, paths, or outputs are stored in the fixtures. Fixtures: Claude
Artifact size
Lower medians and smaller artifacts are better. CI runner noise still applies; use same-run ratios as directional PR feedback, not release guarantees. |
There was a problem hiding this comment.
All reported issues were addressed across 1 file (changes from recent commits).
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
Allow cumulative session rows only for session reports and unbounded requests, so period reports cannot group session totals by creation date. Collect message session IDs across configured directories before adding aggregate fallbacks while preserving legacy and v2 message deduplication. Co-authored-by: amirh-amini <[email protected]>
There was a problem hiding this comment.
✅ No new issues found.
Reviewed changes
- Propagated report kind — passed
AgentReportKindthrough the OpenCode loader and unified adapter wiring so loading can distinguish session reports from period reports. - Restricted cumulative fallback — limited
session/session_v2aggregate rows to unbounded session reports while retaining message-level loading for daily, weekly, and monthly reports. - Added regression coverage — covered unbounded period reports, bounded session requests, cross-directory message suppression, and session-only aggregate fallback behavior.
@v0 or keep the SHA fresh with Dependabot | View workflow run | Using GPT Luna (free via Pullfrog for OSS) | 𝕏
ccusage performance comparisonPR SHA: This compares the Rust PR release binary against the configured base package on the same CI runner. Package runtime diagnosticsCompares the PR package wrapper, the installed native optional dependency binary, and the workspace release binary on the same large fixture. This identifies whether slow package results come from JavaScript wrapper overhead, the published native binary build, or the Rust core itself. Fixtures: Claude
Committed fixture performanceCommitted small fixtures for stable PR-to-PR feedback and explicit Claude/Codex command coverage. Fixtures: Claude
Large real-world-shaped fixture performanceGenerated fixtures shaped from aggregate local log statistics: thousands of JSONL files, many small sessions, and a long tail of larger sessions. No real prompts, paths, or outputs are stored in the fixtures. Fixtures: Claude
Artifact size
Lower medians and smaller artifacts are better. CI runner noise still applies; use same-run ratios as directional PR feedback, not release guarantees. |
ccusage performance comparisonPR SHA: This compares the PR package against the configured base package on the same CI runner. Package runtime diagnosticsCompares the PR package wrapper, the installed native optional dependency binary, and the workspace release binary on the same large fixture. This identifies whether slow package results come from JavaScript wrapper overhead, the published native binary build, or the Rust core itself. Fixtures: Claude
Committed fixture performanceCommitted small fixtures for stable PR-to-PR feedback and explicit Claude/Codex command coverage. Fixtures: Claude
Large real-world-shaped fixture performanceGenerated fixtures shaped from aggregate local log statistics: thousands of JSONL files, many small sessions, and a long tail of larger sessions. No real prompts, paths, or outputs are stored in the fixtures. Fixtures: Claude
Artifact size
Lower medians and smaller artifacts are better. CI runner noise still applies; use same-run ratios as directional PR feedback, not release guarantees. |
Upstream through 8841f92: official Antigravity SQLite adapter (ccusage#1677), ZCode (ccusage#1675) and Grok Build CLI sources, Copilot session-state usage (ccusage#1676), Codex originator breakdowns and cache-write token accounting (ccusage#1663, ccusage#1674), date-window file skipping (ccusage#1665), session totals scoped to the date window (ccusage#1664), OpenCode v2 session usage (ccusage#1668), timestamp-aware DeepSeek V4 pricing (ccusage#1679), ETag-validated pricing cache refreshes (ccusage#1672), and numeric-column preservation in narrow tables (ccusage#1671). Conflict resolutions per the personal divergence ledger: - Antigravity: adopt the upstream native adapter wholesale; remove the personal heuristic adapter and the antigravity-analysis/ provenance directory. - Codex: keep counting copied parent history (replay.rs stays deleted), keep tier changes applying at the following turn_context, keep the pre-v0.144.0 fast windows and the 2x fast-multiplier fallback, and keep the append-aware grouped cache with serde'd parser state. Integrate upstream cache-write tokens, originator sources, session_meta line detection, and filter_codex_usage_files date-window skipping. Bump the group, per-file event, and all-agent row cache discriminators. - Claude: rewire the cached daily/session summary wrappers onto upstream's date-scoped loaders (ccusage#1664). - OpenCode: keep WAL-signature cache signatures, the summary cache wrapper, and --no-cost -> Display mapping; take upstream's v2 session usage loading and split directory loader. - Pricing: keep the explicit GLM-5.2 rates and 1,000,000-token context limit (now via put_builtin_entry for both GLM-5.1 and GLM-5.2); take upstream's DeepSeek V4 scheduled rates and catalog rules. - Terminal: keep full dates whenever the minimum full-date layout fits and attached breakdown rows; take upstream's content-aware fallback minimums and numeric-column floors, adapting the 80-column regression test to the personal full-date policy. - Presentation: keep the hidden-by-default Models column and the all-agent --with-models opt-in; regenerate zcode/copilot session snapshots under the wider first-column floor. - Ledger: audit baseline updated to 8841f92; heuristic Antigravity and replay suppression recorded as retired divergences.
* fix(opencode): count usage from completed v2 compaction rows The OpenCode v2 loader skipped every session_message row whose type was not "assistant". That filter came from the original v2 support (#1668), which ignored non-assistant rows generically to drop user and marker rows; it was not added to avoid double-counting compactions. OpenCode records a completed compaction as its own session_message row whose tokens and cost are the usage of the compaction request itself, not the size of the resulting context. That usage is billed separately from assistant steps: compaction.ts publishes it as a UsageRecorded event with source "compaction", while assistant usage comes from Step.Ended. Skipping these rows therefore understated tokens and cost in every report, for example 12 instead of 174 tokens in the issue's repro. Accept "compaction" rows alongside "assistant" rows. They go through the same path, so message-ID deduplication across source roots and fork-copy exclusion by seq still apply, and session aggregates stay a fallback only for sessions without message usage. Running compactions carry no usage and failed ones record no model, so the existing parser still drops both. Closes #2013 * fix(opencode): keep session totals for compaction-only sessions The previous commit made compaction rows mark their session as covered by message usage, which suppresses the cumulative session aggregate fallback in unbounded session reports. OpenCode's session counters are the sum of every Step.Ended, every Step.Failed with usage, and every UsageRecorded event, and compactions publish UsageRecorded, so the aggregate already includes compaction usage. Revert deletes message rows without lowering the counters, so a session can be left with only compaction rows. Suppressing the aggregate for such a session dropped its assistant usage, which main still reported through the fallback. Adding the aggregate on top of the compaction rows would have double-counted the compaction instead. Keep compaction rows out of the coverage set and load them separately. Session aggregates fill sessions that have no assistant or legacy message usage, and compaction rows then count only for sessions that no aggregate covered. Period and date-bounded reports never use the aggregates, so they still count every completed compaction. * test(opencode): cover compaction usage in CLI reports rust/adapters/AGENTS.md asks for CLI JSON assertions and table snapshots for every report mode an adapter change affects. Run the ccusage binary against an OpenCode v2 database with a mixed assistant and compaction session and a compaction-only session, assert the daily, weekly, monthly, and session JSON totals, and snapshot each table. * fix(opencode): count only completed v2 compaction rows Compaction rows were accepted by type alone. Running and failed compactions stayed out only because the existing parser drops rows without a model, and that was incidental. OpenCode's failed compaction still records usage: compaction.ts publishes Compaction.Failed with the cost and tokens of every call already billed, and the CompactionFailed schema keeps those fields while omitting the model. A failed row that gained a model, from another OpenCode version or a provider that records one, would have been counted, even though attributing failed compactions is outside this change. Pass the row kind to the parser and accept a compaction only when its status is "completed". Group the row fields into a SessionMessageRow so the parser signature stays within clippy's argument limit.

Fixes #1644\n\nOpenCode v2 stores assistant usage in session_message.data instead of the legacy message table. This change:\n\n- reads nested assistant usage from session_message;\n- preserves legacy message loading;\n- supports session_v2 and current session aggregate schemas;\n- ignores non-assistant rows;\n- deduplicates shared message IDs;\n- avoids counting session aggregates when message-level usage exists.\n\nValidation:\n- OpenCode focused tests: 49 passed\n- rustfmt passed\n- clippy passed\n\nThe issue reporter is included as a commit co-author.
Summary by cubic
Fixes #1644. OpenCode v2 stores assistant usage in
session_message.datainstead of the legacymessagetable, so v2 usage was previously missing. This PR reads that usage and falls back tosession_v2orsessionaggregates when no message-level usage exists.session_messagerows.session_messageschemas that lack atime_createdcolumn.Written for commit 5592b88. Summary will update on new commits.
Summary by CodeRabbit
New Features
Bug Fixes