From e5de07b281d0dec6720b2d867542128c8aafeb15 Mon Sep 17 00:00:00 2001 From: Jake Leventhal Date: Sun, 20 Sep 2026 17:48:13 -0400 Subject: [PATCH] fix(server): Grok accounts with no usage yet no longer vanish from Limits xAI omits `creditUsagePercent` from its billing response entirely until an account has accrued metered usage, rather than sending 0. We treated that absence as `unsupported`, which the contract reserves for accounts that can never report quota, such as API keys and Bedrock. The Limits view drops those accounts and deliberately mutes their notice, so a freshly signed-in Grok account disappeared from Usage with no bar and no explanation until it happened to be used. `applyUsageLimitsUpdate` also refuses mid-turn windows for an `unsupported` snapshot, so nothing could recover it in the meantime. Report no windows instead, leaving the `unavailable` marker off. The account keeps its row and gets the existing "No limits reported." notice, and the bar appears on its own once usage registers. The genuine can-never-report paths in `readGrokUsageLimits` (API key, alternate auth deployments, custom config) still return `unsupported` and are unaffected. Co-Authored-By: Claude Opus 5 (1M context) --- apps/server/src/provider/Layers/GrokProvider.test.ts | 5 ++++- apps/server/src/provider/Layers/grokUsageLimits.ts | 10 +++++++++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/apps/server/src/provider/Layers/GrokProvider.test.ts b/apps/server/src/provider/Layers/GrokProvider.test.ts index 495feaf8d61b..1f27f09912cf 100644 --- a/apps/server/src/provider/Layers/GrokProvider.test.ts +++ b/apps/server/src/provider/Layers/GrokProvider.test.ts @@ -564,7 +564,10 @@ describe("Grok usage limits", () => { for (const response of [{}, { config: {} }, { config: { creditUsagePercent: NaN } }]) { const limits = grokUsageResponseToLimits(response, checkedAt); expect(limits.windows).toEqual([]); - expect(limits.unavailable?.reason).toBe("unsupported"); + // Nothing metered yet, which xAI reports by omitting the field until + // usage registers. Marking it `unsupported` would drop the account from + // the Limits view for good; leaving the marker off keeps it listed. + expect(limits.unavailable).toBeUndefined(); } expect( grokUsageResponseToLimits({ config: { creditUsagePercent: 0 } }, checkedAt).windows, diff --git a/apps/server/src/provider/Layers/grokUsageLimits.ts b/apps/server/src/provider/Layers/grokUsageLimits.ts index 8c3db6bea80b..60e76f260f8a 100644 --- a/apps/server/src/provider/Layers/grokUsageLimits.ts +++ b/apps/server/src/provider/Layers/grokUsageLimits.ts @@ -41,7 +41,15 @@ export function grokUsageResponseToLimits( ) { const usedPercent = response.config?.creditUsagePercent; if (usedPercent === undefined || !Number.isFinite(usedPercent)) { - return makeUnavailableUsageLimits({ checkedAt, reason: "unsupported" }); + // A billing read that succeeded but carries no percentage is an account + // with nothing metered yet, not one that can never report: xAI omits the + // field entirely (rather than sending 0) until usage registers, then fills + // it in. Calling that `unsupported` would strand the account — the Limits + // view drops unsupported entries and deliberately mutes their notice, so a + // freshly signed-in Grok account would vanish with no explanation until it + // happened to be used, and `applyUsageLimitsUpdate` would refuse the + // mid-turn windows that could have recovered it. + return makeUsageLimits({ checkedAt, windows: [] }); } const period = response.config?.currentPeriod; const periodType = period?.type?.replace(/^USAGE_PERIOD_TYPE_/, "");