mirror of
https://github.com/fawney19/Aether.git
synced 2026-09-01 17:00:21 +08:00
fix: codex free accounts incorrectly marked as quota exhausted (#366)
* fix: codex free accounts incorrectly marked as quota exhausted when skip_exhausted_accounts enabled - Cross-validate stored exhausted flag against window used_ratio in snapshot reader - Guard has_credits:false check with window data presence in upstream_metadata fallback - Add windows.is_empty() precondition to exhausted_by_credits in snapshot builder Free codex accounts have has_credits:false (they use window-based quotas, not credits), but the old logic treated this as credits depleted, skipping actual window usage checks. This caused all free accounts to be incorrectly marked exhausted. * test: cover codex free quota windows --------- Co-authored-by: root <root@ser488556369540.local> Co-authored-by: fawney19 <elky0401@gmail.com>
This commit is contained in:
@@ -627,7 +627,7 @@ fn build_codex_quota_status_snapshot(
|
||||
.min();
|
||||
let reset_at = quota_windows_min_reset_at(&windows);
|
||||
let exhausted_by_credits =
|
||||
credits_unlimited != Some(true) && credits_has_credits == Some(false);
|
||||
windows.is_empty() && credits_unlimited != Some(true) && credits_has_credits == Some(false);
|
||||
let exhausted_by_window = usage_ratio.is_some_and(|value| value >= 1.0 - 1e-6);
|
||||
let exhausted = exhausted_by_credits || exhausted_by_window;
|
||||
|
||||
@@ -1655,6 +1655,45 @@ mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn provider_key_status_snapshot_payload_keeps_codex_free_window_quota_available() {
|
||||
let mut key = sample_catalog_key();
|
||||
key.upstream_metadata = Some(json!({
|
||||
"codex": {
|
||||
"updated_at": 1_775_553_285u64,
|
||||
"plan_type": "free",
|
||||
"primary_used_percent": 64.0,
|
||||
"primary_reset_at": 1_900_000_000u64,
|
||||
"secondary_used_percent": 3.0,
|
||||
"secondary_reset_at": 1_900_500_000u64,
|
||||
"has_credits": false,
|
||||
"credits_balance": 0.0,
|
||||
"credits_unlimited": false
|
||||
}
|
||||
}));
|
||||
|
||||
let payload = provider_key_status_snapshot_payload(&key, "codex");
|
||||
let quota = payload
|
||||
.get("quota")
|
||||
.and_then(Value::as_object)
|
||||
.expect("quota snapshot should be object");
|
||||
|
||||
assert_eq!(quota.get("code"), Some(&json!("ok")));
|
||||
assert_eq!(quota.get("exhausted"), Some(&json!(false)));
|
||||
assert_eq!(quota.get("usage_ratio"), Some(&json!(0.64)));
|
||||
assert_eq!(
|
||||
quota
|
||||
.get("credits")
|
||||
.and_then(Value::as_object)
|
||||
.and_then(|credits| credits.get("has_credits")),
|
||||
Some(&json!(false))
|
||||
);
|
||||
assert_eq!(
|
||||
quota.get("windows").and_then(Value::as_array).map(Vec::len),
|
||||
Some(2usize)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn provider_key_status_snapshot_payload_derives_codex_reset_at_from_countdown() {
|
||||
let mut key = sample_catalog_key();
|
||||
|
||||
@@ -1779,7 +1779,7 @@ async fn gateway_prefers_status_snapshot_codex_quota_over_stale_metadata() {
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn gateway_shows_codex_quota_reset_for_exhausted_zero_usage_snapshot() {
|
||||
async fn gateway_treats_stale_codex_exhausted_snapshot_as_available_when_windows_have_capacity() {
|
||||
let mut provider = sample_provider("provider-codex", "codex", 10).with_transport_fields(
|
||||
true,
|
||||
false,
|
||||
@@ -1881,11 +1881,8 @@ async fn gateway_shows_codex_quota_reset_for_exhausted_zero_usage_snapshot() {
|
||||
.expect("json body should parse");
|
||||
let keys = payload["keys"].as_array().expect("keys should be array");
|
||||
|
||||
assert_eq!(keys[0]["scheduling_status"], json!("blocked"));
|
||||
assert_eq!(
|
||||
keys[0]["scheduling_reason"],
|
||||
json!("account_quota_exhausted")
|
||||
);
|
||||
assert_eq!(keys[0]["scheduling_status"], json!("available"));
|
||||
assert_eq!(keys[0]["scheduling_reason"], json!("available"));
|
||||
assert_eq!(
|
||||
keys[0]["account_quota"],
|
||||
json!("周剩余 100.0% (7天0小时后重置) | 5H剩余 100.0% (5小时0分钟后重置)")
|
||||
|
||||
Reference in New Issue
Block a user