From e16a23fb332dbd45c75bd332edd636c135fd125e Mon Sep 17 00:00:00 2001 From: RCD <90105158+Finesssee@users.noreply.github.com> Date: Tue, 29 Sep 2026 21:40:00 +0700 Subject: [PATCH 1/2] Port upstream 0.69.0: honor explicit Antigravity quota window cadence --- .../providers/antigravity/quota_summary.rs | 95 +++++++++++++++++-- 1 file changed, 89 insertions(+), 6 deletions(-) diff --git a/rust/src/providers/antigravity/quota_summary.rs b/rust/src/providers/antigravity/quota_summary.rs index 1c03f2fe41..486aaa602a 100644 --- a/rust/src/providers/antigravity/quota_summary.rs +++ b/rust/src/providers/antigravity/quota_summary.rs @@ -63,6 +63,8 @@ struct QuotaSummaryBucket { remaining: Option, #[serde(alias = "reset_time")] reset_time: Option, + /// Explicit cadence (`weekly`, `5h`, ...). When non-empty it replaces the id/name candidates. + window: Option, } #[derive(Debug, Deserialize)] @@ -331,14 +333,16 @@ fn group_scope(group: &QuotaSummaryGroup) -> String { } fn bucket_kind(bucket: &QuotaSummaryBucket) -> BucketKind { - let mut candidates = Vec::new(); - for raw in [ + let names = [ bucket.bucket_id.as_deref().or(bucket.id.as_deref()), bucket.display_name.as_deref().or(bucket.name.as_deref()), - ] - .into_iter() - .flatten() - { + ]; + let raw_candidates: &[Option<&str>] = match non_empty(bucket.window.as_deref()) { + Some(_) => &[non_empty(bucket.window.as_deref())], + None => &names, + }; + let mut candidates = Vec::new(); + for raw in raw_candidates.iter().flatten() { let normalized = raw.trim().to_ascii_lowercase().replace('_', "-"); if normalized.is_empty() { continue; @@ -598,4 +602,83 @@ mod tests { .is_err() ); } + + #[test] + fn explicit_window_sets_cadence_for_opaque_bucket_ids() { + for (cadence, minutes, title) in [ + ("weekly", Some(WEEKLY_MINUTES), "Gemini weekly"), + ("5h", Some(SESSION_MINUTES), "Gemini 5-hour"), + ] { + let data = format!( + r#"{{"groups":[{{"displayName":"Gemini Models","buckets":[ + {{"bucketId":"gemini-allowance","displayName":"Limit Remaining","window":"{cadence}","remainingFraction":1}} + ]}}]}}"# + ); + let snapshot = parse_usage_snapshot(data.as_bytes()).unwrap(); + let window = if minutes == Some(WEEKLY_MINUTES) { + snapshot.secondary.as_ref().unwrap() + } else { + &snapshot.primary + }; + assert_eq!(window.window_minutes, minutes, "{title}"); + } + } + + #[test] + fn explicit_window_replaces_legacy_bucket_names() { + for (cadence, minutes) in [("weekly", Some(WEEKLY_MINUTES)), ("unknown", None)] { + let data = format!( + r#"{{"groups":[{{"displayName":"Gemini Models","buckets":[ + {{"bucketId":"gemini-5h","displayName":"Five Hour Limit","window":"{cadence}","remainingFraction":0.8}} + ]}}]}}"# + ); + let snapshot = parse_usage_snapshot(data.as_bytes()).unwrap(); + let extra = &snapshot.extra_rate_windows; + match minutes { + Some(_) => { + assert_eq!(snapshot.secondary.unwrap().window_minutes, minutes); + assert!(extra.is_empty()); + } + None => { + assert!(snapshot.secondary.is_none()); + assert_eq!(extra.len(), 1, "unknown cadence stays an extra row"); + assert_eq!(extra[0].window.window_minutes, None); + } + } + assert!( + snapshot.primary.is_informational, + "no 5h bucket may be invented" + ); + } + } + + #[test] + fn blank_explicit_window_falls_back_to_bucket_names() { + let data = br#"{"groups":[{"displayName":"Gemini","buckets":[ + {"bucketId":"gemini-5h","displayName":"Five Hour Limit","window":" ","remainingFraction":0.5} + ]}]}"#; + let snapshot = parse_usage_snapshot(data).unwrap(); + assert_eq!(snapshot.primary.window_minutes, Some(SESSION_MINUTES)); + } + + #[test] + fn weekly_only_starter_groups_stay_visible_without_a_five_hour_window() { + let data = br#"{"groups":[ + {"displayName":"Gemini Models","buckets":[ + {"bucketId":"gemini-weekly","displayName":"Weekly Limit","window":"weekly","remainingFraction":1.0}]}, + {"displayName":"Claude and GPT models","buckets":[ + {"bucketId":"3p-weekly","displayName":"Weekly Limit","window":"weekly","remainingFraction":1.0}]} + ]}"#; + let snapshot = parse_usage_snapshot(data).unwrap(); + assert!(snapshot.primary.is_informational); + let secondary = snapshot.secondary.as_ref().unwrap(); + assert_eq!(secondary.window_minutes, Some(WEEKLY_MINUTES)); + assert_eq!(snapshot.secondary_label.as_deref(), Some("Gemini Weekly")); + assert_eq!(snapshot.extra_rate_windows.len(), 1); + assert_eq!(snapshot.extra_rate_windows[0].title, "Claude/GPT weekly"); + assert_eq!( + snapshot.extra_rate_windows[0].window.window_minutes, + Some(WEEKLY_MINUTES) + ); + } } From bf8b80bc5770f77774bdf12c049b42c2b42b0bd1 Mon Sep 17 00:00:00 2001 From: RCD <90105158+Finesssee@users.noreply.github.com> Date: Tue, 29 Sep 2026 21:50:17 +0700 Subject: [PATCH 2/2] Address thermo review --- .../providers/antigravity/quota_summary.rs | 88 ++++++++----------- 1 file changed, 39 insertions(+), 49 deletions(-) diff --git a/rust/src/providers/antigravity/quota_summary.rs b/rust/src/providers/antigravity/quota_summary.rs index 486aaa602a..079f74a029 100644 --- a/rust/src/providers/antigravity/quota_summary.rs +++ b/rust/src/providers/antigravity/quota_summary.rs @@ -333,16 +333,16 @@ fn group_scope(group: &QuotaSummaryGroup) -> String { } fn bucket_kind(bucket: &QuotaSummaryBucket) -> BucketKind { - let names = [ - bucket.bucket_id.as_deref().or(bucket.id.as_deref()), - bucket.display_name.as_deref().or(bucket.name.as_deref()), - ]; - let raw_candidates: &[Option<&str>] = match non_empty(bucket.window.as_deref()) { - Some(_) => &[non_empty(bucket.window.as_deref())], - None => &names, + // An explicit, non-empty `window` replaces the id/name candidates entirely. + let raw_candidates = match non_empty(bucket.window.as_deref()) { + Some(window) => [Some(window), None], + None => [ + bucket.bucket_id.as_deref().or(bucket.id.as_deref()), + bucket.display_name.as_deref().or(bucket.name.as_deref()), + ], }; let mut candidates = Vec::new(); - for raw in raw_candidates.iter().flatten() { + for raw in raw_candidates.into_iter().flatten() { let normalized = raw.trim().to_ascii_lowercase().replace('_', "-"); if normalized.is_empty() { continue; @@ -603,53 +603,43 @@ mod tests { ); } + fn single_bucket_snapshot(bucket_id: &str, display_name: &str, window: &str) -> UsageSnapshot { + let data = format!( + r#"{{"groups":[{{"displayName":"Gemini Models","buckets":[ + {{"bucketId":"{bucket_id}","displayName":"{display_name}","window":"{window}","remainingFraction":0.8}} + ]}}]}}"# + ); + parse_usage_snapshot(data.as_bytes()).unwrap() + } + #[test] fn explicit_window_sets_cadence_for_opaque_bucket_ids() { - for (cadence, minutes, title) in [ - ("weekly", Some(WEEKLY_MINUTES), "Gemini weekly"), - ("5h", Some(SESSION_MINUTES), "Gemini 5-hour"), - ] { - let data = format!( - r#"{{"groups":[{{"displayName":"Gemini Models","buckets":[ - {{"bucketId":"gemini-allowance","displayName":"Limit Remaining","window":"{cadence}","remainingFraction":1}} - ]}}]}}"# - ); - let snapshot = parse_usage_snapshot(data.as_bytes()).unwrap(); - let window = if minutes == Some(WEEKLY_MINUTES) { - snapshot.secondary.as_ref().unwrap() - } else { - &snapshot.primary - }; - assert_eq!(window.window_minutes, minutes, "{title}"); - } + let weekly = single_bucket_snapshot("gemini-allowance", "Limit Remaining", "weekly"); + assert_eq!( + weekly.secondary.unwrap().window_minutes, + Some(WEEKLY_MINUTES) + ); + assert!(weekly.primary.is_informational); + + let session = single_bucket_snapshot("gemini-allowance", "Limit Remaining", "5h"); + assert_eq!(session.primary.window_minutes, Some(SESSION_MINUTES)); } #[test] fn explicit_window_replaces_legacy_bucket_names() { - for (cadence, minutes) in [("weekly", Some(WEEKLY_MINUTES)), ("unknown", None)] { - let data = format!( - r#"{{"groups":[{{"displayName":"Gemini Models","buckets":[ - {{"bucketId":"gemini-5h","displayName":"Five Hour Limit","window":"{cadence}","remainingFraction":0.8}} - ]}}]}}"# - ); - let snapshot = parse_usage_snapshot(data.as_bytes()).unwrap(); - let extra = &snapshot.extra_rate_windows; - match minutes { - Some(_) => { - assert_eq!(snapshot.secondary.unwrap().window_minutes, minutes); - assert!(extra.is_empty()); - } - None => { - assert!(snapshot.secondary.is_none()); - assert_eq!(extra.len(), 1, "unknown cadence stays an extra row"); - assert_eq!(extra[0].window.window_minutes, None); - } - } - assert!( - snapshot.primary.is_informational, - "no 5h bucket may be invented" - ); - } + let weekly = single_bucket_snapshot("gemini-5h", "Five Hour Limit", "weekly"); + assert_eq!( + weekly.secondary.unwrap().window_minutes, + Some(WEEKLY_MINUTES) + ); + assert!(weekly.extra_rate_windows.is_empty()); + assert!(weekly.primary.is_informational); + + let unknown = single_bucket_snapshot("gemini-5h", "Five Hour Limit", "unknown"); + assert!(unknown.secondary.is_none()); + assert!(unknown.primary.is_informational); + assert_eq!(unknown.extra_rate_windows.len(), 1); + assert_eq!(unknown.extra_rate_windows[0].window.window_minutes, None); } #[test]