Skip to content

Port upstream 0.66.0: OpenAI per-day usage history, core and bridge (stacked on #645) - #699

Open
Finesssee wants to merge 2 commits into
port/micro-0.66.0-openai-admin-parityfrom
port/micro-0.66.0-openai-daily-usage-core
Open

Finesssee wants to merge 2 commits into
port/micro-0.66.0-openai-admin-parityfrom
port/micro-0.66.0-openai-daily-usage-core

Conversation

@Finesssee

Copy link
Copy Markdown
Collaborator

Summary

Part (a) of the OpenAI per-day usage chart (upstream 0.66.0): the OpenAI Admin usage fetch now also returns a per-UTC-day history (cost, requests, input/cached/output/total tokens, line items, models). The history travels as ProviderFetchResult.open_ai_api_usage, reaches the frontend as the openAiApiUsage bridge field, and is typed in types/bridge.ts. No UI in this PR; the chart is part (b).

  • rust/src/core/usage_snapshot.rs: OpenAiApiUsageHistory, OpenAiApiDailyUsage, OpenAiApiLineItemCost, OpenAiApiModelUsage; ProviderFetchResult::with_open_ai_api_usage.
  • rust/src/providers/openaiapi/history.rs (new): per-day bucketing keyed by start_time. result_from_admin_usage now derives its totals, top models and top line items from these days, so there is one parsing path.
  • apps/desktop-tauri/src-tauri/src/commands/bridge/openai_usage.rs (new): camelCase DTOs (openAiApiUsage, epoch seconds) and From conversions; ProviderUsageSnapshot.open_ai_api_usage (omitted when absent).
  • apps/desktop-tauri/src/types/bridge.ts: OpenAiApiUsageSnapshot and friends, ProviderUsageSnapshot.openAiApiUsage.
  • The balance fallback (billing-api) has no history, as designed.

Approved design

Design note: design-openai-per-day-chart.md (approved; open questions resolved by the note's recommendations). Summary:

  • Upstream builds card.openAIAPIUsage = {historyDays, projectID|null, daily[]} beside the cost summary. Each UTC-day bucket holds startTime/endTime, costUSD, requests, inputTokens (input + input_audio), cachedInputTokens (separate, a subset of input), outputTokens (output + output_audio), totalTokens, lineItems[] (desc by cost, then name) and models[] (desc by tokens, then name).
  • Windows: provider id openaiapi, Admin API path only. Reuses the two Admin calls already made (/v1/organization/costs grouped by line_item, /v1/organization/usage/completions grouped by model, bucket_width=1d); no new endpoint, credential or dependency.
  • Model: OpenAiApiUsageHistory in usage_snapshot.rs, attached to ProviderFetchResult; bridge DTO openAiApiUsage (camelCase, epoch seconds) mirrored in types/bridge.ts. Upstream bounds apply (366 days, 10000 line-item + model entries).
  • Later UI (part b, not here): collapsed "Daily usage" section in the tray/pop-out MenuCard and a Settings > Providers ChartsSection tab, reusing components/charts/BarChart, Cost | Tokens toggle, one bar per UTC day, keyboard-navigable day selection, detail panel per day, empty state via DetailChartEmpty, 13 new OpenAIChart* locale keys across the 8 locales.
  • Open questions taken as recommended: window fixed at 30 days until an OPENAI_HISTORY_DAYS setting exists (the payload carries historyDays); USD only, no currency conversion; project id masking under hide-personal-info is a UI concern for part (b); the openaiapi id stays out of PROVIDER_CHART_DATA_IDS.

Upstream reference

  • Release 0.66.0 (OpenAI per-day usage chart). All reads pinned to tag v0.66.0.
  • Sources/CodexBarCore/Resources/Plugins/openai.js (daily map, bucket(), card.openAIAPIUsage).
  • Sources/CodexBarCore/Providers/OpenAI/OpenAIAPIProviderDescriptor.swift (mapPluginCard bounds and validation).
  • Sources/CodexBarCore/Providers/OpenAI/OpenAIAPIUsageSnapshot.swift (bucket shape, sort orders).
  • Tests/CodexBarTests/OpenAIAPIUsageFetcherTests.swift (parses admin costs and completions usage into daily summaries; its wire pages are the fixture for the new tests).

Ported / Deferred

Ported: per-day bucketing with upstream semantics (buckets keyed by start_time, first end_time wins, audio tokens folded into input/output, cached kept separate, days after now dropped, newest historyDays kept, upstream sort orders, blank names fall back to API / Responses and Chat Completions, negative or beyond-2^53 counts are parse failures like upstream integer()).

One deliberate deviation: upstream fails the whole fetch when a card bound is broken (a bucket whose end is not after its start, or more than 10000 line-item + model rows). Here the history is dropped with a tracing::warn! and the spend summary still shows, because the chart is auxiliary. With the fixed 30-day window the 366-day bound cannot be reached.

Deferred (per the design): all UI (part b), locale keys, OPENAI_HISTORY_DAYS, currency conversion, proof-harness variant for seeding an OpenAI API snapshot (CODEXBAR_SEED_USAGE_JSON currently seeds only Codex). The design note's risk about payload size (up to 366 days through provider_cache and events) is not an issue at 30 days; revisit if the window becomes configurable.

Behavior change to existing summary: totals, top models and top line items now come from the per-day buckets, so a bucket that starts after now no longer counts (upstream filter(start <= now)), and equal-cost line items tie-break by name.

Validation

Toolchain cargo +1.98.0, E-core wrappers, slot-5 target dir.

  • cargo fmt --all: clean.
  • cargo clippy --workspace --all-targets -- -D warnings: pass (both manifests).
  • cargo test -p codexbar openaiapi: 40 passed, 0 failed (11 new tests: 10 in history_tests.rs, 1 wire-page end-to-end in tests.rs; plus a no-history assertion on the balance-fallback test).
  • cargo test -p codexbar (full, shared core touched): 2194 passed, 0 failed, 1 ignored.
  • cargo test -p codexbar-desktop-tauri (full): 465 passed, 1 failed. The failure is commands::tests::bootstrap_payload_exposes_every_provider_variant (catalog has 79 entries, 78 active providers); this PR does not touch the provider catalog, and the test reads this machine's settings, so it looks environment-dependent. Not confirmed against the base branch.
    • New bridge tests in openai_usage_tests.rs (4) pass: camelCase epoch-second payload, omitted when absent, round trip, empty history.
  • pnpm exec tsc --noEmit: clean. pnpm run lint: only pre-existing warnings. vitest run src/components/MenuCard.test.tsx: 31 passed.

File sizes: no file crosses 1000 lines. mod.rs 783 -> 748, usage_snapshot.rs 819 -> 881; bridge.rs, commands/tests.rs and types/bridge.ts were already over 1000 (bridge.rs and tests.rs only gain the one-line open_ai_api_usage: None field in literals; bridge.ts gains ~45 lines of type declarations per the design).

Affected areas

  • Rust backend (rust/src/core, rust/src/providers/openaiapi)
  • Tauri shell bridge (commands/bridge)
  • Frontend bridge types only (types/bridge.ts)
  • Settings, tray, float bar, or any rendered surface
  • New dependencies or tooling

UI proof

Not applicable: no rendered surface changes in this PR. CUA proof belongs to part (b).

@coderabbitai

coderabbitai Bot commented Sep 29, 2026 •

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Advanced

Run ID: e7faf5e8-bc35-4eb5-b1b1-c4a12a216e7e

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

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.

@Finesssee

Copy link
Copy Markdown
Collaborator Author

Reviewed by Codex gpt-6-luna (xhigh); verified and validated by Claude

Thermo-nuclear review of #699. Part (a) is complete against the approved design note (Admin API history, typed bridge, balance-fallback behavior, backend and bridge tests). Chart UI and locale keys belong to part (b).

  • P2 rust/src/core/usage_snapshot.rs:671: populated history was serialized with ProviderFetchResult although documented as transient. Fixed: #[serde(skip)] plus a regression test.
  • P2 rust/src/providers/openaiapi/history.rs:186: individually valid counts could aggregate past JavaScript's exact integer range and reach the bridge as rounded numbers. Fixed: checked aggregation, unsafe chart history omitted while spend summaries are kept, plus a regression test.

@Finesssee

Copy link
Copy Markdown
Collaborator Author

Fixes for both findings landed in commit "Address thermo review". No items left open.

Commands run: cargo +1.98.0 fmt --all; cargo +1.98.0 clippy --all-targets -D warnings on rust and apps/desktop-tauri/src-tauri (clean); cargo +1.98.0 test --lib filtered to openai/open_ai/usage_snapshot (88 passed). No frontend change, so vitest not run.

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