MiniMax: recharge credits, usage dashboard, and quota utilization#1821
MiniMax: recharge credits, usage dashboard, and quota utilization#1821Yuxin-Qiao wants to merge 57 commits into
Conversation
MiniMax API remains responses omit the console recharge-credit balance. Fetch it from token_plan_credit when a browser session cookie is available, including API-token refreshes that also have cached or manual cookies. Co-authored-by: Cursor <cursoragent@cursor.com>
|
Codex review: needs changes before merge. Reviewed July 5, 2026, 3:10 PM ET / 19:10 UTC. Summary Reproducibility: yes. for the PR blockers: source inspection at the current head shows the same failing guards/cache keys and Keychain path without needing live MiniMax credentials. I did not run live provider probes because repository policy avoids checks that can trigger Keychain prompts. Review metrics: 3 noteworthy metrics.
Merge readiness Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch. Rank-up moves:
Risk before merge
Maintainer options:
Copy recommended automerge instructionNext step before merge
Security Review findings
Review detailsBest possible solution: Land the MiniMax dashboard after the four mechanical blockers are fixed with focused regression coverage for Keychain gating, recovery actions, daily-only usage, and merged-menu width caching. Do we have a high-confidence way to reproduce the issue? Yes for the PR blockers: source inspection at the current head shows the same failing guards/cache keys and Keychain path without needing live MiniMax credentials. I did not run live provider probes because repository policy avoids checks that can trigger Keychain prompts. Is this the best way to solve the issue? No: the feature direction is useful and well-proven, but the current implementation is not the narrowest safe merge until the four mechanical blockers are repaired. The safer path is to keep the enrichment feature but gate Keychain reads, show recovery correctly, prefer fresh daily data, and key width caching by menu context. Full review comments:
Overall correctness: patch is incorrect AGENTS.md: found and applied where relevant. Codex review notes: model internal, reasoning high; reviewed against 8e9a844dbd36. Label changesLabel justifications:
Evidence reviewedSecurity concerns:
Acceptance criteria:
What I checked:
Likely related people:
What the crustacean ranks mean
Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics. How this review workflow works
Review history (11 earlier review cycles; latest 8 shown)
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 88dfac6c95
ℹ️ 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".
| usage = await MiniMaxUsageFetcher.attachingTokenPlanCreditIfAvailable( | ||
| to: usage, | ||
| context: fetchContext, | ||
| groupID: MiniMaxCookieHeader.override(from: cookieHeader)?.groupID) |
There was a problem hiding this comment.
Preserve MiniMax group IDs from cookie overrides
When the configured cookie value is a curl command whose group is only present as x-group-id or a GroupId URL parameter, resolveCookieHeader has already stripped the raw value down to just the Cookie header before this re-parse runs. That drops the group ID even though MiniMaxCookieHeader.override supports extracting it, so the token_plan_credit request omits x-group-id and can fetch no balance or the wrong group balance for multi-group accounts; carry the original MiniMaxCookieOverride through this path instead.
Useful? React with 👍 / 👎.
| return MiniMaxCookieHeader.override(from: raw)?.cookieHeader | ||
| } | ||
| #if os(macOS) | ||
| return CookieHeaderCache.load(provider: .minimax)?.cookieHeader |
There was a problem hiding this comment.
Avoid merging cached cookies into unrelated API results
When a user has a MiniMax API key for one account but the cached browser cookie belongs to another, this automatic cache fallback supplies that cookie to the API strategy and the new enrichment attaches the cookie account's pointsBalance to the API-key quota. The cache entry is not compared with any account or group in the API response, so this can render and export a balance for a different account; require an explicit cookie for API enrichment or verify the account before merging.
Useful? React with 👍 / 👎.
| let fetchContext = MiniMaxUsageFetcher.WebFetchContext( | ||
| cookie: cookie, | ||
| authorizationToken: nil, | ||
| region: region, |
There was a problem hiding this comment.
Use the region that actually served the API quota
For API-key users who leave the region at the default, fetchUsage(apiToken:region:) first tries global and then silently retries China when the global host rejects the key (see the existing retries china host when global rejects token coverage). If that China retry succeeds, this enrichment context still uses the original .global region, so the balance request goes to www.minimax.io instead of www.minimaxi.com and misses the cookie-authenticated credit balance for those existing China-region accounts.
Useful? React with 👍 / 👎.
| if let host = MiniMaxSettingsReader.hostOverride(environment: environment), | ||
| let hostURL = URL(string: "https://\(host)")? | ||
| .appendingPathComponent("backend/account/token_plan_credit") |
There was a problem hiding this comment.
Keep credit fetches on the web host under host overrides
When users set the documented general override such as MINIMAX_HOST=platform.minimaxi.com (or an API host), this branch rewrites the new credit endpoint to https://platform.minimaxi.com/backend/account/token_plan_credit. The endpoint added in this patch defaults to the www.minimaxi.com/www.minimax.io web hosts, so these valid existing host-override setups silently lose the recharge balance after the 404 is swallowed; either keep the default web host for this endpoint or require the specific MINIMAX_TOKEN_PLAN_CREDIT_URL override for proxies.
Useful? React with 👍 / 👎.
Propagate cancellation from token-plan credit enrichment, keep credit fetches on www hosts under MINIMAX_HOST overrides, use the API region that actually served quota, preserve curl group IDs, and only merge explicit cookies into API refreshes. Fix released changelog structure and expand regression tests. Co-authored-by: Cursor <cursoragent@cursor.com>
|
@clawsweeper re-review Addressed the review items in 972cffa:
Proof: API-only diagnose from the built PR CLI is attached in the updated PR body. Full recharge-balance proof still needs an explicit MiniMax cookie on the contributor account (manual settings or |
|
🦞🧹 I asked ClawSweeper to review this item again. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 972cffac68
ℹ️ 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 let override = MiniMaxSettingsReader.tokenPlanCreditURL(environment: environment) { | ||
| return override | ||
| } | ||
| return region.tokenPlanCreditURL |
There was a problem hiding this comment.
Respect host override when choosing credit region
When MiniMax is configured only through the documented MINIMAX_HOST=platform.minimaxi.com env override and no persisted region, quota/billing requests resolve to the China host, but this fallback ignores that override and still sends the new credit lookup to region.tokenPlanCreditURL (defaulting to www.minimax.io). Fresh evidence after the prior host-override comment is that the updated resolver now avoids the platform host but still uses the global web host for China MINIMAX_HOST setups, so those existing env-based users silently lose pointsBalance unless they also know to set MINIMAX_TOKEN_PLAN_CREDIT_URL.
Useful? React with 👍 / 👎.
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
No code changes; prior macOS test shards were cancelled by cancel-in-progress from rapid pushes. Co-authored-by: Cursor <cursoragent@cursor.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 8d40b54e3c
ℹ️ 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".
| let resolved = MiniMaxAPIRegion(rawValue: region), | ||
| self.settings.minimaxAPIRegion != resolved | ||
| else { return } | ||
| self.settings.minimaxAPIRegion = resolved |
There was a problem hiding this comment.
Avoid persisting detected MiniMax region across accounts
When a selected MiniMax token account only succeeds after the global→China retry, this writes .cn into the provider-wide setting. That setting is then reused for other MiniMax token accounts, and fetchAPITokenUsage does not try the global host when the preferred region is already .cn, so any configured global account can start failing on later refreshes until the user manually changes the shared region back. Keep the auto-detected region scoped to the current account/fetch, or only persist it when there are no token accounts to mix.
Useful? React with 👍 / 👎.
Route credit lookups from MINIMAX_HOST, fall back to env cookies when manual settings are empty, and relax the gated live balance assertion. Co-authored-by: Cursor <cursoragent@cursor.com>
|
@clawsweeper re-review Addressed the open findings in 227ed49:
|
|
🦞🧹 I asked ClawSweeper to review this item again. |
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 6c49ef2925
ℹ️ 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".
| var providerConfig = config.providerConfig(for: provider) ?? ProviderConfig(id: provider) | ||
| guard providerConfig.region != trimmed else { return } | ||
| providerConfig.region = trimmed | ||
| config.setProviderConfig(providerConfig) | ||
| try store.save(config) |
There was a problem hiding this comment.
Avoid persisting region from env-only CLI probes
When codexbar usage/diagnose is run with only a temporary MINIMAX_CODING_API_KEY in the environment and the global request falls back to China, this CLI updater creates or updates the persisted MiniMax provider config and saves region = cn. This separate CLI path means a one-shot env probe changes later app/CLI refreshes, and because fetchAPITokenUsage does not try global once the preferred region is .cn, a subsequent global key can fail until the user manually resets the setting; skip this updater for env-backed credentials or scope it to a stored MiniMax config.
Useful? React with 👍 / 👎.
|
@codex review Addressed the remaining MiniMax region findings in
This prevents env-only probes and mixed global/China credentials from changing later routing. SwiftFormat and |
|
🦞🧹 I asked ClawSweeper to review this item again. |
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: b2bc5da376
ℹ️ 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".
| let resolvedBalance = self.pointsBalance ?? pointsBalance | ||
| let resolvedExpiry = self.pointsBalanceExpiresAt ?? expiresAt |
There was a problem hiding this comment.
Use the fetched MiniMax credit balance
When the remains response already contains pointsBalance but token_plan_credit returns a different remaining_credits, this helper keeps self.pointsBalance because of self.pointsBalance ?? pointsBalance, so the Credits card can continue showing the older/general balance while only the expiry metadata updates. Fresh evidence after the earlier guard fix is that the credit request now runs, but its balance is still discarded here whenever any balance was parsed earlier.
Useful? React with 👍 / 👎.
| APP_FINAL="${CODEXBAR_PACKAGE_OUTPUT:-$ROOT/CodexBar.app}" | ||
| APP_STAGE="${CODEXBAR_PACKAGE_STAGE:-$ROOT/.build/package/CodexBar.app}" |
There was a problem hiding this comment.
Reject identical package stage and output paths
If a caller sets only CODEXBAR_PACKAGE_OUTPUT to the default stage path (or otherwise makes these two variables resolve to the same .app), the script builds into APP_STAGE and then the existing finalization step runs rm -rf "$APP_FINAL" before mv "$APP" "$APP_FINAL", deleting the just-built bundle and causing packaging to fail. The new validation should reject identical resolved paths or always stage in a separate temporary bundle.
Useful? React with 👍 / 👎.
| if provider == .minimax { | ||
| return MenuBarMetricWindowResolver.nearestResetWindow(snapshot: snapshot) | ||
| ?? self.menuBarMetricWindow(for: provider, snapshot: snapshot) |
There was a problem hiding this comment.
Honor MiniMax reset-time metric preference
When MiniMax is in menu-bar reset-time mode and the user selected the weekly/secondary metric, this branch ignores that preference and always chooses the soonest reset across all MiniMax lanes; normal accounts with both 5-hour and weekly quotas therefore keep showing and scheduling refreshes for the 5-hour reset instead of the selected weekly reset. Keep the nearest-reset behavior to the automatic case or fall back to menuBarMetricWindow when a specific lane is selected.
Useful? React with 👍 / 👎.
| private static let webCookieHosts: Set<String> = [ | ||
| "www.minimaxi.com", | ||
| "www.minimax.io", | ||
| "platform.minimaxi.com", | ||
| "platform.minimax.io", |
There was a problem hiding this comment.
Accept parent-domain MiniMax Agent cookies
If the MiniMax Agent stores its session cookie on the parent domain (.minimax.io or .minimaxi.com), which is valid for the www/platform endpoints and is already included by the browser-cookie importer, this allow-list drops it because only exact subdomains are accepted. In that common cookie shape the new Agent import path returns no usable session even though the cookie would be sent by the browser; include the parent domains while still excluding Agent-only hosts.
Useful? React with 👍 / 👎.
Keep MiniMax sampling helpers file-local, restore private plan utilization sampling, and split non-macOS API enrichment. Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 048f9b6970
ℹ️ 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".
| usage.usageSummary == nil, | ||
| usage.pointsBalance == nil, |
There was a problem hiding this comment.
Offer recovery when MiniMax token details are missing
When an API-key MiniMax refresh gets points_balance from token-plan remains but the web usage_summary cookie is expired or unavailable, this guard returns before adding the recovery items because pointsBalance is non-nil. That leaves the menu without Token usage details and without the re-import/login actions needed to repair the web session; gate on all required web data being present, or at least on usageSummary for this token-details recovery path, instead of requiring both fields to be nil.
Useful? React with 👍 / 👎.
| "version=\(self.menuSession.contentVersion)", | ||
| "providers=\(providers.map(\.rawValue).joined(separator: ","))", | ||
| "locale=\(self.menuLocalizationSignature())", |
There was a problem hiding this comment.
Include overview state in the merged width cache
When a merged menu is first opened on Overview, menuCardWidth is called with the overview descriptor, where the selected provider's contextual actions are intentionally omitted, but this cache key is reused later when switching to that provider with its full action section. If that provider has the widest action text, the cached width is too small and the first provider switch can render clipped/narrow rows; include the selected/overview descriptor state in the key or measure all providers with the same contextual-action mode before caching.
Useful? React with 👍 / 👎.
| if let day = self.days.first(where: { $0.date == self.snapshotDateKey }) { | ||
| return day | ||
| } | ||
| return self.latestDay |
There was a problem hiding this comment.
Prefer daily MiniMax usage for a missing update day
When last_update_time points to the latest daily_token_usage value but date_model_usage has not yet emitted a row for that date, this fallback returns the previous model day. latestSnapshotTokens then uses that stale positive day total before it can fall back to dailyTokenUsage.last, so the main card shows yesterday's tokens as the latest usage; only fall back to latestDay when there is no daily value for the snapshot date.
Useful? React with 👍 / 👎.
| KeychainNoUIQuery.apply(to: &query) | ||
|
|
||
| var result: AnyObject? | ||
| let status = SecItemCopyMatching(query as CFDictionary, &result) |
There was a problem hiding this comment.
Honor the Keychain opt-out for MiniMax Agent cookies
When Keychain access is disabled (for example via Advanced settings or CODEXBAR_DISABLE_KEYCHAIN_ACCESS) and the MiniMax Agent cookie DB stores encrypted values, this path still reaches SecItemCopyMatching. Browser cookie imports are gated on KeychainAccessGate.isDisabled, so the new Agent importer bypasses the same opt-out during availability checks/API enrichment; return no decryption keys or skip the Agent import while the gate is disabled.
Useful? React with 👍 / 👎.
Co-authored-by: Cursor <cursoragent@cursor.com>
Verify credit group IDs before merging API web enrichment, map login-only usage summaries to invalid credentials, anchor daily-only years from the reference date, prefer dedicated credit balances, gate plan history on the sampled snapshot, honor explicit reset-metric preferences, accept parent- domain Agent cookies, and reject identical package output/stage paths. Co-authored-by: Yuxin Qiao <Yuxin-Qiao@users.noreply.github.com>
Co-authored-by: Yuxin Qiao <Yuxin-Qiao@users.noreply.github.com>
Co-authored-by: Yuxin Qiao <Yuxin-Qiao@users.noreply.github.com>
Co-authored-by: Yuxin Qiao <Yuxin-Qiao@users.noreply.github.com>
Co-authored-by: Yuxin Qiao <Yuxin-Qiao@users.noreply.github.com>
Co-authored-by: Yuxin Qiao <Yuxin-Qiao@users.noreply.github.com>
Co-authored-by: Yuxin Qiao <Yuxin-Qiao@users.noreply.github.com>
|
Closing in favor of a 3-PR feature split for easier review:
Original branch: |
Summary
Token Plan recharge credit balance
GET /backend/account/token_plan_creditonwww.minimaxi.com/www.minimax.iowhen a web session cookie is available.MiniMaxWebEnrichmentResolver, trying candidates in order: manual/env cookie → MiniMax Agent desktop cookies → cached browser cookies → live browser import.MINIMAX_HOSTselects the matchingwww.*credit host for MiniMax-owned domains; custom proxy hosts route through the override path. UseMINIMAX_TOKEN_PLAN_CREDIT_URLfor a full custom credit URL.region: cninto config.pointsBalance; menu rendering reuses the existingMiniMax points balancecost row.Console usage-summary dashboard
usage_summary) alongside quota/credit enrichment when a web cookie is available.Web session enrichment (no MiniMax Code required)
~/Library/Application Support/MiniMax/Cookiesautomatically — no Chrome Keychain prompt.platform.minimaxi.com/www.minimaxi.comin Chrome, then press ⌘R once and approve the Keychain prompt if macOS asks for Chrome safe-storage access.Cookie:header into Preferences → Providers → MiniMax, or setMINIMAX_COOKIE.docs/minimax.mdwith the full source priority and capture steps.Follow-up fixes in this branch
platform.*.com/console/usage(not the Coding Plan page). Settings Open Token Plan still opens the Coding Plan page.remains_timevalues and falls back toend_time.MINIMAX_HOSTcustom proxies also routeusage_summaryenrichment; MiniMax-owned host overrides still map to the matchingwww.*summary host.cache_read_tokenseparately frominput_token.MenuCardModelTests) that failed CI on UTC runners.Review follow-up
Round 1 (
30cf613a/ ClawSweeper)MINIMAX_HOST/ resolved region instead of always using globalwww.minimax.iodiagnose/usageoutput (below)MINIMAX_LIVE_TEST_EXPECTED_BALANCEfor exact assertsMINIMAX_COOKIE/ env when manual cookie settings are emptyRound 2 (
@chatgpt-codex-connector)MINIMAX_HOSToverrides for usage-summary enrichmentMotivation
Users with recharge credits (for example 20,000 points in the MiniMax console) saw quota data via API key but
providerCostPresent: falsein diagnostics and no balance in the menu. The balance lives on a separate cookie-authenticated endpoint discovered from the platform web bundle.The console also exposes a separate usage-summary API with token/cost trends, cache-hit stats, and model breakdowns that CodexBar previously did not fetch or render. This PR adds that enrichment plus Codex-style quota utilization history without duplicating KPI blocks between the main card and submenus.
UI evidence (live Plus account, 2026-07-02)
Main card inline dashboard + credits
Shows 5h / Weekly quota rows, 6 KPI grid, cost trend, top-model line, pricing disclaimer, and 20,000 recharge credits with expiry.
Menu card usage notes (Settings preview)
Subscription Utilization (Session / Weekly history)
Codex-style quota utilization chart with Session/Weekly lanes; footer shows reset time + used %.
Token usage details submenu
7d/30d segmented trend, daily spend, per-model token/cost rows, and window spend KPIs.
Test plan
make checkswift test --filter MiniMaxswift test --filter MiniMaxTokenPlanCreditTestsswift test --filter MiniMaxUsageSummaryswift test --filter MiniMaxResetDescriptionTestsswift test --filter MenuBarMiniMaxResetTimeDisplayTestsswift test --filter UsageStorePlanUtilizationTestsswift test --filter MiniMaxDesktopCookieImporterTestsswift test --filter MiniMaxWebEnrichmentResolverTestsTZ=UTC swift test --filter 'minimax token plan model shows weekly quota'remaining_credits,balance_breakdown.total_balance, andtotal_credits - used_creditsProviderHTTPTransportStubconsole/usage$0.33for 1M input + 500k cache reads on M2.7)./Scripts/compile_and_run.sh— menu card, Usage Dashboard link, and both submenus verified locallyBehavior proof
API-only account (no web session): built PR CLI on this branch
→
source: api, quota present,pointsBalanceomitted (expected; web cookie required).API key + web session cookie (MiniMax Agent desktop or browser/manual): built PR CLI on this branch, 2026-07-02
{ "source": "api", "planName": "Plus", "pointsBalance": 20000, "usageSummaryPresent": true, "providerCost": { "period": "MiniMax points balance", "used": 20000 } }Commands:
Direct endpoint sanity check (same session cookie, redacted):
GET https://www.minimaxi.com/backend/account/token_plan_credit→remaining_credits: 20000,base_resp.status_code: 0.Notes for reviewers
token_plan_credit(console returnsnot login); a web_tokencookie is required for the balance.MINIMAX_TOKEN_PLAN_CREDIT_URL, plus existingMINIMAX_HOST/ remains / coding-plan overrides.docs/minimax.mddocs/screenshots/minimax-usage/for stable PR references.