-
Notifications
You must be signed in to change notification settings - Fork 896
feat(gui): hide the Codex Spark quota by default behind a Codex Auth switch #2649
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -209,22 +209,59 @@ function codexAccountPersistenceConflict( | |
| : undefined; | ||
| } | ||
|
|
||
| /** | ||
| * The exact label `parseUsageQuota` emits for the Codex Spark window (quota.ts). | ||
| * Matching on the label rather than on "is a custom window" is load-bearing: the same array | ||
| * carries Cursor's First-party models / API usage, Anthropic's Fable / Opus / Sonnet, | ||
| * Antigravity's Gem / Cla, Kimi's subscription credits and a dozen dynamic provider meters. | ||
| */ | ||
| const CODEX_SPARK_WINDOW_LABEL = "GPT-5.3-Codex-Spark Weekly"; | ||
|
|
||
| /** | ||
| * Drop the Spark window unless the operator asked for it (default hidden). | ||
| * | ||
| * Applied at the DTO boundary, never at parse or cache time: custom windows participate in | ||
| * quota-presence checks, snapshot reconciliation and capacity aggregation, so removing Spark | ||
| * upstream of this point would change routing state rather than display. | ||
| * | ||
| * Both GUI surfaces funnel through here — the Codex Auth rows directly, and /api/provider-quotas | ||
| * via listCodexAuthAccountsSnapshot — so one filter covers both. Filtering only one would leave | ||
| * the other still rendering the row the operator switched off. | ||
| */ | ||
| export function withSparkVisibility<T extends Omit<StoredAccountQuota, "updatedAt"> | StoredAccountQuota | null>( | ||
| quota: T, | ||
| ): T { | ||
| if (!quota?.customWindows?.length) return quota; | ||
| if (loadConfig().showCodexSparkQuota === true) return quota; | ||
| const kept = quota.customWindows.filter(window => window.label !== CODEX_SPARK_WINDOW_LABEL); | ||
| if (kept.length === quota.customWindows.length) return quota; | ||
| // An empty list is dropped rather than serialized: an absent field and an empty array should | ||
| // not be two different ways of saying "no custom windows" on the wire. | ||
| const next = { ...quota } as Record<string, unknown>; | ||
| if (kept.length > 0) next.customWindows = kept; | ||
| else delete next.customWindows; | ||
| return next as T; | ||
|
Comment on lines
+231
to
+243
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🩺 Stability & Availability | 🟠 Major | 🏗️ Heavy lift Use the request-scoped setting instead of reloading configuration per quota. Line 235 calls Resolve 🤖 Prompt for AI Agents |
||
| } | ||
|
|
||
|
|
||
| function quotaForPlan<T extends Omit<StoredAccountQuota, "updatedAt"> | StoredAccountQuota | null>( | ||
| quota: T, | ||
| plan: unknown, | ||
| ): T { | ||
| if (!quota || !isThirtyDayOnlyCodexPlan(plan)) return quota; | ||
| const visible = withSparkVisibility(quota); | ||
| if (!visible || !isThirtyDayOnlyCodexPlan(plan)) return visible; | ||
| const quotaWindows = visible; | ||
| return { | ||
| ...(quota.monthlyPercent !== undefined ? { monthlyPercent: quota.monthlyPercent } : {}), | ||
| ...(quota.monthlyResetAt !== undefined ? { monthlyResetAt: quota.monthlyResetAt } : {}), | ||
| ...(quotaWindows.monthlyPercent !== undefined ? { monthlyPercent: quotaWindows.monthlyPercent } : {}), | ||
| ...(quotaWindows.monthlyResetAt !== undefined ? { monthlyResetAt: quotaWindows.monthlyResetAt } : {}), | ||
| // A 30-day plan can still carry a burst window, and it blocks the account on its own. | ||
| // Dropping it here would show a healthy card for an account upstream is refusing (#1791). | ||
| ...(quota.shortPercent !== undefined ? { shortPercent: quota.shortPercent } : {}), | ||
| ...(quota.shortResetAt !== undefined ? { shortResetAt: quota.shortResetAt } : {}), | ||
| ...(quota.shortWindowSeconds !== undefined ? { shortWindowSeconds: quota.shortWindowSeconds } : {}), | ||
| ...(quota.customWindows !== undefined ? { customWindows: quota.customWindows } : {}), | ||
| ...(quota.resetCredits !== undefined ? { resetCredits: quota.resetCredits } : {}), | ||
| ...("updatedAt" in quota ? { updatedAt: quota.updatedAt } : {}), | ||
| ...(quotaWindows.shortPercent !== undefined ? { shortPercent: quotaWindows.shortPercent } : {}), | ||
| ...(quotaWindows.shortResetAt !== undefined ? { shortResetAt: quotaWindows.shortResetAt } : {}), | ||
| ...(quotaWindows.shortWindowSeconds !== undefined ? { shortWindowSeconds: quotaWindows.shortWindowSeconds } : {}), | ||
| ...(quotaWindows.customWindows !== undefined ? { customWindows: quotaWindows.customWindows } : {}), | ||
| ...(quotaWindows.resetCredits !== undefined ? { resetCredits: quotaWindows.resetCredits } : {}), | ||
| ...("updatedAt" in quotaWindows ? { updatedAt: quotaWindows.updatedAt } : {}), | ||
|
Comment on lines
+251
to
+264
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift Keep Spark quota data available until capacity aggregation completes.
Aggregate raw stored quotas first. Then apply the visibility filter only to the published quota and aggregation DTO fields. Add a multi-account regression test that proves Spark affects internal aggregation while the response does not render its window when disabled. 🤖 Prompt for AI Agents |
||
| } as T; | ||
| } | ||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When this control is used from the embedded Codex account panel in the Providers workspace,
load(true)refreshes only/api/codex-auth/accountsand/api/codex-auth/active. The provider quota cards are owned byProviderWorkspaceShelland re-fetch only whenquotaRefreshEpochchanges, so their cached Spark row remains in the old visibility state after this toggle. Pass a quota-invalidation callback into this component and force the workspace's/api/provider-quotasrefresh after the setting is saved.Useful? React with 👍 / 👎.