refactor: replace sync.Map credits state with AICredits rate limit key

Replace process-memory sync.Map + per-model runtime state with a single
"AICredits" key in model_rate_limits, making credits exhaustion fully
isomorphic with model-level rate limiting.

Scheduler: rate-limited accounts with overages enabled + credits available
are now scheduled instead of excluded.

Forwarding: when model is rate-limited + credits available, inject credits
proactively without waiting for a 429 round trip.

Storage: credits exhaustion stored as model_rate_limits["AICredits"] with
5h duration, reusing SetModelRateLimit/isRateLimitActiveForKey.

Frontend: show credits_active (yellow ) when model rate-limited but
credits available, credits_exhausted (red) when AICredits key active.

Tests: add unit tests for shouldMarkCreditsExhausted, injectEnabledCreditTypes,
clearCreditsExhausted, and update existing overages tests.
This commit is contained in:
erio
2026-03-16 04:31:22 +08:00
parent e14c87597a
commit 8a260defc2
12 changed files with 692 additions and 327 deletions

View File

@@ -403,6 +403,8 @@ export interface AdminGroup extends Group {
// MCP XML 协议注入(仅 antigravity 平台使用)
mcp_xml_inject: boolean
// Claude usage 模拟开关(仅 anthropic 平台使用)
simulate_claude_max_enabled: boolean
// 支持的模型系列(仅 antigravity 平台使用)
supported_model_scopes?: string[]
@@ -497,6 +499,7 @@ export interface CreateGroupRequest {
fallback_group_id?: number | null
fallback_group_id_on_invalid_request?: number | null
mcp_xml_inject?: boolean
simulate_claude_max_enabled?: boolean
supported_model_scopes?: string[]
// 从指定分组复制账号
copy_accounts_from_group_ids?: number[]
@@ -525,6 +528,7 @@ export interface UpdateGroupRequest {
fallback_group_id?: number | null
fallback_group_id_on_invalid_request?: number | null
mcp_xml_inject?: boolean
simulate_claude_max_enabled?: boolean
supported_model_scopes?: string[]
copy_accounts_from_group_ids?: number[]
}
@@ -664,7 +668,6 @@ export interface Account {
// Extra fields including Codex usage and model-level rate limits (Antigravity smart retry)
extra?: (CodexUsageSnapshot & {
model_rate_limits?: Record<string, { rate_limited_at: string; rate_limit_reset_at: string }>
antigravity_credits_overages?: Record<string, { activated_at: string; active_until: string }>
} & Record<string, unknown>)
proxy_id: number | null
concurrency: number
@@ -721,6 +724,12 @@ export interface Account {
cache_ttl_override_enabled?: boolean | null
cache_ttl_override_target?: string | null
// 客户端亲和调度(仅 Anthropic/Antigravity 平台有效)
// 启用后新会话会优先调度到客户端之前使用过的账号
client_affinity_enabled?: boolean | null
affinity_client_count?: number | null
affinity_clients?: string[] | null
// API Key 账号配额限制
quota_limit?: number | null
quota_used?: number | null