-
Notifications
You must be signed in to change notification settings - Fork 1.4k
Fix Gemini Plus plan display from loadCodeAssist paidTier #1980
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 1 commit
b8a40a1
fec0b0b
16f882a
3e258b3
21c3cfb
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 |
|---|---|---|
|
|
@@ -337,25 +337,10 @@ public struct GeminiStatusProbe: Sendable { | |
|
|
||
| let snapshot = try Self.parseAPIResponse(data, email: claims.email) | ||
|
|
||
| // Plan display strings with tier mapping: | ||
| // - standard-tier: Paid subscription (AI Pro, AI Ultra, Code Assist | ||
| // Standard/Enterprise, Developer Program Premium) | ||
| // - free-tier + hd claim: Workspace account (Gemini included free since Jan 2025) | ||
| // - free-tier: Personal free account (1000 req/day limit) | ||
| // - legacy-tier: Unknown legacy/grandfathered tier | ||
| // - nil (API failed): Leave blank (no display) | ||
| let plan: String? = switch (caStatus.tier, claims.hostedDomain) { | ||
| case (.standard, _): | ||
| "Paid" | ||
| case let (.free, .some(domain)): | ||
| { Self.log.info("Workspace account detected", metadata: ["domain": domain]); return "Workspace" }() | ||
| case (.free, .none): | ||
| { Self.log.info("Personal free account"); return "Free" }() | ||
| case (.legacy, _): | ||
| "Legacy" | ||
| case (.none, _): | ||
| { Self.log.info("Tier detection failed, leaving plan blank"); return nil }() | ||
| } | ||
| let plan = Self.resolveAccountPlan( | ||
| tier: caStatus.tier, | ||
| hostedDomain: claims.hostedDomain, | ||
| paidTierName: caStatus.paidTierName) | ||
|
|
||
| return GeminiStatusSnapshot( | ||
| modelQuotas: snapshot.modelQuotas, | ||
|
|
@@ -411,8 +396,9 @@ public struct GeminiStatusProbe: Sendable { | |
| private struct CodeAssistStatus { | ||
| let tier: GeminiUserTierId? | ||
| let projectId: String? | ||
| let paidTierName: String? | ||
|
|
||
| static let empty = CodeAssistStatus(tier: nil, projectId: nil) | ||
| static let empty = CodeAssistStatus(tier: nil, projectId: nil, paidTierName: nil) | ||
| } | ||
|
|
||
| private static func loadCodeAssistStatus( | ||
|
|
@@ -484,20 +470,26 @@ public struct GeminiStatusProbe: Sendable { | |
| } | ||
|
|
||
| let tierId = (json["currentTier"] as? [String: Any])?["id"] as? String | ||
| let paidTierName = Self.parsePaidTierName(from: json) | ||
|
|
||
| guard let tierId else { | ||
| Self.log.warning("loadCodeAssist: no currentTier.id in response", metadata: [ | ||
| "json": "\(json)", | ||
| ]) | ||
| return CodeAssistStatus(tier: nil, projectId: projectId) | ||
| return CodeAssistStatus(tier: nil, projectId: projectId, paidTierName: paidTierName) | ||
| } | ||
|
|
||
| guard let tier = GeminiUserTierId(rawValue: tierId) else { | ||
| Self.log.warning("loadCodeAssist: unknown tier ID", metadata: ["tierId": tierId]) | ||
| return CodeAssistStatus(tier: nil, projectId: projectId) | ||
| return CodeAssistStatus(tier: nil, projectId: projectId, paidTierName: paidTierName) | ||
| } | ||
|
|
||
| Self.log.info("loadCodeAssist: success", metadata: ["tier": tierId, "projectId": projectId ?? "nil"]) | ||
| return CodeAssistStatus(tier: tier, projectId: projectId) | ||
| Self.log.info("loadCodeAssist: success", metadata: [ | ||
| "tier": tierId, | ||
| "projectId": projectId ?? "nil", | ||
| "paidTierName": paidTierName ?? "nil", | ||
| ]) | ||
| return CodeAssistStatus(tier: tier, projectId: projectId, paidTierName: paidTierName) | ||
| } | ||
|
|
||
| private struct OAuthCredentials { | ||
|
|
@@ -1142,6 +1134,51 @@ public struct GeminiStatusProbe: Sendable { | |
| } | ||
| } | ||
|
|
||
| extension GeminiStatusProbe { | ||
| /// Plan display strings with tier mapping: | ||
| /// - standard-tier: Paid subscription (Code Assist Standard/Enterprise, Developer Program Premium) | ||
| /// - free-tier + hd claim: Workspace account (Gemini included free since Jan 2025) | ||
| /// - free-tier + paidTier.name: Consumer subscription (Google AI Pro/Ultra, shown as Plus/Ultra) | ||
| /// - free-tier: Personal free account | ||
| /// - legacy-tier: Unknown legacy/grandfathered tier | ||
| /// - nil (API failed): Leave blank (no display) | ||
| fileprivate static func resolveAccountPlan( | ||
| tier: GeminiUserTierId?, | ||
| hostedDomain: String?, | ||
| paidTierName: String?) -> String? | ||
| { | ||
| switch (tier, hostedDomain) { | ||
| case (.standard, _): | ||
| return "Paid" | ||
| case let (.free, .some(domain)): | ||
| Self.log.info("Workspace account detected", metadata: ["domain": domain]) | ||
| return "Workspace" | ||
| case (.free, .none): | ||
| if let paidTierName { | ||
| self.log.info("Consumer paid tier detected", metadata: ["plan": paidTierName]) | ||
| return paidTierName | ||
| } | ||
| Self.log.info("Personal free account") | ||
| return "Free" | ||
| case (.legacy, _): | ||
| return "Legacy" | ||
| case (.none, _): | ||
| self.log.info("Tier detection failed, leaving plan blank") | ||
| return nil | ||
| } | ||
| } | ||
|
|
||
| fileprivate static func parsePaidTierName(from json: [String: Any]) -> String? { | ||
| guard let paidTier = json["paidTier"] as? [String: Any], | ||
| let rawName = paidTier["name"] as? String | ||
|
Comment on lines
+1178
to
+1179
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.
When Useful? React with 👍 / 👎. |
||
| else { | ||
| return nil | ||
| } | ||
| let trimmed = rawName.trimmingCharacters(in: .whitespacesAndNewlines) | ||
| return trimmed.isEmpty ? nil : trimmed | ||
| } | ||
| } | ||
|
|
||
| extension GeminiStatusProbe { | ||
| private static let processTimeoutQueue = DispatchQueue( | ||
| label: "com.steipete.codexbar.gemini-process-timeout", | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.