mirror of
https://github.com/fawney19/Aether.git
synced 2026-09-02 09:20:22 +08:00
refactor ai serving modules and crates
This commit is contained in:
@@ -307,7 +307,7 @@ fn read_key_oauth_invalid_map(
|
||||
fn key_requires_oauth_reauth(
|
||||
key: &StoredProviderCatalogKey,
|
||||
provider_type: &str,
|
||||
now_unix_secs: u64,
|
||||
_now_unix_secs: u64,
|
||||
) -> bool {
|
||||
if !key.auth_type.trim().eq_ignore_ascii_case("oauth") {
|
||||
return false;
|
||||
@@ -319,46 +319,41 @@ fn key_requires_oauth_reauth(
|
||||
.map(str::trim)
|
||||
.unwrap_or_default();
|
||||
if !invalid_reason.is_empty() {
|
||||
return oauth_invalid_reason_requires_reauth(key, provider_type, invalid_reason);
|
||||
return oauth_invalid_reason_is_hard_account_block(key, provider_type, invalid_reason);
|
||||
}
|
||||
|
||||
key.expires_at_unix_secs
|
||||
.is_some_and(|value| value > 0 && value <= now_unix_secs)
|
||||
&& !kiro_key_has_refreshable_session(key, provider_type)
|
||||
false
|
||||
}
|
||||
|
||||
fn oauth_invalid_reason_requires_reauth(
|
||||
fn oauth_invalid_reason_is_hard_account_block(
|
||||
key: &StoredProviderCatalogKey,
|
||||
provider_type: &str,
|
||||
invalid_reason: &str,
|
||||
) -> bool {
|
||||
if invalid_reason.starts_with("[REQUEST_FAILED]") {
|
||||
return false;
|
||||
}
|
||||
let account_state = admin_provider_status_pure::resolve_pool_account_state(
|
||||
Some(provider_type),
|
||||
key.upstream_metadata.as_ref(),
|
||||
Some(invalid_reason),
|
||||
);
|
||||
if account_state.blocked && !account_state.recoverable {
|
||||
return true;
|
||||
}
|
||||
if invalid_reason.starts_with("[REFRESH_FAILED]")
|
||||
|| invalid_reason.starts_with("[ACCOUNT_BLOCK]")
|
||||
|| invalid_reason.starts_with("[OAUTH_EXPIRED]")
|
||||
{
|
||||
return true;
|
||||
}
|
||||
!kiro_key_has_refreshable_session(key, provider_type)
|
||||
account_state.blocked
|
||||
&& !account_state.recoverable
|
||||
&& account_state
|
||||
.code
|
||||
.as_deref()
|
||||
.is_some_and(oauth_account_state_code_is_hard_block)
|
||||
}
|
||||
|
||||
fn kiro_key_has_refreshable_session(key: &StoredProviderCatalogKey, provider_type: &str) -> bool {
|
||||
provider_type.trim().eq_ignore_ascii_case("kiro")
|
||||
&& key
|
||||
.encrypted_auth_config
|
||||
.as_deref()
|
||||
.map(str::trim)
|
||||
.is_some_and(|value| !value.is_empty())
|
||||
fn oauth_account_state_code_is_hard_block(code: &str) -> bool {
|
||||
matches!(
|
||||
code.trim().to_ascii_lowercase().as_str(),
|
||||
"account_banned"
|
||||
| "account_suspended"
|
||||
| "account_disabled"
|
||||
| "workspace_deactivated"
|
||||
| "account_forbidden"
|
||||
| "account_blocked"
|
||||
| "account_verification"
|
||||
)
|
||||
}
|
||||
|
||||
fn read_provider_key_rpm_reset_at_map(
|
||||
|
||||
@@ -100,7 +100,7 @@ async fn collect_selectable_candidates_with_skip_reasons(
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn skips_inactive_or_exhausted_monthly_quota_provider() {
|
||||
fn skips_only_exhausted_monthly_quota_provider() {
|
||||
let inactive = StoredProviderQuotaSnapshot::new(
|
||||
"provider-1".to_string(),
|
||||
"monthly_quota".to_string(),
|
||||
@@ -112,7 +112,20 @@ fn skips_inactive_or_exhausted_monthly_quota_provider() {
|
||||
false,
|
||||
)
|
||||
.expect("quota should build");
|
||||
assert!(should_skip_provider_quota(&inactive, 2_000));
|
||||
assert!(!should_skip_provider_quota(&inactive, 2_000));
|
||||
|
||||
let expired = StoredProviderQuotaSnapshot::new(
|
||||
"provider-1".to_string(),
|
||||
"monthly_quota".to_string(),
|
||||
Some(10.0),
|
||||
1.0,
|
||||
Some(30),
|
||||
Some(1_000),
|
||||
Some(1_500),
|
||||
true,
|
||||
)
|
||||
.expect("quota should build");
|
||||
assert!(!should_skip_provider_quota(&expired, 2_000));
|
||||
|
||||
let exhausted = StoredProviderQuotaSnapshot::new(
|
||||
"provider-1".to_string(),
|
||||
@@ -1242,7 +1255,7 @@ async fn skips_codex_candidate_when_account_quota_is_exhausted_and_pool_flag_ena
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn skips_oauth_invalid_candidate_before_local_auth_resolution() {
|
||||
async fn keeps_refresh_failed_oauth_candidate_selectable_before_local_auth_resolution() {
|
||||
let mut first = sample_row();
|
||||
first.provider_id = "provider-codex".to_string();
|
||||
first.provider_name = "codex".to_string();
|
||||
@@ -1312,11 +1325,10 @@ async fn skips_oauth_invalid_candidate_before_local_auth_resolution() {
|
||||
.await
|
||||
.expect("selection should succeed");
|
||||
|
||||
assert_eq!(selected.len(), 1);
|
||||
assert_eq!(selected[0].provider_id, "provider-openai");
|
||||
assert_eq!(skipped.len(), 1);
|
||||
assert_eq!(skipped[0].candidate.provider_id, "provider-codex");
|
||||
assert_eq!(skipped[0].skip_reason, "oauth_invalid");
|
||||
assert_eq!(selected.len(), 2);
|
||||
assert_eq!(selected[0].provider_id, "provider-codex");
|
||||
assert_eq!(selected[1].provider_id, "provider-openai");
|
||||
assert!(skipped.is_empty());
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
@@ -1378,6 +1390,65 @@ async fn keeps_request_failed_oauth_candidate_selectable() {
|
||||
assert!(skipped.is_empty());
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn keeps_codex_candidate_selectable_when_oauth_token_is_expired() {
|
||||
let mut row = sample_row();
|
||||
row.provider_id = "provider-codex".to_string();
|
||||
row.provider_name = "codex".to_string();
|
||||
row.provider_type = "codex".to_string();
|
||||
row.endpoint_id = "endpoint-codex".to_string();
|
||||
row.endpoint_api_format = "openai:responses".to_string();
|
||||
row.key_id = "key-codex".to_string();
|
||||
row.key_name = "codex-token-expired".to_string();
|
||||
row.key_auth_type = "oauth".to_string();
|
||||
row.key_api_formats = Some(vec!["openai:responses".to_string()]);
|
||||
|
||||
let candidates = Arc::new(InMemoryMinimalCandidateSelectionReadRepository::seed(vec![
|
||||
row,
|
||||
]));
|
||||
let mut provider = sample_provider("provider-codex", None);
|
||||
provider.provider_type = "codex".to_string();
|
||||
let provider_catalog = Arc::new(InMemoryProviderCatalogReadRepository::seed(
|
||||
vec![provider],
|
||||
Vec::new(),
|
||||
vec![{
|
||||
let mut key = sample_key("key-codex", "provider-codex", Some(10));
|
||||
key.auth_type = "oauth".to_string();
|
||||
key.oauth_invalid_at_unix_secs = Some(1_710_000_000);
|
||||
key.oauth_invalid_reason = Some("Codex Token 无效或已过期".to_string());
|
||||
key
|
||||
}],
|
||||
));
|
||||
let quotas = Arc::new(InMemoryProviderQuotaRepository::seed(vec![]));
|
||||
let request_candidates = Arc::new(InMemoryRequestCandidateRepository::seed(vec![]));
|
||||
let state = AppState::new()
|
||||
.expect("state should build")
|
||||
.with_data_state_for_tests(
|
||||
GatewayDataState::with_candidate_selection_provider_catalog_quota_and_request_candidates_for_tests(
|
||||
candidates,
|
||||
provider_catalog,
|
||||
quotas,
|
||||
request_candidates,
|
||||
),
|
||||
);
|
||||
|
||||
let (selected, skipped) = collect_selectable_candidates_with_skip_reasons(
|
||||
state.data.as_ref(),
|
||||
&state,
|
||||
"openai:responses",
|
||||
"gpt-4.1",
|
||||
false,
|
||||
None,
|
||||
1_710_000_100,
|
||||
)
|
||||
.await
|
||||
.expect("selection should succeed");
|
||||
|
||||
assert_eq!(selected.len(), 1);
|
||||
assert_eq!(selected[0].provider_id, "provider-codex");
|
||||
assert!(skipped.is_empty());
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn keeps_refreshable_kiro_candidate_selectable_with_runtime_oauth_invalid_marker() {
|
||||
let mut row = sample_row();
|
||||
@@ -1498,7 +1569,7 @@ async fn keeps_refreshable_kiro_candidate_selectable_when_oauth_token_expired()
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn skips_kiro_candidate_after_refresh_failure_requires_reauth() {
|
||||
async fn keeps_kiro_candidate_selectable_after_refresh_failure() {
|
||||
let mut row = sample_row();
|
||||
row.provider_id = "provider-kiro".to_string();
|
||||
row.provider_name = "kiro".to_string();
|
||||
@@ -1555,10 +1626,9 @@ async fn skips_kiro_candidate_after_refresh_failure_requires_reauth() {
|
||||
.await
|
||||
.expect("selection should succeed");
|
||||
|
||||
assert!(selected.is_empty());
|
||||
assert_eq!(skipped.len(), 1);
|
||||
assert_eq!(skipped[0].candidate.provider_id, "provider-kiro");
|
||||
assert_eq!(skipped[0].skip_reason, "oauth_invalid");
|
||||
assert_eq!(selected.len(), 1);
|
||||
assert_eq!(selected[0].provider_id, "provider-kiro");
|
||||
assert!(skipped.is_empty());
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
|
||||
Reference in New Issue
Block a user