-
Notifications
You must be signed in to change notification settings - Fork 127
fix(minimax): fetch real quota via Bearer API key #448
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 |
|---|---|---|
| @@ -0,0 +1,99 @@ | ||
| //! Bearer-authenticated MiniMax coding-plan quota fetch. | ||
| //! | ||
| //! Kept separate from the legacy billing client so the client-rendered console | ||
| //! workaround (#425) does not further grow the already-large provider module. | ||
|
|
||
| use chrono::Utc; | ||
|
|
||
| use crate::core::{FetchContext, ProviderError, ProviderFetchResult}; | ||
|
|
||
| use super::{MiniMaxRegion, coding_plan, coding_plan_html}; | ||
|
|
||
| fn resolve_plain_api_key(explicit: Option<&str>, environment: Option<&str>) -> Option<String> { | ||
| explicit | ||
| .map(str::trim) | ||
| .filter(|key| !key.is_empty()) | ||
| .or_else(|| environment.map(str::trim).filter(|key| !key.is_empty())) | ||
| .map(str::to_string) | ||
| } | ||
|
|
||
| pub(super) fn read_plain_api_key(ctx: &FetchContext) -> Option<String> { | ||
| let environment = std::env::var("MINIMAX_API_KEY").ok(); | ||
| resolve_plain_api_key(ctx.api_key.as_deref(), environment.as_deref()) | ||
| } | ||
|
|
||
| pub(super) async fn fetch_remains_via_api_key( | ||
| api_key: &str, | ||
| region: MiniMaxRegion, | ||
| ) -> Result<ProviderFetchResult, ProviderError> { | ||
| let now = Utc::now(); | ||
| let urls = [region.coding_plan_remains_url(), region.www_remains_url()]; | ||
| let mut last_err: Option<ProviderError> = None; | ||
| for url in urls { | ||
| match fetch_remains_once_via_api_key(api_key, &url).await { | ||
| Ok(snapshot) => { | ||
| let usage = coding_plan_html::to_usage_snapshot(&snapshot, now)?; | ||
|
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. 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win 🔎 Supported by static analysis🏁 Script executed: #!/bin/bash
set -euo pipefail
fd -a -t f '^coding_plan_html\.rs$' rust -x rg -n -C 12 \
'fn to_usage_snapshot|MiniMaxCodingPlanSnapshot::Services|ProviderError::Parse' {}
rg -n -C 10 \
'fetch_remains_via_api_key|fetch_remains_once_via_api_key|to_usage_snapshot' \
rust/src/providers/minimax/remains_api.rsRepository: nesszer/Win-CodexBar Length of output: 7788 🤖 get_repo_knowledge executed:
Length of output: 10925 🏁 Script executed: #!/bin/bash
set -euo pipefail
printf '%s\n' '--- remains_api.rs ---'
cat -n rust/src/providers/minimax/remains_api.rs | sed -n '1,180p'
printf '%s\n' '--- coding_plan_html conversion ---'
cat -n rust/src/providers/minimax/coding_plan_html.rs | sed -n '338,435p'
printf '%s\n' '--- callers and fallback symbols ---'
rg -n -C 12 \
'fetch_remains_via_api_key|legacy|fallback|ProviderFetchResult|to_usage_snapshot' \
rust/src/providers/minimaxRepository: nesszer/Win-CodexBar Length of output: 50376 Keep conversion parse failures inside the URL fallback loop. When 🤖 Prompt for AI Agents |
||
| return Ok(ProviderFetchResult::new(usage, "api")); | ||
| } | ||
| Err(err @ ProviderError::Parse(_)) => last_err = Some(err), | ||
| Err(err) => return Err(err), | ||
| } | ||
| } | ||
| Err(last_err.unwrap_or_else(|| ProviderError::Parse("Missing MiniMax remains URL.".into()))) | ||
| } | ||
|
|
||
| async fn fetch_remains_once_via_api_key( | ||
| api_key: &str, | ||
| url: &str, | ||
| ) -> Result<coding_plan::MiniMaxCodingPlanSnapshot, ProviderError> { | ||
| let client = crate::core::credentialed_http_client_builder() | ||
| .timeout(std::time::Duration::from_secs(30)) | ||
| .build() | ||
| .map_err(|e| ProviderError::Other(e.to_string()))?; | ||
|
|
||
| let response = client | ||
| .get(url) | ||
| .header("Authorization", format!("Bearer {api_key}")) | ||
| .header("Accept", "application/json, text/plain, */*") | ||
| .send() | ||
| .await?; | ||
|
|
||
| let status = response.status(); | ||
| if status == reqwest::StatusCode::UNAUTHORIZED || status == reqwest::StatusCode::FORBIDDEN { | ||
| return Err(ProviderError::AuthRequired); | ||
| } | ||
| if !status.is_success() { | ||
| let message = format!("MiniMax remains (api key) returned status {status}"); | ||
| if status == reqwest::StatusCode::NOT_FOUND | ||
| || status == reqwest::StatusCode::METHOD_NOT_ALLOWED | ||
| { | ||
| return Err(ProviderError::Parse(message)); | ||
| } | ||
| return Err(ProviderError::Other(message)); | ||
| } | ||
|
|
||
| let json: serde_json::Value = response | ||
| .json() | ||
| .await | ||
| .map_err(|e| ProviderError::Parse(format!("Failed to parse remains JSON: {e}")))?; | ||
| coding_plan::parse_coding_plan_value(&json, Utc::now()) | ||
| } | ||
|
|
||
| #[cfg(test)] | ||
| mod tests { | ||
| use super::resolve_plain_api_key; | ||
|
|
||
| #[test] | ||
| fn plain_api_key_prefers_explicit_then_environment_without_mutating_process_env() { | ||
| assert_eq!( | ||
| resolve_plain_api_key(Some(" ctx-key "), Some("env-key")).as_deref(), | ||
| Some("ctx-key") | ||
| ); | ||
| assert_eq!( | ||
| resolve_plain_api_key(Some(" "), Some(" env-key ")).as_deref(), | ||
| Some("env-key") | ||
| ); | ||
| assert_eq!(resolve_plain_api_key(Some(" "), Some(" ")), None); | ||
| assert_eq!(resolve_plain_api_key(None, None), None); | ||
| } | ||
| } | ||
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.
🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift
Do not convert remains API failures into a successful CLI result.
In
SourceMode::Auto, line 1048 discardsAuthRequiredandNetworkerrors from the new plain-key remains request.probe_clithen returns a configured 0% snapshot whenMINIMAX_API_KEYexists. An invalid key or service outage is therefore reported as successful usage data.Preserve errors after a plain API key was attempted. Use the CLI fallback only when no plain key was available or another fallback succeeds.
🤖 Prompt for AI Agents