Skip to content

Add OpenAI Tokens/min tray metric - #925

Merged
Finesssee merged 3 commits into
mainfrom
feat/openai-live-tokens-menubar
Oct 20, 2026
Merged

Finesssee merged 3 commits into
mainfrom
feat/openai-live-tokens-menubar

Conversation

@Finesssee

@Finesssee Finesssee commented Oct 18, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

Ports the optional Tokens/min menu bar token from upstream CodexBar v0.75.0 (steipete#4495, commit 5a40ac4). It builds on the existing OpenAI Live Usage data path (#893, #897) and adds no new fetches.

  • New MetricPreference::TokensPerMinute (tokensPerMinute on the bridge and in settings.json).
  • New Provider::reports_tokens_per_minute() trait hook. The typed fact lives once on ProviderId::reports_tokens_per_minute() and the trait default delegates to it, so the shell can check the capability from a provider id without instantiating a provider. Only openaiapi qualifies. ProviderDetail.tokensPerMinuteMetric exposes it, so the Settings > Providers > OpenAI API "Menu and floating bar metric" picker offers Tokens/min without provider branching in shared code.
  • The Windows tray has no menu bar text slot. The value appears in the two places the tray shows text: the tray tooltip and the tray-menu status row. Both show OpenAI API 49M/min, using the latest reported minute (throughput.latestTokensPerMinute). Formatting matches upstream tokenCountString + "/min", so the output looks like 950/min, 12K/min, 1.5M/min or 0/min.
  • When there is no reported minute, both places show a localized "Tokens/min unavailable". This happens when Live usage is off, there is no Admin key, or no complete minute exists yet. Upstream's accessibility text works the same way.
  • The tray icon pixels are unchanged. Tokens/min is a rate, not a quota, so in usage_metric.rs the meter (and the floating bar) keeps the Automatic lane. The change there is a single match arm.
  • Locale keys MetricTokensPerMinute and TrayTokensPerMinuteUnavailable are in all 10 .ftl files and keyGroups/shell.ts.
  • Proof fixtures add openaiapi to the proof catalog plus a browser scenario for the picker.

The upstream sparkline token (tokensSparkline) is not ported. A 34-px graph next to the icon has no Windows tray equivalent.

Review fixes (second commit)

  • Serde spelling. MetricPreference is rename_all = "lowercase", so TokensPerMinute would have been written as tokensperminute while the bridge uses tokensPerMinute. It now serializes as tokensPerMinute with the lowercase spelling kept as a read alias, same as ExtraUsage. The pre-existing MonthlyPlan had the same mismatch and is fixed the same way (monthlyPlan, alias monthlyplan), so files written by either spelling keep loading. Regression tests cover both spellings for both metrics and confirm a settings file with the camelCase value loads without falling back to defaults (rust/src/settings/tests/metric_preference.rs).
  • Siloing. tokens_per_minute_status (used by both the tray status row and the tooltip) now also requires ProviderId::reports_tokens_per_minute(), so a tokensPerMinute value saved against a provider that cannot report a rate falls back to the Automatic label instead of leaking the rate onto that provider's row. Covered by tokens_per_minute_metric_on_a_provider_without_a_rate_falls_back.
  • Changelog. The two duplicated OpenAI feat(openai): live tokens-per-minute usage with org limits steipete/CodexBar#4495 bullets are consolidated and the stale "menu bar token comes in a later release" sentence is gone.
  • Proof scenario. settings-openaiapi-tokens-per-minute-metric now actually selects Tokens/min in the picker and asserts the persisted value through the mocked bridge (update_settings with providerMetrics.openaiapi = "tokensPerMinute"), then checks the select reads the new value back.
  • MetricPreference::display_name() ("Tokens/min") has no callers in the app, the shell or the CLI; the picker labels come from the localized MetricTokensPerMinute key, so nothing user-facing goes unlocalized.

Commands run

  • cargo fmt --all
  • cargo test --manifest-path rust/Cargo.toml --lib settings::: 208 passed, 0 failed (includes the 3 new metric serde tests)
  • cargo test --manifest-path rust/Cargo.toml --lib openai: 120 passed
  • cargo test --manifest-path apps/desktop-tauri/src-tauri/Cargo.toml tray_presentation: 59 passed (includes the new fallback test); tray_bridge: 13 passed; provider_detail: 9 passed
  • cargo clippy --manifest-path rust/Cargo.toml --all-targets -- -D warnings: clean
  • cargo clippy --manifest-path apps/desktop-tauri/src-tauri/Cargo.toml --all-targets -- -D warnings: clean
  • pnpm test: 145 files, 1373 tests passed (one transient failure in an unrelated test on the first run; passed on both reruns)
  • pnpm run build: OK
  • pnpm proof:check (Chromium, mocked IPC): 13/13 passed
PASS  tray-default  (2 screenshots)
PASS  tray-claude-plan-renews  (1 screenshot)
PASS  tray-claude-plan-hidden  (1 screenshot)
PASS  tray-errors  (1 screenshot)
PASS  tray-empty  (1 screenshot)
PASS  flyout-default  (1 screenshot)
PASS  settings-general-dark  (2 screenshots)
PASS  settings-general-light  (1 screenshot)
PASS  settings-providers  (1 screenshot)
PASS  settings-codex-two-accounts  (1 screenshot)
PASS  settings-openaiapi-tokens-per-minute-metric  (1 screenshot)
PASS  settings-menu-work-days  (2 screenshots)
PASS  floatbar  (1 screenshot)

Proof

Tray-affecting: desktop CUA proof to follow. Still to prove on a fresh Windows desktop build:

  1. Select Settings > Providers > OpenAI API > Menu and floating bar metric > Tokens/min, then check that get_settings_snapshot reports providerMetrics.openaiapi = "tokensPerMinute" and that settings.json contains the camelCase value.
  2. With Live usage on and a seeded throughput snapshot, the tray tooltip line reads OpenAI API: <n>/min and the tray-menu status row reads OpenAI API <n>/min.
  3. With throughput absent, both read "Tokens/min unavailable".
  4. The tray icon pixels match the Automatic metric's pixels.

Reference: upstream steipete/CodexBar steipete#4495 (read-only).

@coderabbitai

coderabbitai Bot commented Oct 18, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: Repository: nesszer/Win-CodexBar/.coderabbit.yaml
  • Review profile: ASSERTIVE
  • Plan: Advanced
  • Run ID: ca602c6f-a972-46a2-9b5d-eeb40b2430ea
📥 Commits

Reviewing files that changed from the base of the PR and between 60b589e and 3971958.

📒 Files selected for processing: 32
  • CHANGELOG.md
  • apps/desktop-tauri/scripts/proof-scenarios.json
  • apps/desktop-tauri/src-tauri/src/commands/bridge/settings_snapshot.rs
  • apps/desktop-tauri/src-tauri/src/commands/provider_detail.rs
  • apps/desktop-tauri/src-tauri/src/tray_bridge.rs
  • apps/desktop-tauri/src-tauri/src/tray_presentation.rs
  • apps/desktop-tauri/src-tauri/src/tray_presentation_tests.rs
  • apps/desktop-tauri/src-tauri/src/usage_metric.rs
  • apps/desktop-tauri/src/i18n/keyGroups/shell.ts
  • apps/desktop-tauri/src/proof/fixtures/bridgeData.ts
  • apps/desktop-tauri/src/proof/fixtures/common.ts
  • apps/desktop-tauri/src/surfaces/settings/providers/sections/MenuBarMetricSection.test.tsx
  • apps/desktop-tauri/src/surfaces/settings/providers/sections/MenuBarMetricSection.tsx
  • apps/desktop-tauri/src/types/bridge/providers.ts
  • apps/desktop-tauri/src/types/bridge/settings.ts
  • rust/src/core/provider/id.rs
  • rust/src/core/provider/traits.rs
  • rust/src/core/throughput.rs
  • rust/src/locale.rs
  • rust/src/locale/en-US.ftl
  • rust/src/locale/es-MX.ftl
  • rust/src/locale/ja-JP.ftl
  • rust/src/locale/ko-KR.ftl
  • rust/src/locale/pt-BR.ftl
  • rust/src/locale/ru-RU.ftl
  • rust/src/locale/tr-TR.ftl
  • rust/src/locale/uk-UA.ftl
  • rust/src/locale/zh-CN.ftl
  • rust/src/locale/zh-TW.ftl
  • rust/src/settings/tests.rs
  • rust/src/settings/tests/metric_preference.rs
  • rust/src/settings/types.rs

Included review availability: This review used your included allowance. Your plan provides up to 4 included reviews per hour; 1 remain after this review.

📝 Walkthrough

Adds a Tokens/min metric preference for OpenAI API. Settings can select and save the metric. The tray status displays the latest reported rate or an unavailable message, while the usage window remains Automatic.

Changes: OpenAI Tokens per Minute

Layer / File(s) Summary
Provider capability and metric preference
rust/src/core/provider/*, rust/src/settings/*, apps/desktop-tauri/src-tauri/src/commands/..., apps/desktop-tauri/src/types/bridge/*, apps/desktop-tauri/src-tauri/src/usage_metric.rs, rust/src/core/throughput.rs
Adds a provider capability for Tokens/min, adds the metric preference and its serialization, exposes it through the bridge, and formats rate labels. Tests cover serialization, parsing, and label formatting.
Settings picker and proof coverage
apps/desktop-tauri/src/surfaces/settings/providers/sections/MenuBarMetricSection.*, apps/desktop-tauri/src/proof/fixtures/*, apps/desktop-tauri/scripts/proof-scenarios.json, apps/desktop-tauri/src/i18n/keyGroups/shell.ts
Offers Tokens/min when the provider advertises support. The setting test and proof scenario cover selecting and saving the preference.
Tray status display and localization
apps/desktop-tauri/src-tauri/src/tray_{bridge,presentation}*.rs, rust/src/locale.rs, rust/src/locale/*.ftl, CHANGELOG.md
Uses the selected metric for tray status text and displays an unavailable label when no latest rate exists. Tests cover reported, zero, and missing rates, unsupported providers, and the unchanged Automatic icon lane. Adds localized strings and updates the changelog.

Priority: ⬇️ Low

Estimated code review effort: 3 (Moderate) | ~25 minutes

Change: Feature

Sequence Diagram(s)

sequenceDiagram
  participant SettingsPicker
  participant SettingsBridge
  participant TrayBridge
  participant TrayPresentation
  SettingsPicker->>SettingsBridge: Save tokensPerMinute preference
  TrayBridge->>SettingsBridge: Read settings
  TrayBridge->>TrayPresentation: Build provider status label
  TrayPresentation->>TrayBridge: Return rate or unavailable label
Loading

Suggested reviewers: pasharm

Merge Risk: ⚪ Minimal · up to 39719

The Tokens/min setting and tray display are ready to merge after normal checks.

Caution

Pre-merge checks failed

Please resolve all errors before merging. Addressing warnings is optional.

  • Ignore

Failed Failed checks: 1 error · 1 warning

Check name Status Explanation Resolution
Provider Data Stays Siloed Error The pull request adds a provider-specific branch in shared code outside the allowed paths. rust/src/core/provider/id.rs:168-170 adds reports_tokens_per_minute() with `matches!(self, ProviderId::Op… Remove the ProviderId::OpenAIApi match from rust/src/core/provider/id.rs. Keep the default capability false in the shared Provider trait, override reports_tokens_per_minute() in rust/src/providers/openaiapi/mod.rs, and route ID-on…
Ui Changes Include Windows Proof Warning The PR changes visible UI. The diff adds a Tokens/min option to the settings picker and changes tray tooltip and status-row text. The description reports Chromium proof and states that desktop CUA pro… Run the proof on a fresh Windows build and add screenshots or a completed proof note to the PR description. Cover the settings selection and persistence, tray tooltip and status row with and without throughput, and unchanged tray icon pixel…
Passed Passed checks: 6 passed
Check name Status Explanation
Linked Issues check Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check Passed Check skipped because no linked issues were found for this pull request.
Secrets Handled Safely Passed No changed code exposes a credential. The new tray path reads only the numeric latest_tokens_per_minute usage count and formats it as a rate; it does not read or format API keys, cookies, OAuth cred…
No Unapproved Dependencies Passed The pull request changes 32 files, and none are Cargo.toml, package.json, npm/yarn lockfiles, or pnpm-lock.yaml. It also does not change the pinned pnpm packageManager version. No dependency addition …
Description Check Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check Passed The title is a short imperative summary that accurately describes the main change: adding an OpenAI Tokens/min tray metric.
Full details: Secrets Handled Safely

Explanation

No changed code exposes a credential. The new tray path reads only the numeric latest_tokens_per_minute usage count and formats it as a rate; it does not read or format API keys, cookies, OAuth credentials, or authorization headers. The added settings and provider fields contain only metric/capability metadata. The diff adds no logging calls, credential snapshots, or credential-like literals, and it contains no deleted, renamed, or overwritten files.

Full details: No Unapproved Dependencies

Explanation

The pull request changes 32 files, and none are Cargo.toml, package.json, npm/yarn lockfiles, or pnpm-lock.yaml. It also does not change the pinned pnpm packageManager version. No dependency addition requires maintainer approval.

Full details: Provider Data Stays Siloed

Explanation

The pull request adds a provider-specific branch in shared code outside the allowed paths. rust/src/core/provider/id.rs:168-170 adds reports_tokens_per_minute() with matches!(self, ProviderId::OpenAIApi). This directly matches a specific ProviderId in shared core code. The new tray and provider-detail paths call this method, so the branch is introduced by this pull request. The changed code otherwise gates the metric to OpenAI and does not show evidence of identity or account data crossing providers.

Resolution

Remove the ProviderId::OpenAIApi match from rust/src/core/provider/id.rs. Keep the default capability false in the shared Provider trait, override reports_tokens_per_minute() in rust/src/providers/openaiapi/mod.rs, and route ID-only capability lookups through a generic API in rust/src/core/provider_factory.rs or another allowed provider-specific mechanism. Do not add provider-specific ProviderId cases in shared tray or core code.

Full details: Ui Changes Include Windows Proof

Explanation

The PR changes visible UI. The diff adds a Tokens/min option to the settings picker and changes tray tooltip and status-row text. The description reports Chromium proof and states that desktop CUA proof is “to follow” and “Still to prove on a fresh Windows desktop build.” It does not include completed fresh-Windows screenshots or proof evidence.

Resolution

Run the proof on a fresh Windows build and add screenshots or a completed proof note to the PR description. Cover the settings selection and persistence, tray tooltip and status row with and without throughput, and unchanged tray icon pixels.

  • Fix all pre-merge checks with AI
✨ 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

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Factory Agent added 2 commits October 19, 2026 03:05

@coderabbitai coderabbitai 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.

Pre-merge checks failed. Please resolve the failing checks before merging.

@Finesssee

Copy link
Copy Markdown
Collaborator Author

UI proof (hybrid CDP + CUA, build 3971958)

Surface: Settings > Providers > OpenAI API (proof mode settings:providers:openaiapi) and the tray tooltip. Change: the OpenAI API "Menu and floating bar metric" picker offers Tokens/min, and the tray text then shows the latest reported minute.

Setup: fresh debug build of 3971958 (pnpm --dir apps/desktop-tauri run tauri:build:debug), staged with the proof kit (bin/BUILT_FROM = W:/wcb-wt/proof-925 3971958b0195bba0333c66166229a05d7ee0b1f5). Isolated kit home with a settings file that enables only OpenAI API and Codex and turns off status checks. Synthetic seed (seed-925.json): OpenAI API primary.usedPercent = 8, throughput.latestTokensPerMinute = 12345; Codex primary.usedPercent = 42, "Resets in 2h 10m". Theme auto, Windows in dark mode. CDP port 9925. park.py kept the kit windows on the secondary monitor for the whole run. Run: runs/proof925-20261020-074617.

Check Method Result
Picker offers Tokens/min, starts on Automatic CDP DOM read of the metric <select> options automatic, session ("Spend"), tokensPerMinute ("Tokens/min"); value automatic
Tooltip under Automatic Kit tray button UIA Name (Shell_TrayWnd, read-only, no hover or click) CodexBar / OpenAI API: 8% / Codex: 42% • Resets in 2h 10m, no /min
Picker state before → after CDP: select change event (same as suite.py selects), then DOM read automatic → tokensPerMinute, label "Tokens/min"
Persisted setting CDP get_settings_snapshot providerMetrics.openaiapi: "tokensPerMinute"
settings.json spelling DPAPI-decrypted kit settings.json provider_metrics: {"openaiapi": "tokensPerMinute"} (camelCase value)
Tray tooltip with Tokens/min Kit tray button UIA Name CodexBar / OpenAI API: 12K/min / Codex: 42% • Resets in 2h 10m
Tray icon pixels unchanged Screen crop of the kit icon's UIA rectangle only, SHA-256 of the pixels Automatic = Tokens/min = 25fb1b0a…ec15de
Siloing: Codex with tokensPerMinute saved CDP update_settings patch providerMetrics.codex = "tokensPerMinute" (the Codex picker doesn't offer it), then the tooltip snapshot holds codex: "tokensPerMinute"; the Codex line stays Codex: 42% • Resets in 2h 10m (Automatic label, no rate, no "unavailable")
Settings window native facts CUA window list + Win32/DWM visible, dwm_dark: true under theme auto (system dark), not topmost
Focus untouched foreground HWND start = end no: see below

Screenshots (cua-driver, real pixels): 925-1-picker-automatic.png (before), 925-2-picker-tokens-per-minute.png (after). Icon crops (screen pixels, icon rectangle only): 925-icon-automatic.png, 925-icon-tokens-per-minute.png. Checked: no emails, account names or user paths.

Not covered:

  • Tray-menu status row (OpenAI API 12K/min). Reading the native menu needs a right-click on the tray icon, and the menu model isn't exposed through a bridge command or a log. The status row and the tooltip call the same tray_presentation::tokens_per_minute_status. Only the tooltip was observed live. The row is covered by the tray_presentation unit tests.
  • "Tokens/min unavailable" with no throughput. This case needs a relaunch with a seed that has no throughput. The relaunch in the first attempt (run proof925-20261020-074340) put the kit window in the foreground, so it wasn't repeated. That run also failed to read the tooltip after the restart, for the reason in the note below. The case is covered by unit tests only.
  • The tray icon itself in the screenshots: only the 24 px crops of the icon's screen rectangle, no cua window shot (the tray isn't a kit window).
  • Live OpenAI Admin API data, multi-monitor and DPI scaling.

Focus: FAIL. The run started with the foreground on the terminal (warp.exe, 0x2b2308d6). Right after launch, the kit's main window (0x29230c6a, Settings rendered in main under proof mode) became the foreground window. No CDP or CUA call caused it: the kit logged a foreground change at the first check, before any click. In the earlier attempt, the first launch kept the foreground, but the relaunch after a kill took it (0x13d00fe, the main window per the dwm log). The behavior is intermittent. It is probably the launch path: the exe started as a descendant of the foreground terminal, so Windows allows its first shown window to activate. It is not something this PR changes. It still breaks the kit's focus rule and needs a separate look.

Note: with a pinned seed, the startup refresh is skipped, so the tray tooltip reads only CodexBar Desktop until the next tray-presentation refresh. The run triggers that refresh with an explicit providerMetrics.openaiapi = "automatic" patch before the baseline read.

@Finesssee
Finesssee merged commit 9f063e3 into main Oct 20, 2026
3 checks passed
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