feat: add MiniMax quota fetcher and brand icon#1662
Conversation
Mirror the live multi-provider quota panel (getpaseo#1278) for MiniMax. Resolves the bearer token from $MINIMAX_API_KEY or the MiniMax CLI config at ~/.mmx/config.json (api_key, oauth.access_token) and credentials at ~/.mmx/credentials.json, then queries the /v1/token_plan/remains endpoint on the configured region (global by default, cn when region='cn'). The response is normalized into ProviderUsage windows per model_remains entry, surfacing the interval and weekly limits with their reset times and a danger tone when the server reports status=2.
The quota panel resolves the icon via resolveProviderIconName, which falls back to a generic Bot for any provider not in BUILTIN_PROVIDER_ICON_NAMES. Register 'minimax' as a built-in icon and vendor the official 24×24 brand mark (single Path, currentColor) as MiniMaxIcon so the usage card stops showing the generic robot.
|
| Filename | Overview |
|---|---|
| packages/server/src/services/quota-fetcher/providers/minimax.ts | New MiniMax quota provider with four-step auth resolution (env → credentials.json → config.json api_key → config.json oauth). Logic is correct and follows existing provider patterns; schema validation, HTTP timeout, and expired-token handling are all in place. |
| packages/server/src/services/quota-fetcher/service.test.ts | Five new MiniMax test cases exercising: env-var happy path, no-credentials short-circuit, OAuth credentials fallback, CN-region config fallback, and exhausted-interval tone. All tests cross the service interface rather than reaching into internals. |
| packages/app/src/components/icons/minimax-icon.tsx | New MiniMax brand icon component following the identical structure of ClaudeIcon and other existing icons (Svg + Path, fill on Svg container, currentColor default). |
| packages/server/src/services/quota-fetcher/manifest.ts | Minimal registration of MiniMaxQuotaProvider in PROVIDER_USAGE_FETCHERS; matches the pattern of all other providers in the manifest. |
| packages/protocol/src/provider-icon-names.ts | Adds 'minimax' to BUILTIN_PROVIDER_ICON_NAMES so the icon resolver returns { kind: 'builtin' } instead of the generic bot fallback. |
| packages/app/src/components/provider-icons.ts | Wires MiniMaxIcon into BUILTIN_PROVIDER_ICONS under the 'minimax' key, consistent with every other provider icon in the map. |
| packages/app/src/components/provider-icon-name.test.ts | Extends the existing builtin icon name test to assert the minimax mapping resolves correctly. |
Flowchart
%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[fetchUsage called] --> B{MINIMAX_API_KEY set?}
B -- yes --> C[Use env token + resolve base URL from MINIMAX_BASE_URL]
B -- no --> D[Read ~/.mmx/credentials.json]
D --> E{access_token present and not expired?}
E -- yes --> F[Use OAuth token + resource_url as base URL]
E -- no --> G[Read ~/.mmx/config.json]
G --> H{api_key present?}
H -- yes --> I[Use api_key + region/base_url]
H -- no --> J{oauth.access_token present and not expired?}
J -- yes --> K[Use oauth token + oauth.resource_url / base_url]
J -- no --> L[return unavailable]
C --> M[GET baseUrl/v1/token_plan/remains]
F --> M
I --> M
K --> M
M --> N{res.ok?}
N -- no --> O[return unavailable]
N -- yes --> P[Parse model_remains]
P --> Q[For each model: build interval + weekly windows]
Q --> R{windows.length > 0?}
R -- yes --> S[return available]
R -- no --> T[return unavailable]
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
A[fetchUsage called] --> B{MINIMAX_API_KEY set?}
B -- yes --> C[Use env token + resolve base URL from MINIMAX_BASE_URL]
B -- no --> D[Read ~/.mmx/credentials.json]
D --> E{access_token present and not expired?}
E -- yes --> F[Use OAuth token + resource_url as base URL]
E -- no --> G[Read ~/.mmx/config.json]
G --> H{api_key present?}
H -- yes --> I[Use api_key + region/base_url]
H -- no --> J{oauth.access_token present and not expired?}
J -- yes --> K[Use oauth token + oauth.resource_url / base_url]
J -- no --> L[return unavailable]
C --> M[GET baseUrl/v1/token_plan/remains]
F --> M
I --> M
K --> M
M --> N{res.ok?}
N -- no --> O[return unavailable]
N -- yes --> P[Parse model_remains]
P --> Q[For each model: build interval + weekly windows]
Q --> R{windows.length > 0?}
R -- yes --> S[return available]
R -- no --> T[return unavailable]
Reviews (3): Last reviewed commit: "fix: format" | Re-trigger Greptile
Greptile review on getpaseo#1662 called out two nested ternaries in toIntervalWindow and toWeeklyWindow. Extract a toneForStatus helper that uses an explicit if/else chain so the same status-to-tone mapping is shared between the interval and weekly windows, and add the missing trailing newline.
Mirrors the live multi-provider quota panel (#1278) for MiniMax, plus the brand icon so the usage card stops showing the generic robot.
Server
New
MiniMaxQuotaProvider(packages/server/src/services/quota-fetcher/providers/minimax.ts) that resolves the bearer token from:$MINIMAX_API_KEY(with optional$MINIMAX_BASE_URLoverride), or~/.mmx/credentials.json(OAuthaccess_token+resource_url, with anexpires_atguard), or~/.mmx/config.json(api_keyoroauth.access_token, honoringregionandbase_url).It hits
{baseUrl}/v1/token_plan/remains(defaulting tohttps://api.minimax.io, switching tohttps://api.minimaxi.comwhenregion='cn') and renders oneProviderUsageWindowpermodel_remainsentry for both the rolling interval and the weekly limit, with reset timestamps fromend_time/weekly_end_time. Acurrent_interval_statusof2(exhausted) maps to adangertone, and3(unlimited) maps todefault.Wired into
PROVIDER_USAGE_FETCHERSinpackages/server/src/services/quota-fetcher/manifest.ts— no other registration points needed; the existing tooltip / Host Usage screen already iterates the manifest.Tests in
packages/server/src/services/quota-fetcher/service.test.ts:MINIMAX_API_KEYagainst the global endpointstatus: unavailable~/.mmx/credentials.json(with customresource_url)api_key+region: 'cn'fallback in~/.mmx/config.json→ CN endpointtone: 'danger'App
MiniMaxIconcomponent (packages/app/src/components/icons/minimax-icon.tsx) using the official 24×24 brand mark (singlePath,currentColor) so the usage card colors it via the existingmutedIconColortheme token. Registered in:packages/protocol/src/provider-icon-names.ts— added"minimax"toBUILTIN_PROVIDER_ICON_NAMESsoresolveProviderIconName("minimax")returns{ kind: "builtin" }instead of falling through to{ kind: "bot" }.packages/app/src/components/provider-icons.ts— import +BUILTIN_PROVIDER_ICONSentry.Test extended in
packages/app/src/components/provider-icon-name.test.tsto assert the new built-in mapping.