From 38d88f65609713abd24166012675295581365fc2 Mon Sep 17 00:00:00 2001 From: Factory Agent Date: Fri, 23 Oct 2026 14:01:42 +0700 Subject: [PATCH 1/3] Keep versioned Gemini quota group names A Gemini group is shown as Gemini only when its title has no digit, so a separate group such as Gemini 4 Argon keeps its own name instead of repeating the generic Gemini label. Claude/GPT and other group titles are unchanged. The CLI usage report and quota summary share this path. Upstream steipete/CodexBar#4585. --- docs/PROVIDERS.md | 1 + .../providers/antigravity/quota_summary.rs | 52 +++++++++++++++++-- 2 files changed, 49 insertions(+), 4 deletions(-) diff --git a/docs/PROVIDERS.md b/docs/PROVIDERS.md index d55efe6ac07..1a18e4fffec 100644 --- a/docs/PROVIDERS.md +++ b/docs/PROVIDERS.md @@ -932,6 +932,7 @@ The Antigravity quota summary picks one Gemini row for the primary and secondary - The ordinary Gemini buckets win: `gemini-5h` (or a session alias such as `gemini-session`) and `gemini-weekly`. Their IDs are matched after lowercasing, with `_` read as `-` and a trailing ` limit` ignored. Display labels never decide this. - A model-specific Gemini allowance, such as `gemini-2.5-pro-5h`, represents Gemini only when the ordinary bucket of that cadence is absent, unknown or disabled. - Every bucket stays visible as an extra window with its own usage and reset. +- A group named like "Gemini" with no digit is shown as **Gemini** (for example **Gemini weekly**). A versioned Gemini group keeps its own name from the usage response, so a separate Gemini 4 Argon group is shown as **Gemini 4 Argon weekly**, alongside the ordinary **Gemini weekly** quota (upstream #4585). ## Window lengths that match the Mac diff --git a/rust/src/providers/antigravity/quota_summary.rs b/rust/src/providers/antigravity/quota_summary.rs index 7337a554c05..80128e1497c 100644 --- a/rust/src/providers/antigravity/quota_summary.rs +++ b/rust/src/providers/antigravity/quota_summary.rs @@ -361,11 +361,22 @@ fn group_rank(group: &QuotaSummaryGroup) -> u8 { group_family(group).1 } +/// Upstream `displayTitle(forQuotaGroup:)`. A Gemini group reads "Gemini" only +/// when its title has no digit, so a versioned group such as "Gemini 4 Argon" +/// keeps its own name. Claude and GPT groups read "Claude/GPT"; any other group +/// keeps its trimmed name, or "Quota" when the name is blank. fn group_title(group: &QuotaSummaryGroup) -> String { - match group_family(group) { - (_, 0) => "Gemini".into(), - (_, 1) => "Claude/GPT".into(), - (title, _) => title.unwrap_or("Quota").to_string(), + let (title, _) = group_family(group); + let title = title.unwrap_or_default(); + let lower = title.to_ascii_lowercase(); + if lower.contains("gemini") && !title.chars().any(char::is_numeric) { + "Gemini".into() + } else if lower.contains("claude") || lower.contains("gpt") { + "Claude/GPT".into() + } else if title.is_empty() { + "Quota".into() + } else { + title.into() } } @@ -702,11 +713,44 @@ mod tests { ); } + #[test] + fn cli_report_keeps_a_versioned_gemini_group_name_distinct() { + // Upstream #4585: "Gemini 4 Argon" is its own quota, not a second "Gemini". + let data = br#"{ + "status": "SUCCESS", + "command": {"name": "usage", "data": {"groups": [ + {"name": "Gemini Models", "buckets": [ + {"id": "gemini-weekly", "name": "Weekly Limit Remaining", "window": "weekly", "remaining_fraction": 0.99} + ]}, + {"name": "Gemini 4 Argon", "description": "For paid Pro plans, Argon quota is separate.", "buckets": [ + {"id": "gemini-argon-wtu-weekly", "name": "Gemini 4 Argon Weekly Limit", "window": "weekly", "remaining_fraction": 0.53, "reset_time": "2026-10-23T10:24:14Z"} + ]} + ]}} + }"#; + + let snapshot = parse_cli_usage_report(data).expect("CLI report"); + + assert_eq!(snapshot.secondary_label.as_deref(), Some("Gemini Weekly")); + let extra_titles: Vec<&str> = snapshot + .extra_rate_windows + .iter() + .map(|window| window.title.as_str()) + .collect(); + assert_eq!(extra_titles, ["Gemini 4 Argon weekly"]); + } + #[test] fn group_rank_title_and_scope_follow_the_group_family() { // (displayName, name, rank, title, scope) let cases = [ (Some("Gemini Pro"), None, 0, "Gemini", "gemini"), + ( + Some("Gemini 4 Argon"), + None, + 0, + "Gemini 4 Argon", + "gemini-4-argon", + ), (None, Some("claude & GPT"), 1, "Claude/GPT", "claude-gpt"), ( Some("OpenAI gpt-oss"), From e521076ed0cd9ee961ee06df864e321836d95046 Mon Sep 17 00:00:00 2001 From: Factory Agent Date: Fri, 23 Oct 2026 20:18:43 +0700 Subject: [PATCH 2/3] Title versioned Gemini groups by name even when they mention GPT --- .../providers/antigravity/quota_summary.rs | 23 +++++++++++++++---- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/rust/src/providers/antigravity/quota_summary.rs b/rust/src/providers/antigravity/quota_summary.rs index 80128e1497c..30e91f6671e 100644 --- a/rust/src/providers/antigravity/quota_summary.rs +++ b/rust/src/providers/antigravity/quota_summary.rs @@ -365,13 +365,19 @@ fn group_rank(group: &QuotaSummaryGroup) -> u8 { /// when its title has no digit, so a versioned group such as "Gemini 4 Argon" /// keeps its own name. Claude and GPT groups read "Claude/GPT"; any other group /// keeps its trimmed name, or "Quota" when the name is blank. +/// +/// Unlike upstream, every Gemini-ranked group is titled in the Gemini branch, +/// so a versioned "Gemini 4 + GPT" keeps its name instead of "Claude/GPT". fn group_title(group: &QuotaSummaryGroup) -> String { - let (title, _) = group_family(group); + let (title, rank) = group_family(group); let title = title.unwrap_or_default(); - let lower = title.to_ascii_lowercase(); - if lower.contains("gemini") && !title.chars().any(char::is_numeric) { - "Gemini".into() - } else if lower.contains("claude") || lower.contains("gpt") { + if rank == 0 { + if title.chars().any(char::is_numeric) { + title.into() + } else { + "Gemini".into() + } + } else if rank == 1 { "Claude/GPT".into() } else if title.is_empty() { "Quota".into() @@ -751,6 +757,13 @@ mod tests { "Gemini 4 Argon", "gemini-4-argon", ), + ( + Some("Gemini 4 + GPT"), + None, + 0, + "Gemini 4 + GPT", + "gemini-4---gpt", + ), (None, Some("claude & GPT"), 1, "Claude/GPT", "claude-gpt"), ( Some("OpenAI gpt-oss"), From 2eabf1797aa146061b264b479f9682e7191df934 Mon Sep 17 00:00:00 2001 From: Factory Agent Date: Fri, 23 Oct 2026 20:31:03 +0700 Subject: [PATCH 3/3] Retrigger CI after runner out-of-memory