Skip to content

feat: add Claude Code session usage and account credits - #38

Merged
BytePioneer-AI merged 2 commits into
mainfrom
feat/claude-code-session-usage
Aug 25, 2026
Merged

feat: add Claude Code session usage and account credits#38
BytePioneer-AI merged 2 commits into
mainfrom
feat/claude-code-session-usage

Conversation

@BytePioneer-AI

Copy link
Copy Markdown
Owner

Summary

  • add Claude Code session usage projection for cost, token totals, cache hit rate, and 5-hour/7-day plan windows
  • add Claude Code account credits with on-demand refresh and shared renderer usage controls
  • add protocol, adapter, host-runtime, renderer, and end-to-end coverage
  • remove automated Claude attribution trailers so commits retain only the actual repository author

Validation

  • git diff --check main...HEAD
  • Tests and type checks were run during implementation; see the commits for the covered packages.

…windows

Implements openspec/changes/project-claude-code-session-usage.

- HostUsage / threadUsageSnapshotSchema: add optional Claude.ai plan-window
  fields (planFiveHourUsedPercent/ResetsAtUnix, planSevenDayUsedPercent/
  ResetsAtUnix); reject a reset without its matching used percent.
- Claude adapter: parse Turn Result usage.result (Session cost, per-model
  token totals, latest cache hit rate) and rate_limit_event plan windows;
  merge into one latest-still-applicable HostUsage snapshot per Session.
- rate_limit_event parsing reads the real Claude Code wire shape
  (rate_limit_info.unifiedWindows.{five_hour,seven_day}, utilization as a
  0-1 fraction) rather than the flat 0-100 shape the SDK's .d.ts implies,
  confirmed against a live payload; keeps a flat-field fallback for
  forward/backward compatibility. Per-model weekly breakdowns and overage
  are intentionally ignored.
- Renderer: Usage details popover gains optional 5-hour / 7-day limit rows;
  collapsed summary and control visibility unchanged (CH/cost only).
- Host inspection round-trips the new fields without touching
  accountCredits; Codex native tokenUsage/updated carrier untouched.

Tests: harness-adapter, shared-contracts, claude-code adapter (native
message, sdk-transport, adapter), renderer-usage-control, protocol-core,
host-runtime, and e2e coverage. Full repo typecheck/lint/vitest pass.
…and refresh

Builds on the earlier Session Usage change with a full account-credits
pipeline for Claude Code, matching (and redesigning) Grok's existing pill.

Renderer (Grok + Claude Code, shared UI):
- Replace the plain dot+percent credits pill with a radial progress ring
  (createRendererUsageRing, shared with a future dual-window pill).
- Rewrite the credits popover as stacked tiles: a headline row (big percent,
  period label, reset) plus one full-width bar per productUsage entry —
  every row gets its own progress bar, not just the sub-rows.
- formatRendererCreditsReset: same-day resets read as a precise time ("4:12
  PM today"); every other reset carries date + time together ("Aug 28, 6:00
  PM") instead of dropping the time once >24h out — the source data is
  minute-precise for both windows, so the display no longer throws that away.
- Both popovers get a raised-card chrome (color-mix over Canvas/CanvasText,
  larger radius, real elevation shadow) instead of a flat system panel;
  the credits popover adds a tone-tinted glow.
- accountCreditsSnapshotSchema: periodType gains "five_hour"/"seven_day";
  accountCreditsProductUsageSchema gains an optional per-entry resetsAt.
- Fix shouldRetryExternalThreadUsage's Grok-only retry-for-credits carve-out
  to cover any agent whose Adapter implements credits() (currently Grok and
  Claude Code) — Claude Code's credits pill was going permanently blank
  after switching threads because Usage alone was enough to stop the retry
  loop before credits ever got a chance to populate for agents other than
  "grok".

Claude Code Adapter:
- Promote plan-limit tracking from Session-level to Adapter-level
  (#latestPlanLimit), since the 5h/7d windows are account-wide, not
  per-thread — shared by every concurrent Session (tested).
- projectClaudePlanLimitToCredits: five-hour leads as the primary metric
  (periodType "five_hour"), seven-day rides along as a productUsage entry
  ("7-day window") when both are known; falls back to seven-day alone.
- New on-demand pull: ClaudeTurnTransport.getPlanLimit() calls the SDK's
  Query#usage_EXPERIMENTAL_MAY_CHANGE_DO_NOT_RELY_ON_THIS_API_YET() control
  method (the same channel getContextUsage() already uses) to ask Claude
  Code's /usage data for the current plan-window utilization right now,
  instead of only replaying whatever the last passive rate_limit_event said.
  refreshCredits() now tries each open Session's live Transport in turn
  until one answers, routing a fresh answer through the same
  #handlePlanLimit path as the push so it updates both the Adapter-wide
  credits() cache and that Thread's own Usage snapshot.
@BytePioneer-AI
BytePioneer-AI merged commit 3db82a0 into main Aug 25, 2026
0 of 3 checks passed

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: eff6296483

ℹ️ 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".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

if (agent === "codex") return false;
if (usage === null) return true;
return agent === "grok" && accountCredits === null;
return externalAgentHasAccountCredits(agent) && accountCredits === null;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Stop retrying credits when Claude plan limits are unavailable

For Claude threads using API-key, Bedrock, or Vertex authentication, Usage can be available while accountCredits is permanently absent. This predicate therefore remains true, the scheduler polls forever at its 8-second ceiling, and every inspection invokes refreshCredits(), producing endless experimental control-channel queries per mounted composer. Make the retry conditional on an observed/capable plan source or bound the attempts.

AGENTS.md reference: AGENTS.md:L61-L66

Useful? React with 👍 / 👎.

Comment on lines +1671 to +1673
if (event.lastRequestUsage) {
const cacheHitRatePercent = claudeCacheHitRatePercent(event.lastRequestUsage);
if (cacheHitRatePercent !== undefined) delta.cacheHitRatePercent = cacheHitRatePercent;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Clear stale cache-hit data after an incomplete request

When one request publishes a cache-hit percentage and a later request omits any required cache field, lastRequestUsage is absent and this branch leaves cacheHitRatePercent untouched; #mergeAndPublishUsage then carries the previous request's percentage forward even though the UI presents it as the latest request. Clear the old value once the newer result and context fallback cannot provide a complete breakdown.

AGENTS.md reference: AGENTS.md:L61-L66

Useful? React with 👍 / 👎.

if (typeof utilization !== "number" || !Number.isFinite(utilization) || utilization < 0) {
return undefined;
}
const utilizationPercent = Math.min(100, Math.max(0, Math.round(utilization * 10_000) / 100));

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve percent-scaled values in flat rate-limit events

The same parser handles live unifiedWindows fractions and the flat SDK fallback, but it always multiplies utilization by 100. Consequently, a documented flat value such as utilization: 45 is projected as 100% after clamping rather than 45%. Parse the flat 0–100 fallback separately from the live 0–1 window shape.

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant