mirror of
https://github.com/router-for-me/Cli-Proxy-API-Management-Center.git
synced 2026-02-19 19:20:49 +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 rateLimit = payload.rate_limit ?? payload.rateLimit ?? undefined;
|
||||||
const codeReviewLimit = payload.code_review_rate_limit ?? payload.codeReviewRateLimit ?? undefined;
|
const codeReviewLimit = payload.code_review_rate_limit ?? payload.codeReviewRateLimit ?? undefined;
|
||||||
|
const additionalRateLimits = payload.additional_rate_limits ?? payload.additionalRateLimits ?? [];
|
||||||
const windows: CodexQuotaWindow[] = [];
|
const windows: CodexQuotaWindow[] = [];
|
||||||
|
|
||||||
const addWindow = (
|
const addWindow = (
|
||||||
id: string,
|
id: string,
|
||||||
labelKey: string,
|
label: string,
|
||||||
|
labelKey: string | undefined,
|
||||||
window?: CodexUsageWindow | null,
|
window?: CodexUsageWindow | null,
|
||||||
limitReached?: boolean,
|
limitReached?: boolean,
|
||||||
allowed?: boolean
|
allowed?: boolean
|
||||||
@@ -229,7 +231,7 @@ const buildCodexQuotaWindows = (payload: CodexUsagePayload, t: TFunction): Codex
|
|||||||
const usedPercent = usedPercentRaw ?? (isLimitReached && resetLabel !== '-' ? 100 : null);
|
const usedPercent = usedPercentRaw ?? (isLimitReached && resetLabel !== '-' ? 100 : null);
|
||||||
windows.push({
|
windows.push({
|
||||||
id,
|
id,
|
||||||
label: t(labelKey),
|
label,
|
||||||
labelKey,
|
labelKey,
|
||||||
usedPercent,
|
usedPercent,
|
||||||
resetLabel,
|
resetLabel,
|
||||||
@@ -247,10 +249,9 @@ const buildCodexQuotaWindows = (payload: CodexUsagePayload, t: TFunction): Codex
|
|||||||
const pickClassifiedWindows = (
|
const pickClassifiedWindows = (
|
||||||
limitInfo?: CodexRateLimitInfo | null
|
limitInfo?: CodexRateLimitInfo | null
|
||||||
): { fiveHourWindow: CodexUsageWindow | null; weeklyWindow: CodexUsageWindow | null } => {
|
): { fiveHourWindow: CodexUsageWindow | null; weeklyWindow: CodexUsageWindow | null } => {
|
||||||
const rawWindows = [
|
const primaryWindow = limitInfo?.primary_window ?? limitInfo?.primaryWindow ?? null;
|
||||||
limitInfo?.primary_window ?? limitInfo?.primaryWindow ?? null,
|
const secondaryWindow = limitInfo?.secondary_window ?? limitInfo?.secondaryWindow ?? null;
|
||||||
limitInfo?.secondary_window ?? limitInfo?.secondaryWindow ?? null,
|
const rawWindows = [primaryWindow, secondaryWindow];
|
||||||
];
|
|
||||||
|
|
||||||
let fiveHourWindow: CodexUsageWindow | null = null;
|
let fiveHourWindow: CodexUsageWindow | null = null;
|
||||||
let weeklyWindow: 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 };
|
return { fiveHourWindow, weeklyWindow };
|
||||||
};
|
};
|
||||||
|
|
||||||
const rateWindows = pickClassifiedWindows(rateLimit);
|
const rateWindows = pickClassifiedWindows(rateLimit);
|
||||||
addWindow(
|
addWindow(
|
||||||
WINDOW_META.codeFiveHour.id,
|
WINDOW_META.codeFiveHour.id,
|
||||||
|
t(WINDOW_META.codeFiveHour.labelKey),
|
||||||
WINDOW_META.codeFiveHour.labelKey,
|
WINDOW_META.codeFiveHour.labelKey,
|
||||||
rateWindows.fiveHourWindow,
|
rateWindows.fiveHourWindow,
|
||||||
rawLimitReached,
|
rawLimitReached,
|
||||||
@@ -278,6 +288,7 @@ const buildCodexQuotaWindows = (payload: CodexUsagePayload, t: TFunction): Codex
|
|||||||
);
|
);
|
||||||
addWindow(
|
addWindow(
|
||||||
WINDOW_META.codeWeekly.id,
|
WINDOW_META.codeWeekly.id,
|
||||||
|
t(WINDOW_META.codeWeekly.labelKey),
|
||||||
WINDOW_META.codeWeekly.labelKey,
|
WINDOW_META.codeWeekly.labelKey,
|
||||||
rateWindows.weeklyWindow,
|
rateWindows.weeklyWindow,
|
||||||
rawLimitReached,
|
rawLimitReached,
|
||||||
@@ -289,6 +300,7 @@ const buildCodexQuotaWindows = (payload: CodexUsagePayload, t: TFunction): Codex
|
|||||||
const codeReviewAllowed = codeReviewLimit?.allowed;
|
const codeReviewAllowed = codeReviewLimit?.allowed;
|
||||||
addWindow(
|
addWindow(
|
||||||
WINDOW_META.codeReviewFiveHour.id,
|
WINDOW_META.codeReviewFiveHour.id,
|
||||||
|
t(WINDOW_META.codeReviewFiveHour.labelKey),
|
||||||
WINDOW_META.codeReviewFiveHour.labelKey,
|
WINDOW_META.codeReviewFiveHour.labelKey,
|
||||||
codeReviewWindows.fiveHourWindow,
|
codeReviewWindows.fiveHourWindow,
|
||||||
codeReviewLimitReached,
|
codeReviewLimitReached,
|
||||||
@@ -296,12 +308,54 @@ const buildCodexQuotaWindows = (payload: CodexUsagePayload, t: TFunction): Codex
|
|||||||
);
|
);
|
||||||
addWindow(
|
addWindow(
|
||||||
WINDOW_META.codeReviewWeekly.id,
|
WINDOW_META.codeReviewWeekly.id,
|
||||||
|
t(WINDOW_META.codeReviewWeekly.labelKey),
|
||||||
WINDOW_META.codeReviewWeekly.labelKey,
|
WINDOW_META.codeReviewWeekly.labelKey,
|
||||||
codeReviewWindows.weeklyWindow,
|
codeReviewWindows.weeklyWindow,
|
||||||
codeReviewLimitReached,
|
codeReviewLimitReached,
|
||||||
codeReviewAllowed
|
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;
|
return windows;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -490,6 +490,8 @@
|
|||||||
"secondary_window": "Weekly limit",
|
"secondary_window": "Weekly limit",
|
||||||
"code_review_primary_window": "Code review 5-hour limit",
|
"code_review_primary_window": "Code review 5-hour limit",
|
||||||
"code_review_secondary_window": "Code review weekly 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_label": "Plan",
|
||||||
"plan_plus": "Plus",
|
"plan_plus": "Plus",
|
||||||
"plan_team": "Team",
|
"plan_team": "Team",
|
||||||
|
|||||||
@@ -493,6 +493,8 @@
|
|||||||
"secondary_window": "Недельный лимит",
|
"secondary_window": "Недельный лимит",
|
||||||
"code_review_primary_window": "Лимит code review на 5 часов",
|
"code_review_primary_window": "Лимит code review на 5 часов",
|
||||||
"code_review_secondary_window": "Недельный лимит code review",
|
"code_review_secondary_window": "Недельный лимит code review",
|
||||||
|
"additional_primary_window": "{{name}}: лимит на 5 часов",
|
||||||
|
"additional_secondary_window": "{{name}}: недельный лимит",
|
||||||
"plan_label": "Тариф",
|
"plan_label": "Тариф",
|
||||||
"plan_plus": "Plus",
|
"plan_plus": "Plus",
|
||||||
"plan_team": "Team",
|
"plan_team": "Team",
|
||||||
|
|||||||
@@ -490,6 +490,8 @@
|
|||||||
"secondary_window": "周限额",
|
"secondary_window": "周限额",
|
||||||
"code_review_primary_window": "代码审查 5 小时限额",
|
"code_review_primary_window": "代码审查 5 小时限额",
|
||||||
"code_review_secondary_window": "代码审查周限额",
|
"code_review_secondary_window": "代码审查周限额",
|
||||||
|
"additional_primary_window": "{{name}} 5 小时限额",
|
||||||
|
"additional_secondary_window": "{{name}} 周限额",
|
||||||
"plan_label": "套餐",
|
"plan_label": "套餐",
|
||||||
"plan_plus": "Plus",
|
"plan_plus": "Plus",
|
||||||
"plan_team": "Team",
|
"plan_team": "Team",
|
||||||
|
|||||||
@@ -88,6 +88,15 @@ export interface CodexRateLimitInfo {
|
|||||||
secondaryWindow?: CodexUsageWindow | null;
|
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 {
|
export interface CodexUsagePayload {
|
||||||
plan_type?: string;
|
plan_type?: string;
|
||||||
planType?: string;
|
planType?: string;
|
||||||
@@ -95,6 +104,8 @@ export interface CodexUsagePayload {
|
|||||||
rateLimit?: CodexRateLimitInfo | null;
|
rateLimit?: CodexRateLimitInfo | null;
|
||||||
code_review_rate_limit?: CodexRateLimitInfo | null;
|
code_review_rate_limit?: CodexRateLimitInfo | null;
|
||||||
codeReviewRateLimit?: CodexRateLimitInfo | null;
|
codeReviewRateLimit?: CodexRateLimitInfo | null;
|
||||||
|
additional_rate_limits?: CodexAdditionalRateLimit[] | null;
|
||||||
|
additionalRateLimits?: CodexAdditionalRateLimit[] | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Claude API payload types
|
// Claude API payload types
|
||||||
|
|||||||
Reference in New Issue
Block a user