feat(resilience): add provider peak-hour protection (#11622)

Merged via /merge-batch (lote 2026-08-26 batch 2, v3.8.51). Boarded no worktree combinado junto com outras ~20 PRs; validação única: typecheck/complexity/cognitive-complexity/changelog-integrity verdes, file-size rebaseado onde necessário (crescimento legítimo), lint com os mesmos 228 achados pré-existentes confirmados via sonda contra o tip puro (não introduzidos por este lote), e 292 testes focados (unit) + 18 (vitest) passando. Obrigado pela contribuição.
This commit is contained in:
Mr White
2026-08-26 20:21:59 +08:00
committed by GitHub
parent 0481f61750
commit c11f661a8a
8 changed files with 689 additions and 13 deletions

View File

@@ -3093,11 +3093,6 @@
"count": 1
}
},
"src/sse/services/auth.ts": {
"@typescript-eslint/no-unused-vars": {
"count": 1
}
},
"src/sse/services/model.ts": {
"no-restricted-imports": {
"count": 2

View File

@@ -0,0 +1,247 @@
"use client";
import { Button, Input, Select, Toggle } from "@/shared/components";
import {
PEAK_HOUR_PROTECTION_DAYS,
type PeakHourProtectionConfig,
type PeakHourProtectionDay,
type PeakHourProtectionMode,
type PeakHourWindow,
} from "@/lib/providers/peakHourProtection";
import { providerText, type ProviderMessageTranslator } from "../providerPageHelpers";
export const EMPTY_PEAK_HOUR_PROTECTION: PeakHourProtectionConfig = {
enabled: false,
mode: "block",
windows: [],
};
const DAY_LABELS: Record<PeakHourProtectionDay, string> = {
mon: "Mon",
tue: "Tue",
wed: "Wed",
thu: "Thu",
fri: "Fri",
sat: "Sat",
sun: "Sun",
};
function cloneConfig(value: unknown): PeakHourProtectionConfig {
if (!value || typeof value !== "object" || Array.isArray(value)) {
return { ...EMPTY_PEAK_HOUR_PROTECTION, windows: [] };
}
const record = value as Record<string, unknown>;
const mode: PeakHourProtectionMode = record.mode === "avoid" ? "avoid" : "block";
const windows = Array.isArray(record.windows)
? record.windows
.filter((entry): entry is PeakHourWindow => !!entry && typeof entry === "object")
.map((entry) => ({
id: typeof entry.id === "string" ? entry.id : crypto.randomUUID(),
name: typeof entry.name === "string" ? entry.name : "",
days: Array.isArray(entry.days)
? entry.days.filter((day): day is PeakHourProtectionDay =>
(PEAK_HOUR_PROTECTION_DAYS as readonly string[]).includes(day)
)
: [],
startUtc: typeof entry.startUtc === "string" ? entry.startUtc : "06:00",
endUtc: typeof entry.endUtc === "string" ? entry.endUtc : "10:00",
}))
: [];
return { enabled: record.enabled === true, mode, windows };
}
function newWindow(): PeakHourWindow {
return { id: crypto.randomUUID(), name: "", days: [], startUtc: "06:00", endUtc: "10:00" };
}
function weekdayWindow(startUtc: string, endUtc: string): PeakHourWindow {
return {
id: crypto.randomUUID(),
name: "Weekday peak",
days: ["mon", "tue", "wed", "thu", "fri"],
startUtc,
endUtc,
};
}
export function normalizePeakHourProtectionForSave(
value: PeakHourProtectionConfig
): PeakHourProtectionConfig | null {
const windows = value.windows
.map((window) => ({
...(window.name?.trim() ? { name: window.name.trim() } : {}),
...(window.days && window.days.length > 0 ? { days: window.days } : {}),
startUtc: window.startUtc,
endUtc: window.endUtc,
}))
.filter(
(window) => /^\d{2}:\d{2}$/.test(window.startUtc) && /^\d{2}:\d{2}$/.test(window.endUtc)
);
if (!value.enabled && windows.length === 0) return null;
return { enabled: value.enabled, mode: value.mode, windows };
}
export function formatPeakHourSummary(value: unknown): string | null {
const config = cloneConfig(value);
if (!config.enabled || config.windows.length === 0) return null;
const mode = config.mode === "avoid" ? "Avoid" : "Block";
return `${mode} during ${config.windows.length} peak window${config.windows.length === 1 ? "" : "s"}`;
}
export default function PeakHourProtectionEditor({
value,
onChange,
t,
}: {
value: PeakHourProtectionConfig;
onChange: (next: PeakHourProtectionConfig) => void;
t: ProviderMessageTranslator;
}) {
const updateWindow = (id: string | undefined, patch: Partial<PeakHourWindow>) => {
onChange({
...value,
windows: value.windows.map((window) => (window.id === id ? { ...window, ...patch } : window)),
});
};
const toggleDay = (window: PeakHourWindow, day: PeakHourProtectionDay) => {
const days = new Set(window.days || []);
if (days.has(day)) days.delete(day);
else days.add(day);
updateWindow(window.id, { days: Array.from(days) });
};
const applyPreset = (provider: "deepseek" | "zai") => {
const windows =
provider === "deepseek"
? [weekdayWindow("01:00", "04:00"), weekdayWindow("06:00", "10:00")]
: [{ ...newWindow(), name: "Daily peak", startUtc: "06:00", endUtc: "10:00" }];
onChange({ enabled: true, mode: value.mode, windows });
};
return (
<div className="flex flex-col gap-4 rounded-lg border border-amber-500/30 bg-amber-500/5 p-4">
<Toggle
checked={value.enabled}
onChange={(enabled) => onChange({ ...value, enabled })}
label={providerText(t, "peakHourProtectionLabel", "Peak-hour protection")}
description={providerText(
t,
"peakHourProtectionDescription",
"Block this connection during configured UTC peak-hour windows. This avoids uncertain peak multipliers instead of trying to price them."
)}
/>
<Select
label={providerText(t, "peakHourProtectionModeLabel", "Protection mode")}
value={value.mode}
options={[
{
value: "block",
label: providerText(t, "peakHourProtectionModeBlock", "Block requests"),
},
{
value: "avoid",
label: providerText(t, "peakHourProtectionModeAvoid", "Avoid in routing"),
},
]}
onChange={(event) =>
onChange({ ...value, mode: event.target.value === "avoid" ? "avoid" : "block" })
}
hint={providerText(
t,
"peakHourProtectionModeHint",
"Direct requests fail while active; combo/auto routing skips protected connections when alternatives exist."
)}
/>
<div className="flex flex-wrap gap-2">
<Button size="sm" variant="secondary" onClick={() => applyPreset("deepseek")}>
{providerText(t, "peakHourDeepSeekPreset", "Use DeepSeek preset")}
</Button>
<Button size="sm" variant="secondary" onClick={() => applyPreset("zai")}>
{providerText(t, "peakHourZaiPreset", "Use Z.ai preset")}
</Button>
<Button
size="sm"
variant="secondary"
icon="add"
onClick={() => onChange({ ...value, windows: [...value.windows, newWindow()] })}
>
{providerText(t, "peakHourAddWindow", "Add window")}
</Button>
</div>
<div className="flex flex-col gap-3">
{value.windows.length === 0 ? (
<p className="text-xs text-text-muted">
{providerText(t, "peakHourNoWindows", "No peak-hour windows configured.")}
</p>
) : (
value.windows.map((window) => (
<div key={window.id} className="rounded-lg border border-border/70 bg-surface/50 p-3">
<div className="mb-3 flex items-center justify-between gap-2">
<Input
label={providerText(t, "peakHourWindowName", "Window name")}
value={window.name || ""}
onChange={(event) => updateWindow(window.id, { name: event.target.value })}
placeholder={providerText(
t,
"peakHourWindowNamePlaceholder",
"e.g. weekday peak"
)}
/>
<Button
size="sm"
variant="ghost"
icon="delete"
onClick={() =>
onChange({
...value,
windows: value.windows.filter((entry) => entry.id !== window.id),
})
}
/>
</div>
<div className="grid grid-cols-1 gap-3 sm:grid-cols-2">
<Input
label={providerText(t, "peakHourStartUtc", "Start UTC")}
type="time"
value={window.startUtc}
onChange={(event) => updateWindow(window.id, { startUtc: event.target.value })}
/>
<Input
label={providerText(t, "peakHourEndUtc", "End UTC")}
type="time"
value={window.endUtc}
onChange={(event) => updateWindow(window.id, { endUtc: event.target.value })}
/>
</div>
<div className="mt-3">
<p className="mb-2 text-xs font-medium text-text-muted">
{providerText(t, "peakHourDays", "Days (empty = every day)")}
</p>
<div className="flex flex-wrap gap-1.5">
{PEAK_HOUR_PROTECTION_DAYS.map((day) => {
const active = (window.days || []).includes(day);
return (
<button
type="button"
key={day}
onClick={() => toggleDay(window, day)}
className={`rounded-full px-2 py-1 text-xs font-medium transition-colors ${
active
? "bg-amber-500 text-white"
: "bg-muted/60 text-text-muted hover:bg-muted"
}`}
>
{DAY_LABELS[day]}
</button>
);
})}
</div>
</div>
</div>
))
)}
</div>
</div>
);
}

View File

@@ -59,6 +59,12 @@ import AgentrouterConsoleFields from "./AgentrouterConsoleFields";
import QuotaScrapingFields, { EMPTY_QUOTA_SCRAPING_FIELDS } from "./QuotaScrapingFields";
import GlmTeamQuotaFields, { EMPTY_GLM_TEAM_QUOTA_FIELDS } from "./GlmTeamQuotaFields";
import ProviderRegionField, { getProviderRegionConfig } from "./AlibabaProviderRegionField";
import PeakHourProtectionEditor, {
EMPTY_PEAK_HOUR_PROTECTION,
formatPeakHourSummary,
normalizePeakHourProtectionForSave,
} from "../PeakHourProtectionEditor";
import type { PeakHourProtectionConfig } from "@/lib/providers/peakHourProtection";
export interface EditConnectionModalConnection {
id?: string;
name?: string;
@@ -154,6 +160,7 @@ export default function EditConnectionModal({
runtimeKey: "",
connectorName: stringField(connectionProviderSpecificData?.connectorName) || "OmniRoute Codex",
m365Tier: normalizeM365TierValue(connectionProviderSpecificData?.tier) as M365TierValue,
peakHourProtection: { ...EMPTY_PEAK_HOUR_PROTECTION, windows: [] } as PeakHourProtectionConfig,
});
const [testing, setTesting] = useState(false);
const [testResult, setTestResult] = useState(null);
@@ -391,6 +398,22 @@ export default function EditConnectionModal({
connectorName:
stringField(connection.providerSpecificData?.connectorName) || "OmniRoute Codex",
m365Tier: normalizeM365TierValue(connection.providerSpecificData?.tier) as M365TierValue,
peakHourProtection: {
...EMPTY_PEAK_HOUR_PROTECTION,
...((connection.providerSpecificData?.peakHourProtection as PeakHourProtectionConfig) ||
{}),
windows: Array.isArray(
(
connection.providerSpecificData?.peakHourProtection as
PeakHourProtectionConfig | undefined
)?.windows
)
? [
...(connection.providerSpecificData?.peakHourProtection as PeakHourProtectionConfig)
.windows,
]
: [],
},
});
const existing = connection.providerSpecificData?.extraApiKeys;
setExtraApiKeys(Array.isArray(existing) ? existing : []);
@@ -699,6 +722,9 @@ export default function EditConnectionModal({
}
if (updates.providerSpecificData) {
updates.providerSpecificData.disableCooling = formData.disableCooling ? true : undefined;
updates.providerSpecificData.peakHourProtection = normalizePeakHourProtectionForSave(
formData.peakHourProtection
);
// Explicit `null`, not `undefined`: the PUT route merges
// { ...existing, ...incoming }, so omitting the key would keep the previous
// choice and switching back to the default would never take effect.
@@ -844,6 +870,16 @@ export default function EditConnectionModal({
label={t("disableCoolingLabel")}
description={t("disableCoolingDescription")}
/>
<PeakHourProtectionEditor
value={formData.peakHourProtection}
onChange={(peakHourProtection) => setFormData({ ...formData, peakHourProtection })}
t={t}
/>
{formatPeakHourSummary(formData.peakHourProtection) && (
<p className="text-xs text-text-muted">
{formatPeakHourSummary(formData.peakHourProtection)}
</p>
)}
</div>
<QuotaScrapingFields
provider={provider}

View File

@@ -0,0 +1,165 @@
export const PEAK_HOUR_PROTECTION_MODES = ["block", "avoid"] as const;
export const PEAK_HOUR_PROTECTION_DAYS = ["mon", "tue", "wed", "thu", "fri", "sat", "sun"] as const;
export type PeakHourProtectionMode = (typeof PEAK_HOUR_PROTECTION_MODES)[number];
export type PeakHourProtectionDay = (typeof PEAK_HOUR_PROTECTION_DAYS)[number];
export type PeakHourWindow = {
id?: string;
name?: string;
days?: PeakHourProtectionDay[];
startUtc: string;
endUtc: string;
};
export type PeakHourProtectionConfig = {
enabled: boolean;
mode: PeakHourProtectionMode;
windows: PeakHourWindow[];
};
export type ActivePeakHourProtection = {
active: true;
mode: PeakHourProtectionMode;
retryAfter: string;
retryAfterSeconds: number;
window: PeakHourWindow;
};
export type InactivePeakHourProtection = { active: false };
export type PeakHourProtectionState = ActivePeakHourProtection | InactivePeakHourProtection;
type JsonRecord = Record<string, unknown>;
const DAY_BY_UTC_INDEX: PeakHourProtectionDay[] = ["sun", "mon", "tue", "wed", "thu", "fri", "sat"];
const MINUTES_PER_DAY = 24 * 60;
const MAX_WINDOWS = 16;
function asRecord(value: unknown): JsonRecord {
return value && typeof value === "object" && !Array.isArray(value) ? (value as JsonRecord) : {};
}
function parseUtcTimeMinutes(value: unknown): number | null {
if (typeof value !== "string") return null;
const match = value.trim().match(/^(\d{1,2}):(\d{2})$/);
if (!match) return null;
const hour = Number(match[1]);
const minute = Number(match[2]);
if (!Number.isInteger(hour) || !Number.isInteger(minute)) return null;
if (hour < 0 || hour > 23 || minute < 0 || minute > 59) return null;
return hour * 60 + minute;
}
function formatUtcTimeMinutes(minutes: number): string {
const normalized = ((minutes % MINUTES_PER_DAY) + MINUTES_PER_DAY) % MINUTES_PER_DAY;
const hour = Math.floor(normalized / 60);
const minute = normalized % 60;
return `${String(hour).padStart(2, "0")}:${String(minute).padStart(2, "0")}`;
}
function normalizeDays(value: unknown): PeakHourProtectionDay[] | undefined {
if (!Array.isArray(value)) return undefined;
const days = value
.map((day) => (typeof day === "string" ? day.trim().toLowerCase() : ""))
.filter((day): day is PeakHourProtectionDay =>
(PEAK_HOUR_PROTECTION_DAYS as readonly string[]).includes(day)
);
const unique = Array.from(new Set(days));
return unique.length > 0 ? unique : undefined;
}
export function normalizePeakHourProtection(value: unknown): PeakHourProtectionConfig | null {
const record = asRecord(value);
const rawWindows = Array.isArray(record.windows) ? record.windows : [];
const windows: PeakHourWindow[] = [];
for (const entry of rawWindows.slice(0, MAX_WINDOWS)) {
const window = asRecord(entry);
const start = parseUtcTimeMinutes(window.startUtc);
const end = parseUtcTimeMinutes(window.endUtc);
if (start === null || end === null || start === end) continue;
windows.push({
...(typeof window.id === "string" && window.id.trim()
? { id: window.id.trim().slice(0, 80) }
: {}),
...(typeof window.name === "string" && window.name.trim()
? { name: window.name.trim().slice(0, 120) }
: {}),
...(normalizeDays(window.days) ? { days: normalizeDays(window.days) } : {}),
startUtc: formatUtcTimeMinutes(start),
endUtc: formatUtcTimeMinutes(end),
});
}
const enabled = record.enabled === true;
const mode = record.mode === "avoid" ? "avoid" : "block";
if (!enabled && windows.length === 0) return null;
return { enabled, mode, windows };
}
export function getPeakHourProtectionConfig(
providerSpecificData: unknown
): PeakHourProtectionConfig | null {
return normalizePeakHourProtection(asRecord(providerSpecificData).peakHourProtection);
}
function isDayAllowed(window: PeakHourWindow, date: Date): boolean {
if (!window.days || window.days.length === 0) return true;
return window.days.includes(DAY_BY_UTC_INDEX[date.getUTCDay()]);
}
function windowActiveAt(window: PeakHourWindow, date: Date): boolean {
if (!isDayAllowed(window, date)) return false;
const start = parseUtcTimeMinutes(window.startUtc);
const end = parseUtcTimeMinutes(window.endUtc);
if (start === null || end === null || start === end) return false;
const now = date.getUTCHours() * 60 + date.getUTCMinutes();
return start < end ? now >= start && now < end : now >= start || now < end;
}
function nextWindowEndMs(window: PeakHourWindow, date: Date): number | null {
const start = parseUtcTimeMinutes(window.startUtc);
const end = parseUtcTimeMinutes(window.endUtc);
if (start === null || end === null || start === end) return null;
const midnight = Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate());
const now = date.getUTCHours() * 60 + date.getUTCMinutes();
let endDayOffset = 0;
if (start > end && now >= start) endDayOffset = 1;
return midnight + (endDayOffset * MINUTES_PER_DAY + end) * 60_000;
}
export function evaluatePeakHourProtection(
providerSpecificData: unknown,
now: Date = new Date()
): PeakHourProtectionState {
const config = getPeakHourProtectionConfig(providerSpecificData);
if (!config?.enabled || config.windows.length === 0) return { active: false };
const active = config.windows
.filter((window) => windowActiveAt(window, now))
.map((window) => ({ window, endMs: nextWindowEndMs(window, now) }))
.filter(
(entry): entry is { window: PeakHourWindow; endMs: number } =>
typeof entry.endMs === "number" &&
Number.isFinite(entry.endMs) &&
entry.endMs > now.getTime()
)
.sort((a, b) => a.endMs - b.endMs)[0];
if (!active) return { active: false };
const retryAfterSeconds = Math.max(1, Math.ceil((active.endMs - now.getTime()) / 1000));
return {
active: true,
mode: config.mode,
retryAfter: new Date(active.endMs).toISOString(),
retryAfterSeconds,
window: active.window,
};
}
export function describePeakHourWindow(window: PeakHourWindow): string {
const name = window.name ? `${window.name} ` : "";
const days = window.days && window.days.length > 0 ? `${window.days.join(",")} ` : "daily ";
return `${name}${days}${window.startUtc}-${window.endUtc} UTC`.trim();
}

View File

@@ -5,6 +5,7 @@ import { normalizeExcludedModelPatterns } from "@/domain/connectionModelRules";
import { normalizeRoutingTags } from "@/domain/tagRouter";
import { normalizeOpenRouterPreset } from "@/shared/constants/openRouterPreset";
import { isForbiddenCustomHeaderName } from "@/shared/constants/upstreamHeaders";
import { normalizePeakHourProtection } from "@/lib/providers/peakHourProtection";
export const CODEX_REASONING_EFFORT_VALUES = [
"none",
@@ -214,6 +215,15 @@ export function normalizeProviderSpecificData(
delete normalized.disableCooling;
}
if ("peakHourProtection" in normalized) {
const peakHourProtection = normalizePeakHourProtection(normalized.peakHourProtection);
if (peakHourProtection) {
normalized.peakHourProtection = peakHourProtection;
} else {
delete normalized.peakHourProtection;
}
}
if ("autoFetchModels" in normalized && typeof normalized.autoFetchModels !== "boolean") {
delete normalized.autoFetchModels;
}

View File

@@ -17,10 +17,81 @@ const CODEX_REASONING_EFFORT_VALUES = new Set(["none", "low", "medium", "high",
const REQUEST_DEFAULT_SERVICE_TIER_VALUES = new Set(["default", "priority", "fast", "flex"]);
const CODEX_FINGERPRINT_MODE_VALUES = new Set(["off", "device", "session", "full"]);
const CACHE_PASSTHROUGH_VALUES = new Set(["strip", "openai-format", "claude-format"]);
const PEAK_HOUR_PROTECTION_MODES = new Set(["block", "avoid"]);
const PEAK_HOUR_PROTECTION_DAYS = new Set(["mon", "tue", "wed", "thu", "fri", "sat", "sun"]);
export const MAX_PROVIDER_SPECIFIC_TIMEOUT_MS = 86_400_000; // 24h — operator cap, anti-DoS
// #6880 — per-connection prompt-cache capability override, extracted so
// validateProviderSpecificData() stays under the complexity gate.
function validatePeakHourProtectionBlock(value: unknown, ctx: z.RefinementCtx): void {
if (!value || typeof value !== "object" || Array.isArray(value)) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message: "providerSpecificData.peakHourProtection must be an object",
path: ["peakHourProtection"],
});
return;
}
const record = value as Record<string, unknown>;
if (record.enabled !== undefined && typeof record.enabled !== "boolean") {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message: "providerSpecificData.peakHourProtection.enabled must be a boolean",
path: ["peakHourProtection", "enabled"],
});
}
if (record.mode !== undefined && !PEAK_HOUR_PROTECTION_MODES.has(String(record.mode))) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message: "providerSpecificData.peakHourProtection.mode must be block or avoid",
path: ["peakHourProtection", "mode"],
});
}
if (!Array.isArray(record.windows)) return;
if (record.windows.length > 16) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message: "providerSpecificData.peakHourProtection.windows supports at most 16 windows",
path: ["peakHourProtection", "windows"],
});
}
record.windows.slice(0, 16).forEach((window, index) => {
if (!window || typeof window !== "object" || Array.isArray(window)) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message: "peak-hour windows must be objects",
path: ["peakHourProtection", "windows", index],
});
return;
}
const entry = window as Record<string, unknown>;
for (const key of ["startUtc", "endUtc"] as const) {
if (typeof entry[key] !== "string" || !/^\d{1,2}:\d{2}$/.test(entry[key])) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message: `providerSpecificData.peakHourProtection.windows.${key} must be HH:MM UTC`,
path: ["peakHourProtection", "windows", index, key],
});
}
}
if (entry.days !== undefined) {
if (!Array.isArray(entry.days)) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message: "providerSpecificData.peakHourProtection.windows.days must be an array",
path: ["peakHourProtection", "windows", index, "days"],
});
} else if (entry.days.some((day) => !PEAK_HOUR_PROTECTION_DAYS.has(String(day)))) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message: "providerSpecificData.peakHourProtection.windows.days contains an invalid day",
path: ["peakHourProtection", "windows", index, "days"],
});
}
}
});
}
function validateCacheBlock(data: Record<string, unknown>, ctx: z.RefinementCtx): void {
const cache = data.cache;
if (cache === undefined) return;
@@ -188,6 +259,11 @@ export function validateProviderSpecificData(
});
}
const peakHourProtection = data.peakHourProtection;
if (peakHourProtection !== undefined && peakHourProtection !== null) {
validatePeakHourProtectionBlock(peakHourProtection, ctx);
}
const autoFetchModels = data.autoFetchModels;
if (autoFetchModels !== undefined && typeof autoFetchModels !== "boolean") {
ctx.addIssue({

View File

@@ -25,6 +25,10 @@ import {
type ExclusiveConnectionLease,
} from "@/lib/db/exclusiveConnectionLeases";
import { getSettings } from "@/lib/db/settings";
import {
describePeakHourWindow,
evaluatePeakHourProtection,
} from "@/lib/providers/peakHourProtection";
import { buildJinaEnvCredentials } from "@/lib/providers/jina";
import { buildGeminiEnvCredentials } from "@/lib/providers/gemini";
import { toNumber } from "@/shared/utils/numeric";
@@ -208,11 +212,6 @@ function asRecord(value: unknown): JsonRecord {
function toStringOrNull(value: unknown): string | null {
return typeof value === "string" && value.trim().length > 0 ? value : null;
}
function toNullableNumber(value: unknown): number | null {
if (value === null || value === undefined) return null;
const parsed = toNumber(value, Number.NaN);
return Number.isFinite(parsed) ? parsed : null;
}
function toBooleanOrDefault(value: unknown, fallback: boolean): boolean {
return typeof value === "boolean" ? value : fallback;
}
@@ -886,6 +885,32 @@ function formatConnectionPrefixesForLog(ids: Iterable<string>, max = 6): string
.map((id) => `${id.slice(0, 8)}...`);
return prefixes.length > 0 ? prefixes.join(",") : "none";
}
function buildPeakHourProtectionRateLimitedResult(
provider: string,
blockedByPeakHour: Array<{
id: string;
retryAfter: string;
windowSummary: string;
}>
) {
const retryAfter =
getEarliestFutureDate(blockedByPeakHour.map((entry) => entry.retryAfter)) ||
new Date(Date.now() + 5 * 60 * 1000).toISOString();
const blockedSummary = blockedByPeakHour
.map((entry) => `${entry.id.slice(0, 8)}(${entry.windowSummary})`)
.join("; ");
log.info("AUTH", `${provider} | peak-hour protection filtered account(s): ${blockedSummary}`);
return {
allRateLimited: true,
retryAfter,
retryAfterHuman: formatRetryAfter(retryAfter),
lastError: `All ${provider} accounts blocked by peak-hour protection`,
lastErrorCode: 429,
};
}
function buildQuotaPreflightRateLimitedResult(
provider: string,
blockedByPreflight: Array<{
@@ -1743,7 +1768,38 @@ export async function getProviderCredentials(
return null;
}
let policyEligibleConnections = availableConnections;
let peakHourEligibleConnections = availableConnections;
const blockedByPeakHour: Array<{ id: string; retryAfter: string; windowSummary: string }> = [];
if (!allowSuppressedConnections) {
peakHourEligibleConnections = availableConnections.filter((connection) => {
const peakHour = evaluatePeakHourProtection(connection.providerSpecificData);
if (!peakHour.active) return true;
blockedByPeakHour.push({
id: connection.id,
retryAfter: peakHour.retryAfter,
windowSummary: describePeakHourWindow(peakHour.window),
});
connectionFilterStatus.set(connection.id, "peakHourProtected");
return false;
});
}
if (blockedByPeakHour.length > 0) {
log.info(
"AUTH",
`${provider} | peak-hour protection filtered ${blockedByPeakHour.length} account(s): ${blockedByPeakHour
.map((entry) => `${entry.id.slice(0, 8)}(${entry.windowSummary})`)
.join("; ")}`
);
}
if (peakHourEligibleConnections.length === 0 && availableConnections.length > 0) {
invalidateManagedLease(options, "QUOTA_UNAVAILABLE");
return buildPeakHourProtectionRateLimitedResult(provider, blockedByPeakHour);
}
let policyEligibleConnections = peakHourEligibleConnections;
const blockedByPolicy: Array<{
id: string;
reasons: string[];
@@ -1752,13 +1808,13 @@ export async function getProviderCredentials(
const quotaResults = new Map<string, { blocked: boolean; exhausted: boolean }>();
if (provider === "codex") {
for (const connection of availableConnections) {
for (const connection of peakHourEligibleConnections) {
hydrateCodexQuotaCacheForRequest(connection, requestedModel);
}
}
if (!bypassQuotaPolicy) {
policyEligibleConnections = availableConnections.filter((connection) => {
policyEligibleConnections = peakHourEligibleConnections.filter((connection) => {
const evaluation = evaluateQuotaLimitPolicy(provider, connection, requestedModel);
quotaResults.set(connection.id, { blocked: evaluation.blocked, exhausted: false });
if (!evaluation.blocked) return true;

View File

@@ -0,0 +1,91 @@
import assert from "node:assert/strict";
import test from "node:test";
import {
describePeakHourWindow,
evaluatePeakHourProtection,
normalizePeakHourProtection,
} from "../../src/lib/providers/peakHourProtection.ts";
test("peak-hour protection activates inside weekday UTC windows", () => {
const state = evaluatePeakHourProtection(
{
peakHourProtection: {
enabled: true,
mode: "block",
windows: [
{
days: ["mon", "tue", "wed", "thu", "fri"],
startUtc: "01:00",
endUtc: "04:00",
},
],
},
},
new Date("2026-08-24T01:30:00.000Z")
);
assert.equal(state.active, true);
assert.equal(state.mode, "block");
assert.equal(state.retryAfter, "2026-08-24T04:00:00.000Z");
assert.equal(state.retryAfterSeconds, 9000);
});
test("peak-hour protection honors weekdays and end boundary", () => {
const providerSpecificData = {
peakHourProtection: {
enabled: true,
windows: [
{
days: ["mon", "tue", "wed", "thu", "fri"],
startUtc: "06:00",
endUtc: "10:00",
},
],
},
};
assert.deepEqual(
evaluatePeakHourProtection(providerSpecificData, new Date("2026-08-22T06:30:00.000Z")),
{ active: false }
);
assert.deepEqual(
evaluatePeakHourProtection(providerSpecificData, new Date("2026-08-24T10:00:00.000Z")),
{ active: false }
);
});
test("peak-hour protection supports daily Z.ai-style windows", () => {
const state = evaluatePeakHourProtection(
{
peakHourProtection: {
enabled: true,
mode: "avoid",
windows: [{ name: "Z.ai peak", startUtc: "06:00", endUtc: "10:00" }],
},
},
new Date("2026-08-23T06:30:00.000Z")
);
assert.equal(state.active, true);
assert.equal(state.mode, "avoid");
assert.equal(describePeakHourWindow(state.window), "Z.ai peak daily 06:00-10:00 UTC");
});
test("normalizer drops malformed windows but keeps operator intent", () => {
assert.deepEqual(
normalizePeakHourProtection({
enabled: true,
mode: "avoid",
windows: [
{ startUtc: "bad", endUtc: "10:00" },
{ days: ["mon", "nope", "mon"], startUtc: "6:00", endUtc: "10:00" },
],
}),
{
enabled: true,
mode: "avoid",
windows: [{ days: ["mon"], startUtc: "06:00", endUtc: "10:00" }],
}
);
});