Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -447,9 +447,22 @@ public struct AntigravityStatusSnapshot: Sendable {
}

private static func rateWindow(for quota: AntigravityModelQuota) -> RateWindow {
RateWindow(
let windowMinutes: Int? = if let desc = quota.resetDescription?.lowercased() {
if desc.contains("weekly") || desc.contains("7-day") || desc.contains("7d") {
10080
} else if desc.contains("session") || desc.contains("5h") || desc.contains("5-hour") || desc
.contains("five hour")

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Derive Antigravity cadence from production fields

These aliases are not present in the model-quota data produced by any production fetch path: remote fetches set resetDescription through UsageFormatter.resetDescription, which yields a clock time, “tomorrow,” or an absolute date, while the local command-model parser sets it to nil. Consequently legacy Antigravity snapshots still emit nil windowMinutes, and the new test passes only because it constructs descriptions that the parsers never produce. Derive cadence from stable quota/model metadata rather than the display-formatted reset string.

Useful? React with 👍 / 👎.

{
300
} else {
nil
}
} else {
nil
}
return RateWindow(
usedPercent: 100 - quota.remainingPercent,
windowMinutes: nil,
windowMinutes: windowMinutes,
resetsAt: quota.resetTime,
resetDescription: quota.resetDescription)
}
Expand Down
2 changes: 1 addition & 1 deletion Sources/CodexBarCore/Providers/Grok/GrokStatusProbe.swift
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ public struct GrokUsageSnapshot: Sendable {
{
primary = RateWindow(
usedPercent: percent,
windowMinutes: nil,
windowMinutes: ProviderPaceCapability.monthlyWindowSentinelMinutes,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve reset-based cadence for Grok web billing

For every Grok web-billing snapshot, this hard-codes a monthly duration even though the web response can represent weekly periods and exposes only resetsAt. GrokProviderDescriptor.primaryLabel(window:now:) prioritizes windowMinutes, so a weekly web period is now labeled Monthly and excluded from the descriptor's weekly pace calculation; this also contradicts the existing web-snapshot test that expects the unknown duration to remain nil. Keep the duration unset or derive it from the reset timestamp before assigning a sentinel.

Useful? React with 👍 / 👎.

resetsAt: webBilling.resetsAt,
resetDescription: nil)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ extension KimiUsageSnapshot {
guard let ratio = balance.amountUsedRatio, ratio.isFinite else { return nil }
let window = RateWindow(
usedPercent: Self.clampedPercent(ratio * 100),
windowMinutes: nil, // Calendar-month duration varies; do not fabricate a fixed 30-day window.
windowMinutes: ProviderPaceCapability.monthlyWindowSentinelMinutes,
resetsAt: Self.parseDate(balance.expireTime),
resetDescription: nil)
return NamedRateWindow(id: "kimi-monthly", title: "Monthly", window: window)
Expand Down
11 changes: 9 additions & 2 deletions Sources/CodexBarCore/Providers/Zai/ZaiUsageStats.swift
Original file line number Diff line number Diff line change
Expand Up @@ -224,9 +224,16 @@ extension ZaiUsageSnapshot {
}

private static func rateWindow(for limit: ZaiLimitEntry) -> RateWindow {
RateWindow(
let windowMinutes: Int? = if limit.type == .timeLimit || limit.isMCPMonthlyMarker {
ProviderPaceCapability.monthlyWindowSentinelMinutes
} else if let minutes = limit.windowMinutes {
minutes
} else {
nil
}
return RateWindow(
usedPercent: limit.usedPercent,
windowMinutes: limit.type == .tokensLimit ? limit.windowMinutes : nil,
windowMinutes: windowMinutes,
resetsAt: limit.nextResetTime,
resetDescription: self.resetDescription(for: limit))
}
Expand Down
32 changes: 32 additions & 0 deletions Tests/CodexBarTests/AntigravityWindowMinutesTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import CodexBarCore
import Foundation
import Testing

@Suite(.serialized)
struct AntigravityWindowMinutesTests {
@Test
func `antigravity model quota derives windowMinutes from reset description`() throws {
let snapshot = AntigravityStatusSnapshot(
modelQuotas: [
AntigravityModelQuota(
label: "Claude 3.5 Sonnet",
modelId: "claude-3-5-sonnet",
remainingFraction: 0.8,
resetTime: Date(),
resetDescription: "5-hour session reset"),
AntigravityModelQuota(
label: "Gemini 2.5 Flash",
modelId: "gemini-2-5-flash",
remainingFraction: 0.5,
resetTime: Date(),
resetDescription: "Weekly reset"),
],
accountEmail: "test@example.com",
accountPlan: "Pro",
source: .remote)

let usage = try snapshot.toUsageSnapshot()
#expect(usage.primary?.windowMinutes == 10080)
#expect(usage.secondary?.windowMinutes == 300)
}
}
2 changes: 1 addition & 1 deletion Tests/CodexBarTests/KimiProviderTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1023,7 +1023,7 @@ struct KimiUsageSnapshotConversionTests {
#expect(monthly.id == "kimi-monthly")
#expect(monthly.title == "Monthly")
#expect(monthly.window.usedPercent == 100)
#expect(monthly.window.windowMinutes == nil)
#expect(monthly.window.windowMinutes == ProviderPaceCapability.monthlyWindowSentinelMinutes)
#expect(monthly.window.resetsAt == Self.date("2026-07-23T00:00:00Z"))
}

Expand Down
4 changes: 2 additions & 2 deletions Tests/CodexBarTests/ZaiProviderTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -253,7 +253,7 @@ struct ZaiUsageParsingTests {
#expect(snapshot.tokenLimit?.percentage == 34.0)

let usage = snapshot.toUsageSnapshot()
#expect(usage.secondary?.windowMinutes == nil)
#expect(usage.secondary?.windowMinutes == ProviderPaceCapability.monthlyWindowSentinelMinutes)
#expect(usage.secondary?.resetDescription == "Monthly")
}

Expand Down Expand Up @@ -292,7 +292,7 @@ struct ZaiUsageParsingTests {
let usage = snapshot.toUsageSnapshot()

#expect(snapshot.timeLimit?.windowDescription == "1 minute")
#expect(usage.secondary?.windowMinutes == nil)
#expect(usage.secondary?.windowMinutes == ProviderPaceCapability.monthlyWindowSentinelMinutes)
#expect(usage.secondary?.resetDescription == "Monthly")
}

Expand Down
Loading