(apiKey, modelKey, ok, reason = '')
| 1477 | * reason: 'success' | 'model_error' | 'rate_limit' | 'transport_error' |
| 1478 | */ |
| 1479 | export function updateCapability(apiKey, modelKey, ok, reason = '') { |
| 1480 | const account = accounts.find(a => a.apiKey === apiKey); |
| 1481 | if (!account) return; |
| 1482 | if (!account.capabilities) account.capabilities = {}; |
| 1483 | // Don't overwrite a confirmed failure with a transient error |
| 1484 | if (reason === 'transport_error') return; |
| 1485 | // rate_limit is temporary — don't mark as permanently failed |
| 1486 | if (!ok && reason === 'rate_limit') return; |
| 1487 | account.capabilities[modelKey] = { |
| 1488 | ok, |
| 1489 | lastCheck: Date.now(), |
| 1490 | reason, |
| 1491 | }; |
| 1492 | if (ok && (account.tier === 'free' || account.tier === 'unknown')) { |
| 1493 | registerDiscoveredFreeModel(modelKey); |
| 1494 | } |
| 1495 | // Only infer tier when we have no authoritative source. GetUserStatus |
| 1496 | // (userStatusLastFetched) and manual override (tierManual) are both |
| 1497 | // authoritative; inferTier only looks at canary model capabilities and |
| 1498 | // would otherwise demote a Pro/Trial account back to 'free' as soon as |
| 1499 | // a non-premium model (e.g. gemini-2.5-flash, gpt-4o-mini) succeeds. |
| 1500 | if (!account.tierManual && !account.userStatusLastFetched) { |
| 1501 | account.tier = inferTier(account.capabilities); |
| 1502 | } |
| 1503 | saveAccounts(); |
| 1504 | } |
| 1505 | |
| 1506 | /** |
| 1507 | * Infer subscription tier from which canary models work. Fallback only — |
no test coverage detected