mirror of
https://github.com/tiennm99/ccs.git
synced 2026-10-13 10:15:40 +00:00
fix(quota): return exhausted models with resetTime from API
- treat models with resetTime but null/missing remainingFraction as 0% - matches CLIProxy Management Center behavior - enables accurate Claude reset time display when quota exhausted - mark primary models at 0% as exhausted for red styling
This commit is contained in:
1 parent
a84cc036df
commit
e3920e0776
2 files changed
+21
-12
No files matched your search
@@ -494,15 +494,22 @@ async function fetchAvailableModels(accessToken: string, _projectId: string): Pr
|
|||||||
const remaining =
|
const remaining =
|
||||||
quotaInfo.remainingFraction ?? quotaInfo.remaining_fraction ?? quotaInfo.remaining;
|
quotaInfo.remainingFraction ?? quotaInfo.remaining_fraction ?? quotaInfo.remaining;
|
||||||
|
|
||||||
// Skip invalid values (NaN, Infinity, non-numbers)
|
|
||||||
if (typeof remaining !== 'number' || !isFinite(remaining)) continue;
|
|
||||||
|
|
||||||
// Convert to percentage (0-100) and clamp to valid range
|
|
||||||
const percentage = Math.max(0, Math.min(100, Math.round(remaining * 100)));
|
|
||||||
|
|
||||||
// Extract reset time
|
// Extract reset time
|
||||||
const resetTime = quotaInfo.resetTime || quotaInfo.reset_time || null;
|
const resetTime = quotaInfo.resetTime || quotaInfo.reset_time || null;
|
||||||
|
|
||||||
|
// If remaining is not a valid number but resetTime exists, treat as exhausted (0%)
|
||||||
|
// This happens when Claude models hit quota limit - API returns resetTime but no fraction
|
||||||
|
let percentage: number;
|
||||||
|
if (typeof remaining === 'number' && isFinite(remaining)) {
|
||||||
|
percentage = Math.max(0, Math.min(100, Math.round(remaining * 100)));
|
||||||
|
} else if (resetTime) {
|
||||||
|
// Model is exhausted but has reset time - show as 0%
|
||||||
|
percentage = 0;
|
||||||
|
} else {
|
||||||
|
// No valid data, skip this model
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
models.push({
|
models.push({
|
||||||
name: modelId,
|
name: modelId,
|
||||||
displayName: modelData.displayName,
|
displayName: modelData.displayName,
|
||||||
|
|||||||
+8
-6
@@ -174,8 +174,8 @@ export function getMinClaudeQuota<
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get reset time for Claude/GPT models (matches getMinClaudeQuota logic).
|
* Get reset time for Claude/GPT models (primary models).
|
||||||
* Falls back to earliest of all models if Claude/GPT not present (still need reset info).
|
* Returns null only if no primary models present in response.
|
||||||
*/
|
*/
|
||||||
export function getClaudeResetTime<
|
export function getClaudeResetTime<
|
||||||
T extends { name: string; displayName?: string; resetTime: string | null },
|
T extends { name: string; displayName?: string; resetTime: string | null },
|
||||||
@@ -183,10 +183,9 @@ export function getClaudeResetTime<
|
|||||||
if (models.length === 0) return null;
|
if (models.length === 0) return null;
|
||||||
|
|
||||||
const primaryModels = filterPrimaryModels(models);
|
const primaryModels = filterPrimaryModels(models);
|
||||||
// Fall back to all models for reset time (we need some reset info even if exhausted)
|
if (primaryModels.length === 0) return null;
|
||||||
const targetModels = primaryModels.length > 0 ? primaryModels : models;
|
|
||||||
|
|
||||||
return targetModels.reduce(
|
return primaryModels.reduce(
|
||||||
(earliest, m) => {
|
(earliest, m) => {
|
||||||
if (!m.resetTime) return earliest;
|
if (!m.resetTime) return earliest;
|
||||||
if (!earliest) return m.resetTime;
|
if (!earliest) return m.resetTime;
|
||||||
@@ -267,11 +266,14 @@ export function getModelsWithTiers<
|
|||||||
// Add all models with tier info
|
// Add all models with tier info
|
||||||
for (const m of models) {
|
for (const m of models) {
|
||||||
const displayName = m.displayName || m.name;
|
const displayName = m.displayName || m.name;
|
||||||
|
const tier = getModelTier(displayName);
|
||||||
result.push({
|
result.push({
|
||||||
name: m.name,
|
name: m.name,
|
||||||
displayName,
|
displayName,
|
||||||
percentage: m.percentage,
|
percentage: m.percentage,
|
||||||
tier: getModelTier(displayName),
|
tier,
|
||||||
|
// Mark primary models at 0% as exhausted for red styling
|
||||||
|
exhausted: tier === 'primary' && m.percentage === 0,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user