mirror of
https://github.com/router-for-me/Cli-Proxy-API-Management-Center.git
synced 2026-02-18 02:30:51 +08:00
feat(quota): support dynamic codex additional limits with i18n
This commit is contained in:
@@ -213,11 +213,13 @@ const buildCodexQuotaWindows = (payload: CodexUsagePayload, t: TFunction): Codex
|
||||
|
||||
const rateLimit = payload.rate_limit ?? payload.rateLimit ?? undefined;
|
||||
const codeReviewLimit = payload.code_review_rate_limit ?? payload.codeReviewRateLimit ?? undefined;
|
||||
const additionalRateLimits = payload.additional_rate_limits ?? payload.additionalRateLimits ?? [];
|
||||
const windows: CodexQuotaWindow[] = [];
|
||||
|
||||
const addWindow = (
|
||||
id: string,
|
||||
labelKey: string,
|
||||
label: string,
|
||||
labelKey: string | undefined,
|
||||
window?: CodexUsageWindow | null,
|
||||
limitReached?: boolean,
|
||||
allowed?: boolean
|
||||
@@ -229,7 +231,7 @@ const buildCodexQuotaWindows = (payload: CodexUsagePayload, t: TFunction): Codex
|
||||
const usedPercent = usedPercentRaw ?? (isLimitReached && resetLabel !== '-' ? 100 : null);
|
||||
windows.push({
|
||||
id,
|
||||
label: t(labelKey),
|
||||
label,
|
||||
labelKey,
|
||||
usedPercent,
|
||||
resetLabel,
|
||||
@@ -247,10 +249,9 @@ const buildCodexQuotaWindows = (payload: CodexUsagePayload, t: TFunction): Codex
|
||||
const pickClassifiedWindows = (
|
||||
limitInfo?: CodexRateLimitInfo | null
|
||||
): { fiveHourWindow: CodexUsageWindow | null; weeklyWindow: CodexUsageWindow | null } => {
|
||||
const rawWindows = [
|
||||
limitInfo?.primary_window ?? limitInfo?.primaryWindow ?? null,
|
||||
limitInfo?.secondary_window ?? limitInfo?.secondaryWindow ?? null,
|
||||
];
|
||||
const primaryWindow = limitInfo?.primary_window ?? limitInfo?.primaryWindow ?? null;
|
||||
const secondaryWindow = limitInfo?.secondary_window ?? limitInfo?.secondaryWindow ?? null;
|
||||
const rawWindows = [primaryWindow, secondaryWindow];
|
||||
|
||||
let fiveHourWindow: CodexUsageWindow | null = null;
|
||||
let weeklyWindow: CodexUsageWindow | null = null;
|
||||
@@ -265,12 +266,21 @@ const buildCodexQuotaWindows = (payload: CodexUsagePayload, t: TFunction): Codex
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback to primary/secondary semantics when window seconds are missing or unknown.
|
||||
if (!fiveHourWindow) {
|
||||
fiveHourWindow = primaryWindow && primaryWindow !== weeklyWindow ? primaryWindow : null;
|
||||
}
|
||||
if (!weeklyWindow) {
|
||||
weeklyWindow = secondaryWindow && secondaryWindow !== fiveHourWindow ? secondaryWindow : null;
|
||||
}
|
||||
|
||||
return { fiveHourWindow, weeklyWindow };
|
||||
};
|
||||
|
||||
const rateWindows = pickClassifiedWindows(rateLimit);
|
||||
addWindow(
|
||||
WINDOW_META.codeFiveHour.id,
|
||||
t(WINDOW_META.codeFiveHour.labelKey),
|
||||
WINDOW_META.codeFiveHour.labelKey,
|
||||
rateWindows.fiveHourWindow,
|
||||
rawLimitReached,
|
||||
@@ -278,6 +288,7 @@ const buildCodexQuotaWindows = (payload: CodexUsagePayload, t: TFunction): Codex
|
||||
);
|
||||
addWindow(
|
||||
WINDOW_META.codeWeekly.id,
|
||||
t(WINDOW_META.codeWeekly.labelKey),
|
||||
WINDOW_META.codeWeekly.labelKey,
|
||||
rateWindows.weeklyWindow,
|
||||
rawLimitReached,
|
||||
@@ -289,6 +300,7 @@ const buildCodexQuotaWindows = (payload: CodexUsagePayload, t: TFunction): Codex
|
||||
const codeReviewAllowed = codeReviewLimit?.allowed;
|
||||
addWindow(
|
||||
WINDOW_META.codeReviewFiveHour.id,
|
||||
t(WINDOW_META.codeReviewFiveHour.labelKey),
|
||||
WINDOW_META.codeReviewFiveHour.labelKey,
|
||||
codeReviewWindows.fiveHourWindow,
|
||||
codeReviewLimitReached,
|
||||
@@ -296,12 +308,54 @@ const buildCodexQuotaWindows = (payload: CodexUsagePayload, t: TFunction): Codex
|
||||
);
|
||||
addWindow(
|
||||
WINDOW_META.codeReviewWeekly.id,
|
||||
t(WINDOW_META.codeReviewWeekly.labelKey),
|
||||
WINDOW_META.codeReviewWeekly.labelKey,
|
||||
codeReviewWindows.weeklyWindow,
|
||||
codeReviewLimitReached,
|
||||
codeReviewAllowed
|
||||
);
|
||||
|
||||
const normalizeWindowId = (raw: string) =>
|
||||
raw
|
||||
.trim()
|
||||
.toLowerCase()
|
||||
.replace(/[^a-z0-9]+/g, '-')
|
||||
.replace(/^-+|-+$/g, '');
|
||||
|
||||
if (Array.isArray(additionalRateLimits)) {
|
||||
additionalRateLimits.forEach((limitItem, index) => {
|
||||
const rateInfo = limitItem?.rate_limit ?? limitItem?.rateLimit ?? null;
|
||||
if (!rateInfo) return;
|
||||
|
||||
const limitName =
|
||||
normalizeStringValue(limitItem?.limit_name ?? limitItem?.limitName) ??
|
||||
normalizeStringValue(limitItem?.metered_feature ?? limitItem?.meteredFeature) ??
|
||||
`additional-${index + 1}`;
|
||||
|
||||
const idPrefix = normalizeWindowId(limitName) || `additional-${index + 1}`;
|
||||
const additionalWindows = pickClassifiedWindows(rateInfo);
|
||||
const additionalLimitReached = rateInfo.limit_reached ?? rateInfo.limitReached;
|
||||
const additionalAllowed = rateInfo.allowed;
|
||||
|
||||
addWindow(
|
||||
`${idPrefix}-five-hour-${index}`,
|
||||
t('codex_quota.additional_primary_window', { name: limitName }),
|
||||
undefined,
|
||||
additionalWindows.fiveHourWindow,
|
||||
additionalLimitReached,
|
||||
additionalAllowed
|
||||
);
|
||||
addWindow(
|
||||
`${idPrefix}-weekly-${index}`,
|
||||
t('codex_quota.additional_secondary_window', { name: limitName }),
|
||||
undefined,
|
||||
additionalWindows.weeklyWindow,
|
||||
additionalLimitReached,
|
||||
additionalAllowed
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
return windows;
|
||||
};
|
||||
|
||||
|
||||
@@ -490,6 +490,8 @@
|
||||
"secondary_window": "Weekly limit",
|
||||
"code_review_primary_window": "Code review 5-hour limit",
|
||||
"code_review_secondary_window": "Code review weekly limit",
|
||||
"additional_primary_window": "{{name}} 5-hour limit",
|
||||
"additional_secondary_window": "{{name}} weekly limit",
|
||||
"plan_label": "Plan",
|
||||
"plan_plus": "Plus",
|
||||
"plan_team": "Team",
|
||||
|
||||
@@ -493,6 +493,8 @@
|
||||
"secondary_window": "Недельный лимит",
|
||||
"code_review_primary_window": "Лимит code review на 5 часов",
|
||||
"code_review_secondary_window": "Недельный лимит code review",
|
||||
"additional_primary_window": "{{name}}: лимит на 5 часов",
|
||||
"additional_secondary_window": "{{name}}: недельный лимит",
|
||||
"plan_label": "Тариф",
|
||||
"plan_plus": "Plus",
|
||||
"plan_team": "Team",
|
||||
|
||||
@@ -490,6 +490,8 @@
|
||||
"secondary_window": "周限额",
|
||||
"code_review_primary_window": "代码审查 5 小时限额",
|
||||
"code_review_secondary_window": "代码审查周限额",
|
||||
"additional_primary_window": "{{name}} 5 小时限额",
|
||||
"additional_secondary_window": "{{name}} 周限额",
|
||||
"plan_label": "套餐",
|
||||
"plan_plus": "Plus",
|
||||
"plan_team": "Team",
|
||||
|
||||
@@ -88,6 +88,15 @@ export interface CodexRateLimitInfo {
|
||||
secondaryWindow?: CodexUsageWindow | null;
|
||||
}
|
||||
|
||||
export interface CodexAdditionalRateLimit {
|
||||
limit_name?: string;
|
||||
limitName?: string;
|
||||
metered_feature?: string;
|
||||
meteredFeature?: string;
|
||||
rate_limit?: CodexRateLimitInfo | null;
|
||||
rateLimit?: CodexRateLimitInfo | null;
|
||||
}
|
||||
|
||||
export interface CodexUsagePayload {
|
||||
plan_type?: string;
|
||||
planType?: string;
|
||||
@@ -95,6 +104,8 @@ export interface CodexUsagePayload {
|
||||
rateLimit?: CodexRateLimitInfo | null;
|
||||
code_review_rate_limit?: CodexRateLimitInfo | null;
|
||||
codeReviewRateLimit?: CodexRateLimitInfo | null;
|
||||
additional_rate_limits?: CodexAdditionalRateLimit[] | null;
|
||||
additionalRateLimits?: CodexAdditionalRateLimit[] | null;
|
||||
}
|
||||
|
||||
// Claude API payload types
|
||||
|
||||
Reference in New Issue
Block a user