mirror of
https://github.com/fawney19/Aether.git
synced 2026-09-02 01:10:23 +08:00
Add provider key cycle stats reset handling
This commit is contained in:
@@ -136,7 +136,7 @@ fn classify_block_reason(reason: &str) -> (&'static str, &'static str) {
|
||||
.iter()
|
||||
.any(|keyword| lowered.contains(keyword))
|
||||
{
|
||||
return ("oauth_expired", "Token 失效");
|
||||
return ("oauth_token_invalid", "Token 失效");
|
||||
}
|
||||
if looks_like_account_verification(reason) {
|
||||
return ("account_verification", "需要验证");
|
||||
@@ -344,23 +344,23 @@ fn resolve_from_oauth_invalid_reason(reason: Option<&str>) -> Option<PoolAccount
|
||||
.unwrap_or_else(|| "OAuth Token 已过期且无法续期".to_string());
|
||||
return Some(PoolAccountState {
|
||||
blocked: true,
|
||||
code: Some("oauth_expired".to_string()),
|
||||
code: Some("oauth_token_invalid".to_string()),
|
||||
label: Some("Token 失效".to_string()),
|
||||
reason: Some(cleaned),
|
||||
source: Some("oauth_invalid".to_string()),
|
||||
recoverable: true,
|
||||
recoverable: false,
|
||||
});
|
||||
}
|
||||
if text.starts_with(OAUTH_REFRESH_FAILED_PREFIX) {
|
||||
let cleaned = clean_text(Some(text.trim_start_matches(OAUTH_REFRESH_FAILED_PREFIX)))
|
||||
.unwrap_or_else(|| "OAuth Token 续期失败".to_string());
|
||||
return Some(PoolAccountState {
|
||||
blocked: false,
|
||||
code: Some("oauth_refresh_failed".to_string()),
|
||||
label: Some("续期失败".to_string()),
|
||||
blocked: true,
|
||||
code: Some("oauth_token_invalid".to_string()),
|
||||
label: Some("Token 失效".to_string()),
|
||||
reason: Some(cleaned),
|
||||
source: Some("oauth_refresh".to_string()),
|
||||
recoverable: true,
|
||||
recoverable: false,
|
||||
});
|
||||
}
|
||||
if text.starts_with(OAUTH_REQUEST_FAILED_PREFIX) {
|
||||
@@ -446,6 +446,38 @@ pub fn resolve_account_status_snapshot(
|
||||
};
|
||||
}
|
||||
|
||||
if let Some(cleaned) = tagged_reason(&text, "OAUTH_EXPIRED") {
|
||||
let reason = if cleaned.is_empty() {
|
||||
"OAuth Token 已过期且无法续期".to_string()
|
||||
} else {
|
||||
cleaned
|
||||
};
|
||||
return AccountStatusSnapshot {
|
||||
code: "oauth_token_invalid".to_string(),
|
||||
label: Some("Token 失效".to_string()),
|
||||
reason: Some(reason),
|
||||
blocked: true,
|
||||
source: Some("oauth_invalid".to_string()),
|
||||
recoverable: false,
|
||||
};
|
||||
}
|
||||
|
||||
if let Some(cleaned) = tagged_reason(&text, "REFRESH_FAILED") {
|
||||
let reason = if cleaned.is_empty() {
|
||||
"OAuth Token 续期失败".to_string()
|
||||
} else {
|
||||
cleaned
|
||||
};
|
||||
return AccountStatusSnapshot {
|
||||
code: "oauth_token_invalid".to_string(),
|
||||
label: Some("Token 失效".to_string()),
|
||||
reason: Some(reason),
|
||||
blocked: true,
|
||||
source: Some("oauth_refresh".to_string()),
|
||||
recoverable: false,
|
||||
};
|
||||
}
|
||||
|
||||
if text.starts_with('[') {
|
||||
return AccountStatusSnapshot::default();
|
||||
}
|
||||
@@ -546,29 +578,46 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn resolves_refresh_failed_as_recoverable_pool_state() {
|
||||
fn resolves_refresh_failed_as_token_invalid_pool_state() {
|
||||
let state = resolve_pool_account_state(
|
||||
Some("codex"),
|
||||
None,
|
||||
Some("[REFRESH_FAILED] Token 续期失败 (401): refresh_token 已失效"),
|
||||
);
|
||||
|
||||
assert!(!state.blocked);
|
||||
assert!(state.recoverable);
|
||||
assert_eq!(state.code.as_deref(), Some("oauth_refresh_failed"));
|
||||
assert!(state.blocked);
|
||||
assert!(!state.recoverable);
|
||||
assert_eq!(state.code.as_deref(), Some("oauth_token_invalid"));
|
||||
assert_eq!(state.label.as_deref(), Some("Token 失效"));
|
||||
assert!(!should_auto_remove_account_state(&state));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn account_snapshot_ignores_refresh_failed_reason() {
|
||||
fn account_snapshot_marks_refresh_failed_as_token_invalid() {
|
||||
let snapshot = resolve_account_status_snapshot(
|
||||
Some("codex"),
|
||||
None,
|
||||
Some("[REFRESH_FAILED] Token 续期失败 (401): refresh_token 已失效"),
|
||||
);
|
||||
|
||||
assert_eq!(snapshot.code, "ok");
|
||||
assert!(!snapshot.blocked);
|
||||
assert_eq!(snapshot.code, "oauth_token_invalid");
|
||||
assert_eq!(snapshot.label.as_deref(), Some("Token 失效"));
|
||||
assert!(snapshot.blocked);
|
||||
assert!(!snapshot.recoverable);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn account_snapshot_marks_oauth_expired_as_token_invalid() {
|
||||
let snapshot = resolve_account_status_snapshot(
|
||||
Some("codex"),
|
||||
None,
|
||||
Some("[OAUTH_EXPIRED] Codex Token 无效或已过期 (401)"),
|
||||
);
|
||||
|
||||
assert_eq!(snapshot.code, "oauth_token_invalid");
|
||||
assert_eq!(snapshot.label.as_deref(), Some("Token 失效"));
|
||||
assert!(snapshot.blocked);
|
||||
assert!(!snapshot.recoverable);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -267,12 +267,16 @@ fn transport_key_allows_candidate_model(
|
||||
.mapping_matched_model
|
||||
.map(str::trim)
|
||||
.filter(|value| !value.is_empty());
|
||||
let requested_base_model = aether_ai_formats::model_directive_base_model(requested_model);
|
||||
|
||||
for allowed_model in allowed_models.iter().map(String::as_str).map(str::trim) {
|
||||
if allowed_model.is_empty() {
|
||||
continue;
|
||||
}
|
||||
if allowed_model == requested_model
|
||||
|| requested_base_model
|
||||
.as_deref()
|
||||
.is_some_and(|base_model| allowed_model == base_model)
|
||||
|| allowed_model == global_model_name
|
||||
|| allowed_model == selected_provider_model_name
|
||||
|| mapping_matched_model.is_some_and(|value| value == allowed_model)
|
||||
@@ -553,6 +557,26 @@ mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn candidate_common_transport_policy_allows_model_directive_base_model() {
|
||||
let mut transport = transport_snapshot("custom", "openai:responses", "bearer", true, None);
|
||||
transport.key.allowed_models = Some(vec!["gpt-5.5".to_string()]);
|
||||
|
||||
assert_eq!(
|
||||
candidate_common_transport_skip_reason(
|
||||
&transport,
|
||||
CandidateTransportPolicyFacts {
|
||||
endpoint_api_format: "openai:responses",
|
||||
global_model_name: "gpt-5",
|
||||
selected_provider_model_name: "provider-gpt-5",
|
||||
mapping_matched_model: None,
|
||||
},
|
||||
Some("gpt-5.5-xhigh"),
|
||||
),
|
||||
None
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fixed_provider_oauth_keys_inherit_endpoint_api_formats_for_candidate_policy() {
|
||||
let mut transport = transport_snapshot("codex", "openai:responses", "oauth", true, None);
|
||||
|
||||
Reference in New Issue
Block a user