From 633e225ea0ea817b3b7c8f367fac2442ed282eb7 Mon Sep 17 00:00:00 2001 From: aict666 Date: Fri, 24 Apr 2026 08:04:56 +0800 Subject: [PATCH] fix(auth): don't demote Pro/Trial tier to 'free' after each chat call updateCapability() ran inferTier() unconditionally after every request, which overwrites the authoritative tier set by GetUserStatus / refreshCredits. When a Pro or 14-day Trial account called a non-premium model such as gemini-2.5-flash or gpt-4o-mini, inferTier() saw only that ok=true and returned 'free', so the dashboard showed the account as FREE right after a successful request. probeAccount() already worked around this by restoring status.tierName at the end, but the chat handler path (handlers/chat.js) had no such restore, so every real API call silently demoted the tier. Skip the inferTier() fallback when an authoritative source is present (userStatusLastFetched > 0, or tierManual=true). The fallback still runs for brand-new accounts that have never been probed. --- src/auth.js | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/auth.js b/src/auth.js index 2bcf577..d86306c 100644 --- a/src/auth.js +++ b/src/auth.js @@ -739,7 +739,14 @@ export function updateCapability(apiKey, modelKey, ok, reason = '') { if (ok && (account.tier === 'free' || account.tier === 'unknown')) { registerDiscoveredFreeModel(modelKey); } - account.tier = inferTier(account.capabilities); + // Only infer tier when we have no authoritative source. GetUserStatus + // (userStatusLastFetched) and manual override (tierManual) are both + // authoritative; inferTier only looks at canary model capabilities and + // would otherwise demote a Pro/Trial account back to 'free' as soon as + // a non-premium model (e.g. gemini-2.5-flash, gpt-4o-mini) succeeds. + if (!account.tierManual && !account.userStatusLastFetched) { + account.tier = inferTier(account.capabilities); + } saveAccounts(); }