Add provider key cycle stats reset handling

This commit is contained in:
fawney19
2026-05-07 03:23:20 +08:00
parent 6c0ac2e8da
commit 10e679bb2f
35 changed files with 1443 additions and 273 deletions
@@ -322,7 +322,11 @@ fn admin_pool_codex_window_usage_bounds(
let reset_at = admin_pool_json_to_u64(window.get("reset_at"))?;
let window_minutes = admin_pool_json_to_u64(window.get("window_minutes"))?;
let window_seconds = window_minutes.checked_mul(60)?;
let start = reset_at.checked_sub(window_seconds)?;
let window_start = reset_at.checked_sub(window_seconds)?;
let usage_reset_at = admin_pool_json_to_u64(window.get("usage_reset_at"))
.filter(|reset_at_override| *reset_at_override < reset_at)
.unwrap_or(window_start);
let start = window_start.max(usage_reset_at);
(start < reset_at).then_some((start, reset_at))
}
@@ -1226,3 +1230,41 @@ pub(super) fn build_admin_pool_key_payload(
serde_json::Value::Object(payload)
}
#[cfg(test)]
mod tests {
use super::*;
use serde_json::json;
#[test]
fn codex_window_usage_bounds_honor_manual_usage_reset_at() {
let window = json!({
"code": "5h",
"reset_at": 20_000,
"window_minutes": 300,
"usage_reset_at": 9_000,
});
let window = window.as_object().expect("window object");
assert_eq!(
admin_pool_codex_window_usage_bounds(window),
Some((9_000, 20_000))
);
}
#[test]
fn codex_window_usage_bounds_ignore_reset_before_window_start() {
let window = json!({
"code": "weekly",
"reset_at": 700_000,
"window_minutes": 10_080,
"usage_reset_at": 1,
});
let window = window.as_object().expect("window object");
assert_eq!(
admin_pool_codex_window_usage_bounds(window),
Some((95_200, 700_000))
);
}
}
@@ -255,23 +255,34 @@ pub(super) async fn build_admin_pool_list_keys_response(
};
let codex_window_usage_requests =
pool_payloads::build_admin_pool_codex_window_usage_requests(&provider.provider_type, &keys);
let codex_window_usage_by_key: pool_payloads::AdminPoolCodexWindowUsageByKey =
if codex_window_usage_requests.is_empty() {
pool_payloads::AdminPoolCodexWindowUsageByKey::new()
} else {
state
.app()
.summarize_usage_by_provider_api_key_windows(&codex_window_usage_requests)
.await?
.into_iter()
.map(|usage| {
(
(usage.provider_api_key_id.clone(), usage.window_code.clone()),
usage,
)
})
.collect()
};
let mut codex_window_usage_by_key = codex_window_usage_requests
.iter()
.map(|request| {
(
(
request.provider_api_key_id.clone(),
request.window_code.clone(),
),
aether_data_contracts::repository::usage::StoredProviderApiKeyWindowUsageSummary {
provider_api_key_id: request.provider_api_key_id.clone(),
window_code: request.window_code.clone(),
..Default::default()
},
)
})
.collect::<pool_payloads::AdminPoolCodexWindowUsageByKey>();
if !codex_window_usage_requests.is_empty() {
for usage in state
.app()
.summarize_usage_by_provider_api_key_windows(&codex_window_usage_requests)
.await?
{
codex_window_usage_by_key.insert(
(usage.provider_api_key_id.clone(), usage.window_code.clone()),
usage,
);
}
}
let items = keys
.into_iter()
@@ -37,7 +37,7 @@ pub(crate) struct AdminPoolKeySort {
impl Default for AdminPoolKeySort {
fn default() -> Self {
Self {
field: AdminPoolKeySortField::Default,
field: AdminPoolKeySortField::ImportedAt,
direction: AdminPoolKeySortDirection::Desc,
}
}
@@ -117,7 +117,8 @@ pub(crate) fn parse_admin_pool_key_sort(query: Option<&str>) -> Result<AdminPool
.filter(|value| !value.is_empty())
.as_deref()
{
None | Some("default") | Some("name") => AdminPoolKeySortField::Default,
None | Some("default") => AdminPoolKeySortField::ImportedAt,
Some("name") => AdminPoolKeySortField::Default,
Some("imported_at") | Some("created_at") => AdminPoolKeySortField::ImportedAt,
Some("last_used_at") | Some("last_used") => AdminPoolKeySortField::LastUsedAt,
Some(_) => {