mirror of
https://github.com/tiennm99/ccs.git
synced 2026-09-02 16:19:27 +00:00
fix(agy): edge case handling for quota failover
- Fix formatQuotaBar crash on percentage > 100 or < 0 (clamp to 0-100) - Fix shared project accounts excluded from failover (same GCP project = pooled quota) - Fix division by zero in avgQuota when models array empty - Fix null account label fallback to 'Unknown Account'
This commit is contained in:
@@ -625,6 +625,10 @@ export async function findAvailableAccount(
|
|||||||
): Promise<{ account: AccountInfo; quota: QuotaResult } | null> {
|
): Promise<{ account: AccountInfo; quota: QuotaResult } | null> {
|
||||||
const allQuotas = await fetchAllProviderQuotas(provider);
|
const allQuotas = await fetchAllProviderQuotas(provider);
|
||||||
|
|
||||||
|
// Get excluded account's project ID to avoid switching to same-project accounts
|
||||||
|
const excludedProjectId = allQuotas.accounts.find((a) => a.account.id === excludeAccountId)?.quota
|
||||||
|
.projectId;
|
||||||
|
|
||||||
for (const { account, quota } of allQuotas.accounts) {
|
for (const { account, quota } of allQuotas.accounts) {
|
||||||
// Skip excluded account
|
// Skip excluded account
|
||||||
if (excludeAccountId && account.id === excludeAccountId) {
|
if (excludeAccountId && account.id === excludeAccountId) {
|
||||||
@@ -636,6 +640,11 @@ export async function findAvailableAccount(
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Skip accounts sharing same GCP project (quota is pooled)
|
||||||
|
if (excludedProjectId && quota.projectId === excludedProjectId) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// Check if any model has remaining quota (> 5% to avoid edge cases)
|
// Check if any model has remaining quota (> 5% to avoid edge cases)
|
||||||
const hasQuota = quota.models.some((m) => m.percentage > 5);
|
const hasQuota = quota.models.some((m) => m.percentage > 5);
|
||||||
if (hasQuota) {
|
if (hasQuota) {
|
||||||
|
|||||||
@@ -609,7 +609,7 @@ async function handleDoctor(): Promise<void> {
|
|||||||
|
|
||||||
// Display per-account quota status
|
// Display per-account quota status
|
||||||
for (const { account, quota } of quotaResult.accounts) {
|
for (const { account, quota } of quotaResult.accounts) {
|
||||||
const accountLabel = account.email || account.id;
|
const accountLabel = account.email || account.id || 'Unknown Account';
|
||||||
const defaultBadge = account.isDefault ? color(' (default)', 'info') : '';
|
const defaultBadge = account.isDefault ? color(' (default)', 'info') : '';
|
||||||
|
|
||||||
if (!quota.success) {
|
if (!quota.success) {
|
||||||
@@ -624,8 +624,11 @@ async function handleDoctor(): Promise<void> {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculate overall quota health
|
// Calculate overall quota health (guard against empty models array)
|
||||||
const avgQuota = quota.models.reduce((sum, m) => sum + m.percentage, 0) / quota.models.length;
|
const avgQuota =
|
||||||
|
quota.models.length > 0
|
||||||
|
? quota.models.reduce((sum, m) => sum + m.percentage, 0) / quota.models.length
|
||||||
|
: 0;
|
||||||
const statusIcon = avgQuota > 50 ? ok('') : avgQuota > 10 ? warn('') : fail('');
|
const statusIcon = avgQuota > 50 ? ok('') : avgQuota > 10 ? warn('') : fail('');
|
||||||
|
|
||||||
console.log(` ${statusIcon}${accountLabel}${defaultBadge}`);
|
console.log(` ${statusIcon}${accountLabel}${defaultBadge}`);
|
||||||
@@ -681,9 +684,10 @@ async function handleDoctor(): Promise<void> {
|
|||||||
|
|
||||||
function formatQuotaBar(percentage: number): string {
|
function formatQuotaBar(percentage: number): string {
|
||||||
const width = 20;
|
const width = 20;
|
||||||
const filled = Math.round((percentage / 100) * width);
|
const clampedPct = Math.max(0, Math.min(100, percentage));
|
||||||
|
const filled = Math.round((clampedPct / 100) * width);
|
||||||
const empty = width - filled;
|
const empty = width - filled;
|
||||||
const filledChar = percentage > 50 ? '█' : percentage > 10 ? '▓' : '░';
|
const filledChar = clampedPct > 50 ? '█' : clampedPct > 10 ? '▓' : '░';
|
||||||
return `[${filledChar.repeat(filled)}${' '.repeat(empty)}]`;
|
return `[${filledChar.repeat(filled)}${' '.repeat(empty)}]`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user