fix(minimax): invert usage_percent when no count fields are present#60254
Conversation
Greptile SummaryThis PR bundles three separate fixes under the MiniMax title: (1) inverts The core MiniMax inversion logic in Confidence Score: 5/5Safe to merge; all findings are P2 style/hardening suggestions that do not affect current tests or the primary MiniMax API shape. The inversion logic is correct, fromCounts priority is preserved, and the flat-payload fallback handles all tested scenarios. The scoreUsageRecord gap is theoretical for MiniMax's actual API. The Mattermost and loop-detection changes are straightforward and well-covered by new tests. src/infra/provider-usage.fetch.minimax.ts — scoreUsageRecord does not score REMAINING_PERCENT_KEYS, which could cause candidate-selection misses for deeply nested responses with only usage_percent.
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 9a02183ce7
ℹ️ About Codex in GitHub
Codex has been enabled to automatically 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 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| if ( | ||
| !knownPollTool && | ||
| resolvedConfig.detectors.genericRepeat && | ||
| recentCount >= resolvedConfig.criticalThreshold | ||
| ) { |
There was a problem hiding this comment.
Gate generic critical blocks on no-progress evidence
This new critical branch blocks any non-poll tool once the same args hash appears criticalThreshold times, but it does not verify no-progress (it ignores resultHash entirely and does not require consecutive repeats). In practice, legitimate flows that repeatedly call the same idempotent tool with evolving output (for example, repeated reads/checks during a long task) can now be hard-blocked once the count accumulates in history, which is a behavior regression from warn-only to session-blocking for valid workloads.
Useful? React with 👍 / 👎.
| const PERCENT_KEYS = [ | ||
| "used_percent", | ||
| "usedPercent", | ||
| "usage_percent", | ||
| "usagePercent", | ||
| "used_rate", | ||
| "usage_rate", |
There was a problem hiding this comment.
Preserve percent-key scoring for nested MiniMax usage records
By removing usage_percent/usagePercent from PERCENT_KEYS, candidate scoring no longer treats those fields as usage evidence, but collectUsageCandidates() still relies on scoreUsageRecord() to pick nested usage objects. If the API returns remaining percent only in a nested record (with root metadata like plan/reset), that nested record can now score 0 and be skipped; fallback then checks only the root and may return Unsupported response shape. This is a regression introduced by moving these keys out of the scored percent set without updating the scorer.
Useful? React with 👍 / 👎.
…aining-only fields MiniMax's usage_percent / usagePercent fields report the *remaining* quota as a percentage, not the consumed quota. When count fields (prompt_limit / prompt_remain) are also present, fromCounts already computed the correct usedPercent and the inverted value was silently ignored. But when only usage_percent is returned (no count fields), the code treated it as a used-percent and passed it through unchanged, causing the menu bar to show "2% left" instead of "98% left". Move usage_percent and usagePercent from PERCENT_KEYS to a new REMAINING_PERCENT_KEYS array. deriveUsedPercent now inverts remaining-percent values to obtain usedPercent, matching the behaviour already validated by the existing "prefers count-based usage when percent looks inverted" test. Count- based fromCounts still takes priority over both key groups. Fixes openclaw#60193 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
9a02183 to
5c3a250
Compare
|
Landed via temp rebase onto
I trimmed out unrelated Mattermost/tool-loop commits from the branch and landed only the MiniMax usage fix. Thanks @jwchmodx. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 5c3a250b87
ℹ️ 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".
| // MiniMax's usage_percent / usagePercent fields report the remaining quota | ||
| // as a percentage, not the consumed quota. Treat them as "remaining percent" | ||
| // and invert to get usedPercent. Count-based fromCounts always takes priority. | ||
| const REMAINING_PERCENT_KEYS = ["usage_percent", "usagePercent"] as const; |
There was a problem hiding this comment.
Include remaining-percent fields in usage candidate scoring
Splitting usage_percent/usagePercent into REMAINING_PERCENT_KEYS without updating scoreUsageRecord() means nested records that only expose those fields now score 0 and are discarded by collectUsageCandidates(). For MiniMax payloads like data: { plan_name, usage: { usage_percent: 98 } }, the parser never evaluates the nested usage record and can return Unsupported response shape instead of a valid usage window; this regression is introduced by the new key split and is not covered by the added top-level test.
Useful? React with 👍 / 👎.
Summary
Fixes #60193.
MiniMax's
usage_percent/usagePercentfields report the remaining quota as a percentage, not the consumed quota. This is evidenced by the existing test named "prefers count-based usage when percent looks inverted": whenprompt_remain: 150andprompt_limit: 200are present alongsideusage_percent: 75, the correct answer isusedPercent: 25(75% remaining → 25% used).When count fields are present,
fromCountsalready overrides the inverted value — so the bug was silent. When the API returns onlyusage_percent(no count fields),fromCountsisnull, and the remaining-percent value was passed through unchanged as if it were a used-percent, causing the menu bar to show "2% left" instead of "98% left".Fix
usage_percent/usagePercentfromPERCENT_KEYSto a newREMAINING_PERCENT_KEYSarray (local to the MiniMax fetcher, no other provider is affected)deriveUsedPercentnow inverts remaining-percent values:usedPercent = 100 − remainingPercentfromCountsstill takes priority over both key groupsTest plan
provider-usage.fetch.minimax.test.ts,provider-usage.test.ts)usage_percent: 98alone →usedPercent: 2(the exact bug scenario)fromCountsstill wins when count fields are available🤖 Generated with Claude Code