feat: add MiniMax token plan usage segment#102
Closed
yearth wants to merge 3 commits intoHaleclipse:masterfrom
Closed
feat: add MiniMax token plan usage segment#102yearth wants to merge 3 commits intoHaleclipse:masterfrom
yearth wants to merge 3 commits intoHaleclipse:masterfrom
Conversation
Add support for checking MiniMax API token plan usage (weekly and 5-hour interval quotas) directly in the statusline. Features: - New MiniMaxTokenPlan segment that queries the MiniMax API - Displays remaining quota percentages with visual circle icons - Caches API responses for 5 minutes to reduce API calls - Configurable via MINIMAX_API_KEY environment variable - Added to all built-in themes (cometix, default, minimal, gruvbox, nord, powerline-dark, powerline-light, powerline-rose-pine, powerline-tokyo-night) Configuration options: - cache_duration: Cache validity in seconds (default: 300) - timeout: API request timeout in seconds (default: 10) Co-Authored-By: Claude <noreply@anthropic.com>
Reviewer's GuideAdds a new MiniMax token plan statusline segment that queries the MiniMax API, computes remaining weekly and 5‑hour quotas with caching, wires it into the segment system, and exposes it across all built‑in themes and UI components. Sequence diagram for MiniMax token plan segment collection and cachingsequenceDiagram
actor User
participant App
participant Statusline
participant MiniMaxTokenPlanSegment
participant FileSystem
participant MiniMaxAPI
User->>App: Render statusline
App->>Statusline: collect_all_segments()
Statusline->>MiniMaxTokenPlanSegment: collect(input)
MiniMaxTokenPlanSegment->>MiniMaxTokenPlanSegment: read MINIMAX_API_KEY
alt API key missing
MiniMaxTokenPlanSegment-->>Statusline: None
Statusline-->>App: Skip MiniMaxTokenPlan
App-->>User: Statusline without MiniMax token plan
else API key present
MiniMaxTokenPlanSegment->>MiniMaxTokenPlanSegment: load Config
MiniMaxTokenPlanSegment->>MiniMaxTokenPlanSegment: read cache_duration, timeout
MiniMaxTokenPlanSegment->>FileSystem: load_cache()
FileSystem-->>MiniMaxTokenPlanSegment: CacheData?
alt Cache valid
MiniMaxTokenPlanSegment->>MiniMaxTokenPlanSegment: use cached weekly_remaining_pct, interval_remaining_pct
else No cache or expired
MiniMaxTokenPlanSegment->>MiniMaxAPI: GET /coding_plan/remains
alt API success
MiniMaxAPI-->>MiniMaxTokenPlanSegment: ApiResponse(model_remains)
MiniMaxTokenPlanSegment->>MiniMaxTokenPlanSegment: find model MiniMax_M2_7
MiniMaxTokenPlanSegment->>MiniMaxTokenPlanSegment: compute remaining percentages
MiniMaxTokenPlanSegment->>FileSystem: save_cache(CacheData)
else API failure
alt Cached data available
MiniMaxTokenPlanSegment->>MiniMaxTokenPlanSegment: fallback to cached CacheData
else No cache
MiniMaxTokenPlanSegment-->>Statusline: None
Statusline-->>App: Skip MiniMax token plan
App-->>User: Statusline without MiniMax token plan
end
end
end
MiniMaxTokenPlanSegment->>MiniMaxTokenPlanSegment: build primary string with circle icons
MiniMaxTokenPlanSegment-->>Statusline: SegmentData{primary, metadata}
Statusline-->>App: Include MiniMax token plan segment
App-->>User: Statusline with MiniMax token plan usage
end
Class diagram for MiniMax token plan segment and related typesclassDiagram
class Segment {
<<trait>>
+collect(input_data) SegmentData?
+id() SegmentId
}
class MiniMaxTokenPlanSegment {
+new() MiniMaxTokenPlanSegment
+collect(input_data) SegmentData?
+id() SegmentId
-get_circle_icon(remaining_pct u32) String
-get_cache_path() PathBuf?
-load_cache() CacheData?
-save_cache(cache CacheData)
-is_cache_valid(cache CacheData, cache_duration u64) bool
-fetch_api(api_key String, timeout_secs u64) ApiResponse?
}
class SegmentId {
<<enum>>
ContextWindow
Cost
Directory
Git
Model
OutputStyle
Session
Update
MiniMaxTokenPlan
}
class SegmentData {
+primary String
+secondary String
+metadata HashMap~String, String~
}
class ApiResponse {
+model_remains Vec~ModelRemain~
}
class ModelRemain {
+model_name String
+current_interval_total_count u64
+current_interval_usage_count u64
+current_weekly_total_count u64
+current_weekly_usage_count u64
}
class CacheData {
+weekly_remaining_pct u32
+interval_remaining_pct u32
+cached_at String
}
class Config {
+segments Vec~SegmentConfig~
+load() Result~Config, Error~
}
class SegmentConfig {
+id SegmentId
+enabled bool
+icon IconConfig
+colors ColorConfig
+styles TextStyleConfig
+options HashMap~String, Value~
}
Segment <|.. MiniMaxTokenPlanSegment
MiniMaxTokenPlanSegment --> SegmentId
MiniMaxTokenPlanSegment --> SegmentData
MiniMaxTokenPlanSegment --> ApiResponse
ApiResponse --> ModelRemain
MiniMaxTokenPlanSegment --> CacheData
MiniMaxTokenPlanSegment --> Config
Config --> SegmentConfig
SegmentConfig --> SegmentId
SegmentData --> SegmentId
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
There was a problem hiding this comment.
Hey - I've found 2 issues, and left some high level feedback:
- The
timeoutoption for the MiniMax token plan segment is currently unused infetch_api(parameter is_timeout_secs); either wire this into theureqcall (e.g., via a request/agent timeout) or remove the option/parameter to avoid confusion. - In
MiniMaxTokenPlanSegment::collect, loading the fullConfigfrom disk on every render just to read segment options may introduce unnecessary I/O; consider wiring the segment options throughInputData(similar to other segments) so you can avoid reloading the config each time. - The MiniMax model name
"MiniMax-M2.7"is hardcoded when selectingmodel_remains; if different models/plans are used, it might be more flexible to make this model identifier configurable via segment options or environment variables.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- The `timeout` option for the MiniMax token plan segment is currently unused in `fetch_api` (parameter is `_timeout_secs`); either wire this into the `ureq` call (e.g., via a request/agent timeout) or remove the option/parameter to avoid confusion.
- In `MiniMaxTokenPlanSegment::collect`, loading the full `Config` from disk on every render just to read segment options may introduce unnecessary I/O; consider wiring the segment options through `InputData` (similar to other segments) so you can avoid reloading the config each time.
- The MiniMax model name `"MiniMax-M2.7"` is hardcoded when selecting `model_remains`; if different models/plans are used, it might be more flexible to make this model identifier configurable via segment options or environment variables.
## Individual Comments
### Comment 1
<location path="src/core/segments/minimax_token_plan.rs" line_range="118-126" />
<code_context>
+ }
+
+ // Load config from file to get segment options
+ let config = crate::config::Config::load().ok()?;
+ let segment_config = config
+ .segments
+ .iter()
+ .find(|s| s.id == SegmentId::MiniMaxTokenPlan);
+
+ let cache_duration = segment_config
+ .and_then(|sc| sc.options.get("cache_duration"))
+ .and_then(|v| v.as_u64())
+ .unwrap_or(300);
+
</code_context>
<issue_to_address>
**suggestion (performance):** Loading the full config on every collect call may be unnecessarily expensive.
Each `collect` call reloads `Config` from disk just to read `cache_duration` and `timeout`, which can add noticeable overhead if this runs often. Consider caching these options on the segment (e.g., via `OnceLock` or similar) or passing them in from an already-loaded config instead of reloading each time.
Suggested implementation:
```rust
}
use std::sync::OnceLock;
#[derive(Clone, Copy, Debug)]
struct MiniMaxSegmentOptions {
cache_duration: u64,
timeout: u64,
}
static MINIMAX_SEGMENT_OPTIONS: OnceLock<MiniMaxSegmentOptions> = OnceLock::new();
fn get_segment_options() -> MiniMaxSegmentOptions {
*MINIMAX_SEGMENT_OPTIONS.get_or_init(|| {
let config = crate::config::Config::load().ok();
let (cache_duration, timeout) = config
.as_ref()
.and_then(|cfg| {
cfg.segments
.iter()
.find(|s| s.id == SegmentId::MiniMaxTokenPlan)
})
.map(|sc| {
let cache_duration = sc
.options
.get("cache_duration")
.and_then(|v| v.as_u64())
.unwrap_or(300);
let timeout = sc
.options
.get("timeout")
.and_then(|v| v.as_u64())
.unwrap_or(10);
(cache_duration, timeout)
})
.unwrap_or((300, 10));
MiniMaxSegmentOptions {
cache_duration,
timeout,
}
})
}
impl Segment for MiniMaxTokenPlanSegment {
```
```rust
// Load config options once and reuse them across collect calls
let options = get_segment_options();
let cache_duration = options.cache_duration;
let timeout = options.timeout;
#[derive(Debug, Deserialize)]
```
1. Ensure the necessary imports exist at the top of the file (or the relevant module scope):
- `use crate::config::{Config, SegmentId};` (or equivalent paths if they differ in your codebase).
- If `Config` and `SegmentId` are already imported, remove any duplicate `use` lines.
2. Replace the hard-coded default values `300` and `10` with the existing defaults used elsewhere in this file (or in your config layer) if they differ, so behavior remains consistent with the pre-PR implementation.
3. Anywhere later in `collect` where `timeout` was previously defined directly (e.g., a local `timeout` variable before the PR), remove or update that code to rely on the `timeout` from `options` to avoid duplicate/conflicting definitions.
</issue_to_address>
### Comment 2
<location path="src/core/segments/minimax_token_plan.rs" line_range="147-149" />
<code_context>
+ match self.fetch_api(&api_key, timeout) {
+ Some(response) => {
+ let model = response
+ .model_remains
+ .iter()
+ .find(|m| m.model_name == "MiniMax-M2.7")?;
+
+ let weekly_remaining_pct = if model.current_weekly_total_count > 0 {
</code_context>
<issue_to_address>
**suggestion:** Hard-coding the model name may limit flexibility and robustness.
This lookup relies on the exact string "MiniMax-M2.7", so a plan change, model rename, or additional models would cause this to return `None`. Consider making the target model configurable (e.g., via segment options) and/or using a sensible default if the preferred model isn’t found.
Suggested implementation:
```rust
match self.fetch_api(&api_key, timeout) {
Some(response) => {
// Prefer a configurable model name, falling back to a sensible default.
let preferred_model_name = self
.preferred_model_name()
.unwrap_or_else(|| "MiniMax-M2.7".to_string());
let model = response
.model_remains
.iter()
.find(|m| m.model_name == preferred_model_name)
// Fallback: if the preferred model isn't found, use the first available model.
.or_else(|| response.model_remains.iter().next())?;
```
To fully support configurability you’ll need to:
1. Add a `preferred_model_name(&self) -> Option<String>` helper (or adjust the call above to match your existing configuration access pattern). For example, this helper might read from segment options or configuration:
- If you already have a generic options struct, implement `preferred_model_name()` to read something like `self.options.preferred_model_name`.
- Otherwise, add a new field (e.g., `preferred_model_name: Option<String>`) to the segment struct and implement the helper to return it.
2. Wire this configuration up from the segment construction site (e.g., from JSON/YAML config, environment, or wherever segment options are currently provided) so users can override the model name.
3. Ensure the `model_remains` collection is non-empty before calling `.iter().next()` or rely on the existing `?` to propagate `None` as appropriate for your error-handling semantics.
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
- Wire timeout_secs through to ureq::Agent via timeout_global() - Cache segment config to avoid repeated disk I/O on each render - Extract shared minimax_token_plan_options() helper in presets.rs Co-Authored-By: Claude <noreply@anthropic.com>
Add preferred_model option to segment config, defaulting to "MiniMax-M2.7". Fallback to first available model if preferred model is not found. Co-Authored-By: Claude <noreply@anthropic.com>
Owner
|
We will not create a separate Usage Segment for any single provider. We will consider aggregating a unified data request extension. |
yearth
pushed a commit
to yearth/CCometixLine
that referenced
this pull request
Mar 23, 2026
Replaces the per-provider MiniMaxTokenPlan approach with a general-purpose ExternalUsage segment that dispatches to pluggable UsageProvider impls. Design: - `UsageProvider` trait: name() + fetch(options) -> Vec<UsageMetric> - `ExternalUsageSegment`: handles caching, circle-icon formatting, config - `MinimaxProvider`: queries MiniMax coding_plan/remains API - Shared `Cache` utility extracted to cache.rs Adding a new provider only requires implementing UsageProvider and registering it in providers/mod.rs — no changes to segment core or types. Default config (disabled, provider=minimax): options.provider = "minimax" options.auth_env = "MINIMAX_API_KEY" options.cache_duration = 300 options.timeout = 10 Supersedes Haleclipse#101 and Haleclipse#102 (MiniMaxTokenPlan).
yearth
added a commit
to yearth/CCometixLine
that referenced
this pull request
Mar 23, 2026
Replaces the per-provider MiniMaxTokenPlan approach with a general-purpose ExternalUsage segment that dispatches to pluggable UsageProvider impls. Design: - `UsageProvider` trait: name() + fetch(options) -> Vec<UsageMetric> - `ExternalUsageSegment`: handles caching, circle-icon formatting, config - `MinimaxProvider`: queries MiniMax coding_plan/remains API - Shared `Cache` utility extracted to cache.rs Adding a new provider only requires implementing UsageProvider and registering it in providers/mod.rs — no changes to segment core or types. Default config (disabled, provider=minimax): options.provider = "minimax" options.auth_env = "MINIMAX_API_KEY" options.cache_duration = 300 options.timeout = 10 Supersedes Haleclipse#101 and Haleclipse#102 (MiniMaxTokenPlan).
Author
|
Superseded by #104, which implements a provider-based extensibility mechanism as suggested. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Add support for checking MiniMax API token plan usage (weekly and 5-hour interval quotas) directly in the statusline.
Features:
Configuration options:
Summary by Sourcery
Add a MiniMax token plan statusline segment that displays cached MiniMax API quota usage and integrate it into all built-in themes and UI settings.
New Features:
Enhancements: