fix: disable sub2api builtin temp unschedulable

This commit is contained in:
Codex
2026-06-11 15:44:53 +00:00
parent 5ba46f0dc3
commit 01b19d9238
4 changed files with 46 additions and 113 deletions
+24 -87
View File
@@ -1041,75 +1041,8 @@ function defaultCodexPoolConfig(): CodexPoolConfig {
export function defaultCodexTempUnschedulablePolicy(): CodexTempUnschedulablePolicy {
return {
enabled: true,
rules: [
{
statusCode: 400,
keywords: ["invalid_encrypted_content", "encrypted content", "could not be verified", "could not be decrypted", "bad_response_status_code", "model_not_found", "no available channel for model", "unsupported", "not supported", "not support", "暂不支持", "可用模型"],
durationMinutes: 120,
description: "Stable upstream 400 model-routing or Responses encrypted-content compatibility failures should use another account.",
},
{
statusCode: 401,
keywords: ["unauthorized", "invalid api key", "invalid_api_key", "authentication", "recovered upstream error"],
durationMinutes: 120,
description: "Credential/auth failures should use the longest cooldown.",
},
{
statusCode: 403,
keywords: ["forbidden", "access denied", "quota", "billing", "capacity", "weekly limit", "less than 10% of your weekly limit left", "run /status for a breakdown", "recovered upstream error"],
durationMinutes: 120,
description: "Permission, quota, or account-state failures should use the longest cooldown.",
},
{
statusCode: 429,
keywords: ["capacity", "rate limit", "rate_limit", "quota", "weekly limit", "less than 10% of your weekly limit left", "run /status for a breakdown", "too many requests", "overloaded", "resource_exhausted", "recovered upstream error"],
durationMinutes: 10,
description: "Capacity and rate-limit responses are often temporary; start with a ten-minute cooldown and use another account.",
},
{
statusCode: 500,
keywords: ["capacity", "overloaded", "temporarily unavailable", "temporary", "upstream", "recovered upstream error"],
durationMinutes: 10,
description: "Transient upstream server failures should start with a ten-minute cooldown and prefer another account.",
},
{
statusCode: 502,
keywords: ["capacity", "overloaded", "temporarily unavailable", "temporary", "upstream", "bad gateway", "upstream request failed", "unknown error", "context deadline exceeded", "context canceled", "websocket dial", "handshake response", "recovered upstream error"],
durationMinutes: 30,
description: "Gateway upstream failures, including recovered upstream error wrappers, should cool down longer.",
},
{
statusCode: 413,
keywords: ["openai_error", "payload too large", "request too large", "context length", "context window", "maximum context"],
durationMinutes: 30,
description: "Large-context upstream failures should cool down the selected account so a larger-context channel can handle the request.",
},
{
statusCode: 503,
keywords: ["capacity", "overloaded", "temporarily unavailable", "temporary", "upstream", "recovered upstream error", "model_not_found", "no available channel for model"],
durationMinutes: 30,
description: "Service unavailable and upstream model-routing failures should cool down longer than one-off transient failures.",
},
{
statusCode: 504,
keywords: ["gateway timeout", "timeout", "upstream", "upstream request failed", "unknown error", "context deadline exceeded", "context canceled", "recovered upstream error"],
durationMinutes: 30,
description: "Gateway timeout responses should cool down the selected account so another account can handle the next request.",
},
{
statusCode: 524,
keywords: ["timeout", "a timeout occurred", "cloudflare", "gateway timeout", "upstream", "upstream request failed", "unknown error", "context deadline exceeded", "context canceled", "recovered upstream error"],
durationMinutes: 30,
description: "Cloudflare 524 timeout responses should cool down the selected account so another account can handle the next request.",
},
{
statusCode: 529,
keywords: ["capacity", "overloaded", "temporarily unavailable", "temporary", "recovered upstream error"],
durationMinutes: 30,
description: "Provider overloaded responses should cool down longer than generic transient failures and use another account.",
},
],
enabled: false,
rules: [],
};
}
@@ -1542,8 +1475,8 @@ function compactProfile(profile: CodexProfile): Record<string, unknown> {
trustUpstream: profile.trustUpstream,
capacity: profile.capacity,
loadFactor: profile.loadFactor,
tempUnschedulableEnabled: profile.tempUnschedulable.enabled && profile.tempUnschedulable.rules.length > 0,
tempUnschedulableRuleCount: profile.tempUnschedulable.enabled ? profile.tempUnschedulable.rules.length : 0,
tempUnschedulableEnabled: profile.tempUnschedulable.enabled,
tempUnschedulableRuleCount: profile.tempUnschedulable.rules.length,
apiKeyPresent: profile.apiKey !== null && profile.apiKey.length > 0,
ok: profile.ok,
error: profile.error,
@@ -1552,24 +1485,23 @@ function compactProfile(profile: CodexProfile): Record<string, unknown> {
}
export function renderSub2ApiTempUnschedulableCredentials(policy: CodexTempUnschedulablePolicy): Record<string, unknown> {
if (!policy.enabled) return {};
return {
temp_unschedulable_enabled: policy.enabled && policy.rules.length > 0,
temp_unschedulable_rules: policy.enabled
? policy.rules.map((rule) => ({
error_code: rule.statusCode,
keywords: [...rule.keywords],
duration_minutes: rule.durationMinutes,
description: rule.description ?? "",
}))
: [],
temp_unschedulable_enabled: policy.enabled,
temp_unschedulable_rules: policy.rules.map((rule) => ({
error_code: rule.statusCode,
keywords: [...rule.keywords],
duration_minutes: rule.durationMinutes,
description: rule.description ?? "",
})),
};
}
function tempUnschedulableSummary(policy: CodexTempUnschedulablePolicy): Record<string, unknown> {
return {
enabled: policy.enabled && policy.rules.length > 0,
ruleCount: policy.enabled ? policy.rules.length : 0,
statusCodes: policy.enabled ? policy.rules.map((rule) => rule.statusCode) : [],
enabled: policy.enabled,
ruleCount: policy.rules.length,
statusCodes: policy.rules.map((rule) => rule.statusCode),
};
}
@@ -3711,8 +3643,9 @@ def account_payload(profile, group_id):
if upstream_user_agent:
credentials["user_agent"] = upstream_user_agent
temp_unschedulable = temp_unschedulable_credentials(profile)
credentials["temp_unschedulable_enabled"] = temp_unschedulable["enabled"]
credentials["temp_unschedulable_rules"] = temp_unschedulable["rules"]
if temp_unschedulable["enabled"]:
credentials["temp_unschedulable_enabled"] = True
credentials["temp_unschedulable_rules"] = temp_unschedulable["rules"]
return {
"name": profile["accountName"],
"notes": f"UniDesk-managed Codex profile {profile['profile']} from {profile['configFile']} and {profile['authFile']}; secret source={profile['apiKeySource']}; fingerprint={profile['apiKeyFingerprint']}.",
@@ -4803,8 +4736,8 @@ def normalize_temp_unschedulable_credentials(credentials):
"description": description,
})
return {
"enabled": enabled and len(rules) > 0,
"rules": rules if enabled else [],
"enabled": enabled,
"rules": rules,
}
def summarize_temp_unschedulable_rules(rules):
@@ -4819,6 +4752,8 @@ def summarize_temp_unschedulable_rules(rules):
def success_body_reclassification_requirement():
for name in sorted(EXPECTED_ACCOUNT_TEMP_UNSCHEDULABLE):
expected = normalize_temp_unschedulable_credentials(EXPECTED_ACCOUNT_TEMP_UNSCHEDULABLE[name])
if expected["enabled"] is not True:
continue
for rule in expected["rules"]:
error_code = rule.get("error_code")
keywords = rule.get("keywords") or []
@@ -4844,6 +4779,8 @@ def model_routing_400_failover_requirement():
preferred = ["暂不支持", "可用模型", "unsupported model", "model not supported", "does not support", "not supported", "model_not_found", "no available channel for model"]
for name in sorted(EXPECTED_ACCOUNT_TEMP_UNSCHEDULABLE):
expected = normalize_temp_unschedulable_credentials(EXPECTED_ACCOUNT_TEMP_UNSCHEDULABLE[name])
if expected["enabled"] is not True:
continue
for rule in expected["rules"]:
error_code = rule.get("error_code")
keywords = rule.get("keywords") or []