Conversation
Two-strategy fetch pipeline: - Primary: Management API billing data (spending limits + invoice preview) - Fallback: Regular API key status check Settings: API key, Management key (for billing), Team ID
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 8417b65f58
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| public enum GrokProviderDescriptor { | ||
| static func makeDescriptor() -> ProviderDescriptor { | ||
| ProviderDescriptor( | ||
| id: .grok, |
There was a problem hiding this comment.
Add GrokProviderDescriptor to the registry
UsageProvider.allCases now includes .grok, but ProviderDescriptorRegistry.descriptorsByID in Sources/CodexBarCore/Providers/ProviderDescriptor.swift:55-78 still has no .grok entry. The bootstrap loop there preconditions on any missing provider, so the first descriptor lookup (for example app startup via ProviderRegistry.shared) crashes with Missing ProviderDescriptor for grok before the new provider can be used.
Useful? React with 👍 / 👎.
| public struct GrokSpendingLimitsResponse: Decodable, Sendable { | ||
| public let hardLimit: Double? | ||
| public let softLimit: Double? | ||
| public let monthlyBudget: Double? | ||
| public let currentSpend: Double? |
There was a problem hiding this comment.
Match xAI's actual Management API billing schema
xAI's Billing Management docs expose postpaid/spending-limits as a nested spendingLimits object and invoice/preview as coreInvoice/effectiveSpendingLimit fields in USD cents, not flat hard_limit/total_amount doubles. Decoding those 200 responses into GrokSpendingLimitsResponse/GrokInvoicePreviewResponse will therefore throw parseFailed, so a configuration that only has XAI_MANAGEMENT_KEY never yields a balance snapshot and either falls back to the less useful API-key status path or errors out entirely.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Pull request overview
Adds a new Grok/xAI usage provider to CodexBar, including a two-stage fetch pipeline (Management API billing as primary, API key status as fallback), along with supporting settings UI, config/env plumbing, and basic widget/UI integration.
Changes:
- Introduces Grok provider core implementation (settings reader, usage fetcher, descriptor + fetch strategies).
- Adds app-side settings persistence/UI for Grok (API key, Management key, Team ID) and provider icon/branding.
- Wires Grok into shared enums/switches (providers list, token resolver, config env injection, CLI/widget stubs).
Reviewed changes
Copilot reviewed 15 out of 16 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| Sources/CodexBarWidget/CodexBarWidgetViews.swift | Adds Grok display name and widget color mapping. |
| Sources/CodexBarWidget/CodexBarWidgetProvider.swift | Marks Grok as not yet supported in widgets (returns nil). |
| Sources/CodexBarCore/Vendored/CostUsage/CostUsageScanner.swift | Treats Grok as unsupported for cost usage scanning (empty report). |
| Sources/CodexBarCore/Providers/ProviderTokenResolver.swift | Adds Grok token + resolution helpers. |
| Sources/CodexBarCore/Providers/Providers.swift | Adds .grok to UsageProvider and IconStyle. |
| Sources/CodexBarCore/Providers/Grok/GrokUsageFetcher.swift | Implements Management API billing fetch + API key status fetch with decoding/models. |
| Sources/CodexBarCore/Providers/Grok/GrokSettingsReader.swift | Reads Grok/xAI-related env vars (API key, management key, team ID, URL overrides). |
| Sources/CodexBarCore/Providers/Grok/GrokProviderDescriptor.swift | Registers Grok descriptor and two-strategy fetch pipeline. |
| Sources/CodexBarCore/Logging/LogCategories.swift | Adds Grok usage logging category. |
| Sources/CodexBarCore/Config/ProviderConfigEnvironment.swift | Injects Grok management key/team ID and API key into the environment. |
| Sources/CodexBarCLI/TokenAccountCLI.swift | Updates switch exhaustiveness for Grok (no token account snapshot). |
| Sources/CodexBar/UsageStore.swift | Adds Grok debug log message for token resolution. |
| Sources/CodexBar/Resources/ProviderIcon-grok.svg | Adds Grok provider icon asset. |
| Sources/CodexBar/Providers/Shared/ProviderImplementationRegistry.swift | Registers Grok settings implementation. |
| Sources/CodexBar/Providers/Grok/GrokSettingsStore.swift | Persists Grok API key, management key, and team ID via ProviderConfig fields. |
| Sources/CodexBar/Providers/Grok/GrokProviderImplementation.swift | Adds Grok provider settings UI (secure fields + team ID + console links). |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
You can also share your feedback on Copilot code review. Take the survey.
| func shouldFallback(on _: Error, context _: ProviderFetchContext) -> Bool { | ||
| true // Fall back to regular API key strategy |
| style: .link, | ||
| isVisible: nil, | ||
| perform: { | ||
| if let url = URL(string: "https://console.x.ai/team/default/management-keys") { |
| public struct GrokSettingsReader: Sendable { | ||
| public static let apiKeyEnvironmentKeys = [ | ||
| "XAI_API_KEY", | ||
| "GROK_API_KEY", | ||
| ] |
| if let teamID = config.workspaceID, !teamID.isEmpty { | ||
| env[GrokSettingsReader.teamIDEnvironmentKey] = teamID |
| public var errorDescription: String? { | ||
| switch self { | ||
| case .missingCredentials: | ||
| "Missing xAI/Grok API key." |
| /// Team ID, stored in the workspaceID field | ||
| var grokTeamID: String { | ||
| get { self.configSnapshot.providerConfig(for: .grok)?.workspaceID ?? "default" } | ||
| set { | ||
| self.updateProviderConfig(provider: .grok) { entry in |
- XAI_MANAGEMENT_KEY → XAI_MANAGEMENT_API_KEY (per official xAI docs) - Remove unofficial GROK_API_KEY (only XAI_API_KEY is documented) - cleaned() returns String? to match Zai/MiniMax/Kilo pattern - Move GrokSettingsError to GrokSettingsReader (matches ZaiSettingsError placement) - Add ensureGrokAPITokenLoaded() stub (matches ensureZaiAPITokenLoaded pattern)
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 3a2f664279
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| case synthetic | ||
| case warp | ||
| case openrouter | ||
| case grok |
There was a problem hiding this comment.
Register Grok descriptor in ProviderDescriptorRegistry
Adding .grok to UsageProvider here makes it part of UsageProvider.allCases, but ProviderDescriptorRegistry.descriptorsByID was not updated with .grok (checked Sources/CodexBarCore/Providers/ProviderDescriptor.swift, map at lines 55-78). During bootstrap, the loop over allCases hits preconditionFailure("Missing ProviderDescriptor for grok"), which will crash as soon as descriptor metadata is accessed (startup path for app/CLI config).
Useful? React with 👍 / 👎.
| func shouldFallback(on _: Error, context _: ProviderFetchContext) -> Bool { | ||
| true // Fall back to regular API key strategy |
There was a problem hiding this comment.
Preserve management-fetch errors when fallback is unavailable
This unconditional true causes the pipeline to drop real management API errors whenever only a management key is configured (no API key): GrokManagementFetchStrategy fails, fallback proceeds, GrokAPIFetchStrategy is unavailable, and ProviderFetchPlan returns noAvailableStrategy instead of the original 4xx/5xx/network error. That makes misconfigured or failing management credentials much harder to diagnose.
Useful? React with 👍 / 👎.
- Add .grok to ProviderDescriptorRegistry.descriptorsByID (startup crash) - Rewrite billing Decodable models to match actual xAI Management API response: nested spendingLimits with cent-string vals, coreInvoice with amountBeforeVat, effectiveSpendingLimit at top level - shouldFallback only on credential errors, not API/network failures - Fix management key URL to team-agnostic path - Trim workspaceID before env injection - Split missingCredentials into missingAPIKey / missingManagementKey - Fix management key placeholder to match actual format (xai-token-...) - Add explicit browserCookieOrder: nil to metadata
|
@ratulsarna Addressed all review feedback:
Verified decoding against a live account: The Management API returns nested |
Summary
management-api.x.ai) for real billing data (spending limits, invoice preview, usage percentage)api.x.ai/v1/api-key) showing active/blocked stateImplementation
6 new files (~350 lines of new Swift):
GrokSettingsReader- env var:XAI_API_KEY(per official xAI docs),XAI_MANAGEMENT_API_KEY,XAI_TEAM_IDGrokUsageFetcher- two fetch paths (billing + key status) with Decodable response modelsGrokProviderDescriptor- descriptor with two-strategy pipeline (GrokManagementFetchStrategyprimary,GrokAPIFetchStrategyfallback)GrokProviderImplementation- settings UI (2 secure fields + team ID text field + console link)GrokSettingsStore- config persistence (management key viacookieHeader, team ID viaworkspaceID)ProviderIcon-grok.svg- X-shaped icon10 modified files (~15 lines each):
Providers.swift-case grokinUsageProvider+IconStyleProviderTokenResolver.swift-grokToken()+grokResolution()ProviderConfigEnvironment.swift- management key + team ID injectionLogCategories.swift,ProviderImplementationRegistry.swift,UsageStore.swiftCostUsageScanner.swift,TokenAccountCLI.swift- exhaustive switch casesCodexBarWidgetProvider.swift,CodexBarWidgetViews.swift- widget stubsxAI Management API
xAI exposes billing data via a Management API (
https://management-api.x.ai/v1):GET /v1/billing/teams/{team_id}/postpaid/spending-limits- usage capGET /v1/billing/teams/{team_id}/postpaid/invoice/preview- current usage amountThis gives real usage percentage bars rather than just key status.
Environment Variables
All env var names verified against official xAI documentation:
XAI_API_KEY- standard API key (official)XAI_MANAGEMENT_API_KEY- management API key (per management API docs)XAI_TEAM_ID- team identifier (defaults to"default")Test plan
swift build --target CodexBarCorecompiles cleanswift build --target CodexBarCLIcompiles clean